From 7734605735a027b5e998563e8cbc46b9ae3f9dbb Mon Sep 17 00:00:00 2001 From: dakkar Date: Wed, 29 Dec 2021 13:37:28 +0000 Subject: scandir --- lib/App/MediaControl.rakumod | 25 +++++++++++++++++++++ lib/App/MediaControl/DB.rakumod | 41 ++++++++++++++++++++++++++++++---- lib/ScanDir.rakumod | 49 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 lib/ScanDir.rakumod (limited to 'lib') diff --git a/lib/App/MediaControl.rakumod b/lib/App/MediaControl.rakumod index 77fda99..cf635d4 100644 --- a/lib/App/MediaControl.rakumod +++ b/lib/App/MediaControl.rakumod @@ -1,5 +1,6 @@ use v6.d; use DB::SQLite; +use ScanDir; use Vlc::Client; use Lirc::Client; use Lirc::Commands; @@ -35,8 +36,32 @@ class App::MediaControl { ); } + method !start-scan() { + my $root = $.config; + $!db.clear-seen(); + start react { + whenever scan-dir($root) -> $item { + when $item ~~ $root {} + when $item ~~ ScanDir::End { $!db.remove-unseen() } + + my $path = $item.parent.relative($root); + $path = '' if $path eq '.'; + my $name = $item.basename; + + if !$item.e { + $!db.remove-entry(:$path,:$name); + } + else { + my $is-dir = $item.d; + $!db.add-entry(:$path,:$name,:$is-dir); + } + } + } + } + method start() { $!db.ensure-schema(); + self!start-scan(); $!web.start(); } diff --git a/lib/App/MediaControl/DB.rakumod b/lib/App/MediaControl/DB.rakumod index 7ce562e..da86d24 100644 --- a/lib/App/MediaControl/DB.rakumod +++ b/lib/App/MediaControl/DB.rakumod @@ -26,17 +26,36 @@ class App::MediaControl::DB { .query(q:to/END/); CREATE TABLE files ( id INTEGER PRIMARY KEY, - parent_id INTEGER NULL REFERENCES files(id), + parent_id INTEGER NULL REFERENCES files(id) + ON DELETE CASCADE, matpath TEXT NOT NULL, name TEXT NOT NULL, is_dir BOOLEAN NOT NULL, watched_time INTEGER NULL, + seen BOOLEAN NOT NULL DEFAULT false, UNIQUE (matpath, name) ) END } } + method clear-seen() { + self!db: { + .query(q:to/END/) + UPDATE files SET seen=false + END + } + } + + method remove-unseen() { + self!db: { + .query(q:to/END/) + DELETE FROM files + WHERE seen=false + END + } + } + method add-entry(Str :$path! is copy, Str :$name!, Bool :$is-dir!) { $path ~~ s{$} = '/'; $path ~~ s{^} = '/'; @@ -50,12 +69,26 @@ class App::MediaControl::DB { newrow(path,name,is_dir) AS ( VALUES($path, $name, $is_dir) ) - INSERT INTO files(parent_id,matpath,name,is_dir) - SELECT id, newrow.path, name, is_dir + INSERT INTO files(parent_id,matpath,name,is_dir,seen) + SELECT id, newrow.path, name, is_dir, true FROM newrow LEFT JOIN parent ON parent.path=newrow.path WHERE true - ON CONFLICT (matpath,name) DO NOTHING + ON CONFLICT (matpath,name) DO UPDATE SET seen=true + END + } + } + + method remove-entry(Str :$path! is copy, Str :$name!) { + $path ~~ s{$} = '/'; + $path ~~ s{^} = '/'; + + note "remove-entry($path,$name)"; + self!db: { + .query(q:to/END/, :$path, :$name); + DELETE FROM files + WHERE name=$name + AND matpath=$path END } } diff --git a/lib/ScanDir.rakumod b/lib/ScanDir.rakumod new file mode 100644 index 0000000..f3173a4 --- /dev/null +++ b/lib/ScanDir.rakumod @@ -0,0 +1,49 @@ +use v6.d; +unit module ScanDir; + +class End {}; + +sub scan-dir(*@paths --> Supply) is export { + supply { + my %watched-dirs; + + CATCH { when X::IO { }; default { warn $_; done } } + + sub start-watching(IO::Path $dir) { + return if %watched-dirs{$dir.Str}; + %watched-dirs{$dir.Str} = True; + + whenever $dir.watch { + my $path-io = .path.IO; + emit $path-io; + when $path-io ~~ :e & :d { + add-dir($path-io) unless %watched-dirs{$path-io.Str}; + } + when $path-io ~~ :!e { + %watched-dirs{$path-io.Str}:delete + } + } + } + + sub add-dir(*@todo) { + while @todo { + my $next = @todo.shift; + + next unless $next ~~ :e & :r & :d; + start-watching($next); + + for $next.dir { + emit $_; + when .e && .d { + @todo.push($_); + start-watching($_); + } + } + } + + } + + add-dir(@paths».IO); + emit End; + } +} -- cgit v1.2.3