merge in media-preview stuff

Squashed commit of the following:

commit 4087cee2f2a72bc2d3e44832809cbe99d25a3309
Author: rabite <rabite@posteo.de>
Date:   Tue May 21 20:40:27 2019 +0200

    rename to preview-gen

commit 275fd420a01c24393ae9cc07287204fde309130a
Author: rabite <rabite@posteo.de>
Date:   Tue May 21 20:30:50 2019 +0200

    update Cargo.toml and README

commit bf4c3fec0f8e0ff4628153297ac64fe165b4e443
Author: rabite <rabite@posteo.de>
Date:   Tue May 21 20:30:33 2019 +0200

    add config options for media

commit 3bf681cd078177d634507c51d04a45bdae184f1b
Author: rabite <rabite@posteo.de>
Date:   Tue May 21 13:46:00 2019 +0200

    always use unicode icons for play/pause/mute

commit ed2a0b31d1911e4d42086699ca1db636c327bacf
Author: rabite <rabite@posteo.de>
Date:   Tue May 21 13:04:11 2019 +0200

    rename to mediaview and some fixups

commit bda3f8f83bec07c3f52d06cf5f8eaad7fdbd85a0
Author: rabite <rabite@posteo.de>
Date:   Tue May 21 11:44:52 2019 +0200

    fix warnings

commit 9c917903cfa958b225f268ed4fb9f55f27162be0
Author: rabite <rabite@posteo.de>
Date:   Tue May 21 01:10:58 2019 +0200

    play audio through viedo widget

commit 9fe208b213710fae889f7701bdb3bf96d599c9a8
Author: rabite <rabite@posteo.de>
Date:   Tue May 21 00:15:12 2019 +0200

    fixed play when autoplay is off

commit d4036d52864d0a4e08f7da2cf6f7419ef070c1a9
Author: rabite <rabite@posteo.de>
Date:   Mon May 20 13:15:44 2019 +0200

    add icons for play/pause/mute

commit 29f0d203cfd7501b50d80501de146da9d89388bb
Author: rabite <rabite@posteo.de>
Date:   Mon May 20 12:26:53 2019 +0200

    add basic gif support

commit 8d28e4c23a91b0ef83739554c3a2f6671a9ff6f5
Author: rabite <rabite@posteo.de>
Date:   Mon May 20 11:43:57 2019 +0200

    fixed play after pause

commit 142017df78de77bcfffd8f3dd9612a06927e183b
Author: rabite <rabite@posteo.de>
Date:   Sun May 19 14:22:16 2019 +0200

    change to stale on drop

commit c0026c7f56f6a841df18e41bd1c9b33543e26cfb
Author: rabite <rabite@posteo.de>
Date:   Sat May 18 23:46:27 2019 +0200

    handle errors in gstreamer closure

commit ef37f872c54b9d21ed5505c2edb480c793afaef9
Author: rabite <rabite@posteo.de>
Date:   Sat May 18 23:40:24 2019 +0200

    add image-only mode to preview-gen

commit 15752464563463c6ecf892c1d8a14651bf32e1e5
Author: rabite <rabite@posteo.de>
Date:   Sat May 18 23:28:33 2019 +0200

    add copyright note

commit 4c9f08fc4de5d3bffefd42284b60aa81cfbae9f7
Author: rabite <rabite@posteo.de>
Date:   Sat May 18 23:27:30 2019 +0200

    make image/video previews optional

commit 9c2c2db2b20ecd4c30acbb1c77ad18c71f528c4c
Author: rabite <rabite@posteo.de>
Date:   Sat May 18 22:13:25 2019 +0200

    remove blank space under video

commit f7056d70fbe9147b3b95d7c10950653eadbb4f48
Author: rabite <rabite@posteo.de>
Date:   Sat May 18 22:06:49 2019 +0200

    remove dbg

commit cce820657ff1258cdb78d455dd3cf04564450cea
Author: rabite <rabite@posteo.de>
Date:   Sat May 18 21:50:25 2019 +0200

    added error handling to preview-gen

commit 80bbe15bacb99d1f4f97504a5d10ecf59544993f
Author: rabite <rabite@posteo.de>
Date:   Sat May 18 21:04:31 2019 +0200

    add time and visual seek bars to videoview

commit 4349945cc5549334f246be64bc7c8e2db43f9150
Author: rabite <rabite@posteo.de>
Date:   Thu May 16 22:39:19 2019 +0200

    fix sneaky process

commit 373128b7096d4de29924617e549a613a3aeea5b2
Author: rabite <rabite@posteo.de>
Date:   Thu May 16 22:07:27 2019 +0200

    fix out of controll processes

commit e061e065e913ab3923ffac1079a9f0a2be0df532
Author: rabite <rabite@posteo.de>
Date:   Thu May 16 20:51:56 2019 +0200

    add media_preview

commit f68c754895a9718d1a962980de9fbf02e5cb48cd
Author: rabite <rabite@posteo.de>
Date:   Thu May 16 19:37:04 2019 +0200

    beta image/video previews

commit 9a5460e553dd26ebccffaf819c64a8dc6ba74818
Author: rabite <rabite@posteo.de>
Date:   Tue May 14 20:36:25 2019 +0200

    external img preview

commit 3c4edfcb7611b36f6e537c73743e0b6bd269037b
Author: rabite <rabite@posteo.de>
Date:   Tue May 14 20:35:12 2019 +0200

    video preview
This commit is contained in:
rabite 2019-05-21 20:50:54 +02:00
parent 6f8a636603
commit e8d9c6ad1f
13 changed files with 1620 additions and 76 deletions

469
Cargo.lock generated
View File

@ -1,5 +1,10 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "adler32"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "aho-corasick"
version = "0.7.3"
@ -40,13 +45,11 @@ dependencies = [
[[package]]
name = "async_value"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
version = "0.2.3"
dependencies = [
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"objekt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -91,6 +94,11 @@ dependencies = [
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byteorder"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytesize"
version = "0.1.3"
@ -124,6 +132,11 @@ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "color_quant"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "constant_time_eq"
version = "0.1.3"
@ -160,6 +173,15 @@ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "deflate"
version = "0.7.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dirs"
version = "1.0.5"
@ -261,19 +283,150 @@ name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gif"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glib"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glib-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gobject-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gstreamer"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"muldiv 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gstreamer-app"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-app-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-base 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-base-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gstreamer-app-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-base-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gstreamer-base"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-base-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gstreamer-base-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gstreamer-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hunter"
version = "1.1.4"
dependencies = [
"alphanumeric-sort 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"async_value 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"async_value 0.2.3",
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs-2 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-app 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"lscolors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 4.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"osstrtools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parse-ansi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -287,6 +440,31 @@ dependencies = [
"users 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "image"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gif 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"tiff 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inflate"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inotify"
version = "0.6.1"
@ -314,6 +492,15 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jpeg-decoder"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@ -359,6 +546,11 @@ dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lzw"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "1.0.2"
@ -377,6 +569,25 @@ name = "memoffset"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mime"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mime_guess"
version = "2.0.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio"
version = "0.6.16"
@ -417,6 +628,11 @@ dependencies = [
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "muldiv"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "net2"
version = "0.2.33"
@ -463,6 +679,16 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-derive"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.39"
@ -471,6 +697,33 @@ dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-rational"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-rational"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.6"
@ -489,11 +742,6 @@ name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "objekt"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ordermap"
version = "0.3.5"
@ -558,6 +806,57 @@ dependencies = [
"ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "phf"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "phf_codegen"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "phf_generator"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "phf_shared"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pkg-config"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "png"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)",
"inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.4.30"
@ -586,6 +885,33 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
@ -599,6 +925,32 @@ name = "rand_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_os"
version = "0.1.3"
@ -612,6 +964,23 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon"
version = "1.0.3"
@ -728,6 +1097,11 @@ dependencies = [
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "siphasher"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.4.2"
@ -797,6 +1171,17 @@ dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tiff"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.42"
@ -824,6 +1209,22 @@ name = "ucd-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicase"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicase"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-width"
version = "0.1.5"
@ -847,6 +1248,11 @@ name = "utf8-ranges"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
version = "2.2.7"
@ -904,26 +1310,29 @@ dependencies = [
]
[metadata]
"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
"checksum alphanumeric-sort 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7cd2580c95c654d681db0194a310af67a293f5e1c8bafa5b35b63269c4665a39"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum async_value 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c4cd683ef2421e8767b2a0c02b105707812a98a4e1eb0559f615a15e3a80183"
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
"checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum bytesize 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "16d794c5fe594cfa8fbe8ae274de4048176c69f2d9ac5e637166e73b71d460b8"
"checksum cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86"
"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
"checksum dirs-2 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50b7e2b65c73137ec48935d50a5ae89b03150df566b7e14a1371df044e76765c"
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
@ -937,9 +1346,22 @@ dependencies = [
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum gif 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4bca55ac1f213920ce3527ccd62386f1f15fa3f1714aeee1cf93f2c416903f"
"checksum glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e0be1b1432e227bcd1a9b28db9dc1474a7e7fd4227e08e16f35304f32d09b61"
"checksum glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615bef979b5838526aee99241afc80cfb2e34a8735d4bcb8ec6072598c18a408"
"checksum gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70409d6405db8b1591602fcd0cbe8af52cd9976dd39194442b4c149ba343f86d"
"checksum gstreamer 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6c5a43723784a8b3a308541f3752370ee0ee3b6dc26ed50cdd06e8d9f5399cc"
"checksum gstreamer-app 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4e68d96a6a86fe4e4796d7ecb5a3cacd6b4680277da6daea7934612fa8c5c2bf"
"checksum gstreamer-app-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a224d33c7780957c30f9280b1256b3882792dda6916f75b54bb30b5b71ed505a"
"checksum gstreamer-base 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05ec7a84b4160b61c72ea27ccf3f46eb9c8f996c5991746623e69e3e532e3cb5"
"checksum gstreamer-base-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "501a7add44f256aab6cb5b65ef121c449197cf55087d6a7586846c8d1e42e88b"
"checksum gstreamer-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b2f51e25a6f97dd4bfd640cba96f192f8759b8766afd66d6d9ea0f82ca14a37"
"checksum image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "293e54ce142a936a39da748ba8178ae6aa1914b82d846a4278f11590c89bf116"
"checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
@ -947,22 +1369,29 @@ dependencies = [
"checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum lscolors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9938fd8c379393454f73ec4c9c5b40f3d8332d80b25a29da05e41ee0ecbb559"
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425"
"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed"
"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum muldiv 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1cbef5aa2e8cd82a18cc20e26434cc9843e1ef46e55bfabe5bddb022236c5b3e"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum nom 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf51a729ecf40266a2368ad335a5fdde43471f545a967109cd62146ecf8b66ff"
"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
"checksum notify 4.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ceb1a496a81dd6125f68ce772b41b83efe89a54d21768ed6d0c33c95832604e6"
"checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum objekt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2069a3ae3dad97a4ae47754e8f47e5d2f1fd32ab7ad8a84bb31d051faa59cc3c"
"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
"checksum osstrtools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63557d11f265b66ffcda9cc624d5f92315cfeebb7ee01c76257f890f7d730f5b"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
@ -971,12 +1400,25 @@ dependencies = [
"checksum parse-ansi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "50c48b4d524f8a10bf6ab37dc0b7583f17c8ec88b617b364ddfc3baee4dcf878"
"checksum pathbuftools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "908eefc77ffb9f995c7eb707eed61e66ef34fa66a735673517e65a34da3ef7a0"
"checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f"
"checksum phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18"
"checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e"
"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
"checksum png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63daf481fdd0defa2d1d2be15c674fbfa1b0fd71882c303a91f9a79b3252c359"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473"
"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
@ -991,6 +1433,7 @@ dependencies = [
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum signal-notify 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "847fbedad7c2e6fbb6077befa1fa61a6336658eaae2d9fe66cb94a0024742f4e"
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
@ -999,13 +1442,17 @@ dependencies = [
"checksum systemstat 0.1.5 (git+https://github.com/myfreeweb/systemstat)" = "<none>"
"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum tiff 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4834f28a0330cb9f3f2c87d2649dca723cb33802e2bdcf18da32759fbec7ce"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum tree_magic 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8ed063ec7b632ba8173200d7e818db4ba01564b6c085c1a7d1041b93b55b0e02"
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
"checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum users 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fed7d0912567d35f88010c23dbaf865e9da8b5227295e8dc0f2fdd109155ab7"
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"

View File

@ -29,9 +29,35 @@ notify = "4.0.9"
parse-ansi = "0.1.6"
signal-notify = "0.1.3"
systemstat = "0.1.4"
mime_guess = "2.0.0-alpha.6"
osstrtools = "0.1"
pathbuftools = "0.1"
async_value = "0.2.2"
image = { version = "0.21.1", optional = true }
gstreamer = { version = "0.11.2", optional = true }
gstreamer-app = { version = "0.11.2", optional = true }
[dependencies.async_value]
path = "../async_value/"
[features]
default = ["img", "video"]
img = ["image"]
video = ["img", "gstreamer", "gstreamer-app"]
[[bin]]
name = "hunter"
path = "src/main.rs"
[[bin]]
name = "preview-gen"
path = "src/media_preview.rs"
required-features = ["img"]
[patch.crates-io]
systemstat = { git = 'https://github.com/myfreeweb/systemstat' }

View File

@ -29,6 +29,7 @@ A big thanks to ranger and its developers. Without its inspiration this wouldn't
* Exit and cd into last directory and put selected files into shell variables
* Slide up animation for previews for a smoother experience (configurable)
* Can show icons with the [right fonts](https://github.com/ryanoasis/nerd-fonts)
* Optional support for previews of image/video/audio files using Unicode half-block drawing
@ -45,16 +46,21 @@ If it works on a system not mentioned here, please open an issue. Also feel free
* gcc
* libmagic-dev
* Rust-nighly compiler
* GStreamer for video/audio previews
### Debian/Ubuntu
* ```apt install gcc libmagic-dev```
* ```apt install gcc libmagic-dev gstreamer1.0-devel gst-plugins-base gst-plugins-good```
## INSTALLATION:
Compiling hunter currently requires a nightly Rust compiler!
The easiest way to get a nightly compiler is with [rustup](https://rustup.rs/). If you have rustup installed it will automatically download and use a version that is known to work when you run cargo.
By default it will install a full-featured version with support for media-previews. You can control this using the feature flags ```img```, and ```video```. These can be disabled by calling cargo with ```--features ""```, if you want to disable all media previews, or ```--features=img"``` if you only want to disable video/audio previews.
Note that this only works if hunter can find the "preview-gen" tool somewhere in $PATH!
### Install rustup
```
@ -65,34 +71,26 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
### Build with cargo
```
cargo install hunter
cargo install (--features=...) hunter
```
### Build from source
```
// Clone the git repo
git clone https://github.com/rabite0/hunter.git
// Clone the git repo
git clone https://github.com/rabite0/hunter.git
// Go into the repos directory
cd {source_dir}/hunter/
// Note: if you want vim bindings you will have to switch to the evil branch.
// git checkout evil
// (Optional) Build
// cargo build --release (--features=...)
// Build
cargo build --release
// Install
cargo install (--features=...) --path .
```
###
This will create a binary in {source_dir}/hunter/target/release/hunter. If you want to call this like any other terminal app you have to put this binary in your path.
```ln -s {source_dir}/hunter/target/release/hunter /usr/bin/local/hunter```
This will link the the binary to your local bin file. You can call hunter from anywhere. To update repeat the process, but you will **not** need to redo the binary link.
## NOTE:
hunter uses [ranger's rifle](https://github.com/ranger/ranger/blob/master/ranger/ext/rifle.py) to open files if rifle is in your $PATH. If it can't find rifle it uses xdg-open. It also uses ranger's scope.sh to generate previews for non-text files. A slightly modified version is included in the "extra" directory. Put it in your $PATH somewhere if you want previews for non-text files.
@ -105,6 +103,8 @@ show_hidden=off
select_cmd=find -type f | fzf -m
cd_cmd=find -type d | fzf
icons=off
media_autostart=off
media_mute=off
```
## Drop into hunter cwd on quit
@ -160,6 +160,10 @@ By default hunter uses vi-style keybindings. If you use a QWERTY-like keyboard l
| z | open subshell in cwd |
| c | toggle columns |
| F(n) | switch to tab |
| Alt(m) | toggle media pause and autoplay |
| Alt(M) | toggle media mute |
| Alt(>) | seek media +5s |
| Alt(<) | seek media -5s |

View File

@ -7,7 +7,9 @@ pub struct Config {
pub show_hidden: bool,
pub select_cmd: String,
pub cd_cmd: String,
pub icons: bool
pub icons: bool,
pub media_autoplay: bool,
pub media_mute: bool,
}
@ -18,7 +20,9 @@ impl Config {
show_hidden: false,
select_cmd: "find -type f | fzf -m".to_string(),
cd_cmd: "find -type d | fzf".to_string(),
icons: false
icons: false,
media_autoplay: false,
media_mute: false
}
}
@ -47,6 +51,10 @@ impl Config {
let cmd = cmd.to_string();
config.cd_cmd = cmd;
}
Ok(("media_autoplay", "on")) => { config.media_autoplay = true; },
Ok(("media_autoplay", "off")) => { config.media_autoplay = false; },
Ok(("media_mute", "on")) => { config.media_mute = true; },
Ok(("media_mute", "off")) => { config.media_mute = false; },
_ => { HError::config_error::<Config>(line.to_string()).log(); }
}
config

View File

@ -97,6 +97,10 @@ pub enum HError {
ConfigLineError(String),
#[fail(display = "New input in Minibuffer")]
MiniBufferInputUpdated(String),
#[fail(display = "Failed to parse into UTF8")]
UTF8ParseError(std::str::Utf8Error),
#[fail(display = "Failed to parse integer!")]
ParseIntError(std::num::ParseIntError),
}
impl HError {
@ -308,3 +312,18 @@ impl From<async_value::AError> for HError {
err
}
}
impl From<std::str::Utf8Error> for HError {
fn from(error: std::str::Utf8Error) -> Self {
let err = HError::UTF8ParseError(error);
err
}
}
impl From<std::num::ParseIntError> for HError {
fn from(error: std::num::ParseIntError) -> Self {
let err = HError::ParseIntError(error);
err
}
}

View File

@ -1280,7 +1280,12 @@ impl Widget for FileBrowser {
Key::Char('g') => self.show_log()?,
Key::Char('z') => self.run_subshell()?,
Key::Char('c') => self.toggle_colums(),
_ => { self.main_widget_mut()?.on_key(key)?; },
_ => {
let main_widget_result = self.main_widget_mut()?.on_key(key);
if let Err(HError::WidgetUndefinedKeyError{..}) = main_widget_result {
self.preview_widget_mut()?.on_key(key)?;
}
},
}
if !self.columns.zoom_active { self.update_preview().log(); }
Ok(())

View File

@ -18,6 +18,8 @@ use failure::Error;
use notify::DebouncedEvent;
use rayon::{ThreadPool, ThreadPoolBuilder};
use alphanumeric_sort::compare_str;
use mime_guess;
use pathbuftools::PathBufTools;
use async_value::{Async, Stale};
@ -830,9 +832,12 @@ impl File {
Ok((size, unit))
}
// pub fn get_mime(&self) -> String {
// tree_magic::from_filepath(&self.path)
// }
pub fn get_mime(&self) -> Option<mime_guess::Mime> {
if let Some(ext) = self.path.extension() {
let mime = mime_guess::get_mime_type(&ext.to_string_lossy());
Some(mime)
} else { None }
}
pub fn is_text(&self) -> bool {
tree_magic::match_filepath("text/plain", &self.path)

86
src/imgview.rs Normal file
View File

@ -0,0 +1,86 @@
use crate::widget::{Widget, WidgetCore};
use crate::fail::HResult;
use std::path::{Path, PathBuf};
impl std::cmp::PartialEq for ImgView {
fn eq(&self, other: &Self) -> bool {
self.core == other.core &&
self.buffer == other.buffer
}
}
pub struct ImgView {
pub core: WidgetCore,
pub buffer: Vec<String>,
pub file: PathBuf
}
impl ImgView {
pub fn new_from_file(core: WidgetCore, file: &Path) -> HResult<ImgView> {
let (xsize, ysize) = core.coordinates.size_u();
let output = std::process::Command::new("preview-gen")
.arg(format!("{}", (xsize)))
.arg(format!("{}", (ysize+1)))
.arg("image")
.arg(format!("true"))
.arg(format!("true"))
.arg(file.to_string_lossy().to_string())
.output()?
.stdout;
let output = std::str::from_utf8(&output)?;
let output = output.lines()
.map(|l| l.to_string())
.collect();
Ok(ImgView {
core: core,
buffer: output,
file: file.to_path_buf()
})
}
pub fn set_image_data(&mut self, img_data: Vec<String>) {
self.buffer = img_data;
}
pub fn lines(&self) -> usize {
self.buffer.len()
}
}
impl Widget for ImgView {
fn get_core(&self) -> HResult<&WidgetCore> {
Ok(&self.core)
}
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
fn refresh(&mut self) -> HResult<()> {
Ok(())
}
fn get_drawlist(&self) -> HResult<String> {
let (xpos, ypos) = self.core.coordinates.position_u();
let mut draw = self.buffer
.iter()
.enumerate()
.fold(String::new(), |mut draw, (pos, line)| {
draw += &format!("{}", crate::term::goto_xy_u(xpos+1,
ypos + pos));
draw += line;
draw
});
draw += &format!("{}", termion::style::Reset);
Ok(draw)
}
}

View File

@ -21,6 +21,8 @@ extern crate parse_ansi;
extern crate signal_notify;
extern crate tree_magic;
extern crate systemstat;
extern crate mime_guess;
extern crate osstrtools;
extern crate pathbuftools;
extern crate async_value;
@ -52,6 +54,11 @@ mod config;
mod stats;
mod icon;
#[cfg(feature = "img")]
mod imgview;
#[cfg(feature = "video")]
mod mediaview;

442
src/mediaview.rs Normal file
View File

@ -0,0 +1,442 @@
use lazy_static;
use termion::event::{Event, Key};
use crate::widget::{Widget, WidgetCore};
use crate::async_value::Stale;
use crate::fail::{HResult, HError, ErrorLog};
use crate::imgview::ImgView;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex, RwLock,
mpsc::{channel, Sender}};
use std::io::{BufRead, BufReader, Write};
use std::process::Child;
impl std::cmp::PartialEq for MediaView {
fn eq(&self, other: &Self) -> bool {
self.core == other.core
}
}
lazy_static! {
static ref MUTE: Arc<RwLock<bool>> = Arc::new(RwLock::new(false));
static ref AUTOPLAY: Arc<RwLock<bool>> = Arc::new(RwLock::new(true));
}
pub struct MediaView {
core: WidgetCore,
imgview: Arc<Mutex<ImgView>>,
file: PathBuf,
controller: Sender<String>,
paused: bool,
media_type: MediaType,
position: Arc<Mutex<usize>>,
duration: Arc<Mutex<usize>>,
stale: Stale,
process: Arc<Mutex<Option<Child>>>,
preview_runner: Option<Box<dyn FnOnce(bool,
bool,
Arc<Mutex<usize>>,
Arc<Mutex<usize>>)
-> HResult<()> + Send + 'static>>
}
#[derive(Clone,Debug)]
pub enum MediaType {
Video,
Audio
}
impl MediaType {
pub fn to_str(&self) -> &str {
match self {
MediaType::Video => "video",
MediaType::Audio => "audio"
}
}
}
impl MediaView {
pub fn new_from_file(core: WidgetCore,
file: &Path,
media_type: MediaType) -> MediaView {
let (xsize, ysize) = core.coordinates.size_u();
let (tx_cmd, rx_cmd) = channel();
let imgview = ImgView {
core: core.clone(),
buffer: vec![],
file: file.to_path_buf()
};
let imgview = Arc::new(Mutex::new(imgview));
let thread_imgview = imgview.clone();
let path = file.to_string_lossy().to_string();
let sender = core.get_sender();
let stale = Stale::new();
let tstale = stale.clone();
let rx_cmd = Arc::new(Mutex::new(rx_cmd));
let process = Arc::new(Mutex::new(None));
let cprocess = process.clone();
let ctype = media_type.clone();
let run_preview = Box::new(move | auto,
mute,
position: Arc<Mutex<usize>>,
duration: Arc<Mutex<usize>>| -> HResult<()> {
loop {
if tstale.is_stale()? {
return Ok(());
}
let mut previewer = std::process::Command::new("preview-gen")
.arg(format!("{}", (xsize)))
// Leave space for position/seek bar
.arg(format!("{}", (ysize-3)))
.arg(format!("{}", ctype.to_str()))
.arg(format!("{}", auto))
.arg(format!("{}", mute))
.arg(&path)
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::inherit())
.spawn()?;
let mut stdout = BufReader::new(previewer.stdout.take()?);
let mut stdin = previewer.stdin.take()?;
cprocess.lock().map(|mut p| *p = Some(previewer))?;
let mut frame = vec![];
let newline = String::from("\n");
let mut line_buf = String::new();
let rx_cmd = rx_cmd.clone();
std::thread::spawn(move || -> HResult<()> {
for cmd in rx_cmd.lock()?.iter() {
write!(stdin, "{}", cmd)?;
write!(stdin, "\n")?;
stdin.flush()?;
}
Ok(())
});
loop {
// Check if preview-gen finished and break out of loop to restart
if let Ok(Some(code)) = cprocess.lock()?
.as_mut()?
.try_wait() {
if code.success() {
break;
} else { return Ok(()); }
}
stdout.read_line(&mut line_buf)?;
// Newline means frame is complete
if line_buf == newline {
line_buf.clear();
stdout.read_line(&mut line_buf)?;
let pos = &line_buf.trim();
*position.lock().unwrap() = pos
.parse::<usize>()?;
line_buf.clear();
stdout.read_line(&mut line_buf)?;
let dur = &line_buf.trim();
*duration.lock().unwrap() = dur
.parse::<usize>()?;
if let Ok(mut imgview) = thread_imgview.lock() {
imgview.set_image_data(frame);
sender.send(crate::widget::Events::WidgetReady)
.map_err(|e| HError::from(e))
.log();;
}
line_buf.clear();
frame = vec![];
continue;
} else {
frame.push(line_buf);
line_buf = String::new();
}
}
}
});
MediaView {
core: core.clone(),
imgview: imgview,
file: file.to_path_buf(),
media_type: media_type,
controller: tx_cmd,
paused: false,
position: Arc::new(Mutex::new(0)),
duration: Arc::new(Mutex::new(0)),
stale: stale,
process: process,
preview_runner: Some(run_preview)
}
}
pub fn start_video(&mut self) -> HResult<()> {
let runner = self.preview_runner.take();
let stale = self.stale.clone();
let autoplay = self.autoplay();
let mute = self.mute();
let position = self.position.clone();
let duration = self.duration.clone();
if runner.is_some() {
self.clear().log();
std::thread::spawn(move || -> HResult<()> {
let sleeptime = std::time::Duration::from_millis(50);
std::thread::sleep(sleeptime);
if !stale.is_stale()? {
runner.map(|runner| runner(autoplay,
mute,
position,
duration));
}
Ok(())
});
}
Ok(())
}
pub fn play(&self) -> HResult<()> {
Ok(self.controller.send(String::from("p"))?)
}
pub fn pause(&self) -> HResult<()> {
Ok(self.controller.send(String::from ("a"))?)
}
pub fn progress_bar(&self) -> HResult<String> {
let xsize = self.core.coordinates.xsize_u();
let position = self.position.lock()?.clone();
let duration = self.duration.lock()?.clone();
if duration == 0 || position == 0 {
Ok(format!("{:elements$}", "|", elements=xsize))
} else {
let element_percent = 100 as f32 / xsize as f32;
let progress_percent = position as f32 / duration as f32 * 100 as f32;
let element_count = progress_percent as f32 / element_percent as f32;
Ok(format!("{:|>elements$}|{: >empty$}",
"",
"",
empty=xsize - (element_count as usize + 1),
elements=element_count as usize))
}
}
pub fn progress_string(&self) -> HResult<String> {
let position = self.position.lock()?.clone();
let duration = self.duration.lock()?.clone();
let fposition = self.format_secs(position);
let fduration = self.format_secs(duration);
Ok(format!("{} / {}", fposition, fduration))
}
pub fn get_icons(&self, lines: usize) -> HResult<String> {
let (xpos, ypos) = self.core.coordinates.position_u();
let (xsize, _) = self.core.coordinates.size_u();
let mute_char = "🔇";
let pause_char = "";
let play_char = "";
let mut icons = String::new();
if *MUTE.read()? == true {
icons += &crate::term::goto_xy_u(xpos+xsize-2, ypos+lines);
icons += mute_char;
} else {
// Clear the mute symbol, or it doesn't go away
icons += &crate::term::goto_xy_u(xpos+xsize-2, ypos+lines);
icons += " ";
}
if *AUTOPLAY.read()? == true {
icons += &crate::term::goto_xy_u(xpos+xsize-4, ypos+lines);
icons += play_char;
} else {
icons += &crate::term::goto_xy_u(xpos+xsize-4, ypos+lines);
icons += pause_char;
}
Ok(icons)
}
pub fn format_secs(&self, secs: usize) -> String {
let hours = if secs >= 60*60 { (secs / 60) / 60 } else { 0 };
let mins = if secs >= 60 { (secs / 60) %60 } else { 0 };
format!("{:02}:{:02}:{:02}", hours, mins, secs % 60)
}
pub fn toggle_pause(&mut self) -> HResult<()> {
let auto = AUTOPLAY.read()?.clone();
let pos = self.position.lock()?.clone();
// This combination means only first frame show, since
// self.paused will be false, even with autoplay off
if pos == 0 && auto == false && self.paused == false {
self.toggle_autoplay();
// Since GStreamer sucks, just create a new instace
let mut view = MediaView::new_from_file(self.core.clone(),
&self.file.clone(),
self.media_type.clone());
// Insert buffer to prevent flicker
let buffer = self.imgview.lock()?.buffer.clone();
view.imgview.lock()?.buffer = buffer;
view.start_video()?;
view.paused = false;
view.play()?;
std::mem::swap(self, &mut &mut view);
return Ok(())
}
if self.paused {
self.toggle_autoplay();
self.play()?;
self.paused = false;
} else {
self.pause()?;
self.toggle_autoplay();
self.paused = true;
}
Ok(())
}
pub fn quit(&self) -> HResult<()> {
Ok(self.controller.send(String::from("q"))?)
}
pub fn seek_forward(&self) -> HResult<()> {
Ok(self.controller.send(String::from(">"))?)
}
pub fn seek_backward(&self) -> HResult<()> {
Ok(self.controller.send(String::from("<"))?)
}
pub fn autoplay(&self) -> bool {
if let Ok(autoplay) = AUTOPLAY.read() {
return *autoplay;
}
return true;
}
pub fn mute(&self) -> bool {
if let Ok(mute) = MUTE.read() {
return *mute;
}
return false;
}
pub fn toggle_autoplay(&self) {
if let Ok(mut autoplay) = AUTOPLAY.write() {
*autoplay = !*autoplay;
}
}
pub fn toggle_mute(&self) {
if let Ok(mut mute) = MUTE.write() {
*mute = !*mute;
if *mute {
self.controller.send(String::from("m")).ok();
} else {
self.controller.send(String::from("u")).ok();
}
}
}
pub fn kill(&mut self) -> HResult<()> {
let proc = self.process.clone();
std::thread::spawn(move || -> HResult<()> {
proc.lock()?
.as_mut()
.map(|p| {
p.kill().map_err(|e| HError::from(e)).log();
p.wait().map_err(|e| HError::from(e)).log();
});
Ok(())
});
Ok(())
}
}
impl Widget for MediaView {
fn get_core(&self) -> HResult<&WidgetCore> {
Ok(&self.core)
}
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
fn refresh(&mut self) -> HResult<()> {
self.start_video().log();
Ok(())
}
fn get_drawlist(&self) -> HResult<String> {
let (xpos, ypos) = self.core.coordinates.position_u();
let progress_str = self.progress_string()?;
let progress_bar = self.progress_bar()?;
let (frame, lines) = self.imgview
.lock()
.map(|img| (img.get_drawlist(), img.lines()))?;
let mut frame = frame?;
frame += &crate::term::goto_xy_u(xpos+1, ypos+lines);
frame += &progress_str;
frame += &self.get_icons(lines)?;
frame += &crate::term::goto_xy_u(xpos+1, ypos+lines+1);
frame += &progress_bar;
Ok(frame)
}
fn on_key(&mut self, key: Key) -> HResult<()> {
match key {
Key::Alt('>') => self.seek_forward(),
Key::Alt('<') => self.seek_backward(),
Key::Alt('m') => self.toggle_pause(),
Key::Alt('M') => Ok(self.toggle_mute()),
_ => self.bad(Event::Key(key))
}
}
}
impl Drop for MediaView {
fn drop(&mut self) {
self.stale.set_stale().ok();
self.kill().log();
self.clear().log();
}
}

412
src/preview-gen.rs Normal file
View File

@ -0,0 +1,412 @@
// Based on https://github.com/jD91mZM2/termplay
// MIT License
use image::{Pixel, FilterType, DynamicImage, GenericImageView};
use termion::{color::{Bg, Fg, Rgb},
input::TermRead,
event::Key};
#[cfg(feature = "video")]
use gstreamer::{self, prelude::*};
#[cfg(feature = "video")]
use gstreamer_app;
use failure::{Error, format_err};
use rayon::prelude::*;
use std::io::Write;
pub type MResult<T> = Result<T, Error>;
fn main() -> MResult<()> {
let args = std::env::args().collect::<Vec<String>>();
let xsize: usize = args.get(1)
.expect("Provide xsize")
.parse::<usize>()
.unwrap();
let ysize = args.get(2)
.expect("provide ysize")
.parse()
.unwrap();
let preview_type = args.get(3)
.expect("Provide preview type")
.parse::<String>()
.unwrap();
let autoplay = args.get(4)
.expect("Autoplay?")
.parse::<bool>()
.unwrap();
let mute = args.get(5)
.expect("Muted?")
.parse::<bool>()
.unwrap();
let path = args.get(6).expect("Provide path");
#[cfg(feature = "video")]
let result =
match preview_type.as_ref() {
"video" => video_preview(path, xsize, ysize, autoplay, mute),
"image" => image_preview(path, xsize, ysize),
"audio" => audio_preview(path, autoplay, mute),
_ => { panic!("Available types: video/image/audio") }
};
#[cfg(not(feature = "video"))]
let result = image_preview(path, xsize, ysize);
if result.is_err() {
println!("{:?}", &result);
result
} else {
Ok(())
}
}
fn image_preview(path: &str,
xsize: usize,
ysize: usize) -> MResult<()> {
let img = image::open(&path)?;
let renderer = Renderer {
xsize,
ysize
};
renderer.send_image(img)?;
Ok(())
}
fn video_preview(path: &String,
xsize: usize,
ysize: usize,
autoplay: bool,
mute: bool)
-> MResult<()> {
let (player, appsink) = make_gstreamer()?;
let uri = format!("file://{}", &path);
player.set_property("uri", &uri)?;
let renderer = Renderer {
xsize,
ysize
};
let p = player.clone();
appsink.set_callbacks(
gstreamer_app::AppSinkCallbacks::new()
.new_sample({
move |sink| {
let sample = match sink.pull_sample() {
Some(sample) => sample,
None => return gstreamer::FlowReturn::Eos,
};
let position = p.query_position::<gstreamer::ClockTime>()
.map(|p| p.seconds().unwrap_or(0))
.unwrap_or(0);
let duration = p.query_duration::<gstreamer::ClockTime>()
.map(|d| d.seconds().unwrap_or(0))
.unwrap_or(0);
match renderer.send_frame(&*sample,
position,
duration) {
Ok(()) => {
if autoplay == false {
// Just render first frame to get a static image
match p.set_state(gstreamer::State::Paused)
.into_result() {
Ok(_) => gstreamer::FlowReturn::Eos,
Err(_) => gstreamer::FlowReturn::Error
}
} else {
gstreamer::FlowReturn::Ok
}
}
Err(err) => {
println!("{:?}", err);
gstreamer::FlowReturn::Error
}
}
}
})
.eos({
move |_| {
std::process::exit(0);
}
})
.build()
);
if mute == true || autoplay == false {
player.set_property("volume", &0.0)?;
}
player.set_state(gstreamer::State::Playing).into_result()?;
read_keys(player)?;
Ok(())
}
pub fn read_keys(player: gstreamer::Element) -> MResult<()> {
let seek_time = gstreamer::ClockTime::from_seconds(5);
for key in std::io::stdin().keys() {
match key {
Ok(Key::Char('q')) => std::process::exit(0),
Ok(Key::Char('>')) => {
if let Some(mut time) = player.query_position::<gstreamer::ClockTime>() {
time += seek_time;
player.seek_simple(
gstreamer::SeekFlags::FLUSH,
gstreamer::format::GenericFormattedValue::from_time(time)
)?;
}
},
Ok(Key::Char('<')) => {
if let Some(mut time) = player.query_position::<gstreamer::ClockTime>() {
if time >= seek_time {
time -= seek_time;
} else {
time = gstreamer::ClockTime(Some(0));
}
player.seek_simple(
gstreamer::SeekFlags::FLUSH,
gstreamer::format::GenericFormattedValue::from_time(time)
)?;
}
}
Ok(Key::Char('p')) => {
player.set_state(gstreamer::State::Playing).into_result()?;
// To actually start playing again
if let Some(time) = player.query_position::<gstreamer::ClockTime>() {
player.seek_simple(
gstreamer::SeekFlags::FLUSH,
gstreamer::format::GenericFormattedValue::from_time(time)
)?;
}
}
Ok(Key::Char('a')) => {
player.set_state(gstreamer::State::Paused).into_result()?;
}
Ok(Key::Char('m')) => {
player.set_property("volume", &0.0)?;
}
Ok(Key::Char('u')) => {
player.set_property("volume", &1.0)?;
}
_ => {}
}
}
Ok(())
}
pub fn audio_preview(path: &String,
autoplay: bool,
mute: bool)
-> MResult<()> {
let (player, _) = make_gstreamer()?;
let uri = format!("file://{}", &path);
player.set_property("uri", &uri)?;
let p = player.clone();
// Since events don't work with audio files...
std::thread::spawn(move || -> MResult<()> {
let mut last_pos = None;
let sleep_duration = std::time::Duration::from_millis(50);
let mut stdout = std::io::stdout();
loop {
std::thread::sleep(sleep_duration);
let position = p.query_position::<gstreamer::ClockTime>()
.map(|p| p.seconds().unwrap_or(0))
.unwrap_or(0);
let duration = p.query_duration::<gstreamer::ClockTime>()
.map(|d| d.seconds().unwrap_or(0))
.unwrap_or(0);
// Just redo loop until position changes
if last_pos == Some(position) {
continue
}
last_pos = Some(position);
// MediaView needs empty line as separator
writeln!(stdout, "")?;
// Send position and duration
writeln!(stdout, "{}", position)?;
writeln!(stdout, "{}", duration)?;
stdout.flush()?;
}
});
if mute == true || autoplay == false{
player.set_property("volume", &0.0)?;
} else {
player.set_state(gstreamer::State::Playing).into_result()?;
}
read_keys(player)?;
Ok(())
}
pub fn make_gstreamer() -> MResult<(gstreamer::Element,
gstreamer_app::AppSink)> {
gstreamer::init()?;
let player = gstreamer::ElementFactory::make("playbin", None)
.ok_or(format_err!("Can't create playbin"))?;
let videorate = gstreamer::ElementFactory::make("videorate", None)
.ok_or(format_err!("Can't create videorate element"))?;
let pnmenc = gstreamer::ElementFactory::make("pnmenc", None)
.ok_or(format_err!("Can't create PNM-encoder"))?;
let sink = gstreamer::ElementFactory::make("appsink", None)
.ok_or(format_err!("Can't create appsink"))?;
let appsink = sink.clone()
.downcast::<gstreamer_app::AppSink>()
.unwrap();
videorate.set_property("max-rate", &60)?;
let elems = &[&videorate, &pnmenc, &sink];
let bin = gstreamer::Bin::new(None);
bin.add_many(elems)?;
gstreamer::Element::link_many(elems)?;
// make input for bin point to first element
let sink = elems[0].get_static_pad("sink").unwrap();
let ghost = gstreamer::GhostPad::new("sink", &sink)
.ok_or(format_err!("Can't create GhostPad"))?;
ghost.set_active(true)?;
bin.add_pad(&ghost)?;
player.set_property("video-sink", &bin.upcast::<gstreamer::Element>())?;
Ok((player, appsink))
}
struct Renderer {
xsize: usize,
ysize: usize
}
impl Renderer {
fn send_image(&self, image: DynamicImage) -> MResult<()> {
let rendered_img = self.render_image(image);
for line in rendered_img {
write!(std::io::stdout(), "{}\n", line)?;
}
Ok(())
}
fn send_frame(&self,
frame: &gstreamer::sample::SampleRef,
position: u64,
duration: u64)
-> MResult<()> {
let buffer = frame.get_buffer()
.ok_or(format_err!("Couldn't get buffer from frame!"))?;
let map = buffer.map_readable()
.ok_or(format_err!("Couldn't get buffer from frame!"))?;
let img = image::load_from_memory_with_format(&map,
image::ImageFormat::PNM)?;
let rendered_img = self.render_image(img);
for line in rendered_img {
writeln!(std::io::stdout(), "{}", line)?;
}
// Empty line means end of frame
writeln!(std::io::stdout(), "")?;
// Send position and duration
writeln!(std::io::stdout(), "{}", position)?;
writeln!(std::io::stdout(), "{}", duration)?;
Ok(())
}
pub fn render_image(&self, image: DynamicImage) -> Vec<String> {
let (xsize, ysize) = self.max_size(&image);
let img = image.resize_exact(xsize as u32,
ysize as u32,
FilterType::Nearest).to_rgba();
let rows = img.pixels()
.collect::<Vec<_>>()
.chunks(xsize as usize)
.map(|line| line.to_vec())
.collect::<Vec<Vec<_>>>();
rows.par_chunks(2)
.map(|rows| {
rows[0]
.par_iter()
.zip(rows[1].par_iter())
.map(|(upper, lower)| {
let upper_color = upper.to_rgb();
let lower_color = lower.to_rgb();
format!("{}{}{}",
Fg(Rgb(upper_color[0], upper_color[1], upper_color[2])),
Bg(Rgb(lower_color[0], lower_color[1], lower_color[2])),
termion::style::Reset
)
}).collect()
}).collect()
}
pub fn max_size(&self, image: &DynamicImage) -> (usize, usize)
{
let xsize = self.xsize;
let img_xsize = image.width();
let img_ysize = image.height();
let img_ratio = img_xsize as f32 / img_ysize as f32;
let mut new_y = if img_ratio < 1 as f32 {
xsize as f32 * img_ratio
} else {
xsize as f32 / img_ratio
};
if new_y as u32 % 2 == 1 {
new_y += 1 as f32;
}
(xsize, new_y as usize)
}
}

View File

@ -1,6 +1,7 @@
use std::sync::{Arc, Mutex};
use async_value::{Async, Stale};
use termion::event::Key;
use std::sync::{Arc, Mutex};
use crate::files::{File, Files, Kind};
use crate::fscache::FsCache;
@ -11,6 +12,11 @@ use crate::coordinates::Coordinates;
use crate::fail::{HResult, HError, ErrorLog};
use crate::dirty::Dirtyable;
#[cfg(feature = "img")]
use crate::imgview::ImgView;
#[cfg(feature = "video")]
use crate::mediaview::MediaView;
pub type AsyncWidgetFn<W> = FnOnce(&Stale, WidgetCore)
-> HResult<W> + Send + Sync;
@ -55,8 +61,10 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
let sender = Arc::new(Mutex::new(core.get_sender()));
let mut widget = Async::new(move |stale|
closure(stale).map_err(|e| e.into()));
widget.on_ready(move |_, _| {
sender.lock().map(|s| s.send(crate::widget::Events::WidgetReady)).ok();
widget.on_ready(move |_, stale| {
if !stale.is_stale()? {
sender.lock().map(|s| s.send(crate::widget::Events::WidgetReady)).ok();
}
Ok(())
}).log();
widget.run().log();
@ -80,7 +88,7 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
Ok(closure(stale, core.clone())?)
});
widget.on_ready(move |_, _| {
widget.on_ready(move |mut w, stale| {
sender.lock().map(|s| s.send(crate::widget::Events::WidgetReady)).ok();
Ok(())
}).log();
@ -187,7 +195,11 @@ impl PartialEq for Previewer {
#[derive(PartialEq)]
enum PreviewWidget {
FileList(ListView<Files>),
TextView(TextView)
TextView(TextView),
#[cfg(feature = "img")]
ImgView(ImgView),
#[cfg(feature = "video")]
MediaView(MediaView)
}
@ -311,39 +323,73 @@ impl Previewer {
self.animator.set_stale().ok();
}
self.become_preview(Ok(AsyncWidget::new(&self.core,
move |stale: &Stale| {
kill_proc().unwrap();
self.become_preview(Ok(AsyncWidget::new(
&self.core,
move |stale: &Stale|
{
kill_proc().unwrap();
if file.kind == Kind::Directory {
let preview = Previewer::preview_dir(&file,
cache,
&core,
&stale,
&animator);
return Ok(preview?);
}
if file.kind == Kind::Directory {
let preview = Previewer::preview_dir(&file,
cache,
&core,
&stale,
&animator);
return Ok(preview?);
}
if file.is_text() {
return Ok(Previewer::preview_text(&file,
&core,
&stale,
&animator)?);
}
let preview = Previewer::preview_external(&file,
if file.is_text() {
return Ok(Previewer::preview_text(&file,
&core,
&stale,
&animator);
if preview.is_ok() { return Ok(preview?); }
else {
let mut blank = TextView::new_blank(&core);
blank.set_coordinates(&coordinates).log();
blank.refresh().log();
blank.animate_slide_up(Some(&animator)).log();
return Ok(PreviewWidget::TextView(blank))
}
})))
&animator)?);
}
if let Some(mime) = file.get_mime() {
let mime_type = mime.type_().as_str();
let is_gif = mime.subtype() == "gif";
match mime_type {
#[cfg(feature = "video")]
_ if mime_type == "video" || is_gif => {
let media_type = crate::mediaview::MediaType::Video;
let mediaview = MediaView::new_from_file(core.clone(),
&file.path,
media_type);
return Ok(PreviewWidget::MediaView(mediaview));
}
#[cfg(feature = "img")]
"image" => {
let imgview = ImgView::new_from_file(core.clone(),
&file.path())?;
return Ok(PreviewWidget::ImgView(imgview));
}
#[cfg(feature = "video")]
"audio" => {
let media_type = crate::mediaview::MediaType::Audio;
let mediaview = MediaView::new_from_file(core.clone(),
&file.path,
media_type);
return Ok(PreviewWidget::MediaView(mediaview));
}
_ => {}
}
}
let preview = Previewer::preview_external(&file,
&core,
&stale,
&animator);
if preview.is_ok() { return Ok(preview?); }
else {
let mut blank = TextView::new_blank(&core);
blank.set_coordinates(&coordinates).log();
blank.refresh().log();
blank.animate_slide_up(Some(&animator)).log();
return Ok(PreviewWidget::TextView(blank))
}
})))
}
pub fn reload(&mut self) {
@ -454,7 +500,6 @@ impl Previewer {
}
HError::preview_failed(file)
}
}
@ -487,37 +532,72 @@ impl Widget for Previewer {
fn get_drawlist(&self) -> HResult<String> {
self.widget.get_drawlist()
}
fn on_key(&mut self, key: Key) -> HResult<()> {
self.widget.on_key(key)
}
}
impl Widget for PreviewWidget {
fn get_core(&self) -> HResult<&WidgetCore> {
match self {
PreviewWidget::FileList(widget) => widget.get_core(),
PreviewWidget::TextView(widget) => widget.get_core()
PreviewWidget::TextView(widget) => widget.get_core(),
#[cfg(feature = "img")]
PreviewWidget::ImgView(widget) => widget.get_core(),
#[cfg(feature = "video")]
PreviewWidget::MediaView(widget) => widget.get_core()
}
}
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
match self {
PreviewWidget::FileList(widget) => widget.get_core_mut(),
PreviewWidget::TextView(widget) => widget.get_core_mut()
PreviewWidget::TextView(widget) => widget.get_core_mut(),
#[cfg(feature = "img")]
PreviewWidget::ImgView(widget) => widget.get_core_mut(),
#[cfg(feature = "video")]
PreviewWidget::MediaView(widget) => widget.get_core_mut()
}
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
match self {
PreviewWidget::FileList(widget) => widget.set_coordinates(coordinates),
PreviewWidget::TextView(widget) => widget.set_coordinates(coordinates),
#[cfg(feature = "img")]
PreviewWidget::ImgView(widget) => widget.set_coordinates(coordinates),
#[cfg(feature = "video")]
PreviewWidget::MediaView(widget) => widget.set_coordinates(coordinates),
}
}
fn refresh(&mut self) -> HResult<()> {
match self {
PreviewWidget::FileList(widget) => widget.refresh(),
PreviewWidget::TextView(widget) => widget.refresh()
PreviewWidget::TextView(widget) => widget.refresh(),
#[cfg(feature = "img")]
PreviewWidget::ImgView(widget) => widget.refresh(),
#[cfg(feature = "video")]
PreviewWidget::MediaView(widget) => widget.refresh()
}
}
fn get_drawlist(&self) -> HResult<String> {
match self {
PreviewWidget::FileList(widget) => widget.get_drawlist(),
PreviewWidget::TextView(widget) => widget.get_drawlist()
PreviewWidget::TextView(widget) => widget.get_drawlist(),
#[cfg(feature = "img")]
PreviewWidget::ImgView(widget) => widget.get_drawlist(),
#[cfg(feature = "video")]
PreviewWidget::MediaView(widget) => widget.get_drawlist()
}
}
fn on_key(&mut self, key: Key) -> HResult<()> {
match self {
PreviewWidget::FileList(widget) => widget.on_key(key),
PreviewWidget::TextView(widget) => widget.on_key(key),
#[cfg(feature = "img")]
PreviewWidget::ImgView(widget) => widget.on_key(key),
#[cfg(feature = "video")]
PreviewWidget::MediaView(widget) => widget.on_key(key)
}
}
}

View File

@ -159,7 +159,7 @@ pub trait Widget {
fn on_key(&mut self, key: Key) -> HResult<()> {
match key {
_ => { self.bad(Event::Key(key)).unwrap() },
_ => { self.bad(Event::Key(key))? },
}
Ok(())
}
@ -179,7 +179,10 @@ pub trait Widget {
}
fn bad(&mut self, event: Event) -> HResult<()> {
self.show_status(&format!("Stop it!! {:?} does nothing!", event))
self.show_status(&format!("Stop it!! {:?} does nothing!", event)).log();
if let Event::Key(key) = event {
HError::undefined_key(key)
} else { Ok(()) }
}
fn get_header_drawlist(&mut self) -> HResult<String> {