aboutsummaryrefslogtreecommitdiff
path: root/doc/tips/dumb_metadata_extraction_from_xbmc/git-annex-xbmc-playcount.pl
blob: 56f902cb03cbb4a761fe028da7402bcdc12ebca8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#! /usr/bin/perl -w

use Getopt::Long;
use Pod::Usage;

my $help = 0;
my $usage = 0;
my $dryrun = 0;
my $verbose = 0;
my $path = '';
my $annex = '';
my $home = $ENV{'HOME'};

sub main() {
    checkargs();
    if (!$path) {
        $path = $home . '/.xbmc/userdata/Database';
    }
    print("# checking XBMC directory '$path'\n") if ($verbose);
    $dbpath = finddb($path);
    if (!$dbpath) {
        pod2usage("$0: can't find a XBMC database in '$path'.");
    }
    print("# using database '$dbpath'\n") if ($verbose);
    checkdb();
}

# list videos database, find the latest one
# modified version of
# http://stackoverflow.com/questions/4651092/getting-the-list-of-files-sorted-by-modification-date-in-perl
sub finddb($) {
    my $path = shift(@_);
    opendir my($dirh), $path or die "can't opendir $path: $!";
    my @flist = sort {  -M $a <=> -M $b } # Sort by modification time
        map  { "$path/$_" } # We need full paths for sorting
        grep { /^MyVideos.*\.db$/ }
        readdir $dirh;
    closedir $dirh;
    if ($#flist > 0) {
        return $flist[0];
    }
    else {
        return 0;
    }
}

sub checkargs() {
    pod2usage(1) if $help;
    pod2usage(-exitval => 0, -verbose => 2) if $usage;

    GetOptions('h|?' => \$help,
               'help|usage' => \$usage,
               # we want to operate on relative links, so set this to
               # the common annex to the git annex repo
               'annex=s' => \$annex,
               'path=s' => \$path,
               'home=s' => \$home,
               'dryrun|n' => \$dryrun,
               'verbose|v' => \$verbose,
        )
        or die("Error parsing commandline\n");
}

sub checkdb() {
    my @lines = `echo 'SELECT playCount, path.strPath, files.strFileName FROM movie JOIN files ON files.idFile=movie.idFile JOIN path ON path.idPath=files.idPath;' | sqlite3 $dbpath`;
    print "# finding files...\n" if $verbose;
    for (@lines) {
        my ($count, $dir, $file) = split /\|/;
        chomp $file;
        # empty or non-numeric count is zero
        if ($count !~ /[0-9]/) {
            $count = 0;
        }
        print "# $dir/$file\n" if $verbose;
        if ($file =~ s#stack://##) {
            for (split /,/, $file) {
                s/$annex//;
                s/^ //;
                s/ $//;
                my @cmd = (qw(git annex metadata --set), "playCount=$count", $_);
                if ($dryrun) {
                    print join(' ', @cmd) . "\n";
                }
                else {
                    system(@cmd);
                }
            }
        }
        else {
            $dir =~ s/$annex//;
            my @cmd = (qw(git annex metadata --set), "playCount=$count", "$dir$file");
            if ($dryrun) {
                print join(' ', @cmd) . "\n";
            }
            else {
                system(@cmd);
            }
        }
    }
}

main();

__END__
=encoding utf8

=head1 NAME

git-annex-xbmc-playcount - register XBMC playcounts as git-annex metadata

=head1 SYNOPSIS

git-annex-xbmc-playcount [--path .xbmc/userdata/Database]

 Options:
  -h         short usage
  --help     complete help
  --dryrun, -n do nothing and show the commands that would be ran
  --annex    path to the git-annex repo
  --home     the home directory where the .xbmc directory is located
  --path     the location of the Database directory of XBMC, overrides --home
  --verbose  show interaction details with the database

=head1 DESCRIPTION

This program will look into the XBMC database for the "playcount"
field to register that number as metadata in the git-annex repository.

=head1 OPTIONS

=over 8

=item B<--dryrun>

Do nothing but show all the steps that would be ran. The output can be
piped through a POSIX shell after inspection. B<-n> is an alias of
this command. Example:

    git-annex-xbmc-playcount -n | tee runme
    # inspect the output
    sh < runme

=item B<--annex>

This option allows the user to specify the root of the git-annex
repository, which is then stripped off the paths found in the XBMC
database.

=item B<--home>

Home of the user running XBMC. If not specified, defaults to the $HOME
environment variables. The script will look into
B<$home/.xbmc/userdata/Database> for a file matching
B<^MyVideos.*\.db$> and will fail if none is found.

=item B<--path>

Manually specify the path to B<.xbmc/userdata/Database>. This
overrides B<--home>.

Note that this doesn't point directly to the database itself, because
there are usually many database files and we want to automatically
find the latest. This may be a stupid limitation.

=item B<--verbose>

Show more information about path discovery. Doesn't obstruct
B<--dryrun> output because lines are prefixed with C<#>.

=back

=head1 EXAMPLES

You have a git annex in B</srv/video> and XBMC is ran as the
B<video> user and you want to be cautious:

    $ ./git-annex-xbmc-playcount.pl --home /home/video/ -n --annex /srv/video/ | tee set-metadata
    git annex metadata --set playCount=0 films/Animal.Farm.1954.DVDRip.DivX-MDX.avi

This looks about right, set the metadata:

    $ git annex metadata --set playCount=0 films/Animal.Farm.1954.DVDRip.DivX-MDX.avi
    metadata films/Animal.Farm.1954.DVDRip.DivX-MDX.avi
      lastchanged=2014-10-04@22-17-42
      playCount=0
      playCount-lastchanged=2014-10-04@22-17-42
    ok
    (Recording state in git...)

=head1 ENVIRONMENT

B<$HOME> is looked into to find the B<.xbmc> home directory if none of
B<--home> or B<--path> is specified.

=head1 FILES

=over 8

=item B<$HOME/.xbmc/userdata/Database/MyVideos.*\.db>

This is where we assume the SQLite database of videos XBMC uses is
stored.

=back

=head1 BUGS

If there are pipes (C<|>) in filenames, the script may fail to find
the files properly. We would need to rewrite the database code to use
B<DBD::SQLite>(3pm) instead of a pipe to B<sqlite3>(1).

=head1 LIMITATIONS

It took longer writing this help than writing the stupid script.

The script will not tag files not yet detected by XBMC.

The script is not incremental, so it will repeatedly add the same
counts to files it has already found.

=head1 SEE ALSO

B<git-annex>(1), B<xbmc>(1)

=head1 AUTHOR

Written by Antoine Beaupré <anarcat@debian.org>