M Cargo.lock => Cargo.lock +103 -0
@@ 1,6 1,17 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 19,6 30,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
+name = "chrono"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b"
+dependencies = [
+ "num-integer",
+ "num-traits",
+ "time",
+]
+
+[[package]]
+name = "colored"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
+dependencies = [
+ "atty",
+ "lazy_static",
+ "winapi",
+]
+
+[[package]]
name = "curl"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 50,6 83,21 @@ dependencies = [
]
[[package]]
+name = "hermit-abi"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
+
+[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 84,6 132,25 @@ dependencies = [
]
[[package]]
+name = "num-integer"
+version = "0.1.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
name = "openssl-probe"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 115,6 182,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+
+[[package]]
name = "schannel"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 125,6 198,23 @@ dependencies = [
]
[[package]]
+name = "serde"
+version = "1.0.115"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
+
+[[package]]
+name = "serde_json"
+version = "1.0.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
name = "socket2"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 137,6 227,16 @@ dependencies = [
]
[[package]]
+name = "time"
+version = "0.1.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
name = "vcpkg"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 168,5 268,8 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
name = "wtwitch-rust"
version = "0.1.0"
dependencies = [
+ "chrono",
+ "colored",
"curl",
+ "serde_json",
]
M Cargo.toml => Cargo.toml +4 -1
@@ 4,7 4,10 @@ version = "0.1.0"
authors = ["Hunter Peavey <srht@krathalan.net>"]
edition = "2018"
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+[dependencies]
+serde_json = "1.0"
+chrono = "0.4"
+colored = "2.0.0"
[dependencies.curl]
version = "0.4.31"
M TODO => TODO +9 -5
@@ 10,13 10,17 @@ Commands:
- player
- quality
- block
- - implemented: adding to blocklist, printing to blocklist
- - unimplemented: remove from blocklist
- - version
- - help
Misc:
- colors
- debug/logging facilities
- translations
- - environment.sh?>
\ No newline at end of file
+ - environment.sh?
+
+==============
+ 100% DONE
+==============
+
+Commands:
+ - help
+ - version<
\ No newline at end of file
M src/main.rs => src/main.rs +71 -6
@@ 2,8 2,11 @@ use std::env;
use std::fs;
use std::io::prelude::*;
use std::path::Path;
+use chrono::prelude::*;
const PROGRAM_NAME: &str = "wtwitch";
+const PROGRAM_VERSION: &str = "0.1.0";
+const PROGRAM_CONTRIBUTORS: &str = "krathalan, nycko123, Léo Villeveygoux, René de Hesselle";
// Twitch API information
// This API key is intended to be used for wtwitch only -- do not use this API
@@ 50,8 53,9 @@ fn main() {
panic!("Couldn't create config directory {}: {}", cache_path, why);
}
- // Load data
+ // Load user config
let blocklist = load_blocklist(&blocklist_file);
+ let config = load_config(&config_file);
// Parse user command
let command = &cli_args[1].chars().next().unwrap();
@@ 60,7 64,8 @@ fn main() {
match command {
'b' => block(cli_args, blocklist_file, blocklist),
- 'w' => watch(cli_args),
+ 'w' => watch(cli_args[2].clone(), config["player"].to_string(), config["quality"].to_string()),
+ 'v' => version(),
_ => help()
}
}
@@ 107,6 112,32 @@ fn load_blocklist(path_to_blocklist: &str) -> String {
}
}
+// TODO: if config file doesn't exist yet, seed it with the default config
+fn load_config(path_to_config: &str) -> serde_json::Value {
+ // Load config file into string
+ let path = Path::new(&path_to_config);
+
+ // Create config file if not exists
+ if !path.exists() {
+ if let Err(why) = fs::File::create(&path) {
+ panic!("Couldn't create config file {}: {}", path_to_config, why);
+ }
+ }
+
+ // Open the path in read-only mode
+ let mut file = match fs::File::open(&path) {
+ Err(why) => panic!("couldn't open {}: {}", path.display(), why),
+ Ok(file) => file,
+ };
+
+ // Read the file contents into a string
+ let mut s = String::new();
+ file.read_to_string(&mut s).unwrap();
+
+ // Convert string into serde_json::Value
+ serde_json::from_str(&s).unwrap()
+}
+
// Commands
// TODO: Remove streamer if it's already on the blocklist
@@ 143,17 174,51 @@ fn block(args: Vec<String>, blocklist_file: String, blocklist: String) {
}
fn help() {
- unimplemented!("TODO: Implement print help")
+ println!("{} - terminal user interface for Twitch
+
+ => [w]atch [name] - Watch [name] streamer.
+ => [s]ub [name(s)] - Subscribe to [name] streamer.
+ You can subscribe to multiple streamers in one command.
+ => [u]nsub [name(s)] - Unsubscribe from [name] streamer.
+ You can unsubscribe from multiple streamers in one command.
+ => [c]heck - View your settings and the status of streamers you are
+ subscribed to.
+ => [e] [search-term] - Search games/categories for [search-term].
+ => [n] [search-term] - Search streamers/channels for [search-term].
+ => [g]ame [name] - View the top streamers for [name] game/category.
+ => [t]op - View the top games and streamers on Twitch.
+ => [l] - Toggle the usage of colors in wtwitch output.
+ => [p]layer [program] - Change the player program that gets passed to streamlink.
+ => [q]uality [quality] - Change the video quality that gets passed to streamlink.
+ => [b]lock [name(s)] - Block [name] streamer, preventing them from appearing in any
+ output. You can block multiple streamers in one command.
+ => [v]ersion - Print the current version of wtwitch.
+ => [h]elp - Print this help.
+
+ See \"man {}\" or https://krathalan.net/wtwitch.html for more information.", PROGRAM_NAME, PROGRAM_NAME);
+}
+
+fn version() {
+ // Get current year
+ let local_time : DateTime<Local> = Local::now();
+
+ println!("{} v{}
+
+ Copyright (C) {} 2019-{}
+ This is free software: you are free to change and redistribute it.
+ There is NO WARRANTY, to the extent permitted by law.", PROGRAM_NAME, PROGRAM_VERSION, PROGRAM_CONTRIBUTORS, local_time.year());
}
-// TODO: use user player and quality settings, fork to background
-fn watch(args: Vec<String>) {
+// TODO: check to make sure user player is installed and openable
+// check to make sure streamer is online
+// send notification if stream fails or cannot be opened
+fn watch(streamer: String, player: String, quality: String) {
use std::process;
if cfg!(target_os = "windows") {
panic!("{} does not yet support launching a stream on Windows", PROGRAM_NAME);
} else {
- let streamlink_command = format!("streamlink -p mpv --twitch-disable-ads \"https://www.twitch.tv/{}\" best", args[2]);
+ let streamlink_command = format!("streamlink -p {} --twitch-disable-ads \"https://www.twitch.tv/{}\" {}", player, streamer, quality);
process::Command::new("sh")
.arg("-c")
.arg(streamlink_command)