diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f9fdf03..8726f9e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,53 +14,34 @@ before_script: # kcov # - apt-get install -y libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc binutils-dev libiberty-dev +.cargo_test_template: &cargo_test + stage: test + script: + - rustc --version && cargo --version + - cargo build + - cargo test --verbose -- --test-threads=1 + variables: # RUSTFLAGS: "-C link-dead-code" RUST_BACKTRACE: "FULL" -# Currently doesnt work. -# # Build with meson -# build:stable: -# # Stable img -# # https://hub.docker.com/_/rust/ -# image: "rust" -# script: -# - rustc --version && cargo --version -# - ./configure --prefix=/usr/local -# - make && sudo make install - -# build:nightly: -# # Nightly -# # https://hub.docker.com/r/rustlang/rust/ -# image: "rustlang/rust:nightly" -# script: -# - rustc --version && cargo --version -# - ./configure --prefix=/usr/local -# - make && sudo make install - -test:stable: - # Stable img +stable:test: # https://hub.docker.com/_/rust/ image: "rust" - script: - - rustc --version && cargo --version - - cargo build - - cargo test --verbose -- --test-threads=1 + <<: *cargo_test -test:nightly: - # Nightly +nightly:test: # https://hub.docker.com/r/rustlang/rust/ image: "rustlang/rust:nightly" - script: - - rustc --version && cargo --version - - cargo build - - cargo test --verbose -- --test-threads=1 - # - cargo bench + <<: *cargo_test # Configure and run rustfmt on nightly # Exits and builds fails if on bad format -lint:rustfmt: +rustfmt: image: "rustlang/rust:nightly" + stage: lint + variables: + CFG_RELEASE_CHANNEL: "nightly" script: - rustc --version && cargo --version - cargo install rustfmt-nightly @@ -68,8 +49,9 @@ lint:rustfmt: # Configure and run clippy on nightly # Only fails on errors atm. -lint:clippy: +clippy: image: "rustlang/rust:nightly" + stage: lint script: - rustc --version && cargo --version - cargo install clippy diff --git a/Cargo.lock b/Cargo.lock index 1a740c6..f6037b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,10 +14,23 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ammonia" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "html5ever 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "maplit 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -38,7 +51,7 @@ dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -48,7 +61,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -62,7 +75,7 @@ dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -73,7 +86,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -81,7 +94,7 @@ name = "base64" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -107,7 +120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -115,7 +128,7 @@ name = "bytes" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -133,7 +146,7 @@ dependencies = [ "cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -142,7 +155,7 @@ name = "cairo-sys-rs" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -162,7 +175,7 @@ name = "chrono" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -181,7 +194,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -189,7 +202,7 @@ name = "core-foundation-sys" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -256,31 +269,30 @@ dependencies = [ [[package]] name = "diesel" -version = "0.16.0" -source = "git+https://github.com/diesel-rs/diesel.git#07f80c3a0d07daa26efff3166fbf0297dc0f0a7b" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "diesel_derives 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", "libsqlite3-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "diesel_codegen" -version = "0.16.0" -source = "git+https://github.com/diesel-rs/diesel.git#07f80c3a0d07daa26efff3166fbf0297dc0f0a7b" +name = "diesel_derives" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "diesel 0.16.0 (git+https://github.com/diesel-rs/diesel.git)", - "diesel_infer_schema 0.16.0 (git+https://github.com/diesel-rs/diesel.git)", - "dotenv 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "diesel_infer_schema" -version = "0.16.0" -source = "git+https://github.com/diesel-rs/diesel.git#07f80c3a0d07daa26efff3166fbf0297dc0f0a7b" +name = "diesel_migrations" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "diesel 0.16.0 (git+https://github.com/diesel-rs/diesel.git)", + "migrations_internals 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", + "migrations_macros 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -299,7 +311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "derive-error-chain 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -338,7 +350,15 @@ dependencies = [ [[package]] name = "foreign-types" -version = "0.2.0" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -394,7 +414,7 @@ dependencies = [ "glib 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -407,7 +427,7 @@ dependencies = [ "glib 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -419,7 +439,7 @@ dependencies = [ "gio-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -434,7 +454,7 @@ dependencies = [ "gio-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -449,7 +469,7 @@ dependencies = [ "glib 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -460,7 +480,7 @@ dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -473,7 +493,7 @@ dependencies = [ "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (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.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -482,7 +502,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -493,7 +513,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -515,7 +535,7 @@ dependencies = [ "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gtk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -532,7 +552,7 @@ dependencies = [ "gio-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -541,20 +561,22 @@ dependencies = [ name = "hammond-data" version = "0.1.0" dependencies = [ + "ammonia 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "diesel 0.16.0 (git+https://github.com/diesel-rs/diesel.git)", - "diesel_codegen 0.16.0 (git+https://github.com/diesel-rs/diesel.git)", + "derive_builder 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", + "diesel_migrations 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "r2d2 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "r2d2-diesel 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2-diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rfc822_sanitizer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rss 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rss 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -564,12 +586,12 @@ dependencies = [ name = "hammond-downloader" version = "0.1.0" dependencies = [ - "diesel 0.16.0 (git+https://github.com/diesel-rs/diesel.git)", + "diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "hammond-data 0.1.0", "hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 1.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mime_guess 1.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -578,8 +600,7 @@ dependencies = [ name = "hammond-gtk" version = "0.1.0" dependencies = [ - "diesel 0.16.0 (git+https://github.com/diesel-rs/diesel.git)", - "diesel_codegen 0.16.0 (git+https://github.com/diesel-rs/diesel.git)", + "diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", "dissolve 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "gdk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gdk-pixbuf 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -589,9 +610,10 @@ dependencies = [ "hammond-data 0.1.0", "hammond-downloader 0.1.0", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "loggerv 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "loggerv 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -663,7 +685,7 @@ name = "iovec" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -691,6 +713,11 @@ name = "lazy_static" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazy_static" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazycell" version = "0.5.1" @@ -698,7 +725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.33" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -707,7 +734,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -727,7 +754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "loggerv" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -740,6 +767,11 @@ name = "mac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "maplit" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "markup5ever" version = "0.6.2" @@ -760,10 +792,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memchr" -version = "1.0.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "migrations_internals" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "migrations_macros" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "migrations_internals 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -784,7 +834,7 @@ dependencies = [ [[package]] name = "mime_guess" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -795,7 +845,7 @@ dependencies = [ [[package]] name = "mime_guess" -version = "2.0.0-alpha.2" +version = "2.0.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -814,7 +864,7 @@ dependencies = [ "iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -838,7 +888,7 @@ name = "native-tls" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "openssl 0.9.21 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)", "schannel 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -852,19 +902,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -872,7 +922,7 @@ name = "num-integer" version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -881,12 +931,12 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -894,7 +944,7 @@ name = "num_cpus" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -904,23 +954,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.9.21" +version = "0.9.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (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.33 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.9.21" +version = "0.9.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -934,7 +984,7 @@ dependencies = [ "glib 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -946,7 +996,7 @@ dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1002,12 +1052,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quick-xml" -version = "0.9.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1017,21 +1067,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "r2d2" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "scheduled-thread-pool 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "r2d2-diesel" -version = "0.16.0" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "diesel 0.16.0 (git+https://github.com/diesel-rs/diesel.git)", - "r2d2 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1040,7 +1090,7 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1059,14 +1109,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "coco 0.1.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.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1074,16 +1124,16 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1113,10 +1163,10 @@ dependencies = [ "hyper-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libflate 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mime_guess 2.0.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1132,16 +1182,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rss" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "derive_builder 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-xml 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-xml 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1175,7 +1225,7 @@ dependencies = [ [[package]] name = "scheduled-thread-pool" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1207,7 +1257,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1217,23 +1267,23 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_json" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1243,7 +1293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1276,7 +1326,7 @@ dependencies = [ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1343,8 +1393,8 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1363,8 +1413,8 @@ version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1552,7 +1602,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" -"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" +"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" +"checksum ammonia 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2cc0ea12b4977283c563e78eaf227b024d89d72a6394040fad4063899bfcfb48" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" "checksum atk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "33a67fd81e1922dddc335887516f2f5254534e89c9d39fa89bca5d79bd150d34" @@ -1564,7 +1615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" -"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" +"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6" "checksum c_vec 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6237ac5a4b1e81c213c24c6437964c61e646df910a914b4ab1487b46df20bd13" "checksum cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6b5695f59fd036fe5741bc5a4eb20c78fbe42256e3b08a2af26bbcbe8070bf3" @@ -1582,9 +1633,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum derive-error-chain 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9ca9ade651388daad7c993f005d0d20c4f6fe78c1cdc93e95f161c6f5ede4a" "checksum derive_builder 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03600ae366b6eb2314e54d62adc833d9866da03798acc61c61789654ceaa227a" "checksum derive_builder_core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eed37eae64daa5511467b1a55cebdf472deeaef108d22f62f25e8bbcaffd56ac" -"checksum diesel 0.16.0 (git+https://github.com/diesel-rs/diesel.git)" = "" -"checksum diesel_codegen 0.16.0 (git+https://github.com/diesel-rs/diesel.git)" = "" -"checksum diesel_infer_schema 0.16.0 (git+https://github.com/diesel-rs/diesel.git)" = "" +"checksum diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b97bd43f72d4819fac99f24d0030184c64c5ebdee96f94c7a7d4215c50506a7" +"checksum diesel_derives 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad228b6fd05c86050b95f56e497a8135073ffce28602e2200e63a21047eb474d" +"checksum diesel_migrations 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)" = "745dcfe39e3043c267e46dbe4f2ebbc9917039bdf4d81b108950be61244dfc89" "checksum dissolve 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "898542be4716d992082c8e4fc331b792d626cfa71cb2b4790f828b9a8f921a90" "checksum dotenv 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d6f0e2bb24d163428d8031d3ebd2d2bd903ad933205a97d0f18c7c1aade380f3" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" @@ -1592,7 +1643,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f5215aabf22b83153be3ee44dfe3f940214541b2ce13d419c55e7a115c8c51a9" "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" -"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" +"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" "checksum futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "51f93f3de6ba1794dcd5810b3546d004600a59a98266487c8407bc4b24e398f3" @@ -1619,32 +1671,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" +"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" -"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2" +"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0" "checksum libflate 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ae46bcdafa496981e996e57c5be82c0a7f130a071323764c6faa4803619f1e67" "checksum libsqlite3-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "370090ad578ba845a3ad4f383ceb3deba7abd51ab1915ad1f2c982cc6035e31c" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" -"checksum loggerv 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5bb7c9e1ed99294067005cc7d4413441197ba354e8286c36b72a66a557c13661" +"checksum loggerv 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b178879253fab6ddb4ea931e1e6f514d45ce6a53f7fe618a0a8751f43e42e4f1" "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +"checksum maplit 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ed95049d40b8a1a7691adbabca028ad481f7e6a2921ce4846e1ee168b4e4ca5" "checksum markup5ever 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2cf89d3e0486c32c9d99521455ddf9a438910a1ce2bd376936086edc15dff5fc" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" +"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" +"checksum migrations_internals 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ac1d17f6f161f4d91cb7e5a72cce5b24a60b80f96580a8ac94351c56b8606a" +"checksum migrations_macros 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc767420eac6b718cd593aaa09c06a31d4ed228291c8538b274737e28a29939b" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e00e17be181010a91dbfefb01660b17311059dc8c7f48b9017677721e732bd" -"checksum mime_guess 1.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bbee1a836f344ac39d4a59bfe7be2bd3150353ff71678afb740216f8270b333e" -"checksum mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27a5e6679a0614e25adc14c6434ba84e41632b765a6d9cb2031a0cca682699ae" +"checksum mime_guess 1.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7e82a15629bb4ecd9e72365bf33d1382be91e030f820edb8e2a21c02430da8" +"checksum mime_guess 2.0.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "013572795763289e14710c7b279461295f2673b2b338200c235082cd7ca9e495" "checksum mio 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0e8411968194c7b139e9105bc4ae7db0bae232af087147e72f0616ebf5fdb9cb" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04b781c9134a954c84f0594b9ab3f5606abc516030388e8511887ef4c204a1e5" "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" -"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" +"checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca" "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" -"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" +"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" -"checksum openssl 0.9.21 (registry+https://github.com/rust-lang/crates.io-index)" = "2225c305d8f57001a0d34263e046794aa251695f20773102fbbfeb1e7b189955" -"checksum openssl-sys 0.9.21 (registry+https://github.com/rust-lang/crates.io-index)" = "92867746af30eea7a89feade385f7f5366776f1c52ec6f0de81360373fa88363" +"checksum openssl 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "419ef26bb651d72b6c5a603bcc4e4856a362460e62352dfffa53de91d2e81181" +"checksum openssl-sys 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5483bdc56756041ba6aa37c9cb59cc2219f012a2a1377d97ad35556ac6676ee7" "checksum pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e81c404ab81ea7ea2fc2431a0a7672507b80e4b8bf4b41eac3fc83cc665104e" "checksum pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34f34a1be107fe16abb2744e0e206bee4b3b07460b5fddd3009a6aaf60bd69ab" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" @@ -1654,33 +1710,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -"checksum quick-xml 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "19a3a610544419c527d5f51ae1a6ae3db533e25c117d3eed8fce6434f70c5e95" +"checksum quick-xml 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d0fb3e41d968cd20da34a9e81abae097398b38fe0987149e321572eb75d3317" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum r2d2 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2c8284508b38df440f8f3527395e23c4780b22f74226b270daf58fee38e4bcce" -"checksum r2d2-diesel 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6b921696a6c45991296d21b52ed973b9fb56f6c47524fda1f99458c2d6c0478" +"checksum r2d2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "59611202bee496c586ecd84e3ed149b4ec75981b0fc10d7f60e878fa23ae16e9" +"checksum r2d2-diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77aaed149a82720f4b664427f359e1b2a34d8787c1bc3fb1d167b104a1ddd866" "checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd" "checksum rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf" "checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53" -"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" +"checksum redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ab105df655884ede59d45b7070c8a65002d921461ee813a024558ca16030eea0" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" +"checksum regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ac6ab4e9218ade5b423358bbd2567d1617418403c7a512603630181813316322" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f301bafeb60867c85170031bdb2fcf24c8041f33aee09e7b116a58d4e9f781c5" "checksum reqwest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f73a8482e3b2b20ef5c07168b27048fc3778a012ce9b11a021556a450a01e9b5" "checksum rfc822_sanitizer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "680e8305c1e0cdf836dc4bec5424e045f278c975a3cac36d1ca01c4695f9d815" -"checksum rss 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70294b2be2d620fed3939032067684c53b8ccae18e8ca0b8410447f0f07228c5" +"checksum rss 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3fbc1a0587ebbc7404b3295c8e1f717d00dad48e3c205adadf916f15ff67d05b" "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum schannel 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7554288337c1110e34d7a2433518d889374c1de1a45f856b7bcddb03702131fc" -"checksum scheduled-thread-pool 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d9fbe48ead32343b76f544c85953bf260ed39219a8bbbb62cd85f6a00f9644f" +"checksum scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a2ff3fc5223829be817806c6441279c676e454cc7da608faf03b0ccc09d3889" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f412dfa83308d893101dd59c10d6fda8283465976c28c287c5c855bf8d216bc" "checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" "checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" -"checksum serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6eda663e865517ee783b0891a3f6eb3a253e0b0dabb46418969ee9635beadd9e" -"checksum serde_json 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e4586746d1974a030c48919731ecffd0ed28d0c40749d0d18d43b3a7d6c9b20e" +"checksum serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7c37d7f192f00041e8a613e936717923a71bc0c9051fc4425a49b104140f05" +"checksum serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ea28ea0cca944668919bec6af209864a8dfe769fd2b0b723f36b22e20c1bf69f" "checksum serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce0fd303af908732989354c6f02e05e2e6d597152870f2c6990efb0577137480" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" diff --git a/Cargo.toml b/Cargo.toml index 545646a..d1deebf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,3 @@ members = [ [profile.release] debug = false -[patch.crates-io] -diesel = { git = "https://github.com/diesel-rs/diesel.git" } -diesel_infer_schema = { git = "https://github.com/diesel-rs/diesel.git" } -diesel_codegen = { git = "https://github.com/diesel-rs/diesel.git" } diff --git a/TODO.md b/TODO.md index 0316ac8..1ed5678 100644 --- a/TODO.md +++ b/TODO.md @@ -1,14 +1,9 @@ ## TODOs: -**General:** - -- [ ] Write docs - ## Planned Features ## Priorities: -- [ ] Discuss and decide when to schedule the download cleaner. [#3](https://gitlab.gnome.org/alatiera/Hammond/issues/3) - [ ] Unplayed Only and Downloaded only view. - [ ] Auto-updater - [ ] OPML import/export // Probably need to create a crate. diff --git a/hammond-data/Cargo.toml b/hammond-data/Cargo.toml index 2083fe0..34e41c4 100644 --- a/hammond-data/Cargo.toml +++ b/hammond-data/Cargo.toml @@ -5,27 +5,29 @@ version = "0.1.0" workspace = "../" [dependencies] +ammonia = "1.0.0" chrono = "0.4.0" +derive_builder = "0.5.0" dotenv = "0.10.1" error-chain = "0.11.0" -lazy_static = "0.2.11" +lazy_static = "1.0.0" log = "0.3.8" -r2d2 = "0.7.4" -r2d2-diesel = "0.16.0" +r2d2 = "0.8.1" +r2d2-diesel = "0.99.0" rayon = "0.9.0" reqwest = "0.8.1" rfc822_sanitizer = "0.3.3" -rss = "1.1.0" +rss = "1.2.1" url = "1.6.0" xdg = "2.1.0" [dependencies.diesel] features = ["sqlite"] -git = "https://github.com/diesel-rs/diesel.git" +version = "0.99.0" -[dependencies.diesel_codegen] +[dependencies.diesel_migrations] features = ["sqlite"] -git = "https://github.com/diesel-rs/diesel.git" +version = "0.99.0" [dev-dependencies] rand = "0.3.18" diff --git a/hammond-data/src/database.rs b/hammond-data/src/database.rs index c3f024e..bb18bda 100644 --- a/hammond-data/src/database.rs +++ b/hammond-data/src/database.rs @@ -3,16 +3,14 @@ use diesel::prelude::*; use r2d2; use std::path::PathBuf; -use std::sync::Arc; use std::io; -use std::time::Duration; use errors::*; #[cfg(not(test))] use xdg_dirs; -type Pool = Arc>>; +type Pool = r2d2::Pool>; embed_migrations!("migrations/"); @@ -38,19 +36,18 @@ lazy_static! { } pub(crate) fn connection() -> Pool { - Arc::clone(&POOL) + POOL.clone() } fn init_pool(db_path: &str) -> Pool { - let config = r2d2::Config::builder() - .pool_size(1) - .connection_timeout(Duration::from_secs(60)) - .build(); let manager = ConnectionManager::::new(db_path); - let pool = Arc::new(r2d2::Pool::new(config, manager).expect("Failed to create pool.")); + let pool = r2d2::Pool::builder() + .max_size(1) + .build(manager) + .expect("Failed to create pool."); { - let db = Arc::clone(&pool).get().expect("Failed to initialize pool."); + let db = pool.get().expect("Failed to initialize pool."); run_migration_on(&*db).expect("Failed to run migrations during init."); } info!("Database pool initialized."); diff --git a/hammond-data/src/dbqueries.rs b/hammond-data/src/dbqueries.rs index f4c0791..1604547 100644 --- a/hammond-data/src/dbqueries.rs +++ b/hammond-data/src/dbqueries.rs @@ -198,9 +198,10 @@ pub fn update_none_to_played_now(parent: &Podcast) -> Result { let epoch_now = Utc::now().timestamp() as i32; con.transaction(|| -> Result { - Ok(diesel::update( - Episode::belonging_to(parent).filter(played.is_null()), - ).set(played.eq(Some(epoch_now))) - .execute(&*con)?) + Ok( + diesel::update(Episode::belonging_to(parent).filter(played.is_null())) + .set(played.eq(Some(epoch_now))) + .execute(&*con)?, + ) }) } diff --git a/hammond-data/src/errors.rs b/hammond-data/src/errors.rs index 372cc55..274a1a1 100644 --- a/hammond-data/src/errors.rs +++ b/hammond-data/src/errors.rs @@ -1,5 +1,5 @@ use diesel::result; -use diesel::migrations::RunMigrationsError; +use diesel_migrations::RunMigrationsError; use rss; use reqwest; use r2d2; @@ -8,7 +8,7 @@ use std::io; error_chain! { foreign_links { - R2D2TimeoutError(r2d2::GetTimeout); + R2D2Error(r2d2::Error); DieselResultError(result::Error); DieselMigrationError(RunMigrationsError); RSSError(rss::Error); diff --git a/hammond-data/src/feed.rs b/hammond-data/src/feed.rs index 5fd9d33..af38f1a 100644 --- a/hammond-data/src/feed.rs +++ b/hammond-data/src/feed.rs @@ -4,7 +4,7 @@ use rayon::prelude::*; use diesel::prelude::*; use rayon::iter::IntoParallelIterator; -use diesel::Identifiable; +use diesel::associations::Identifiable; use rss; use dbqueries; @@ -276,13 +276,12 @@ mod tests { f2.get_episodes().unwrap() }; - eps1.into_par_iter() - .zip(eps2) - .into_par_iter() - .for_each(|(ep1, ep2): (Episode, Episode)| { + eps1.into_par_iter().zip(eps2).into_par_iter().for_each( + |(ep1, ep2): (Episode, Episode)| { assert_eq!(ep1, ep2); assert_eq!(ep1.id(), ep2.id()); assert_eq!(ep1.podcast_id(), ep2.podcast_id()); - }); + }, + ); } } diff --git a/hammond-data/src/lib.rs b/hammond-data/src/lib.rs index e8ca7f4..9828740 100644 --- a/hammond-data/src/lib.rs +++ b/hammond-data/src/lib.rs @@ -1,5 +1,4 @@ #![recursion_limit = "1024"] -#![deny(missing_docs)] #![cfg_attr(feature = "cargo-clippy", allow(blacklisted_name))] #![cfg_attr(feature = "clippy", warn(option_unwrap_used, result_unwrap_used, print_stdout, @@ -11,6 +10,15 @@ //! A libraty for parsing, indexing and retrieving podcast Feeds, //! into and from a Database. +#![deny(bad_style, const_err, dead_code, improper_ctypes, legacy_directory_ownership, + non_shorthand_field_patterns, no_mangle_generic_items, overflowing_literals, + path_statements, patterns_in_fns_without_body, plugin_as_library, private_in_public, + private_no_mangle_fns, private_no_mangle_statics, safe_extern_statics, + unconditional_recursion, unions_with_drop_fields, unused, unused_allocation, + unused_comparisons, unused_parens, while_true)] +#![deny(missing_debug_implementations, missing_docs, trivial_casts, trivial_numeric_casts, + unused_extern_crates)] + #[macro_use] extern crate error_chain; @@ -22,9 +30,14 @@ extern crate log; #[macro_use] extern crate diesel; -#[macro_use] -extern crate diesel_codegen; +#[macro_use] +extern crate diesel_migrations; + +#[macro_use] +extern crate derive_builder; + +extern crate ammonia; extern crate chrono; extern crate r2d2; extern crate r2d2_diesel; @@ -49,6 +62,7 @@ mod schema; pub use models::queryables::{Episode, Podcast, Source}; /// [XDG Base Direcotory](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) Paths. +#[allow(missing_debug_implementations)] pub mod xdg_dirs { use std::path::PathBuf; use xdg; diff --git a/hammond-data/src/models/insertables.rs b/hammond-data/src/models/insertables.rs index 7a0ddef..c303dfa 100644 --- a/hammond-data/src/models/insertables.rs +++ b/hammond-data/src/models/insertables.rs @@ -1,3 +1,5 @@ +#![allow(unused_mut)] + use diesel::prelude::*; use schema::{episode, podcast, source}; @@ -20,7 +22,10 @@ trait Update { #[derive(Insertable)] #[table_name = "source"] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default, Builder)] +#[builder(default)] +#[builder(derive(Debug))] +#[builder(setter(into))] pub(crate) struct NewSource { uri: String, last_modified: Option, @@ -63,15 +68,15 @@ impl NewSource { #[derive(Insertable, AsChangeset)] #[table_name = "podcast"] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default, Builder)] +#[builder(default)] +#[builder(derive(Debug))] +#[builder(setter(into))] pub(crate) struct NewPodcast { title: String, link: String, description: String, image_uri: Option, - favorite: bool, - archive: bool, - always_dl: bool, source_id: i32, } @@ -124,78 +129,6 @@ impl NewPodcast { } } -#[derive(Debug, Default)] -pub(crate) struct NewPodcastBuilder { - title: String, - link: String, - description: String, - image_uri: Option, - favorite: bool, - archive: bool, - always_dl: bool, - source_id: i32, -} - -#[allow(dead_code)] -impl NewPodcastBuilder { - pub(crate) fn new() -> NewPodcastBuilder { - NewPodcastBuilder::default() - } - - pub(crate) fn title(mut self, s: String) -> NewPodcastBuilder { - self.title = s; - self - } - - pub(crate) fn link(mut self, s: String) -> NewPodcastBuilder { - self.link = s; - self - } - - pub(crate) fn description(mut self, s: String) -> NewPodcastBuilder { - self.description = s; - self - } - - pub(crate) fn image_uri(mut self, s: Option) -> NewPodcastBuilder { - self.image_uri = s; - self - } - - pub(crate) fn source_id(mut self, s: i32) -> NewPodcastBuilder { - self.source_id = s; - self - } - - pub(crate) fn favorite(mut self, s: bool) -> NewPodcastBuilder { - self.favorite = s; - self - } - - pub(crate) fn archive(mut self, s: bool) -> NewPodcastBuilder { - self.archive = s; - self - } - - pub(crate) fn always_dl(mut self, s: bool) -> NewPodcastBuilder { - self.always_dl = s; - self - } - - pub(crate) fn build(self) -> NewPodcast { - NewPodcast { - title: self.title, - link: self.link, - description: self.description, - image_uri: self.image_uri, - favorite: self.favorite, - archive: self.archive, - always_dl: self.always_dl, - source_id: self.source_id, - } - } -} - #[allow(dead_code)] // Ignore the following geters. They are used in unit tests mainly. impl NewPodcast { @@ -222,19 +155,18 @@ impl NewPodcast { #[derive(Insertable, AsChangeset)] #[table_name = "episode"] -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, Builder)] +#[builder(default)] +#[builder(derive(Debug))] +#[builder(setter(into))] pub(crate) struct NewEpisode { title: Option, uri: String, - local_uri: Option, description: Option, published_date: Option, length: Option, guid: Option, epoch: i32, - played: Option, - favorite: bool, - archive: bool, podcast_id: i32, } @@ -256,8 +188,6 @@ impl Update for NewEpisode { } impl NewEpisode { - // TODO: Currently using diesel from master git. - // Watch out for v0.99.0 beta and change the toml. // TODO: Refactor into batch indexes instead. pub(crate) fn into_episode(self, con: &SqliteConnection) -> Result { self.index(con)?; @@ -287,108 +217,8 @@ impl NewEpisode { } } -#[derive(Debug, Default)] -pub(crate) struct NewEpisodeBuilder { - title: Option, - uri: String, - local_uri: Option, - description: Option, - published_date: Option, - length: Option, - guid: Option, - epoch: i32, - played: Option, - favorite: bool, - archive: bool, - podcast_id: i32, -} - #[allow(dead_code)] -impl NewEpisodeBuilder { - pub(crate) fn new() -> NewEpisodeBuilder { - NewEpisodeBuilder::default() - } - - pub(crate) fn title(mut self, s: Option) -> NewEpisodeBuilder { - self.title = s; - self - } - - pub(crate) fn uri(mut self, s: String) -> NewEpisodeBuilder { - self.uri = s; - self - } - - pub(crate) fn local_uri(mut self, s: Option) -> NewEpisodeBuilder { - self.local_uri = s; - self - } - - pub(crate) fn description(mut self, s: Option) -> NewEpisodeBuilder { - self.description = s; - self - } - - pub(crate) fn published_date(mut self, s: Option) -> NewEpisodeBuilder { - self.published_date = s; - self - } - - pub(crate) fn length(mut self, s: Option) -> NewEpisodeBuilder { - self.length = s; - self - } - - pub(crate) fn played(mut self, s: Option) -> NewEpisodeBuilder { - self.played = s; - self - } - - pub(crate) fn guid(mut self, s: Option) -> NewEpisodeBuilder { - self.guid = s; - self - } - - pub(crate) fn epoch(mut self, s: i32) -> NewEpisodeBuilder { - self.epoch = s; - self - } - - pub(crate) fn podcast_id(mut self, s: i32) -> NewEpisodeBuilder { - self.podcast_id = s; - self - } - - pub(crate) fn favorite(mut self, s: bool) -> NewEpisodeBuilder { - self.favorite = s; - self - } - - pub(crate) fn archive(mut self, s: bool) -> NewEpisodeBuilder { - self.archive = s; - self - } - - pub(crate) fn build(self) -> NewEpisode { - NewEpisode { - title: self.title, - uri: self.uri, - local_uri: self.local_uri, - description: self.description, - published_date: self.published_date, - length: self.length, - guid: self.guid, - epoch: self.epoch, - played: self.played, - favorite: self.favorite, - archive: self.archive, - podcast_id: self.podcast_id, - } - } -} - -#[allow(dead_code)] -// Ignore the following geters. They are used in unit tests mainly. +// Ignore the following getters. They are used in unit tests mainly. impl NewEpisode { pub(crate) fn title(&self) -> Option<&str> { self.title.as_ref().map(|s| s.as_str()) diff --git a/hammond-data/src/models/queryables.rs b/hammond-data/src/models/queryables.rs index 2e991df..2e41ea6 100644 --- a/hammond-data/src/models/queryables.rs +++ b/hammond-data/src/models/queryables.rs @@ -342,9 +342,9 @@ impl<'a> Source { let lmod = headers.get::(); // FIXME: This dsnt work most of the time apparently - if self.http_etag() != etag.map(|x| x.tag()) - || self.last_modified != lmod.map(|x| format!("{}", x)) - { + if self.http_etag() != etag.map(|x| x.tag()) || self.last_modified != lmod.map(|x| { + format!("{}", x) + }) { self.http_etag = etag.map(|x| x.tag().to_string().to_owned()); self.last_modified = lmod.map(|x| format!("{}", x)); self.save()?; diff --git a/hammond-data/src/parser.rs b/hammond-data/src/parser.rs index 5ea6ce2..97043a5 100644 --- a/hammond-data/src/parser.rs +++ b/hammond-data/src/parser.rs @@ -1,3 +1,4 @@ +use ammonia; use rss::{Channel, Item}; use rfc822_sanitizer::parse_from_rfc2822_with_fallback; @@ -9,10 +10,10 @@ use errors::*; // TODO: Extend the support for parsing itunes extensions /// Parses a `rss::Channel` into a `NewPodcast` Struct. pub(crate) fn new_podcast(chan: &Channel, source_id: i32) -> NewPodcast { - let title = chan.title().trim().to_owned(); - let description = chan.description().trim().to_owned(); + let title = chan.title().trim(); + let description = ammonia::clean(chan.description().trim()); - let link = url_cleaner(chan.link()).to_owned(); + let link = url_cleaner(chan.link()); let x = chan.itunes_ext().map(|s| s.image()); let image_uri = if let Some(img) = x { img.map(|s| url_cleaner(s)) @@ -20,19 +21,20 @@ pub(crate) fn new_podcast(chan: &Channel, source_id: i32) -> NewPodcast { chan.image().map(|foo| url_cleaner(foo.url())) }; - NewPodcastBuilder::new() + NewPodcastBuilder::default() .title(title) .description(description) .link(link) .image_uri(image_uri) .source_id(source_id) .build() + .unwrap() } /// Parses an `rss::Item` into a `NewEpisode` Struct. pub(crate) fn new_episode(item: &Item, parent_id: i32) -> Result { let title = item.title().map(|s| s.trim().to_owned()); - let description = item.description().map(|s| s.trim().to_owned()); + let description = item.description().map(|s| ammonia::clean(s.trim())); let guid = item.guid().map(|s| s.value().trim().to_owned()); // Its kinda weird this being an Option type. @@ -60,18 +62,17 @@ pub(crate) fn new_episode(item: &Item, parent_id: i32) -> Result { let length = item.enclosure().map(|x| x.length().parse().unwrap_or(0)); - Ok( - NewEpisodeBuilder::new() - .title(title) - .uri(uri) - .description(description) - .length(length) - .published_date(pub_date) - .epoch(epoch) - .guid(guid) - .podcast_id(parent_id) - .build(), - ) + Ok(NewEpisodeBuilder::default() + .title(title) + .uri(uri) + .description(description) + .length(length) + .published_date(pub_date) + .epoch(epoch) + .guid(guid) + .podcast_id(parent_id) + .build() + .unwrap()) } @@ -274,10 +275,10 @@ mod tests { let channel = Channel::read_from(BufReader::new(file)).unwrap(); let firstitem = channel.items().first().unwrap(); - let descr = - "Audit your network with a couple of easy commands on Kali Linux. Chris decides to \ - blow off a little steam by attacking his IoT devices, Wes has the scope on Equifax \ - blaming open source & the Beard just saved the show. It’s a really packed episode!"; + let descr = "Audit your network with a couple of easy commands on Kali Linux. Chris \ + decides to blow off a little steam by attacking his IoT devices, Wes has the \ + scope on Equifax blaming open source & the Beard just saved the show. \ + It’s a really packed episode!"; let i = new_episode(&firstitem, 0).unwrap(); assert_eq!(i.title(), Some("Hacking Devices with Kali Linux | LUP 214")); @@ -299,7 +300,7 @@ mod tests { decisions for the next version of Gnome have us worried about the \ future.

\n\n

Plus we chat with Wimpy about the Ubuntu Rally in NYC, \ Microsoft’s sneaky move to turn Windows 10 into the “ULTIMATE LINUX \ - RUNTIME”, community news & more!

"; + RUNTIME”, community news & more!

"; assert_eq!(i2.title(), Some("Gnome Does it Again | LUP 213")); assert_eq!( i2.uri(), @@ -318,9 +319,8 @@ mod tests { let channel = Channel::read_from(BufReader::new(file)).unwrap(); let firstitem = channel.items().iter().nth(9).unwrap(); - let descr = "This week we look at RFC 2094 \ - \"Non-lexical lifetimes\""; + let descr = "This week we look at RFC 2094 \"Non-lexical lifetimes\""; let i = new_episode(&firstitem, 0).unwrap(); assert_eq!(i.title(), Some("Episode #9 - A Once in a Lifetime RFC")); @@ -342,8 +342,9 @@ mod tests { let i2 = new_episode(&second, 0).unwrap(); let descr2 = "This week we look at RFC 2071 \"Add \ - impl Trait type alias and variable declarations\""; + href=\"https://github.com/rust-lang/rfcs/pull/2071\" rel=\"noopener \ + noreferrer\">RFC 2071 \"Add impl Trait type alias and variable \ + declarations\""; assert_eq!(i2.title(), Some("Episode #8 - An Existential Crisis")); assert_eq!( i2.uri(), diff --git a/hammond-data/src/utils.rs b/hammond-data/src/utils.rs index a29ad6b..d297102 100644 --- a/hammond-data/src/utils.rs +++ b/hammond-data/src/utils.rs @@ -105,6 +105,16 @@ pub fn url_cleaner(s: &str) -> String { } } +/// Placeholder +// TODO: Docs +pub fn replace_extra_spaces(s: &str) -> String { + s.lines() + .map(|x| x.split_whitespace().collect::>().join(" ")) + .filter(|x| !x.is_empty()) + .collect::>() + .join("\n") +} + #[cfg(test)] mod tests { extern crate tempdir; @@ -129,20 +139,29 @@ mod tests { // Setup episodes let db = connection(); let con = db.get().unwrap(); - NewEpisodeBuilder::new() + NewEpisodeBuilder::default() .uri("foo_bar".to_string()) - .local_uri(Some(valid_path.to_str().unwrap().to_owned())) .build() + .unwrap() .into_episode(&con) .unwrap(); - NewEpisodeBuilder::new() + NewEpisodeBuilder::default() .uri("bar_baz".to_string()) - .local_uri(Some(bad_path.to_str().unwrap().to_owned())) .build() + .unwrap() .into_episode(&con) .unwrap(); + let mut ep1 = dbqueries::get_episode_from_uri(&con, "foo_bar").unwrap(); + let mut ep2 = dbqueries::get_episode_from_uri(&con, "bar_baz").unwrap(); + ep1.set_local_uri(Some(valid_path.to_str().unwrap())); + ep2.set_local_uri(Some(bad_path.to_str().unwrap())); + + drop(con); + ep1.save().unwrap(); + ep2.save().unwrap(); + tmp_dir } @@ -232,4 +251,22 @@ mod tests { assert_eq!(url_cleaner(good_url), good_url); assert_eq!(url_cleaner(&format!(" {}\t\n", bad_url)), good_url); } + + #[test] + fn test_whitespace() { + let bad_txt = "1 2 3 4 5"; + let valid_txt = "1 2 3 4 5"; + + assert_eq!(replace_extra_spaces(&bad_txt), valid_txt); + + let bad_txt = "1 2 3 \n 4 5\n"; + let valid_txt = "1 2 3\n4 5"; + + assert_eq!(replace_extra_spaces(&bad_txt), valid_txt); + + let bad_txt = "1 2 3 \n\n\n \n 4 5\n"; + let valid_txt = "1 2 3\n4 5"; + + assert_eq!(replace_extra_spaces(&bad_txt), valid_txt); + } } diff --git a/hammond-downloader/Cargo.toml b/hammond-downloader/Cargo.toml index 7d19efc..f063adc 100644 --- a/hammond-downloader/Cargo.toml +++ b/hammond-downloader/Cargo.toml @@ -8,13 +8,13 @@ workspace = "../" error-chain = "0.11.0" hyper = "0.11.7" log = "0.3.8" -mime_guess = "1.8.2" +mime_guess = "1.8.3" reqwest = "0.8.1" tempdir = "0.3.5" [dependencies.diesel] features = ["sqlite"] -git = "https://github.com/diesel-rs/diesel.git" +version = "0.99" [dependencies.hammond-data] path = "../hammond-data" diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index 64df7de..f3b695a 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -38,24 +38,7 @@ fn download_into(dir: &str, file_title: &str, url: &str) -> Result { ct_len.map(|x| info!("File Lenght: {}", x)); ct_type.map(|x| info!("Content Type: {}", x)); - // This could be prettier. - // Determine the file extension from the http content-type header. - let ext = if let Some(t) = ct_type { - let mime = mime_guess::get_extensions(t.type_().as_ref(), t.subtype().as_ref()); - if let Some(m) = mime { - if m.contains(&t.subtype().as_ref()) { - t.subtype().as_ref().to_string() - } else { - m.first().unwrap().to_string() - } - } else { - error!("Unkown mime type. {}", t); - "unkown".to_string() - } - } else { - error!("Unkown mime type."); - "unkown".to_string() - }; + let ext = get_ext(ct_type.cloned()).unwrap_or(String::from("unkown")); info!("Extension: {}", ext); // Construct a temp file to save desired content. @@ -74,6 +57,20 @@ fn download_into(dir: &str, file_title: &str, url: &str) -> Result { Ok(target) } +// Determine the file extension from the http content-type header. +fn get_ext(content: Option) -> Option { + let cont = content.clone()?; + content + .and_then(|c| mime_guess::get_extensions(c.type_().as_ref(), c.subtype().as_ref())) + .and_then(|c| { + if c.contains(&cont.subtype().as_ref()) { + Some(cont.subtype().as_ref().to_string()) + } else { + Some(c.first().unwrap().to_string()) + } + }) +} + // TODO: Write unit-tests. /// Handles the I/O of fetching a remote file and saving into a Buffer and A File. fn save_io(file: &str, resp: &mut reqwest::Response, content_lenght: Option) -> Result<()> { @@ -185,7 +182,7 @@ mod tests { use hammond_data::Source; use hammond_data::feed::index; use hammond_data::dbqueries; - use diesel::Identifiable; + use diesel::associations::Identifiable; use std::fs; diff --git a/hammond-gtk/Cargo.toml b/hammond-gtk/Cargo.toml index 39b12fe..810cbbb 100644 --- a/hammond-gtk/Cargo.toml +++ b/hammond-gtk/Cargo.toml @@ -12,17 +12,14 @@ gdk-pixbuf = "0.3.0" gio = "0.3.0" glib = "0.4.0" log = "0.3.8" -loggerv = "0.5.1" +loggerv = "0.6.0" open = "1.2.1" rayon = "0.9.0" +regex = "0.2.3" [dependencies.diesel] features = ["sqlite"] -git = "https://github.com/diesel-rs/diesel.git" - -[dependencies.diesel_codegen] -features = ["sqlite"] -git = "https://github.com/diesel-rs/diesel.git" +version = "0.99.0" [dependencies.gtk] features = ["v3_22"] diff --git a/hammond-gtk/resources/gtk/headerbar.ui b/hammond-gtk/resources/gtk/headerbar.ui index e84409d..d28c2ae 100644 --- a/hammond-gtk/resources/gtk/headerbar.ui +++ b/hammond-gtk/resources/gtk/headerbar.ui @@ -3,7 +3,6 @@ - True False Add a new feed center diff --git a/hammond-gtk/resources/gtk/podcast_widget.ui b/hammond-gtk/resources/gtk/podcast_widget.ui index f8e9b44..0241f05 100644 --- a/hammond-gtk/resources/gtk/podcast_widget.ui +++ b/hammond-gtk/resources/gtk/podcast_widget.ui @@ -109,7 +109,6 @@ Warn: This will delete downloaded content associated with this Podcast. - True True True Mark all episodes as Played. diff --git a/hammond-gtk/resources/gtk/podcasts_view.ui b/hammond-gtk/resources/gtk/podcasts_view.ui index 4cdc447..5a3dff6 100644 --- a/hammond-gtk/resources/gtk/podcasts_view.ui +++ b/hammond-gtk/resources/gtk/podcasts_view.ui @@ -12,7 +12,7 @@ True in - + True False diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs new file mode 100644 index 0000000..249f589 --- /dev/null +++ b/hammond-gtk/src/content.rs @@ -0,0 +1,269 @@ +use gtk; +use gtk::prelude::*; + +use hammond_data::Podcast; +use hammond_data::dbqueries; + +use widgets::podcast::PodcastWidget; +use views::podcasts::PopulatedView; +use views::empty::EmptyView; + +#[derive(Debug)] +pub struct Content { + pub stack: gtk::Stack, + pub widget: PodcastWidget, + pub podcasts: PopulatedView, + pub empty: EmptyView, +} + +impl Content { + pub fn new() -> Content { + let stack = gtk::Stack::new(); + + let widget = PodcastWidget::new(); + let podcasts = PopulatedView::new(); + let empty = EmptyView::new(); + + stack.add_named(&widget.container, "widget"); + stack.add_named(&podcasts.container, "podcasts"); + stack.add_named(&empty.container, "empty"); + + Content { + stack, + widget, + empty, + podcasts, + } + } + + pub fn new_initialized() -> Content { + let ct = Content::new(); + ct.init(); + ct + } + + pub fn init(&self) { + self.podcasts.init(&self.stack); + if self.podcasts.flowbox.get_children().is_empty() { + self.stack.set_visible_child_name("empty"); + return; + } + + self.stack.set_visible_child_name("podcasts"); + } + + fn replace_widget(&mut self, pdw: PodcastWidget) { + let vis = self.stack.get_visible_child_name().unwrap(); + let old = self.stack.get_child_by_name("widget").unwrap(); + self.stack.remove(&old); + + self.widget = pdw; + self.stack.add_named(&self.widget.container, "widget"); + self.stack.set_visible_child_name(&vis); + old.destroy(); + } + + fn replace_podcasts(&mut self, pop: PopulatedView) { + let vis = self.stack.get_visible_child_name().unwrap(); + let old = self.stack.get_child_by_name("podcasts").unwrap(); + self.stack.remove(&old); + + self.podcasts = pop; + self.stack.add_named(&self.podcasts.container, "podcasts"); + self.stack.set_visible_child_name(&vis); + old.destroy(); + } +} + +#[derive(Debug)] +// Experiementing with Wrapping gtk::Stack into a State machine. +// Gonna revist it when TryInto trais is stabilized. +pub struct ContentState { + content: Content, + state: S, +} + +pub trait UpdateView { + fn update(&mut self); +} + +#[derive(Debug)] +pub struct Empty {} + +#[derive(Debug)] +pub struct PodcastsView {} + +#[derive(Debug)] +pub struct WidgetsView {} + +impl Into> for ContentState { + fn into(self) -> ContentState { + self.content.stack.set_visible_child_name("podcasts"); + + ContentState { + content: self.content, + state: PodcastsView {}, + } + } +} + +impl UpdateView for ContentState { + fn update(&mut self) {} +} + +impl Into> for ContentState { + fn into(self) -> ContentState { + self.content.stack.set_visible_child_name("empty"); + ContentState { + content: self.content, + state: Empty {}, + } + } +} + +impl Into> for ContentState { + fn into(self) -> ContentState { + self.content.stack.set_visible_child_name("widget"); + + ContentState { + content: self.content, + state: WidgetsView {}, + } + } +} + +impl UpdateView for ContentState { + fn update(&mut self) { + let pop = PopulatedView::new_initialized(&self.content.stack); + self.content.replace_podcasts(pop) + } +} + +impl Into> for ContentState { + fn into(self) -> ContentState { + self.content.stack.set_visible_child_name("podcasts"); + ContentState { + content: self.content, + state: PodcastsView {}, + } + } +} + +impl Into> for ContentState { + fn into(self) -> ContentState { + self.content.stack.set_visible_child_name("empty"); + ContentState { + content: self.content, + state: Empty {}, + } + } +} + +impl UpdateView for ContentState { + fn update(&mut self) { + let old = self.content.stack.get_child_by_name("widget").unwrap(); + let id = WidgetExt::get_name(&old).unwrap(); + let pd = dbqueries::get_podcast_from_id(id.parse::().unwrap()).unwrap(); + + let pdw = PodcastWidget::new_initialized(&self.content.stack, &pd); + self.content.replace_widget(pdw); + } +} + +impl ContentState { + #[allow(dead_code)] + pub fn new() -> Result, ContentState> { + let content = Content::new(); + + content.podcasts.init(&content.stack); + if content.podcasts.flowbox.get_children().is_empty() { + content.stack.set_visible_child_name("empty"); + return Err(ContentState { + content, + state: Empty {}, + }); + } + + content.stack.set_visible_child_name("podcasts"); + Ok(ContentState { + content, + state: PodcastsView {}, + }) + } + + #[allow(dead_code)] + pub fn get_stack(&self) -> gtk::Stack { + self.content.stack.clone() + } +} + +fn replace_widget(stack: >k::Stack, pdw: &PodcastWidget) { + let old = stack.get_child_by_name("widget").unwrap(); + stack.remove(&old); + stack.add_named(&pdw.container, "widget"); + old.destroy(); +} + +fn replace_podcasts(stack: >k::Stack, pop: &PopulatedView) { + let old = stack.get_child_by_name("podcasts").unwrap(); + stack.remove(&old); + stack.add_named(&pop.container, "podcasts"); + old.destroy(); +} + +#[allow(dead_code)] +pub fn show_widget(stack: >k::Stack) { + stack.set_visible_child_name("widget") +} + +pub fn show_podcasts(stack: >k::Stack) { + stack.set_visible_child_name("podcasts") +} + +pub fn show_empty(stack: >k::Stack) { + stack.set_visible_child_name("empty") +} + +pub fn update_podcasts(stack: >k::Stack) { + let pods = PopulatedView::new_initialized(stack); + + if pods.flowbox.get_children().is_empty() { + show_empty(stack) + } + + replace_podcasts(stack, &pods); +} + +pub fn update_widget(stack: >k::Stack, pd: &Podcast) { + let pdw = PodcastWidget::new_initialized(stack, pd); + replace_widget(stack, &pdw); +} + +pub fn update_podcasts_preserve_vis(stack: >k::Stack) { + let vis = stack.get_visible_child_name().unwrap(); + update_podcasts(stack); + if vis != "empty" { + stack.set_visible_child_name(&vis) + } +} + +pub fn update_widget_preserve_vis(stack: >k::Stack, pd: &Podcast) { + let vis = stack.get_visible_child_name().unwrap(); + update_widget(stack, pd); + stack.set_visible_child_name(&vis) +} + +pub fn on_podcasts_child_activate(stack: >k::Stack, pd: &Podcast) { + update_widget(stack, pd); + stack.set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft); +} + +pub fn on_home_button_activate(stack: >k::Stack) { + let vis = stack.get_visible_child_name().unwrap(); + + if vis != "widget" { + update_podcasts(stack); + } + + show_podcasts(stack); +} diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index ac6c736..20f491e 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -4,57 +4,77 @@ use gtk::prelude::*; use hammond_data::Source; use hammond_data::utils::url_cleaner; -use podcasts_view::update_podcasts_view; use utils; +use content; -pub fn get_headerbar(stack: >k::Stack) -> gtk::HeaderBar { - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); - - let header: gtk::HeaderBar = builder.get_object("headerbar1").unwrap(); - let home_button: gtk::Button = builder.get_object("homebutton").unwrap(); - let refresh_button: gtk::Button = builder.get_object("refbutton").unwrap(); - - let add_toggle_button: gtk::MenuButton = builder.get_object("add-toggle-button").unwrap(); - let add_popover: gtk::Popover = builder.get_object("add-popover").unwrap(); - let new_url: gtk::Entry = builder.get_object("new-url").unwrap(); - let add_button: gtk::Button = builder.get_object("add-button").unwrap(); - // TODO: check if url exists in the db and lock the button - new_url.connect_changed(move |url| { - println!("{:?}", url.get_text()); - }); - - add_button.connect_clicked(clone!(stack, add_popover => move |_| { - let url = new_url.get_text().unwrap_or_default(); - let url = url_cleaner(&url); - on_add_bttn_clicked(&stack, &url); - - // TODO: lock the button instead of hiding and add notification of feed added. - // TODO: map the spinner - add_popover.hide(); - })); - add_popover.hide(); - add_toggle_button.set_popover(&add_popover); - - // TODO: make it a back arrow button, that will hide when appropriate, - // and add a StackSwitcher when more views are added. - home_button.connect_clicked(clone!(stack => move |_| { - let vis = stack.get_visible_child_name().unwrap(); - stack.set_visible_child_name("fb_parent"); - if vis != "pdw" { - update_podcasts_view(&stack); - } - })); - - // FIXME: There appears to be a memmory leak here. - refresh_button.connect_clicked(clone!(stack => move |_| { - utils::refresh_feed(&stack, None, None); - })); - - header +#[derive(Debug)] +pub struct Header { + pub container: gtk::HeaderBar, + home: gtk::Button, + refresh: gtk::Button, + add_toggle: gtk::MenuButton, } -fn on_add_bttn_clicked(stack: >k::Stack, url: &str) { - let source = Source::from_url(url); +impl Header { + pub fn new() -> Header { + let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); + + let header: gtk::HeaderBar = builder.get_object("headerbar1").unwrap(); + let home: gtk::Button = builder.get_object("homebutton").unwrap(); + let refresh: gtk::Button = builder.get_object("refbutton").unwrap(); + let add_toggle: gtk::MenuButton = builder.get_object("add-toggle-button").unwrap(); + + Header { + container: header, + home, + refresh, + add_toggle, + } + } + + pub fn new_initialized(stack: >k::Stack) -> Header { + let header = Header::new(); + header.init(stack); + header + } + + fn init(&self, stack: >k::Stack) { + let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); + + let add_popover: gtk::Popover = builder.get_object("add-popover").unwrap(); + let new_url: gtk::Entry = builder.get_object("new-url").unwrap(); + let add_button: gtk::Button = builder.get_object("add-button").unwrap(); + + new_url.connect_changed(move |url| { + println!("{:?}", url.get_text()); + }); + + add_button.connect_clicked(clone!(stack, add_popover, new_url => move |_| { + on_add_bttn_clicked(&stack, &new_url); + + // TODO: lock the button instead of hiding and add notification of feed added. + // TODO: map the spinner + add_popover.hide(); + })); + self.add_toggle.set_popover(&add_popover); + + // TODO: make it a back arrow button, that will hide when appropriate, + // and add a StackSwitcher when more views are added. + self.home.connect_clicked(clone!(stack => move |_| { + content::on_home_button_activate(&stack); + })); + + // FIXME: There appears to be a memmory leak here. + self.refresh.connect_clicked(clone!(stack => move |_| { + utils::refresh_feed(&stack, None, None); + })); + } +} + +fn on_add_bttn_clicked(stack: >k::Stack, entry: >k::Entry) { + let url = entry.get_text().unwrap_or_default(); + let url = url_cleaner(&url); + let source = Source::from_url(&url); if let Ok(s) = source { info!("{:?} feed added", url); diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index 5f65291..f4fd89b 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -12,6 +12,7 @@ extern crate hammond_downloader; extern crate log; extern crate loggerv; extern crate open; +extern crate regex; // extern crate rayon; // use rayon::prelude::*; @@ -43,12 +44,11 @@ macro_rules! clone { mod views; mod widgets; mod headerbar; +mod content; mod utils; mod static_resource; -use views::podcasts_view; - /* THIS IS STILL A PROTOTYPE. */ @@ -62,8 +62,13 @@ fn build_ui(app: >k::Application) { // Get the main window let window = gtk::ApplicationWindow::new(app); window.set_default_size(1150, 650); - // Setup the Stack that will manage the switch between podcasts_view and podcast_widget. - let stack = podcasts_view::setup_stack(); + + // TODO: this will blow horribly + // let ct = content::ContentState::new().unwrap(); + // let stack = ct.get_stack(); + + let ct = content::Content::new_initialized(); + let stack = ct.stack; window.add(&stack); window.connect_delete_event(|w, _| { @@ -98,8 +103,8 @@ fn build_ui(app: >k::Application) { }); // Get the headerbar - let header = headerbar::get_headerbar(&stack); - window.set_titlebar(&header); + let header = headerbar::Header::new_initialized(&stack); + window.set_titlebar(&header.container); window.show_all(); window.activate(); diff --git a/hammond-gtk/src/utils.rs b/hammond-gtk/src/utils.rs index 69bd584..5402b90 100644 --- a/hammond-gtk/src/utils.rs +++ b/hammond-gtk/src/utils.rs @@ -1,14 +1,18 @@ use glib; use gtk; +use gdk_pixbuf::Pixbuf; use hammond_data::feed; -use hammond_data::Source; +use hammond_data::{Podcast, Source}; +use hammond_downloader::downloader; use std::{thread, time}; use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; +use std::borrow::Cow; -use views::podcasts_view; +use content; +use regex::Regex; type Foo = RefCell)>>; @@ -55,9 +59,54 @@ fn refresh_podcasts_view() -> glib::Continue { GLOBAL.with(|global| { if let Some((ref stack, ref reciever)) = *global.borrow() { if reciever.try_recv().is_ok() { - podcasts_view::update_podcasts_view(stack); + content::update_podcasts_preserve_vis(stack); } } }); glib::Continue(false) } + +pub fn get_pixbuf_from_path(pd: &Podcast) -> Option { + let img_path = downloader::cache_image(pd)?; + Pixbuf::new_from_file_at_scale(&img_path, 256, 256, true).ok() +} + +#[allow(dead_code)] +// WIP: parse html to markup +pub fn html_to_markup(s: &mut str) -> Cow { + s.trim(); + s.replace('&', "&"); + s.replace('<', "<"); + s.replace('>', ">"); + + let re = Regex::new("(?Phttps?://[^\\s&,)(\"]+(&\\w=[\\w._-]?)*(#[\\w._-]+)?)").unwrap(); + re.replace_all(s, "$url") +} + +#[cfg(test)] +mod tests { + use hammond_data::Source; + use hammond_data::feed::index; + use hammond_data::dbqueries; + use diesel::associations::Identifiable; + use super::*; + + #[test] + fn test_get_pixbuf_from_path() { + let url = "http://www.newrustacean.com/feed.xml"; + + // Create and index a source + let source = Source::from_url(url).unwrap(); + // Copy it's id + let sid = source.id().clone(); + + // Convert Source it into a Feed and index it + let feed = source.into_feed().unwrap(); + index(vec![feed]); + + // Get the Podcast + let pd = dbqueries::get_podcast_from_source_id(sid).unwrap(); + let pxbuf = get_pixbuf_from_path(&pd); + assert!(pxbuf.is_some()); + } +} diff --git a/hammond-gtk/src/views/empty.rs b/hammond-gtk/src/views/empty.rs new file mode 100644 index 0000000..1c93da7 --- /dev/null +++ b/hammond-gtk/src/views/empty.rs @@ -0,0 +1,15 @@ +use gtk; + +#[derive(Debug, Clone)] +pub struct EmptyView { + pub container: gtk::Box, +} + +impl EmptyView { + pub fn new() -> EmptyView { + let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/empty_view.ui"); + let view: gtk::Box = builder.get_object("empty_view").unwrap(); + + EmptyView { container: view } + } +} diff --git a/hammond-gtk/src/views/mod.rs b/hammond-gtk/src/views/mod.rs index 69e01ee..9c47e7d 100644 --- a/hammond-gtk/src/views/mod.rs +++ b/hammond-gtk/src/views/mod.rs @@ -1 +1,2 @@ -pub mod podcasts_view; +pub mod podcasts; +pub mod empty; diff --git a/hammond-gtk/src/views/podcasts.rs b/hammond-gtk/src/views/podcasts.rs new file mode 100644 index 0000000..711be87 --- /dev/null +++ b/hammond-gtk/src/views/podcasts.rs @@ -0,0 +1,144 @@ +use gtk; +use gtk::prelude::*; +use gdk_pixbuf::Pixbuf; +use diesel::associations::Identifiable; + +use hammond_data::dbqueries; +use hammond_data::Podcast; + +use utils::get_pixbuf_from_path; + +use content; + +#[derive(Debug, Clone)] +pub struct PopulatedView { + pub container: gtk::Box, + pub flowbox: gtk::FlowBox, + viewport: gtk::Viewport, +} + +#[derive(Debug)] +struct PodcastChild { + container: gtk::Box, + title: gtk::Label, + cover: gtk::Image, + banner: gtk::Image, + number: gtk::Label, + child: gtk::FlowBoxChild, +} + +impl PopulatedView { + pub fn new() -> PopulatedView { + let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_view.ui"); + let container: gtk::Box = builder.get_object("fb_parent").unwrap(); + let flowbox: gtk::FlowBox = builder.get_object("flowbox").unwrap(); + let viewport: gtk::Viewport = builder.get_object("viewport").unwrap(); + + PopulatedView { + container, + flowbox, + viewport, + } + } + + #[allow(dead_code)] + pub fn new_initialized(stack: >k::Stack) -> PopulatedView { + let pop = PopulatedView::new(); + pop.init(stack); + pop + } + + pub fn init(&self, stack: >k::Stack) { + use gtk::WidgetExt; + + // TODO: handle unwraps. + self.flowbox + .connect_child_activated(clone!(stack => move |_, child| { + // This is such an ugly hack... + // let id = child.get_name().unwrap().parse::().unwrap(); + let id = WidgetExt::get_name(child).unwrap().parse::().unwrap(); + let parent = dbqueries::get_podcast_from_id(id).unwrap(); + on_flowbox_child_activate(&stack, &parent); + })); + // Populate the flowbox with the Podcasts. + self.populate_flowbox(); + } + + fn populate_flowbox(&self) { + let podcasts = dbqueries::get_podcasts(); + + if let Ok(pds) = podcasts { + pds.iter().for_each(|parent| { + let flowbox_child = PodcastChild::new_initialized(parent); + self.flowbox.add(&flowbox_child.child); + }); + self.flowbox.show_all(); + } + } +} + +impl PodcastChild { + fn new() -> PodcastChild { + let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_child.ui"); + + // Copy of gnome-music AlbumWidget + let container: gtk::Box = builder.get_object("fb_child").unwrap(); + let title: gtk::Label = builder.get_object("pd_title").unwrap(); + let cover: gtk::Image = builder.get_object("pd_cover").unwrap(); + let banner: gtk::Image = builder.get_object("banner").unwrap(); + let number: gtk::Label = builder.get_object("banner_label").unwrap(); + + let child = gtk::FlowBoxChild::new(); + child.add(&container); + + PodcastChild { + container, + title, + cover, + banner, + number, + child, + } + } + + fn init(&self, pd: &Podcast) { + self.title.set_text(pd.title()); + + let cover = get_pixbuf_from_path(pd); + if let Some(img) = cover { + self.cover.set_from_pixbuf(&img); + }; + + WidgetExt::set_name(&self.child, &pd.id().to_string()); + self.configure_banner(pd); + } + + pub fn new_initialized(pd: &Podcast) -> PodcastChild { + let child = PodcastChild::new(); + child.init(pd); + + child + } + + fn configure_banner(&self, pd: &Podcast) { + let bann = + Pixbuf::new_from_resource_at_scale("/org/gnome/hammond/banner.png", 256, 256, true); + if let Ok(b) = bann { + self.banner.set_from_pixbuf(&b); + + let new_episodes = dbqueries::get_pd_unplayed_episodes(pd); + + if let Ok(n) = new_episodes { + if !n.is_empty() { + self.number.set_text(&n.len().to_string()); + self.banner.show(); + self.number.show(); + } + } + } + } +} + +fn on_flowbox_child_activate(stack: >k::Stack, parent: &Podcast) { + content::on_podcasts_child_activate(stack, parent) +} diff --git a/hammond-gtk/src/views/podcasts_view.rs b/hammond-gtk/src/views/podcasts_view.rs deleted file mode 100644 index 44de32e..0000000 --- a/hammond-gtk/src/views/podcasts_view.rs +++ /dev/null @@ -1,152 +0,0 @@ -use gtk; -use gtk::prelude::*; -use gdk_pixbuf::Pixbuf; -use diesel::associations::Identifiable; - -use hammond_data::dbqueries; -use hammond_data::Podcast; - -use widgets::podcast::*; - -fn setup_empty_view(stack: >k::Stack) { - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/empty_view.ui"); - let view: gtk::Box = builder.get_object("empty_view").unwrap(); - stack.add_named(&view, "empty"); -} - -fn show_empty_view(stack: >k::Stack) { - stack.set_visible_child_name("empty"); - - info!("Empty view."); -} - -fn populate_flowbox(flowbox: >k::FlowBox) { - let podcasts = dbqueries::get_podcasts(); - - if let Ok(pds) = podcasts { - pds.iter().for_each(|parent| { - let f = create_flowbox_child(parent); - flowbox.add(&f); - }); - flowbox.show_all(); - } -} - -fn create_flowbox_child(pd: &Podcast) -> gtk::FlowBoxChild { - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_child.ui"); - - // Copy of gnome-music AlbumWidget - let box_: gtk::Box = builder.get_object("fb_child").unwrap(); - let pd_title: gtk::Label = builder.get_object("pd_title").unwrap(); - let pd_cover: gtk::Image = builder.get_object("pd_cover").unwrap(); - let banner: gtk::Image = builder.get_object("banner").unwrap(); - let banner_title: gtk::Label = builder.get_object("banner_label").unwrap(); - - pd_title.set_text(pd.title()); - - let cover = get_pixbuf_from_path(pd); - if let Some(img) = cover { - pd_cover.set_from_pixbuf(&img); - }; - - configure_banner(pd, &banner, &banner_title); - - let fbc = gtk::FlowBoxChild::new(); - // There's probably a better way to store the id somewhere. - // fbc.set_name(&pd.id().to_string()); - WidgetExt::set_name(&fbc, &pd.id().to_string()); - fbc.add(&box_); - fbc -} - -fn configure_banner(pd: &Podcast, banner: >k::Image, banner_title: >k::Label) { - let bann = Pixbuf::new_from_resource_at_scale("/org/gnome/hammond/banner.png", 256, 256, true); - if let Ok(b) = bann { - banner.set_from_pixbuf(&b); - - let new_episodes = dbqueries::get_pd_unplayed_episodes(pd); - - if let Ok(n) = new_episodes { - if !n.is_empty() { - banner_title.set_text(&n.len().to_string()); - banner.show(); - banner_title.show(); - } - } - } -} - -fn on_flowbox_child_activate(stack: >k::Stack, parent: &Podcast) { - let old = stack.get_child_by_name("pdw").unwrap(); - let pdw = podcast_widget(stack, parent); - - stack.remove(&old); - stack.add_named(&pdw, "pdw"); - stack.set_visible_child(&pdw); - - // aggresive memory cleanup - // probably not needed - old.destroy(); -} - -fn setup_podcasts_flowbox(stack: >k::Stack) -> gtk::FlowBox { - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_view.ui"); - let fb_parent: gtk::Box = builder.get_object("fb_parent").unwrap(); - let flowbox: gtk::FlowBox = builder.get_object("flowbox").unwrap(); - init_flowbox(stack, &flowbox); - - stack.add_named(&fb_parent, "fb_parent"); - - if flowbox.get_children().is_empty() { - show_empty_view(stack); - } else { - stack.set_visible_child(&fb_parent); - }; - - flowbox -} - -pub fn setup_stack() -> gtk::Stack { - let stack = gtk::Stack::new(); - stack.set_transition_type(gtk::StackTransitionType::SlideLeftRight); - setup_empty_view(&stack); - setup_podcast_widget(&stack); - setup_podcasts_flowbox(&stack); - stack -} - -pub fn update_podcasts_view(stack: >k::Stack) { - let vis = stack.get_visible_child_name().unwrap(); - let old = stack.get_child_by_name("fb_parent").unwrap(); - stack.remove(&old); - - let flowbox = setup_podcasts_flowbox(stack); - - if vis == "empty" && !flowbox.get_children().is_empty() { - stack.set_visible_child_name("fb_parent"); - } else if vis == "fb_parent" && flowbox.get_children().is_empty() { - stack.set_visible_child_name("empty"); - } else { - // preserve the visible widget - stack.set_visible_child_name(&vis); - }; - - // aggresive memory cleanup - // probably not needed - old.destroy(); -} - -fn init_flowbox(stack: >k::Stack, flowbox: >k::FlowBox) { - use gtk::WidgetExt; - - // TODO: handle unwraps. - flowbox.connect_child_activated(clone!(stack => move |_, child| { - // This is such an ugly hack... - // let id = child.get_name().unwrap().parse::().unwrap(); - let id = WidgetExt::get_name(child).unwrap().parse::().unwrap(); - let parent = dbqueries::get_podcast_from_id(id).unwrap(); - on_flowbox_child_activate(&stack, &parent); - })); - // Populate the flowbox with the Podcasts. - populate_flowbox(flowbox); -} diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 4851a03..c113b51 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -1,115 +1,170 @@ +use glib; +use gtk; +use gtk::prelude::*; +use gtk::{ContainerExt, TextBufferExt}; + use open; +use dissolve::strip_html_tags; +use diesel::associations::Identifiable; + use hammond_data::dbqueries; use hammond_data::{Episode, Podcast}; use hammond_downloader::downloader; use hammond_data::utils::*; use hammond_data::errors::*; +use hammond_data::utils::replace_extra_spaces; -use dissolve::strip_html_tags; -use diesel::associations::Identifiable; +// use utils::html_to_markup; use std::thread; use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; use std::path::Path; -use glib; -use gtk; -use gtk::prelude::*; -use gtk::{ContainerExt, TextBufferExt}; - type Foo = RefCell)>>; thread_local!(static GLOBAL: Foo = RefCell::new(None)); -fn epidose_widget(episode: &mut Episode, pd_title: &str) -> gtk::Box { - // This is just a prototype and will be reworked probably. - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/episode_widget.ui"); +#[derive(Debug)] +struct EpisodeWidget { + container: gtk::Box, + download: gtk::Button, + play: gtk::Button, + delete: gtk::Button, + played: gtk::Button, + unplayed: gtk::Button, + title: gtk::Label, + description: gtk::TextView, + // description: gtk::Label, + expander: gtk::Expander, +} - let ep: gtk::Box = builder.get_object("episode_box").unwrap(); - let download_button: gtk::Button = builder.get_object("download_button").unwrap(); - let play_button: gtk::Button = builder.get_object("play_button").unwrap(); - let delete_button: gtk::Button = builder.get_object("delete_button").unwrap(); - let played_button: gtk::Button = builder.get_object("mark_played_button").unwrap(); - let unplayed_button: gtk::Button = builder.get_object("mark_unplayed_button").unwrap(); +impl EpisodeWidget { + fn new() -> EpisodeWidget { + // This is just a prototype and will be reworked probably. + let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/episode_widget.ui"); - let title_label: gtk::Label = builder.get_object("title_label").unwrap(); - // let desc_label: gtk::Label = builder.get_object("desc_label").unwrap(); - let expander: gtk::Expander = builder.get_object("expand_desc").unwrap(); - let desc_text_view: gtk::TextView = builder.get_object("desc_text_view").unwrap(); + let container: gtk::Box = builder.get_object("episode_box").unwrap(); + let download: gtk::Button = builder.get_object("download_button").unwrap(); + let play: gtk::Button = builder.get_object("play_button").unwrap(); + let delete: gtk::Button = builder.get_object("delete_button").unwrap(); + let played: gtk::Button = builder.get_object("mark_played_button").unwrap(); + let unplayed: gtk::Button = builder.get_object("mark_unplayed_button").unwrap(); - title_label.set_xalign(0.0); + let title: gtk::Label = builder.get_object("title_label").unwrap(); + let expander: gtk::Expander = builder.get_object("expand_desc").unwrap(); + let description: gtk::TextView = builder.get_object("desc_text_view").unwrap(); + // let description: gtk::Label = builder.get_object("desc_text").unwrap(); - if let Some(t) = episode.title() { - title_label.set_text(t); + EpisodeWidget { + container, + download, + play, + delete, + played, + unplayed, + title, + expander, + description, + } } - if episode.description().is_some() { - let d = episode.description().unwrap().to_owned(); - - expander.connect_activate(move |_| { - let plain_text = strip_html_tags(&d).join(" "); - // TODO: handle unwrap - let buff = desc_text_view.get_buffer().unwrap(); - buff.set_text(plain_text.trim()); - }); + pub fn new_initialized(episode: &mut Episode, pd: &Podcast) -> EpisodeWidget { + let widget = EpisodeWidget::new(); + widget.init(episode, pd); + widget } - if episode.played().is_some() { - unplayed_button.show(); - played_button.hide(); + fn init(&self, episode: &mut Episode, pd: &Podcast) { + self.title.set_xalign(0.0); + + if let Some(t) = episode.title() { + self.title.set_text(t); + } + + if episode.description().is_some() { + let text = episode.description().unwrap().to_owned(); + let description = &self.description; + self.expander + .connect_activate(clone!(description, text => move |_| { + // let mut text = text.clone(); + // html_to_markup(&mut text); + // description.set_markup(&text) + + let plain_text = strip_html_tags(&text).join(" "); + // TODO: handle unwrap + let buff = description.get_buffer().unwrap(); + buff.set_text(&replace_extra_spaces(&plain_text)); + })); + } + + if episode.played().is_some() { + self.unplayed.show(); + self.played.hide(); + } + + // Show or hide the play/delete/download buttons upon widget initialization. + let local_uri = episode.local_uri(); + if local_uri.is_some() && Path::new(local_uri.unwrap()).exists() { + self.download.hide(); + self.play.show(); + self.delete.show(); + } + + let played = &self.played; + let unplayed = &self.unplayed; + self.play + .connect_clicked(clone!(episode, played, unplayed => move |_| { + let mut episode = episode.clone(); + on_play_bttn_clicked(*episode.id()); + let _ = episode.set_played_now(); + played.hide(); + unplayed.show(); + })); + + let play = &self.play; + let download = &self.download; + self.delete + .connect_clicked(clone!(episode, play, download => move |del| { + on_delete_bttn_clicked(*episode.id()); + del.hide(); + play.hide(); + download.show(); + })); + + let unplayed = &self.unplayed; + self.played + .connect_clicked(clone!(episode, unplayed => move |played| { + let mut episode = episode.clone(); + let _ = episode.set_played_now(); + played.hide(); + unplayed.show(); + })); + + let played = &self.played; + self.unplayed + .connect_clicked(clone!(episode, played => move |un| { + let mut episode = episode.clone(); + episode.set_played(None); + let _ = episode.save(); + un.hide(); + played.show(); + })); + + let pd_title = pd.title().to_owned(); + let play = &self.play; + let delete = &self.delete; + self.download + .connect_clicked(clone!(play, delete, episode => move |dl| { + on_download_clicked( + &pd_title, + &mut episode.clone(), + dl, + &play, + &delete, + ); + })); } - - // Show or hide the play/delete/download buttons upon widget initialization. - let local_uri = episode.local_uri(); - if local_uri.is_some() && Path::new(local_uri.unwrap()).exists() { - download_button.hide(); - play_button.show(); - delete_button.show(); - } - - play_button.connect_clicked(clone!(episode, played_button, unplayed_button => move |_| { - let mut episode = episode.clone(); - on_play_bttn_clicked(*episode.id()); - let _ = episode.set_played_now(); - played_button.hide(); - unplayed_button.show(); - })); - - delete_button.connect_clicked(clone!(episode, play_button, download_button => move |del| { - on_delete_bttn_clicked(*episode.id()); - del.hide(); - play_button.hide(); - download_button.show(); - })); - - played_button.connect_clicked(clone!(episode, unplayed_button => move |played| { - let mut episode = episode.clone(); - let _ = episode.set_played_now(); - played.hide(); - unplayed_button.show(); - })); - - unplayed_button.connect_clicked(clone!(episode, played_button => move |un| { - let mut episode = episode.clone(); - episode.set_played(None); - let _ = episode.save(); - un.hide(); - played_button.show(); - })); - - let pd_title = pd_title.to_owned(); - download_button.connect_clicked(clone!(play_button, delete_button, episode => move |dl| { - on_download_clicked( - &pd_title, - &mut episode.clone(), - dl, - &play_button, - &delete_button, - ); - })); - - ep } // TODO: show notification when dl is finished. @@ -192,8 +247,9 @@ pub fn episodes_listbox(pd: &Podcast) -> Result { let list = gtk::ListBox::new(); episodes.into_iter().for_each(|mut ep| { - let w = epidose_widget(&mut ep, pd.title()); - list.add(&w) + // let w = epidose_widget(&mut ep, pd.title()); + let widget = EpisodeWidget::new_initialized(&mut ep, pd); + list.add(&widget.container) }); list.set_vexpand(false); diff --git a/hammond-gtk/src/widgets/podcast.rs b/hammond-gtk/src/widgets/podcast.rs index 6d765a3..206ffd9 100644 --- a/hammond-gtk/src/widgets/podcast.rs +++ b/hammond-gtk/src/widgets/podcast.rs @@ -1,6 +1,6 @@ use gtk::prelude::*; use gtk; -use gdk_pixbuf::Pixbuf; +use diesel::Identifiable; use std::fs; @@ -9,48 +9,90 @@ use hammond_data::Podcast; use hammond_downloader::downloader; use widgets::episode::episodes_listbox; -use podcasts_view::update_podcasts_view; +use utils::get_pixbuf_from_path; +use content; -pub fn podcast_widget(stack: >k::Stack, pd: &Podcast) -> gtk::Box { - // Adapted from gnome-music AlbumWidget - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcast_widget.ui"); - let pd_widget: gtk::Box = builder.get_object("podcast_widget").unwrap(); +#[derive(Debug)] +pub struct PodcastWidget { + pub container: gtk::Box, + cover: gtk::Image, + title: gtk::Label, + description: gtk::TextView, + view: gtk::Viewport, + unsub: gtk::Button, + played: gtk::Button, +} - let cover: gtk::Image = builder.get_object("cover").unwrap(); - let title_label: gtk::Label = builder.get_object("title_label").unwrap(); - let desc_text_view: gtk::TextView = builder.get_object("desc_text_view").unwrap(); - let view: gtk::Viewport = builder.get_object("view").unwrap(); - let unsub_button: gtk::Button = builder.get_object("unsub_button").unwrap(); - let played_button: gtk::Button = builder.get_object("mark_all_played_button").unwrap(); +impl PodcastWidget { + pub fn new() -> PodcastWidget { + // Adapted from gnome-music AlbumWidget + let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcast_widget.ui"); + let container: gtk::Box = builder.get_object("podcast_widget").unwrap(); - // TODO: should spawn a thread to avoid locking the UI probably. - unsub_button.connect_clicked(clone!(stack, pd => move |bttn| { - on_unsub_button_clicked(&stack, &pd, bttn); - })); + let cover: gtk::Image = builder.get_object("cover").unwrap(); + let title: gtk::Label = builder.get_object("title_label").unwrap(); + let description: gtk::TextView = builder.get_object("desc_text_view").unwrap(); + let view: gtk::Viewport = builder.get_object("view").unwrap(); + let unsub: gtk::Button = builder.get_object("unsub_button").unwrap(); + let played: gtk::Button = builder.get_object("mark_all_played_button").unwrap(); - title_label.set_text(pd.title()); - let listbox = episodes_listbox(pd); - if let Ok(l) = listbox { - view.add(&l); + PodcastWidget { + container, + cover, + title, + description, + view, + unsub, + played, + } } - { - let buff = desc_text_view.get_buffer().unwrap(); - buff.set_text(pd.description()); + pub fn new_initialized(stack: >k::Stack, pd: &Podcast) -> PodcastWidget { + let pdw = PodcastWidget::new(); + pdw.init(stack, pd); + pdw } - let img = get_pixbuf_from_path(pd); - if let Some(i) = img { - cover.set_from_pixbuf(&i); + pub fn init(&self, stack: >k::Stack, pd: &Podcast) { + WidgetExt::set_name(&self.container, &pd.id().to_string()); + + // TODO: should spawn a thread to avoid locking the UI probably. + self.unsub.connect_clicked(clone!(stack, pd => move |bttn| { + on_unsub_button_clicked(&stack, &pd, bttn); + })); + + self.title.set_text(pd.title()); + let listbox = episodes_listbox(pd); + if let Ok(l) = listbox { + self.view.add(&l); + } + + { + let buff = self.description.get_buffer().unwrap(); + buff.set_text(pd.description()); + } + + let img = get_pixbuf_from_path(pd); + if let Some(i) = img { + self.cover.set_from_pixbuf(&i); + } + + self.played.connect_clicked(clone!(stack, pd => move |_| { + on_played_button_clicked(&stack, &pd); + })); + + self.show_played_button(pd); } - played_button.connect_clicked(clone!(stack, pd => move |_| { - on_played_button_clicked(&stack, &pd); - })); + fn show_played_button(&self, pd: &Podcast) { + let new_episodes = dbqueries::get_pd_unplayed_episodes(pd); - show_played_button(pd, &played_button); - - pd_widget + if let Ok(n) = new_episodes { + if !n.is_empty() { + self.played.show() + } + } + } } fn on_unsub_button_clicked(stack: >k::Stack, pd: &Podcast, unsub_button: >k::Button) { @@ -69,76 +111,12 @@ fn on_unsub_button_clicked(stack: >k::Stack, pd: &Podcast, unsub_button: >k: } }; } - stack.set_visible_child_name("fb_parent"); - update_podcasts_view(stack); + content::update_podcasts(stack); + content::show_podcasts(stack); } fn on_played_button_clicked(stack: >k::Stack, pd: &Podcast) { let _ = dbqueries::update_none_to_played_now(pd); - update_podcast_widget(stack, pd); -} - -fn show_played_button(pd: &Podcast, played_button: >k::Button) { - let new_episodes = dbqueries::get_pd_unplayed_episodes(pd); - - if let Ok(n) = new_episodes { - if !n.is_empty() { - played_button.show() - } - } -} - -pub fn get_pixbuf_from_path(pd: &Podcast) -> Option { - let img_path = downloader::cache_image(pd); - if let Some(i) = img_path { - Pixbuf::new_from_file_at_scale(&i, 256, 256, true).ok() - } else { - None - } -} - -pub fn setup_podcast_widget(stack: >k::Stack) { - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcast_widget.ui"); - let pd_widget: gtk::Box = builder.get_object("podcast_widget").unwrap(); - - stack.add_named(&pd_widget, "pdw"); -} - -pub fn update_podcast_widget(stack: >k::Stack, pd: &Podcast) { - let old = stack.get_child_by_name("pdw").unwrap(); - let pdw = podcast_widget(stack, pd); - let vis = stack.get_visible_child_name().unwrap(); - - stack.remove(&old); - stack.add_named(&pdw, "pdw"); - stack.set_visible_child_name(&vis); - old.destroy(); -} - -#[cfg(test)] -mod tests { - use hammond_data::Source; - use hammond_data::feed::index; - use diesel::Identifiable; - use super::*; - - #[test] - fn test_get_pixbuf_from_path() { - let url = "http://www.newrustacean.com/feed.xml"; - - // Create and index a source - let source = Source::from_url(url).unwrap(); - // Copy it's id - let sid = source.id().clone(); - - // Convert Source it into a Feed and index it - let feed = source.into_feed().unwrap(); - index(vec![feed]); - - // Get the Podcast - let pd = dbqueries::get_podcast_from_source_id(sid).unwrap(); - let pxbuf = get_pixbuf_from_path(&pd); - assert!(pxbuf.is_some()); - } + content::update_widget_preserve_vis(stack, pd); } diff --git a/org.gnome.Hammond.json b/org.gnome.Hammond.json index 459b13c..ea403fc 100644 --- a/org.gnome.Hammond.json +++ b/org.gnome.Hammond.json @@ -14,18 +14,18 @@ "--talk-name=org.freedesktop.Notifications" ], "build-options": { + "append-path": "/usr/lib/sdk/rust-stable/bin", + "build-args": [ + "--share=network" + ], "env": { "CARGO_HOME": "/run/build/Hammond/cargo" - }, - "build-args": [ "--share=network" ] + } }, "modules": [ { "name": "Hammond", - "buildsystem": "simple", - "build-commands": [ - "source /usr/lib/sdk/rust-stable/enable.sh && ./configure --prefix=/app && make && make install" - ], + "buildsystem": "meson", "sources": [ { "type": "git", diff --git a/rustfmt.toml b/rustfmt.toml index 3a40cc5..477cd1c 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,4 @@ +unstable_features = true verbose = false disable_all_formatting = false skip_children = false diff --git a/scripts/release.sh b/scripts/release.sh index 9715f8b..cced5a7 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -12,14 +12,12 @@ mkdir -p $DIST cp -rf hammond-data $DIST cp -rf hammond-gtk $DIST cp -rf hammond-downloader $DIST -cp build.rs $DIST cp Cargo.toml $DIST cp configure $DIST cp meson.build $DIST cp Hammond.doap $DIST cp LICENSE $DIST cp README.md $DIST -# cp -rf assets/org.gnome.Hammond.desktop $DIST cp -rf assets $DIST cp -rf scripts $DIST