$File::Sticker::VERSION
=
'4.0101'
;
search_path
=> [
'File::Sticker::Scribe'
],
sub_name
=>
'all_scribes'
;
sub
whoami { (
caller
(1) )[3] }
sub
new {
my
$class
=
shift
;
my
%parameters
= (
@_
);
my
$self
=
bless
({
%parameters
},
ref
(
$class
) ||
$class
);
my
%new_args
= ();
foreach
my
$key
(
qw(wanted_fields verbose topdir)
)
{
if
(
exists
$self
->{
$key
})
{
$new_args
{
$key
} =
$self
->{
$key
};
}
}
my
%to_disable
= ();
foreach
my
$mod
(@{
$self
->{disable}})
{
$to_disable
{
$mod
} = 1;
}
my
@scribes
=
$self
->all_scribes();
$self
->{_scribe_pri} = {};
foreach
my
$rd
(
@scribes
)
{
my
$nm
=
$rd
->name();
my
$priority
=
$rd
->priority();
if
(
$to_disable
{
$nm
})
{
print
STDERR
"DISABLE SCRIBE: ${nm}\n"
if
$self
->{verbose} > 1;
}
else
{
print
STDERR
"SCRIBE: ${nm}\n"
if
$self
->{verbose} > 1;
$rd
->init(
%new_args
);
if
(!
exists
$self
->{_scribe_pri}->{
$priority
})
{
$self
->{_scribe_pri}->{
$priority
} = [];
}
push
@{
$self
->{_scribe_pri}->{
$priority
}},
$rd
;
}
}
if
(
exists
$self
->{dbname}
and
defined
$self
->{dbname}
and
exists
$self
->{wanted_fields}
and
defined
$self
->{wanted_fields}
and
exists
$self
->{field_order}
and
defined
$self
->{field_order}
and
exists
$self
->{primary_table}
and
defined
$self
->{primary_table})
{
$self
->{db} = File::Sticker::Database->new(
dbname
=>
$self
->{dbname},
wanted_fields
=>
$self
->{wanted_fields},
field_order
=>
$self
->{field_order},
primary_table
=>
$self
->{primary_table},
taggable_fields
=>
$self
->{taggable_fields},
topdir
=>
$self
->{topdir},
tagfield
=>
$self
->{tagfield},
space_sep
=>
$self
->{space_sep},
readonly
=>
$self
->{readonly},
verbose
=>
$self
->{verbose},
);
$self
->{db}->do_connect();
$self
->{db}->create_tables();
}
return
(
$self
);
}
sub
read_meta ($%) {
my
$self
=
shift
;
my
%args
=
@_
;
my
$filename
=
$args
{filename};
say
STDERR whoami(),
" filename=$filename"
if
$self
->{verbose} > 2;
if
(!-r
$filename
)
{
return
{};
}
my
@possible_scribes
= ();
foreach
my
$pri
(
reverse
sort
keys
%{
$self
->{_scribe_pri}})
{
foreach
my
$rd
(@{
$self
->{_scribe_pri}->{
$pri
}})
{
if
(
$rd
->allow(
$filename
))
{
push
@possible_scribes
,
$rd
;
say
STDERR
"Scribe($pri) "
,
$rd
->name()
if
$self
->{verbose} > 1;
}
}
}
my
$merge
= Hash::Merge->new(
'LEFT_PRECEDENT'
);
my
$meta
= {};
foreach
my
$scribe
(
@possible_scribes
)
{
say
STDERR
"Reading "
,
$scribe
->name()
if
$self
->{verbose} > 1;
my
$info
=
$scribe
->read_meta(
$filename
);
my
$newmeta
=
$merge
->merge(
$meta
,
$info
);
$meta
=
$newmeta
;
print
STDERR
"META: "
, Dump(
$meta
),
"\n"
if
$self
->{verbose} > 1;
}
if
(
$args
{read_all} or
$args
{derive})
{
my
$derived
=
$self
->derive_values(
filename
=>
$filename
,
meta
=>
$meta
);
foreach
my
$field
(
sort
keys
%{
$derived
})
{
if
(!
exists
$meta
->{
$field
} and
$derived
->{
$field
})
{
$meta
->{
$field
} =
$derived
->{
$field
};
}
if
(
$field
eq
'filesize'
)
{
$meta
->{
$field
} =
$derived
->{
$field
};
}
}
}
if
(!
$args
{read_all}
and
exists
$self
->{wanted_fields}
and
defined
$self
->{wanted_fields})
{
my
@fields
=
sort
keys
%{
$meta
};
foreach
my
$fn
(
@fields
)
{
if
(!
exists
$self
->{wanted_fields}->{
$fn
})
{
delete
$meta
->{
$fn
};
}
}
}
return
$meta
;
}
sub
add_field_to_file {
my
$self
=
shift
;
my
%args
=
@_
;
say
STDERR whoami(),
" filename=$args{filename}"
if
$self
->{verbose} > 2;
my
$filename
=
$args
{filename};
my
$field
=
$args
{field};
my
$value
=
$args
{value};
if
(!-w
$filename
)
{
return
undef
;
}
my
$scribe
=
$self
->_get_scribe(
$filename
);
if
(
defined
$scribe
)
{
my
$readonly_fields
=
$scribe
->readonly_fields();
if
(
exists
$readonly_fields
->{
$field
}
and
defined
$readonly_fields
->{
$field
})
{
return
undef
;
}
my
$old_meta
=
$self
->read_meta(
filename
=>
$filename
,
read_all
=>0);
my
$derived
=
$self
->derive_values(
filename
=>
$filename
,
meta
=>
$old_meta
);
if
(
$self
->{derive} and
defined
$derived
->{
$field
})
{
$value
=
$derived
->{
$field
};
}
$scribe
->add_field_to_file(
filename
=>
$filename
,
field
=>
$field
,
value
=>
$value
,
old_meta
=>
$old_meta
);
}
}
sub
delete_field_from_file {
my
$self
=
shift
;
my
%args
=
@_
;
say
STDERR whoami(),
" filename=$args{filename}"
if
$self
->{verbose} > 2;
my
$filename
=
$args
{filename};
my
$field
=
$args
{field};
if
(!-w
$filename
)
{
return
undef
;
}
my
$scribe
=
$self
->_get_scribe(
$filename
);
if
(
defined
$scribe
)
{
my
$readonly_fields
=
$scribe
->readonly_fields();
if
(
exists
$readonly_fields
->{
$field
}
or
defined
$readonly_fields
->{
$field
})
{
return
undef
;
}
$scribe
->delete_field_from_file(
filename
=>
$filename
,
field
=>
$field
);
}
}
sub
replace_all_meta {
my
$self
=
shift
;
my
%args
=
@_
;
say
STDERR whoami(),
" filename=$args{filename}"
if
$self
->{verbose} > 2;
my
$filename
=
$args
{filename};
my
$meta
=
$args
{meta};
if
(!-w
$filename
)
{
return
undef
;
}
my
$scribe
=
$self
->_get_scribe(
$filename
);
if
(
defined
$scribe
)
{
my
$writable_fields
=
$scribe
->writable_fields();
my
%new_meta
= ();
foreach
my
$field
(
sort
keys
%{
$meta
})
{
if
(
exists
$writable_fields
->{
$field
}
and
defined
$writable_fields
->{
$field
})
{
$new_meta
{
$field
} =
$meta
->{
$field
};
}
}
$scribe
->replace_all_meta(
filename
=>
$filename
,
meta
=>\
%new_meta
);
}
}
sub
query_by_tags {
my
$self
=
shift
;
my
$query
=
shift
;
return
$self
->{db}->query_by_tags(
$query
);
}
sub
query_one_file {
my
$self
=
shift
;
my
$file
=
shift
;
if
(
$self
->{db})
{
return
$self
->{db}->get_file_meta(
$file
);
}
return
undef
;
}
sub
missing_files {
my
$self
=
shift
;
my
@missing_files
= ();
my
@files
= @{
$self
->{db}->get_all_files()};
foreach
my
$file
(
@files
)
{
say
STDERR
"checking $file"
if
$self
->{verbose} > 2;
if
(!-r
$file
and !-d
$file
)
{
push
@missing_files
,
$file
;
}
}
return
\
@missing_files
;
}
sub
overlooked_files {
my
$self
=
shift
;
my
@files
=
@_
;
my
@overlooked
= ();
foreach
my
$file
(
@files
)
{
my
$id
=
$self
->{db}->get_file_id(
$file
);
if
(!
$id
)
{
push
@overlooked
,
$file
;
}
}
return
\
@overlooked
;
}
sub
list_tags {
my
$self
=
shift
;
my
$tags
=
$self
->{db}->get_all_tags();
return
$tags
;
}
sub
update_db {
my
$self
=
shift
;
my
@files
=
@_
;
my
$transaction_on
= 0;
my
$num_trans
= 0;
foreach
my
$filename
(
@files
)
{
say
$filename
if
!
$self
->{quiet};
if
(!
$transaction_on
)
{
$self
->{db}->start_transaction();
$transaction_on
= 1;
$num_trans
= 0;
}
my
$meta
=
$self
->read_meta(
filename
=>
$filename
,
read_all
=>0);
my
$scribe
=
$self
->_get_scribe(
$filename
);
my
$derived
=
$self
->derive_values(
filename
=>
$filename
,
meta
=>
$meta
);
my
$readonly_fields
=
$scribe
->readonly_fields();
foreach
my
$field
(@{
$self
->{field_order}})
{
if
(!
$meta
->{
$field
} and
defined
$derived
->{
$field
})
{
$meta
->{
$field
} =
$derived
->{
$field
};
}
if
(
exists
$readonly_fields
->{
$field
}
and
defined
$readonly_fields
->{
$field
}
and
defined
$derived
->{
$field
})
{
$meta
->{
$field
} =
$derived
->{
$field
};
}
}
$self
->{db}->add_meta_to_db(
$filename
,%{
$meta
});
$num_trans
++;
if
(
$transaction_on
and
$num_trans
> 100)
{
$self
->{db}->commit();
$transaction_on
= 0;
$num_trans
= 0;
say
" "
if
$self
->{verbose};
}
}
$self
->{db}->commit();
}
sub
delete_file_from_db {
my
$self
=
shift
;
my
$filename
=
shift
;
return
$self
->{db}->delete_file_from_db(
$filename
);
}
sub
delete_missing_files {
my
$self
=
shift
;
my
$missing_files
=
$self
->missing_files();
foreach
my
$file
(@{
$missing_files
})
{
$self
->delete_file_from_db(
$file
);
}
return
$missing_files
;
}
sub
derive_values {
my
$self
=
shift
;
my
%args
=
@_
;
say
STDERR whoami(),
" filename=$args{filename}"
if
$self
->{verbose} > 2;
my
$filename
=
$args
{filename};
my
$meta
=
$args
{meta};
my
$fp
= path(
$filename
);
if
(-r
$filename
)
{
$meta
->{file} =
$fp
->realpath->stringify;
}
else
{
$meta
->{file} =
$fp
->absolute->stringify;
}
$meta
->{basename} =
$fp
->basename();
$meta
->{id_name} =
$fp
->basename(
qr/\.\w+/
);
if
(
$meta
->{basename} =~ /\.(\w+)$/)
{
$meta
->{ext} = $1;
}
if
(!
$meta
->{title})
{
my
@words
= wordsplit(
$meta
->{id_name});
my
$title
=
join
(
' '
,
@words
);
$title
=~ s/(\w+)/\u\L$1/g;
$title
=~ s/(\d+)$/ $1/;
$meta
->{title} =
$title
;
}
if
(
$self
->{topdir})
{
$meta
->{relpath} =
$fp
->relative(
$self
->{topdir})->stringify;
my
$rel_parent
=
$fp
->parent->relative(
$self
->{topdir})->stringify;
if
(
$meta
->{relpath} =~ /\.\./)
{
$meta
->{relpath} =~ s!\.\./!!g;
$rel_parent
=~ s!\.\./!!g;
}
if
(-r
$fp
->parent .
'/.thumbnails/'
.
$meta
->{id_name} .
'.jpg'
)
{
$meta
->{thumbnail} =
$rel_parent
.
'/.thumbnails/'
.
$meta
->{id_name} .
'.jpg'
}
elsif
(-r
$fp
->parent .
'/.thumbnails/'
.
$meta
->{id_name} .
'.png'
)
{
$meta
->{thumbnail} =
$rel_parent
.
'/.thumbnails/'
.
$meta
->{id_name} .
'.png'
}
elsif
(
$meta
->{ext} =~ /jpg|png|gif/)
{
$meta
->{thumbnail} =
$meta
->{relpath};
}
my
@bits
=
split
(/\//,
$rel_parent
);
splice
(
@bits
,3);
$meta
->{grouping} =
join
(
' '
,
@bits
);
for
(
my
$i
=0;
$i
<
@bits
;
$i
++)
{
my
$id
=
$i
+ 1;
$meta
->{
"section${id}"
} =
$bits
[
$i
];
}
}
if
(-r
$filename
)
{
my
$stat
=
$fp
->
stat
;
$meta
->{filesize} =
$stat
->size;
$meta
->{filedate} = strftime
'%Y-%m-%d %H:%M:%S'
,
localtime
$stat
->mtime;
if
(!
$meta
->{linkdate})
{
$meta
->{linkdate} =
$meta
->{filedate};
}
if
(!
$meta
->{date_added})
{
$meta
->{date_added} =
(
$meta
->{date} ?
$meta
->{date} :
$meta
->{filedate});
}
}
return
$meta
;
}
sub
_get_scribe {
my
$self
=
shift
;
my
$filename
=
shift
;
my
$scribe
;
foreach
my
$pri
(
reverse
sort
keys
%{
$self
->{_scribe_pri}})
{
foreach
my
$wt
(@{
$self
->{_scribe_pri}->{
$pri
}})
{
if
(
$wt
->allow(
$filename
))
{
$scribe
=
$wt
;
say
STDERR
"Scribe($pri) "
,
$scribe
->name()
if
$self
->{verbose} > 1;
last
;
}
}
if
(
defined
$scribe
)
{
last
;
}
}
return
$scribe
;
}
1;