about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/Lacerta/CLI.rakumod113
1 files changed, 62 insertions, 51 deletions
diff --git a/lib/Lacerta/CLI.rakumod b/lib/Lacerta/CLI.rakumod
index d6b80bc..3ce42b0 100644
--- a/lib/Lacerta/CLI.rakumod
+++ b/lib/Lacerta/CLI.rakumod
@@ -1,12 +1,15 @@
-use Terminal::Table;
 use Terminal::Spinners;
+use Text::Table::Simple;
 
-# Parses the WhatsApp logs.
+#| parses WhatsApp export
+unit sub MAIN (
+    Str $input where *.IO.f = "input", #= input log file to parse
+    Str $profile-name = "Andinus", #= your WhatsApp profile name
+);
+
+#| Parses the WhatsApp logs.
 grammar WhatsApp {
-    token TOP {
-        || <Text>
-        || <Notice>
-    }
+    token TOP { <Text> || <Notice> }
 
     token Notice { <date> ', ' <time> ' - ' <message> }
     token Text { <date> ', ' <time> ' - ' <name> ': ' <message> }
@@ -18,61 +21,69 @@ grammar WhatsApp {
     token message { .* }
 }
 
-#| parses WhatsApp export
-sub MAIN (
-    Str $profile-name = "Andinus", #= WhatsApp profile name
-    Str $input where *.IO.f = "input", #= input log file to parse
-
-) {
-    my WhatsApp @logs;
-    {
-        my $bar = Bar.new: :type<equals>;
-        $bar.show: 0;
-
-        my Int $count = 0;
-        my Int $total = $input.IO.lines.elems; # Roughly the number of messages.
-        my Int $interval = $total div 40; # Interval for update.
-
-        @logs = gather for $input.IO.lines -> $line {
-            if WhatsApp.parse($line) -> $m { take $m }
-            $bar.show: $count / $total * 100 if $count++ %% $interval;
-        }
-        $bar.show: 100;
+my WhatsApp @logs;
 
-        put "\n" ~ "Parsed {@logs.elems} logs in " ~ (now - ENTER now) ~ "s";
+{
+    Spinner.new(:type<bounce2>).await: Promise.start: {
+        @logs = $input.IO.lines.race.map({WhatsApp.parse($_)}).grep(so *);
     }
+    put "Parsed {@logs.elems} logs in " ~ (now - ENTER now) ~ "s";
+}
+
+{
+    my List @data;
+    my List @given-data;
+    my List @most-spoken-data;
+    my Int $no-of-spoken = 8;
 
-    {
-        my @data;
-        my @given-data;
-        push @data, <Name Messages Words Deleted Media MostActiveHour Left>;
-        push @given-data, <Name FucksGiven>;
+    Spinner.new(:type<bounce>).await: Promise.start: {
+        my Promise @promises;
         for @logs.grep(*<Text>).map(*<Text>).map(*<name>.Str).unique -> $name {
-            with @logs.grep(*<Text>).map(*<Text>).grep(*<name>.Str eq $name) {
+            next if $name eq "ERROR";
+            push @promises, start with @logs.grep(*<Text>).map(*<Text>).grep(*<name> eq $name) {
                 @data.push(
                     (
                         $name,
-                        .elems.Str,
-                        .map(*<message>.words).sum.Str,
-                        .grep(*<message> eq "You deleted this message"|"This message was deleted").elems.Str,
-                        .grep(*<message> eq "<Media omitted>").elems.Str,
-                        .map(*<time>[0][0].Int).Bag.max(*.values).key.Str,
-                        $name eq $profile-name
-                         ?? @logs.grep(*<Notice>).grep(*<Notice><message> eq "You left").elems.Str
-                         !! @logs.grep(*<Notice>).grep(*<Notice><message> eq "{$name} left").elems.Str,
-                    )
-                );
-
-                @given-data.push(
-                    (
-                        $name,
-                        .grep(*<message>.lc.contains("fuck")).elems.Str,
+                        .elems,
+                        .map(*<message>.words).sum,
+                        .grep(*<message> eq ($name eq $profile-name
+                                             ?? "You deleted this message"
+                                             !! "This message was deleted")).elems,
+                        .grep(*<message> eq "<Media omitted>").elems,
+                        .map(*<time>[0][0].Int).Bag.max(*.values).key,
+                        @logs.grep(*<Notice>).grep(
+                            *<Notice><message>
+                            eq ($name eq $profile-name ?? "You left" !! "$name left")
+                        ).elems,
                     )
                 );
+                with .map(*<message>).map(*.lc).cache {
+                    @given-data.push(
+                        (
+                            $name,
+                            .grep(*.contains: "fuck").elems,
+                        )
+                    );
+                    @most-spoken-data.push(
+                        (
+                            $name,
+                            .grep(* ne "<media omitted>")
+                             .grep(* ne ($name eq $profile-name
+                                         ?? "you deleted this message"
+                                         !! "this message was deleted")
+                                  ).map(*.words).Bag.grep(*.key.chars >= 4)
+                             .sort(*.values).reverse.map({"{$_.key} ({$_.value})"}).head($no-of-spoken).Slip,
+                        )
+                    );
+                }
             }
         }
-        put "Generated data in " ~ (now - ENTER now) ~ "s";
-        print-table(@data, :style<single>);
-        print-table(@given-data, :style<single>);
+        await @promises;
     }
+    put "Generated data in " ~ (now - ENTER now) ~ "s" ~ "\n";
+
+    my List %options = headers => (corner_marker => "*", bottom_border => "-");
+    .say for lol2table(<Name Messages Words Deleted Media ActiveHour Left>, @data, |%options);
+    .say for lol2table(<Name FucksGiven>, @given-data, |%options);
+    .say for lol2table((|<Name MostSpoken-#1>, |("#" X~ (2..$no-of-spoken))), @most-spoken-data, |%options);
 }