0

I'm trying to use a script found here written in Perl, but it runs into an error. I've already contacted the author but haven't had a response yet. I'm hoping you can help me.

The error is the following:

ERROR: unable to copy /home/bruno321/.config/Clementine/albumcovers/271b13967f57caba893b366730337fb03439c60a.jpg to /media/mp3_1/Musica/Amarok/Two%20Lone%20Swordsmen/A%20Bag%20of%20Blue%20Sparks/. error: File or directory does not exist

I believe the error is in handling the spaces, because in directories that don't have spaces it runs OK, however it doesn't rename the file into "cover.jpg" as I believe the script intends to do (and I certainly need it to do that).

#!/usr/bin/perl

use strict;
use warnings;
use Carp;

use DBI;
use strict;

use Data::Dumper;
use File::Basename;
use File::Copy;

my $db_filename = shift(@ARGV);
$db_filename
  || croak
"missing mandatory param: sqlite filename\n(try ~/.config/Clementine/clementine.db\n";

if ( !-f $db_filename ) {
    croak "no such database file: $db_filename\n";
}

my $force_rewrite = shift(@ARGV) || 0;

my $dbh =
  DBI->connect( "dbi:SQLite:$db_filename", q{}, q{},
    { 'RaiseError' => 1, 'AutoCommit' => 1 } );

my $query = q{SELECT artist,album, art_automatic,art_manual,filename
             FROM songs WHERE art_manual IS NOT NULL GROUP BY(album)  ORDER BY artist};

my $sth = $dbh->prepare($query);
$sth || croak 'prepare error: ' . $dbh->errstr . "\n";

$sth->execute || croak 'execute error: ' . $dbh->errstr . "\n";

my %treated = ();
while ( my $res = $sth->fetchrow_hashref ) {

    ( undef, my $dest_dir, undef ) = fileparse( $res->{'filename'} );

    next if $treated{$dest_dir};
    $treated{$dest_dir}++;

    # strip leading file://  -> should do this better
    $dest_dir =~ s/^file:\/\///g;

    my $dest_file = $dest_dir . 'cover.jpg';

    # unless we are given overwrite option, skip dirs that have covers
    if ( !$force_rewrite ) {
        next if ( -f $dest_file );
    }

    #print "CMD: cp $res->{'art_manual'} $dest_file\n";
    copy( $res->{'art_manual'}, $dest_dir )
      || printf( "ERROR: unable to copy %s to %s. error: %s\n",
        $res->{'art_manual'}, $dest_dir, $! );
}
exit;
Bruno Stonek
  • 111
  • 4
  • 3
    There are no spaces in that file name. The error message is clear; the destination directory does not exist. – tripleee Aug 14 '13 at 20:24
  • @tripleee: But it does, actually! Well, at least replacing the %20 by blank spaces. To be clearer, on the few folders that don't have spaces it works alright, except it copies the file verbatim instead of renaming it to "cover.jpg" as I believe it is intended. – Bruno Stonek Aug 14 '13 at 20:24

1 Answers1

7

Apparently $dest_dir is URL-encoded where you need it to be literal. In other words, after trimming the file:// prefix, you need to decode any %NN hex escapes into the corresponding literal character. See Using Perl, how do I decode or create those %-encodings on the web? Basically, you want to

use URI::Escape 'uri_unescape';

and then

$dest_dir = uri_unescape($dest_dir);

Additionally, you are creating $dest_file but then ignoring it and copying the file to $dest_dir instead after all.

As an additional stylistic issue, warnings and errors should go to stderr, not stdout.

Community
  • 1
  • 1
tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Thanks! I'm modifying this in the code. Where should I change `$dest_dir` by `$dest_file` in order to copy the file as I want it to? – Bruno Stonek Aug 14 '13 at 20:43
  • Nevermind, I changed it in the last two instances and it worked wonders. Thank you very much, tripleee! – Bruno Stonek Aug 14 '13 at 20:56