Sign up here and you can log into the forum!

fast linksheet script

Everything (else) to do with Movie Sheets and homebrew firmware on the WDTV(s), including how the %*#^ do I get them working?

fast linksheet script   

Postby Chris Bone » Sun Jan 22, 2012 12:30 pm

Hi Guys:

Been reviewing the linksheet script and have got an impressive speed win by replacing calls to basename/dirname/grep with bash string manipulation... about 4x over all... but now I don't know what to do... stuck trying to install it on my box as the regular linksheet script because I'm confused by the read-only nature of the /usr mount... and the second point of confusion is how I submit these changes back to the maintainers... yeah, it's a fine line between n00b and guru sometimes.

Cheers
Chris
Chris Bone
n00b
 
Posts: 14
Joined: Fri Nov 04, 2011 4:43 am

Re: fast linksheet script   

Postby recliq » Sun Jan 22, 2012 2:00 pm

To get a r/w system use the Ext3-Boot version of the firmware.
And the magic programm you are searching for regarding submitting changes is: diff
­WDLXTV Project Maintainer
-:] If you like my contributions feel free to donate for a beer or a new flash drive. ...and always remember: RTFM! (README, FAQ, WIKI) [:-
User avatar
recliq
WDLXTV Team
 
Posts: 5513
Joined: Thu Apr 15, 2010 8:09 am
Location: Kiel, Germany

Re: fast linksheet script   

Postby KAD » Sun Jan 22, 2012 2:20 pm

and if you want to have recliq or b-rad review and possibly include in future versions,

I'd just post the contents here in code tags
If you like my work please consider a Donation. Donate
Please read the appropriate documentation before posting questions! READ ME FAQ WIKI
PM's are for private matters. Post support questions to the appropriate forum, or they will be ignored.
User avatar
KAD
Global Moderator
 
Posts: 5103
Joined: Mon Apr 12, 2010 4:59 pm
Location: Seattle, WA USA

Re: fast linksheet script   

Postby Chris Bone » Sun Jan 22, 2012 5:10 pm

I'll do the ext3-boot switch over tonight, thanks for the tip, seems obvious now :)

As for diff, yeah, know about it, I was more unclear as to 'official' channels for submitting code for review but you guys seem to be all over these posts so code tags it is then... please note that not all code paths have been tested as I my setup only goes through the 'l3' section but the changes were straightforward enough to apply everywhere. My paths have tons of special characters in them (spaces, ampersands, etc.) so I don't think any escaping issues have been introduced... a fair number of comments have also been peppered into the code as the bash string manipulations are a bit more vague than a call to basename which is pretty obvious in what it's trying to do.

Oh, and a bit more detail about the speed, the 4x improvement was noted over the creation of about 4800 links (lots of which are for playlists, ie: all films with actor X in them). This took over 20 minutes with the original linksheets script, now is under 5 minutes... ymmv.

One additional speed improvement I debated over was to change the link creation from -fs to just -s (and ultimately skipping the fork to ln if the link already exists). This helps if there are a lot of collisions, which in my case there is because of the microscopic all-named-the-same playlists I'm using. In my case it would be fine because all collisions actually resolve to the same image anyway and the choice of taking first hit (like a change to -s would) .vs. taking the last hit (which is what -fs is doing) makes no difference, for other people it would mean that the wrong image is shown but the wrong ones would be different and previously wrong ones would now be correct... six of one, half dozen of the other.

And while I'm on a roll with the typing... I would kill to be able to avoid linksheets and not have to explore the existing alternatives either... can't there just be an option that always goes to the storage and reads the sheet or thumb file? This might introduce small browsing latency but at least be a mode where new sheets/thumbs show up right away so you can confirm everything is named properly and looks good. Effectively this is what is happening with 'folder.jpg' because that particular name is ubiquitous and can't be linked in... so can I select a behaviour like that for all sheet/thumbs and not just folder.jpg? Given that the actual image data has to be read off the device/network anyway I see little actual performance advantage in this indirect and imperfect mapping through /msheets... seriously, networks and disks are fast enough to just use directly for all cases, the limitations of linksheets and it's rebuild latency are far worse than the few 100ms it's going to take to get the exact right image every time.

Cheers
Chris

Code: Select all
#!/usr/bin/bash
### Copyright 2010 b-rad.cc
### http://wdlxtv.com & http://b-rad.cc & http://nextdimension.cc
### GPLv3 - full license located @ /usr/share/LICENSE
### Stipulations:
### - the full copyright notices in /osd/setup_about.xml must be left intact, as it is the publicly displayed copyright portion of this software as dictated by the GPLv3
### - this entire header must be left intact

## linksheets <location> <mode>
##  recursively searches and symlinks movie sheets into /msheets
##  /msheets is joined with /osd via unionfs
##  -- if <mode> == 2 then max-levels=2
##
## valid types
##  video thumb view:
##  audio thumb view:
##  list mode:
##   - STD
##   - SHEET
##   - WALL
##

[ -e /tmp/STOP_DMARENDER ] && exit 55
eval `egrep 'LISTNUM|GENTHUMBS|THUMBRESO|MSHEET|DEFAULTSHEET' /conf/config`
MODE=$2

if [ "$MSHEETMODE" == "wall" -o "$MSHEETMODE" == "sheet" -o "$MSHEETMODE" == "std" -a "$GENMSHEET" == "ON" -o "$VIDMSHEET" == "ON" -o "$LISTMSHEET" == "ON" -o "$MODE" == "5" ] ; then
    SEARCHSTRING=".*_sheet.$MSHEETMODE.jpg"
else
    exit 3
fi

[ ! -e "$1" ] && echo "PATH: $1 does not exist!" && exit 2
[ "$MODE" == "1" -o "$MODE" == "2" ] && DEPTH="-maxdepth $MODE" || DEPTH=""
logger -t linksheets "Generating MovieSheets for $1, mode $2"

echo "power led blink on" >> /proc/led

if [ "$DEFAULTSHEET" != "" -a ! -L /tmp/defaultsheet.jpg ]; then
    if [ `echo "$DEFAULTSHEET" | grep -q '^/';echo $?` -eq 0 ]; then
        ln -s "$DEFAULTSHEET" /tmp/defaultsheet.jpg
    else
        ln -s "/osd/$DEFAULTSHEET" /tmp/defaultsheet.jpg
    fi
fi

cd /msheets
find "$1/" -type f -regextype posix-egrep -iregex ".*_sheet.jpg|.*wd_tv.jpg|$SEARCHSTRING" $DEPTH 2>/dev/null | while read msheet ; do
    MSHEETBASE=${msheet##*/}
    if [ "$MSHEETBASE" == "wd_tv.jpg" -o "$MSHEETBASE" == ".wd_tv.jpg" -a "$MSHEETMODE" != "std" ] ; then
        if [ "$MSHEETBASE" == ".wd_tv.jpg" ] ; then
            DIRNAME=${msheet/.wd_tv.jpg/}
        else
            DIRNAME=${msheet/wd_tv.jpg/}
        fi
        DIRNAME=${DIRNAME##*/}  # extract the basename
   if [ -h "$BASELINK" ] ; then # only spawn readlink if we have to
            BASELINK="`/usr/bin/readlink "$DIRNAME"`"
   else
            BASELINK=$DIRNAME
   fi
        BASELINK=${BASELINK##*/} # extract the link's basepath
        [ -n "$BASELINK" -a "$MSHEETMODE" == "std" -a "$BASELINK" == "$MSHEETBASE" ] && unlink "$DIRNAME" && [ -n "$LDEBUG" ] && echo "ul1  $MSHEETBASE -> $DIRNAME"
        [ "$MSHEETMODE" != "std" ] && ln -fs "$msheet" "$DIRNAME" 2>/dev/null && [ -n "$LDEBUG" ] && echo "l1  $MSHEETBASE -> $DIRNAME"
    elif [ "$MSHEETBASE" == "folder.jpg_sheet.jpg" -o "$MSHEETBASE" == ".folder.jpg_sheet.jpg" -a "$MSHEETMODE" != "std" ] ; then
        if [ "$MSHEETBASE" == ".folder.jpg_sheet.jpg" ] ; then
            DIRNAME=${msheet/.folder.jpg_sheet.jpg/}
        else
            DIRNAME=${msheet/folder.jpg_sheet.jpg/}
        fi
        DIRNAME=${DIRNAME##*/} # extract the dir's basepath
        NOEXT=${msheet/.jpg/}
   if [ -h "$BASELINK" ] ; then # only spawn readlink if we have to
            BASELINK="`/usr/bin/readlink "$DIRNAME"`"
   else
            BASELINK=$DIRNAME
   fi
        BASELINK=${BASELINK##*/}  # extract the link's basepath
        [ -n "$BASELINK" -a "$MSHEETMODE" == "std" -a "$BASELINK" == "$MSHEETBASE" ] && unlink "$DIRNAME" && [ -n "$LDEBUG" ] && echo "ul2  $MSHEETBASE -> $DIRNAME"
        [ "$MSHEETMODE" != "std" -a ! -f "$NOEXT.$MSHEETMODE.jpg" ] && ln -fs "$msheet" "$DIRNAME" 2>/dev/null && [ -n "$LDEBUG" ] && echo "l2  $MSHEETBASE -> $DIRNAME"
    elif [ "${msheet/_sheet.jpg/}" != "$msheet" ] ; then
        BASENAME=${msheet/_sheet.jpg/}
   BASENAME=${BASENAME##*/} # extract basepath
   BASENAME=${BASENAME#.}   # remove leading period (if it exists)
        NOEXT=${msheet/.jpg/}
        DIRPATH=${msheet%/*}     # extract dirpath
        DIRNAME=${DIRPATH##*/}   # extract the dir's basepath
   if [ -h "$BASELINK" ] ; then  # only spawn readlink if we have to
            BASELINK="`/usr/bin/readlink "$DIRNAME"`"
   else
       BASELINK=$DIRNAME
   fi
        BASELINK=${BASELINK##*/} # extract the link's basepath
        [ -n "$BASELINK" -a "$MSHEETMODE" == "std" -a "${BASELINK/_sheet.jpg/}" != "$DIRNAME" ] && unlink $DIRNAME && [ -n "$LDEBUG" ] && echo "ul3  $MSHEETBASE -> $DIRNAME"
        if [ ! -f "$NOEXT.$MSHEETMODE.jpg" -a ! -f "$DIRPATH/folder.jpg_sheet.jpg" -a ! -f "$DIRPATH/folder.jpg_sheet.$MSHEETMODE.jpg" ] ; then
            [ "$MSHEETMODE" != "std" ] && ln -fs "$msheet" "$DIRNAME" 2>/dev/null && [ -n "$LDEBUG" ] && echo "l3  $MSHEETBASE -> $DIRNAME"
        fi
        [ ! -f "$NOEXT.$MSHEETMODE.jpg" ] && ln -fs "$msheet" "$BASENAME" 2>/dev/null && [ -n "$LDEBUG" ] && echo "l3a $BASENAME -> $MSHEETBASE"
    else   
        BASENAME=${msheet/_sheet.$MSHEETMODE.jpg/}
   BASENAME=${BASENAME##*/}  # extract basepath
   BASENAME=${BASENAME#.}    # remove leading period (if it exists)
        DIRPATH=${msheet%/*}      # extract dirpath
        DIRNAME=${DIRPATH##*/}    # extract the dir's basepath
   if [ -h "$BASELINK" ] ; then # only spawn readlin if we have to
            BASELINK="`/usr/bin/readlink "$DIRNAME"`"
   else
            BASELINK=$DIRNAME
   fi
        BASELINK=${BASELINK##*/}  # extract the link's basepath
        [ -n "$BASELINK" -a "$MSHEETMODE" == "std" -a "${BASELINK/_sheet.$MSHEETMODE.jpg/}" != "$DIRNAME" ] && unlink "$DIRNAME" && [ -n "$LDEBUG" ] && echo "ul4  $MSHEETBASE -> $DIRNAME"
        if [ "$MSHEETMODE" != "std" -a "$BASENAME" == "folder.jpg" -o "$MSHEETMODE" != "std" ] ; then
            [ ! -f "$DIRPATH/folder.jpg_sheet.jpg" -a ! -f "$DIRPATH/folder.jpg_sheet.$MSHEETMODE.jpg" ] && ln -fs "$msheet" "$DIRNAME" 2>/dev/null && [ -n "$LDEBUG" ] && echo "l4  $MSHEETBASE -> $DIRNAME"
        fi
        ln -fs "$msheet" "$BASENAME" 2>/dev/null && [ -n "$LDEBUG" ] && echo "l4a $MSHEETBASE -> $BASENAME"
    fi
    [ -f /tmp/linksheets.stop.$MODE -o -f /tmp/linksheets.stop ] && echo "power led blink off" >> /proc/led && echo "power led on" >> /proc/led && logger -t linksheets "linksheets.stop found, exiting immediately!!!" && exit 3
#    usleep 750
done

echo "power led blink off" >> /proc/led
echo "power led on" >> /proc/led

Chris Bone
n00b
 
Posts: 14
Joined: Fri Nov 04, 2011 4:43 am

Re: fast linksheet script   

Postby Chris Bone » Mon Jan 23, 2012 6:08 am

The change over to ext3-boot was trivial, installed my updated linksheet script and rebooted again, confirmed that on reboot it's running the new script and has whizzed through comparatively speaking... stoked, thanks for your help. Hope others can get the benefit too as slowness is cited as a top problem with linksheet on non-trivial sized collections of files.

Cheers
Chris
Chris Bone
n00b
 
Posts: 14
Joined: Fri Nov 04, 2011 4:43 am

Re: fast linksheet script   

Postby KAD » Mon Jan 23, 2012 11:24 am

as for something that dynamically looks for the sheet when a file is selected, it already exist
WDTVext Moviesheet Plugin

but the downside is WDTVext is only available on firmwares with base version 1.02.21

KAD
If you like my work please consider a Donation. Donate
Please read the appropriate documentation before posting questions! READ ME FAQ WIKI
PM's are for private matters. Post support questions to the appropriate forum, or they will be ignored.
User avatar
KAD
Global Moderator
 
Posts: 5103
Joined: Mon Apr 12, 2010 4:59 pm
Location: Seattle, WA USA

Re: fast linksheet script   

Postby Chris Bone » Tue Jan 24, 2012 4:33 pm

Hi Guys:

So, I'm detecting a bug in linksheet and have confirmed that it exists in the original unmodified version (ie: I didn't break it). The issue is that the result depends on the order of files that 'find' returns, even if there are no collisions. The problem has to do with the folder level sheets, often the last jpg for a directory is incorrectly linked in as the folder sheet. By 'last' I don't mean alphabetically, I'm referring to the order inside the actual directory structure itself. I'm currently working around the problem by removing all the files in the file system to be scanned and then rebuilding, being careful to generate the folder sheet last but that's not ideal and introduces another lengthy delay into the whole refresh playlists part of my system.

It would appear that the problem is hard to solve in a pure bash implementation as there are no data structures to exploit w.r.t. gathering up all the 'find' results and then performing some filtering/processing of the list prior to creation of the links. Therefore I propose that linksheets be rewritten as a perl script... would have preferred python but perl is part of the busybox install so I know that everyone will have it already.

Are there any thoughts/concerns/suggestions regarding a port of this script to perl? If not, I'll get started on that and post the results when available.

Cheers
Chris
Chris Bone
n00b
 
Posts: 14
Joined: Fri Nov 04, 2011 4:43 am

Re: fast linksheet script   

Postby Chris Bone » Wed Jan 25, 2012 4:31 am

OK, so the fast form of the bash script I posted has a small defect but rather than post a correction to that I'm going to go ahead and post the perl form of it. This was freshly ported from the original linksheet script rather than from my first (potentially buggy) mods. In my head to head test of the original script and the new perl form there were exactly the same set of links produced so I'm fairly confident that it's a faithful port (though not all code paths were executed)... the good news is that the perl form is much faster than any previous effort... for reference, on creation of 4800 links:

original bash script: 20 minutes
udated bash script: 5 minutes
perl script: 80 seconds

So, all up an order of magnitude faster.... that's gotta be worth getting into the next release... I'll monitor this thread for bug reports.

Cheers
Chris

Code: Select all
#!/usr/bin/perl

### Copyright 2012 b-rad.cc
### http://wdlxtv.com & http://b-rad.cc & http://nextdimension.cc
### GPLv3 - full license located @ /usr/share/LICENSE
### Stipulations:
### - the full copyright notices in /osd/setup_about.xml must be left intact, as it is the publicly displayed copyright portion of this software as dictated by the GPLv3
### - this entire header must be left intact

## linksheets <location> <mode>
##  recursively searches and symlinks movie sheets into /msheets
##  /msheets is joined with /osd via unionfs
##  -- if <mode>  is 1 or 2 then max-levels=<mode>
##
## valid types
##  video thumb view:
##  audio thumb view:
##  list mode:
##   - STD
##   - SHEET
##   - WALL
##

use strict;
use File::Basename;
use Cwd 'realpath';

# utility function for controlling the led
sub set_power_led{
    my $mode = shift;
    open(my $fh, ">>", "/proc/led");
    print $fh "power led $mode\n";
    close($fh);
}

# make sure the link replaces the thing it currently points to
sub force_symlink{
    my $src = shift;
    my $dst = shift;
    if ( -e $dst ) { unlink($dst); }
    symlink($src, $dst);
}

if ( ! -e $ARGV[0] ) {
    print ("PATH: " . $ARGV[0] . " does not exist!\n");
    exit 2
}

my $MODE = $ARGV[1];

if ( -e '/tmp/STOP_DMARENDER' ) {
    print "stop\n";
    exit 55
}

# parse config file into environment (so that it augments env)
open(my $fh, "<", "/conf/config");
while (!eof($fh)) {
    my $inline = readline($fh);
    if ($inline =~ /LISTNUM/ ||
        $inline =~ /GENTHUMBS/ ||
        $inline =~ /THUMBRESO/ ||
        $inline =~ /MSHEET/ ||
        $inline =~ /DEFAULTSHEET/) {
        chomp($inline);
        (my $var, my $val) = split("=", $inline);
        $val =~ s/'//g;
        #print ($var . "=" . $val . "\n");
        $ENV{$var} = $val
    }
}
close($fh);

# now extract the parameters from the augmented environment
my $MSHEETMODE   = $ENV{'MSHEETMODE'};
my $GENMSHEET    = $ENV{'GENMSHEET'};
my $VIDMSHEET    = $ENV{'VIDMSHEET'};
my $LISTMSHEET   = $ENV{'LISTMSHEET'};
my $DEFAULTSHEET = $ENV{'DEFAULTSHEET'};
my $LDEBUG       = $ENV{'LDEBUG'};

# check that MSHEETMODE is legal
if ( $MSHEETMODE ne "wall" && $MSHEETMODE ne "sheet" && $MSHEETMODE ne "std" ) {
    print "illegal MSHEETMODE\n";
    exit 3;
}

# check that one of the sheet modes is active
if ( $GENMSHEET ne "ON" && $VIDMSHEET ne "ON" && $LISTMSHEET ne "ON" && $MODE ne "5" ) {
    print "no generation mode selected\n";
    exit 3;
}

# configure the per-mode sheet pattern
my $SEARCHSTRING = ".*_sheet.$MSHEETMODE.jpg";

# setup the 'find' argument that will control the depth of it's recursive search
my $DEPTH = "";
if ( $MODE eq "1" || $MODE eq "2" ) {
    $DEPTH = "-maxdepth " . $MODE;
}

system("logger -t linksheets \"Generating MovieSheets for " . $ARGV[0] . ", mode " . $ARGV[1] . "\"");

set_power_led('blink on');

if ( $DEFAULTSHEET ne "" && ! -l "/tmp/defaultsheet.jpg" ) {
    # if the valut of DEFAULTSHEET starts with a / then it's
    # a full path and we want to use it exactly, otherwise
    # assume it's a path relative to /osd/
    if ( /^\// ) {
        symlink($DEFAULTSHEET, "/tmp/defaultsheet.jpg");
    } else {
        symlink("/osd/" . $DEFAULTSHEET, "/tmp/defaultsheet.jpg");
    }
}

chdir("/msheets");

my $find_cmd = "find $ARGV[0]/ -type f $DEPTH ";
$find_cmd .= "-regextype posix-egrep ";
$find_cmd .= "-iregex \".*_sheet.jpg|.*wd_tv.jpg|" . $SEARCHSTRING . "\"";
open(my $fh, $find_cmd . " 2>/dev/null |");
while (!eof($fh)) {
    my $msheet = readline($fh);
    chomp($msheet);
    my $basename_msheet = basename($msheet);
    if ( $MSHEETMODE ne "std" && ($basename_msheet eq "wd_tv.jpg" ||
              $basename_msheet eq ".wd_tv.jpg") ) {
        my $DIRNAME = basename(dirname($msheet));
        my $BASELINK = basename(realpath($DIRNAME));
        if ( $BASELINK ne "" && $MSHEETMODE eq "std" && $BASELINK eq $basename_msheet ) {
            unlink($DIRNAME);
            if ( $LDEBUG ne "" ) { print "ul1  $msheet -> $DIRNAME\n"; }
        }
        if ( $MSHEETMODE ne "std" ) {
            force_symlink($msheet, $DIRNAME);
            if ( $LDEBUG ne "" ) { print "l1  $msheet -> $DIRNAME\n"; }
        }
    } elsif ( $MSHEETMODE ne "std" && ($basename_msheet eq "folder.jpg_sheet.jpg" ||
                   $basename_msheet eq ".folder.jpg_sheet.jpg" ) ) {
        my $DIRNAME = basename(dirname($msheet));
        my $NOEXT = substr($msheet,0,-4);
        my $BASELINK = basename(realpath($DIRNAME));
        if ( $BASELINK ne "" && $MSHEETMODE eq "std" && $BASELINK eq $basename_msheet ) {
            unlink($DIRNAME);
            if ( $LDEBUG ne "" ) { print "ul2  $msheet -> $DIRNAME\n"; }
        }
        if ( $MSHEETMODE ne "std" && ! -f "$NOEXT.$MSHEETMODE.jpg" ) {
            force_symlink($msheet, $DIRNAME);
            if ( $LDEBUG ne "" ) { print "l2  $msheet -> $DIRNAME\n"; }
        }
    } elsif ( basename($msheet, "_sheet.jpg") ne $msheet ) {
        my $BASENAME = basename($msheet, "_sheet.jpg");
        $BASENAME =~ s/^\.//;   # remove leading '.' (if it exists)
        my $NOEXT = substr($msheet, 0, -4);
        my $DIRPATH = dirname($msheet);
        my $DIRNAME = basename($DIRPATH);
        my $BASELINK = basename(realpath($DIRNAME));
        if ( $BASELINK ne "" && $MSHEETMODE eq "std" && substr($BASELINK,0,-10) ne $DIRNAME ) {
            unlink($DIRNAME);
            if ( $LDEBUG ne "" ) { print "ul3  $msheet -> $DIRNAME\n"; }
        }
        if ( ! -f "$NOEXT.$MSHEETMODE.jpg" &&
             ! -f "$DIRPATH/folder.jpg_sheet.jpg" &&
             ! -f "$DIRPATH/folder.jpg_sheet.$MSHEETMODE.jpg" ) {
            if ( $MSHEETMODE ne "std" ) {
                force_symlink($msheet, $DIRNAME);
                if ( $LDEBUG ne "" ) { print "l3  $msheet -> $DIRNAME\n"; }
            }
        }
        if ( ! -f "$NOEXT.$MSHEETMODE.jpg" ) {
            force_symlink($msheet, $BASENAME);
            if ( $LDEBUG ne "" ) { print "l3a $msheet -> $BASENAME\n"; }
        }
    } else {
        my $BASENAME = basename($msheet,"_sheet.$MSHEETMODE.jpg");
        $BASENAME =~ s/^\.//g;    # remove leading '.' (if it exists)
        my $DIRPATH = dirname($msheet);
        my $DIRNAME = basename($DIRPATH);
        my $BASELINK = basename(realpath($DIRNAME));
        if ( $BASELINK ne "" && $MSHEETMODE eq "std" && substr($BASELINK,0,-(11+length($MSHEETMODE))) ne $DIRNAME ) {
            unlink($DIRNAME);
            if ( $LDEBUG ne "" ) { print "ul4  $msheet -> $DIRNAME\n"; }
        }
        if ( $MSHEETMODE ne "std" && $BASENAME eq "folder.jpg" || $MSHEETMODE ne "std" ) {
            if ( ! -f "$DIRPATH/folder.jpg_sheet.jpg" &&
                 ! -f "$DIRPATH/folder.jpg_sheet.$MSHEETMODE.jpg" ) {
      force_symlink($msheet, $DIRNAME);
                if ( $LDEBUG ne "" ) { print "l4  $msheet -> $DIRNAME\n"; }
            }
        }
        force_symlink($msheet, $BASENAME);
        if ( $LDEBUG ne "" ) { print "l4a $msheet -> $BASENAME\n"; }
    }
    if ( -f "/tmp/linksheets.stop.$MODE" ||
         -f "/tmp/linksheets.stop" ) {
        set_power_led('blink off');
        set_power_led('on');
        system("logger -t linksheets \"linksheets.stop found, exiting immediately!!!\"");
        exit 3;
    }
}

set_power_led('blink off');
set_power_led('on');
system("logger -t linksheets \"Done MovieSheets for " . $ARGV[0] . ", mode " . $ARGV[1] . "\"");
Chris Bone
n00b
 
Posts: 14
Joined: Fri Nov 04, 2011 4:43 am

Re: fast linksheet script   

Postby recliq » Wed Jan 25, 2012 5:44 am

Nice work, I will testdrive this as soon as I get my linksheets test-setup back up and running.
This (find the dir sheet bug) was on my todo list for quite some time. Moving the script to perl was my intention as well as I chewed on the linking problem...
the speedup is much more than I expected... :mrgreen:

There is a fair chance we will replace the current linksheets script with your perl version.

Keep it up!
­WDLXTV Project Maintainer
-:] If you like my contributions feel free to donate for a beer or a new flash drive. ...and always remember: RTFM! (README, FAQ, WIKI) [:-
User avatar
recliq
WDLXTV Team
 
Posts: 5513
Joined: Thu Apr 15, 2010 8:09 am
Location: Kiel, Germany

Re: fast linksheet script   

Postby Chris Bone » Wed Jan 25, 2012 6:12 am

Here is an updated version, I noticed a couple of redudant 'if' clauses, ie: it was already inside a block that had checked MSHEETMODE!=std and then did the test again, this cluttered the logic and revealed additional redundant code in the wd_tv.jpg block (no need to conditionally unlink the dst as it's going to be force_symlink'd anyway).

A few additional calls to 'logger' have been added, one on every exit path.

Also, a bunch of commenting was added, hopefully this will make it clearer for the next person.

I still have not tackled the folder linking bug yet, first priority was to shift languages in the hopes that would provide the tools required to tackle the bug and/or perform additional optimizations... at the very least it should be possible to provide deterministic behaviour whereas the current behaviour is non-deterministic because it relies on the order of files returned by find and as find is not doing any sorting it's output is dependent on the order the files were created in. At the very best it should get a bit faster if all collisions can be handled gracefully... in my setup about 1/3rd of the files have a doppleganger that is hard to avoid, avoiding those link creations and subsequent destroy must amount to about 50% of the remaining system time.

Cheers
Chris

Code: Select all
#!/usr/bin/perl

### Copyright 2012 b-rad.cc
### http://wdlxtv.com & http://b-rad.cc & http://nextdimension.cc
### GPLv3 - full license located @ /usr/share/LICENSE
### Stipulations:
### - the full copyright notices in /osd/setup_about.xml must be left intact, as it is the publicly displayed copyright portion of this software as dictated by the GPLv3
### - this entire header must be left intact

## linksheets <location> <mode>
##  recursively searches and symlinks movie sheets into /msheets
##  /msheets is joined with /osd via unionfs
##  -- if <mode>  is 1 or 2 then max-levels=<mode>
##
## valid types
##  video thumb view:
##  audio thumb view:
##  list mode:
##   - STD
##   - SHEET
##   - WALL
##

use strict;
use File::Basename;
use Cwd 'realpath';

# utility function for controlling the led
sub set_power_led{
    my $mode = shift;
    open(my $fh, ">>", "/proc/led");
    print $fh "power led $mode\n";
    close($fh);
}

# make sure the link replaces the thing it currently points to
sub force_symlink{
    my $src = shift;
    my $dst = shift;
    if ( -e $dst ) { unlink($dst); }
    symlink($src, $dst);
}

if ( ! -e $ARGV[0] ) {
    print ("PATH: " . $ARGV[0] . " does not exist!\n");
    system("logger -t linksheets \"$ARGV[0] not found, exiting immediately!!!\"");
    exit 2
}

my $MODE = $ARGV[1];

if ( -e '/tmp/STOP_DMARENDER' ) {
    print "stop\n";
    system("logger -t linksheets \"/tmp/STOP_DMARENDER exists, exiting immediately!!!\"");
    exit 55
}

# parse config file into environment (so that it augments env)
open(my $fh, "<", "/conf/config");
while (!eof($fh)) {
    my $inline = readline($fh);
    if ($inline =~ /LISTNUM/ ||
        $inline =~ /GENTHUMBS/ ||
        $inline =~ /THUMBRESO/ ||
        $inline =~ /MSHEET/ ||
        $inline =~ /DEFAULTSHEET/) {
        chomp($inline);
        (my $var, my $val) = split("=", $inline);
        $val =~ s/'//g;
        #print ($var . "=" . $val . "\n");
        $ENV{$var} = $val
    }
}
close($fh);

# now extract the parameters from the augmented environment
my $MSHEETMODE   = $ENV{'MSHEETMODE'};
my $GENMSHEET    = $ENV{'GENMSHEET'};
my $VIDMSHEET    = $ENV{'VIDMSHEET'};
my $LISTMSHEET   = $ENV{'LISTMSHEET'};
my $DEFAULTSHEET = $ENV{'DEFAULTSHEET'};
my $LDEBUG       = $ENV{'LDEBUG'};

# check that MSHEETMODE is legal
if ( $MSHEETMODE ne "wall" && $MSHEETMODE ne "sheet" && $MSHEETMODE ne "std" ) {
    print "illegal MSHEETMODE\n";
    system("logger -t linksheets \"illegal MSHEETMODE $MSHEETMODE, exiting immediately!!!\"");
    exit 3;
}

# check that one of the sheet modes is active
if ( $GENMSHEET ne "ON" && $VIDMSHEET ne "ON" && $LISTMSHEET ne "ON" && $MODE ne "5" ) {
    print "no generation mode selected\n";
    system("logger -t linksheets \"no generation mode selected, exiting immediately!!!\"");
    exit 3;
}

# configure the per-mode sheet pattern
my $SEARCHSTRING = ".*_sheet.$MSHEETMODE.jpg";

# setup the 'find' argument that will control the depth of it's recursive search
my $DEPTH = "";
if ( $MODE eq "1" || $MODE eq "2" ) {
    $DEPTH = "-maxdepth " . $MODE;
}

system("logger -t linksheets \"Generating MovieSheets for " . $ARGV[0] . ", mode " . $ARGV[1] . "\"");

set_power_led('blink on');

if ( $DEFAULTSHEET ne "" && ! -l "/tmp/defaultsheet.jpg" ) {
    # if the valut of DEFAULTSHEET starts with a / then it's
    # a full path and we want to use it exactly, otherwise
    # assume it's a path relative to /osd/
    if ( /^\// ) {
        symlink($DEFAULTSHEET, "/tmp/defaultsheet.jpg");
    } else {
        symlink("/osd/" . $DEFAULTSHEET, "/tmp/defaultsheet.jpg");
    }
}

chdir("/msheets");

my $find_cmd = "find $ARGV[0]/ -type f $DEPTH ";
$find_cmd .= "-regextype posix-egrep ";
$find_cmd .= "-iregex \".*_sheet.jpg|.*wd_tv.jpg|" . $SEARCHSTRING . "\"";
open(my $fh, $find_cmd . " 2>/dev/null |");
while (!eof($fh)) {
    my $msheet = readline($fh);
    chomp($msheet);
    my $basename_msheet = basename($msheet);
    if ( $MSHEETMODE ne "std" && ($basename_msheet eq "wd_tv.jpg" ||
              $basename_msheet eq ".wd_tv.jpg") ) {
   # special handling for [.]wd_tv.jpg:
   #    just link it as it's folder name
        my $DIRNAME = basename(dirname($msheet));
   force_symlink($msheet, $DIRNAME);
   if ( $LDEBUG ne "" ) { print "l1  $msheet -> $DIRNAME\n"; }
    } elsif ( $MSHEETMODE ne "std" && ($basename_msheet eq "folder.jpg_sheet.jpg" ||
                   $basename_msheet eq ".folder.jpg_sheet.jpg" ) ) {
   # special handling for [.]folder.jpg_sheet.jpg
   #    just link it as it's folder name if there is no $MSHEETMODE.jpg form
   #    (as we intend to use that one in instead as the sheet for $DIRNAME)
        my $NOEXT = substr($msheet,0,-4);
        if ( ! -f "$NOEXT.$MSHEETMODE.jpg" ) {
       my $DIRNAME = basename(dirname($msheet));
            force_symlink($msheet, $DIRNAME);
            if ( $LDEBUG ne "" ) { print "l2  $msheet -> $DIRNAME\n"; }
        }
    } elsif ( substr($msheet,-10) eq "_sheet.jpg" ) {
   # handle all images that end in _sheet.jpg
        my $BASENAME = basename($msheet, "_sheet.jpg");
        $BASENAME =~ s/^\.//;   # remove leading '.' (if it exists)
        my $NOEXT = substr($msheet, 0, -4);
        my $DIRPATH = dirname($msheet);
        my $DIRNAME = basename($DIRPATH);
        my $BASELINK = basename(realpath($DIRNAME));
        if ( $BASELINK ne "" && $MSHEETMODE eq "std" && substr($BASELINK,0,-10) ne $DIRNAME ) {
            unlink($DIRNAME);
            if ( $LDEBUG ne "" ) { print "ul3  $msheet -> $DIRNAME\n"; }
        }
   # link in as folder sheet if more specialized do not exist
        if ( ! -f "$NOEXT.$MSHEETMODE.jpg" &&
             ! -f "$DIRPATH/folder.jpg_sheet.jpg" &&
             ! -f "$DIRPATH/folder.jpg_sheet.$MSHEETMODE.jpg" ) {
            if ( $MSHEETMODE ne "std" ) {
                force_symlink($msheet, $DIRNAME);
                if ( $LDEBUG ne "" ) { print "l3  $msheet -> $DIRNAME\n"; }
            }
        }
   # link in as folder sheet if more specialized do not exist
        if ( ! -f "$NOEXT.$MSHEETMODE.jpg" ) {
            force_symlink($msheet, $BASENAME);
            if ( $LDEBUG ne "" ) { print "l3a $msheet -> $BASENAME\n"; }
        }
    } else {
   # handle all other images
        my $BASENAME = basename($msheet,"_sheet.$MSHEETMODE.jpg");
        $BASENAME =~ s/^\.//g;    # remove leading '.' (if it exists)
        my $DIRPATH = dirname($msheet);
        my $DIRNAME = basename($DIRPATH);
        my $BASELINK = basename(realpath($DIRNAME));
        if ( $BASELINK ne "" && $MSHEETMODE eq "std" && substr($BASELINK,0,-(11+length($MSHEETMODE))) ne $DIRNAME ) {
            unlink($DIRNAME);
            if ( $LDEBUG ne "" ) { print "ul4  $msheet -> $DIRNAME\n"; }
        }
        if ( $MSHEETMODE ne "std" && $BASENAME eq "folder.jpg" || $MSHEETMODE ne "std" ) {
            if ( ! -f "$DIRPATH/folder.jpg_sheet.jpg" &&
                 ! -f "$DIRPATH/folder.jpg_sheet.$MSHEETMODE.jpg" ) {
      force_symlink($msheet, $DIRNAME);
                if ( $LDEBUG ne "" ) { print "l4  $msheet -> $DIRNAME\n"; }
            }
        }
        force_symlink($msheet, $BASENAME);
        if ( $LDEBUG ne "" ) { print "l4a $msheet -> $BASENAME\n"; }
    }
    if ( -f "/tmp/linksheets.stop.$MODE" ||
         -f "/tmp/linksheets.stop" ) {
        set_power_led('blink off');
        set_power_led('on');
        system("logger -t linksheets \"linksheets.stop found, exiting immediately!!!\"");
        exit 3;
    }
}

set_power_led('blink off');
set_power_led('on');
system("logger -t linksheets \"Done MovieSheets for " . $ARGV[0] . ", mode " . $ARGV[1] . "\"");
Chris Bone
n00b
 
Posts: 14
Joined: Fri Nov 04, 2011 4:43 am

Next

Return to Movie Sheet Support & Discussion

Who is online

Users browsing this forum: No registered users and 1 guest