41 Commits
0.1.3 ... 0.3.0

Author SHA1 Message Date
AB
0f5a1aaaed Hotfix 2020-05-14 21:53:47 +03:00
AB
1030e69932 Hotfix 2020-05-14 21:53:41 +03:00
AB
474d48d15c Add mpd. Rewrite. 2020-05-14 21:18:37 +03:00
Alexandr Bogomyakov
31c3237a5c Add SCP to deploy 2020-05-04 13:48:14 +03:00
Alexandr Bogomyakov
46f641220c Add SCP to deploy 2020-05-04 13:41:24 +03:00
Alexandr Bogomyakov
7e793c68c2 Update CI procedures. 2020-05-04 12:53:33 +03:00
Alexandr Bogomyakov
942e767c7e Update CI procedures. 2020-05-04 12:48:06 +03:00
Alexandr Bogomyakov
a276c1a2aa Merge branch 'master' of github.com:house-of-vanity/tmux_helper 2020-05-04 12:15:12 +03:00
Alexandr Bogomyakov
2150aaf5cd Update CI procedures. 2020-05-04 12:14:33 +03:00
AB
b1e418a633 Cleanup cpu_load_bar func. Using lib. 2020-04-11 16:35:55 +03:00
Alexandr Bogomyakov
8e569078de Minor fixes. 2020-04-10 17:20:02 +03:00
Alexandr Bogomyakov
5d23b7da2d Bump version 2019-12-24 13:17:20 +03:00
Alexandr Bogomyakov
5cf2ab0e40 Add time feature with custom format. 2019-12-24 13:16:23 +03:00
AB
7c7d9070a4 Update separator. 2019-12-19 01:39:22 +03:00
AB
456d423f47 Improve player metadata displaying. 2019-12-19 01:36:57 +03:00
Ultra Desu
cd854d450a Fix files. 2019-12-19 00:03:15 +03:00
Ultra Desu
7a934a063f Fix player metadata shorting. 2019-12-19 00:02:33 +03:00
Alexandr Bogomyakov
08cf01ee81 Add multiplayer support. 2019-12-17 15:10:31 +03:00
Alexandr Bogomyakov
530a753527 Add multiplayer support. 2019-12-17 15:05:24 +03:00
House of Vanity
614185e7f8 Create LICENSE-WTFPL
Add license
2019-12-10 13:38:34 +03:00
Alexandr Bogomyakov
ddd09761f5 Fix workflow. 2019-12-04 15:24:04 +03:00
Alexandr Bogomyakov
b264f3b823 Fix workflow. 2019-12-04 14:52:59 +03:00
Alexandr Bogomyakov
86a95efa49 Fix workflow. 2019-12-04 14:50:59 +03:00
Alexandr Bogomyakov
3e131088e6 Add env to workflow. 2019-12-04 14:30:56 +03:00
Alexandr Bogomyakov
f96467272b Add env to workflow. 2019-12-04 14:30:43 +03:00
Alexandr Bogomyakov
8cdaf4628b Add push action - build. 2019-12-04 14:23:28 +03:00
House of Vanity
23cc78cc0a Update README.md 2019-12-04 13:06:54 +03:00
House of Vanity
dec3226f41 Update README.md
Update readme.
2019-12-04 13:06:32 +03:00
House of Vanity
e085d55dde Create README.md 2019-12-04 12:58:26 +03:00
Alexandr Bogomyakov
17228e3ca8 Add screenshot 2019-12-04 12:57:00 +03:00
Ultra Desu
3b3f77a0e0 Merge colorize with player status 2019-12-03 23:53:21 +03:00
Alexandr Bogomyakov
f655e542fc Add player status icon. 2019-12-03 09:33:26 +03:00
Ultra Desu
5785b15a78 Colorize media player applet. 2019-11-30 16:21:33 +03:00
Ultra Desu
c69a95009d Add media player metadata. 2019-11-30 14:10:05 +03:00
Ultra Desu
b95183fd94 lifetime issue 2019-11-30 03:14:00 +03:00
Alexandr Bogomyakov
a9216ff630 Add dbus support 2019-11-29 18:17:57 +03:00
Alexandr Bogomyakov
b070d50bc7 Merge branch 'master' of github.com:house-of-vanity/tmux_helper 2019-11-28 18:00:10 +03:00
Alexandr Bogomyakov
139e7c7577 Linting 2019-11-28 18:00:00 +03:00
Alexandr Bogomyakov
23730088d5 Add dbus client. 2019-11-28 17:59:24 +03:00
House of Vanity
3a04d115bf Delete rust.yml 2019-11-25 12:31:33 +03:00
House of Vanity
971de9c6f0 Update release-upload.yml 2019-11-25 12:27:06 +03:00
11 changed files with 683 additions and 105 deletions

BIN
.github/prev.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

33
.github/workflows/PKGBUILD vendored Normal file
View File

@@ -0,0 +1,33 @@
# Maintainer: Alexandr Bogomyakov (ultradesu) <ab@hexor.ru>
pkgname=tmux-helper
pkgver=0.2.1
pkgrel=1
pkgdesc="Tmux helper"
url="https://github.com/house-of-vanity/tmux-helper.git"
arch=($CARCH)
license=(WTFPL custom)
depends=(tmux dbus)
makedepends=(cargo git dbus)
source=("git+https://github.com/house-of-vanity/$pkgname")
sha512sums=('SKIP')
pkgver() {
cd "$srcdir/$pkgname"
git describe --long --tags | awk -F '-' '{print $1}'| sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
}
prepare() {
cd "$srcdir/$pkgname"
cargo fetch --target $CARCH-unknown-linux-gnu
}
build() {
cd "$srcdir/$pkgname"
cargo build --release --frozen --all-targets
}
package() {
cd "$srcdir/$pkgname"
install -Dt "$pkgdir/usr/bin" target/release/$pkgname
}

95
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,95 @@
name: Build and publish
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
jobs:
make_bin:
name: Build binary
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Pre-build
run: sudo apt install -y libdbus-1-dev pkg-config libdbus-1-3 libfuse-dev
- uses: actions/checkout@v2
- name: Build binary
run: cargo build --release
- name: Upload binary
uses: actions/upload-artifact@v1
with:
name: tmux-helper
path: ./target/release/tmux-helper
make_arch:
name: Make Arch Linux package
runs-on: ubuntu-latest
container:
image: archlinux
options: --privileged
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup
steps:
- uses: actions/checkout@v2
- name: Build Arch Linux package
uses: FFY00/build-arch-package@master
with:
PKGBUILD: $GITHUB_WORKSPACE/.github/workflows/PKGBUILD
OUTDIR: $HOME/arch-packages
- run: mv $HOME/arch-packages/*pkg.tar.zst tmux-helper-x86_64.pkg.tar.zst
- name: Upload Arch Package
uses: actions/upload-artifact@v1
with:
name: arch_linux_tmux-helper-x86_64.pkg.tar.zst
path: ./tmux-helper-x86_64.pkg.tar.zst
publish:
name: Publish release
needs: [make_bin, make_arch]
runs-on: ubuntu-latest
steps:
- name: Get the version (git tag)
id: get_version
run: |
echo ${GITHUB_REF/refs\/tags\/v/}
echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\/v/}
echo ::set-output name=FULL_TAG::${GITHUB_REF/refs\/tags\//}
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Download binary
uses: actions/download-artifact@v1
with:
name: tmux-helper
path: ./
- name: Download Arch Package
uses: actions/download-artifact@v1
with:
name: arch_linux_tmux-helper-x86_64.pkg.tar.zst
path: ./
- name: Upload binary assets
run: |
wget https://github.com/aktau/github-release/releases/download/v0.7.2/linux-amd64-github-release.tar.bz2
tar xjf linux-amd64-github-release.tar.bz2
export GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
./bin/linux/amd64/github-release upload -u house-of-vanity -r tmux-helper --tag ${{ steps.get_version.outputs.FULL_TAG }} --name arch_linux_tmux-helper-${{ steps.get_version.outputs.VERSION }}-x86_64.pkg.tar.zst --file ./tmux-helper-x86_64.pkg.tar.zst
./bin/linux/amd64/github-release upload -u house-of-vanity -r tmux-helper --tag ${{ steps.get_version.outputs.FULL_TAG }} --name tmux-helper-${{ steps.get_version.outputs.VERSION }} --file ./tmux-helper
# SCP to arch repo
- name: Copy package to repository
uses: appleboy/scp-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: github_deploy
port: 22
key: ${{ secrets.SSH_KEY }}
source: "./tmux-helper-x86_64.pkg.tar.zst"
target: "/srv/arch-repo/"

View File

@@ -1,19 +0,0 @@
name: Rust
on: release
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build
run: cargo build --verbose --release
- name: Upload to release
uses: JasonEtco/upload-to-release@master
with:
args: target/release/tmux-helper application/x-pie-executable
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,15 +0,0 @@
name: Rust
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose

View File

@@ -1,8 +1,13 @@
[package] [package]
name = "tmux-helper" name = "tmux-helper"
version = "0.1.0" version = "0.3.0"
description = "Utility for printing system info for tmux status line."
authors = ["Ultra Desu <ultradesu@hexor.ru>"] authors = ["Ultra Desu <ultradesu@hexor.ru>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
sys-info = "*" sys-info = "*"
dbus = "*"
chrono = "*"
mpd = "*"
clap = "*"

13
LICENSE-WTFPL Normal file
View File

@@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

16
README.md Normal file
View File

@@ -0,0 +1,16 @@
# Tmux helper
Small app that perform system check and print TMUX friendly output.
![Preview](.github/prev.png)
### Features:
1. `tmux-helper -cb` print cpu load with bar.
2. `tmux-helper -mb` print memory usage with bar.
3. `tmux-helper -p` show current player status using d-bus.
### Building
`cargo build --release`
or get binary on release page
### Customization
Colours are hardcoded but it's easy to change it. It defined as CONST in very beginning of main.rs file.

226
src/config.rs Normal file
View File

@@ -0,0 +1,226 @@
use clap::{App, Arg};
#[derive(Debug)]
pub enum Action {
Mem,
Cpu,
Mpris,
Mpd,
Localtime,
Utctime,
}
impl Default for Action {
fn default() -> Action {
Action::Cpu
}
}
#[derive(Default, Debug)]
pub struct Config {
pub action: Action,
pub mpd_server: String,
pub lt_format: Option<String>,
pub ut_format: Option<String>,
pub color_low: String,
pub color_mid: String,
pub color_high: String,
pub color_track_name: String,
pub color_track_artist: String,
pub color_track_time: String,
pub color_end: String,
}
fn colorize(color: String) -> String {
format!("#[fg=colour{}]", color)
}
pub fn read() -> Config {
// Parse opts and args
let cli_args = App::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.author(env!("CARGO_PKG_AUTHORS"))
.about(env!("CARGO_PKG_DESCRIPTION"))
// Flags
.arg(
Arg::with_name("cpu")
.short("c")
.long("cpu")
.help("Print cpu load bar.")
.conflicts_with_all(&["mem", "mpris", "mpd", "localtime", "utctime"])
.required(false),
)
.arg(
Arg::with_name("mem")
.short("m")
.long("mem")
.help("Print mem usage bar.")
// .conflicts_with("cpu")
// .conflicts_with("mpris")
// .conflicts_with("mpd")
// .conflicts_with("localtime")
// .conflicts_with("utctime")
.required(false),
)
.arg(
Arg::with_name("mpris")
.short("p")
.long("mpris")
.help("Show player info using MPRIS2 interface.")
// .conflicts_with("cpu")
// .conflicts_with("mem")
// .conflicts_with("localtime")
// .conflicts_with("mpd")
// .conflicts_with("utctime")
.required(false),
)
.arg(
Arg::with_name("mpd")
.short("d")
.long("mpd")
.help("Show mpd player using MPD native protocol.")
// .conflicts_with("cpu")
// .conflicts_with("mem")
// .conflicts_with("localtime")
// .conflicts_with("mpris")
// .conflicts_with("utctime")
.required(false),
)
// Options
.arg(
Arg::with_name("localtime")
.short("l")
.long("localtime")
.help("Local time")
// .conflicts_with_all(&["mem", "mpris", "mpd", "cpu", "utctime"])
.takes_value(true)
.required(false),
)
.arg(
Arg::with_name("utctime")
.short("u")
.long("utctime")
.help("UTC time")
// .conflicts_with_all(&["mem", "mpris", "mpd", "cpu", "localtime"])
.takes_value(true)
.required(false),
)
.arg(
Arg::with_name("mpd_address")
.short("a")
.long("mpd-address")
.help("<ADDR>:<PORT> of MPD server.")
.takes_value(true)
.default_value("127.0.0.1:6600")
.required(false),
)
.arg(
Arg::with_name("COLOR_LOW")
.long("COLOR_LOW")
.help("CPU and MEM bar color while low usage.")
.takes_value(true)
.default_value("119")
.required(false),
)
.arg(
Arg::with_name("COLOR_MID")
.long("COLOR_MID")
.help("CPU and MEM bar color while mid usage.")
.takes_value(true)
.default_value("220")
.required(false),
)
.arg(
Arg::with_name("COLOR_HIGH")
.long("COLOR_HIGH")
.help("CPU and MEM bar color while high usage.")
.takes_value(true)
.default_value("197")
.required(false),
)
.arg(
Arg::with_name("COLOR_TRACK_NAME")
.long("COLOR_TRACK_NAME")
.help("Color of track name filed.")
.takes_value(true)
.default_value("46")
.required(false),
)
.arg(
Arg::with_name("COLOR_TRACK_ARTIST")
.long("COLOR_TRACK_ARTIST")
.help("Color of artist name filed.")
.takes_value(true)
.default_value("46")
.required(false),
)
.arg(
Arg::with_name("COLOR_TRACK_TIME")
.long("COLOR_TRACK_TIME")
.help("Color of playing time field.")
.takes_value(true)
.default_value("153")
.required(false),
)
.arg(
Arg::with_name("COLOR_END")
.long("COLOR_END")
.help("Default color using to terminate others.")
.takes_value(true)
.default_value("153")
.required(false),
)
.get_matches();
// cpu - cpu usage bar
// mem - mem usage bar
// mpris - player info using MPRIS2 interface
// mpd - player info using MPD native interface
// utctime - utc time
// localtime - local time
// lt_format - local time format
// ut_format - utc time format
let lt_format = Some(match cli_args.value_of("localtime") {
Some(format) => format.to_string(),
None => "%H:%M".to_string(),
});
let ut_format = Some(match cli_args.value_of("utctime") {
Some(format) => format.to_string(),
None => "%H:%M".to_string(),
});
let mut cfg = Config {
action: Action::Cpu,
mpd_server: cli_args.value_of("mpd_address").unwrap().to_string(),
lt_format: lt_format,
ut_format: ut_format,
color_low: colorize(cli_args.value_of("COLOR_LOW").unwrap().to_string()),
color_mid: colorize(cli_args.value_of("COLOR_MID").unwrap().to_string()),
color_high: colorize(cli_args.value_of("COLOR_HIGH").unwrap().to_string()),
color_track_name: colorize(cli_args.value_of("COLOR_TRACK_NAME").unwrap().to_string()),
color_track_artist: colorize(cli_args.value_of("COLOR_TRACK_ARTIST").unwrap().to_string()),
color_track_time: colorize(cli_args.value_of("COLOR_TRACK_TIME").unwrap().to_string()),
color_end: colorize(cli_args.value_of("COLOR_END").unwrap().to_string()),
};
if cli_args.is_present("cpu") {
cfg.action = Action::Cpu;
}
if cli_args.is_present("mem") {
cfg.action = Action::Mem;
}
if cli_args.is_present("localtime") {
cfg.action = Action::Localtime;
}
if cli_args.is_present("utctime") {
cfg.action = Action::Utctime;
}
if cli_args.is_present("mpris") {
cfg.action = Action::Mpris;
}
if cli_args.is_present("mpd") {
cfg.action = Action::Mpd;
}
cfg
}

View File

@@ -1,76 +1,33 @@
use std::fs; extern crate chrono;
use std::env; extern crate dbus;
use sys_info; extern crate mpd;
const LOW: &str = "#[fg=colour186]"; mod config;
const MID: &str = "#[fg=colour208]"; mod utils;
const HIGH: &str = "#[fg=colour160]";
const END: &str = "#[fg=colour7]";
fn read_file(file_path: &str) -> String { #[derive(Debug, Clone)]
fs::read_to_string(file_path) struct TrackInfo {
.expect("Cant read file.") title: String,
} artist: String,
position: String,
duration: String,
fn to_bar(value: i32, max: i32, low: f32, mid: f32) { status: String,
let mut bar = "".to_string();
let bar_sym = "".to_string();
if (value as f32) / (max as f32) < low {
bar.push_str(LOW);
} else if (value as f32) / (max as f32) < mid {
bar.push_str(MID);
} else {
bar.push_str(HIGH);
}
for i in 0..max {
if i < value as i32 {
bar.push_str(&bar_sym);
} else {bar.push_str(" ")}
}
bar.push_str(END);
bar.push_str("|");
print!("{}", bar)
}
fn mem_load_bar(bar_len: i32) {
let memory;
match sys_info::mem_info() {
Err(w) => panic!("{:?}", w),
Ok(mem_data) => memory = mem_data,
}
let len = ((memory.total - memory.avail) as f32 / (memory.total as f32) * bar_len as f32) as i32;
to_bar(len, bar_len, 0.7, 0.9);
print!("{:.0} MiB", memory.avail/1024);
}
fn cpu_load_bar(bar_len: i32) {
let load = read_file("/proc/loadavg");
let load_data = load.split_whitespace().collect::<Vec<&str>>();
let _cpu_count = read_file("/proc/cpuinfo");
let cpu_count = _cpu_count.matches("model name").count();
let one: f32 = load_data[0].parse().unwrap();
let len: f32 = one as f32 / cpu_count as f32 * bar_len as f32;
to_bar(len as i32, bar_len, 0.3, 0.7);
print!("{:.2} LA1", one);
} }
fn main() { fn main() {
let args: Vec<String> = env::args().collect(); let conf = config::read();
let help_text: &str = "Available commands -mb, -cb"; // cpu - cpu usage bar
match args.len() { // mem - mem usage bar
1 => { // mpris - player info using MPRIS2 interface
panic!(help_text); // mpd - player info using MPD native interface
}, // utctime - utc time
2 => { // localtime - local time
match args[1].as_ref() { match conf.action {
"-cb" => cpu_load_bar(15), config::Action::Cpu => utils::cpu_load_bar(15, &conf),
"-mb" => mem_load_bar(15), config::Action::Mem => utils::mem_load_bar(15, &conf),
_ => panic!(help_text), config::Action::Mpris => utils::mpris(&conf),
} config::Action::Utctime => utils::get_time(true, conf.ut_format),
}, config::Action::Localtime => utils::get_time(false, conf.lt_format),
_ => { config::Action::Mpd => utils::mpd(&conf),
panic!(help_text); }
}
}
} }

267
src/utils.rs Normal file
View File

@@ -0,0 +1,267 @@
use crate::config;
use crate::dbus::blocking::stdintf::org_freedesktop_dbus::Properties;
use chrono::{DateTime, Local, Utc};
use dbus::{arg, blocking::Connection};
use std::time::Duration;
use sys_info;
use mpd::Client;
use std::process;
#[derive(Debug, Clone)]
pub struct TrackInfo {
title: String,
artist: String,
position: String,
duration: String,
status: String,
}
pub fn to_bar(value: i32, max: i32, low: f32, mid: f32, config: &config::Config) {
let mut bar = "".to_string();
let bar_sym = "".to_string();
if (value as f32) / (max as f32) < low {
bar.push_str(&config.color_low);
} else if (value as f32) / (max as f32) < mid {
bar.push_str(&config.color_mid);
} else {
bar.push_str(&config.color_high);
}
for i in 0..max {
if i < value as i32 {
bar.push_str(&bar_sym);
} else {
bar.push_str(" ")
}
}
bar.push_str(&config.color_end);
bar.push_str("|");
print!("{}", bar)
}
pub fn mem_load_bar(bar_len: i32, config: &config::Config) {
let memory;
match sys_info::mem_info() {
Err(w) => panic!("{:?}", w),
Ok(mem_data) => memory = mem_data,
}
let len =
((memory.total - memory.avail) as f32 / (memory.total as f32) * bar_len as f32) as i32;
to_bar(len, bar_len, 0.7, 0.9, config);
print!("{:.0} MiB#[default]", memory.avail / 1024);
}
pub fn cpu_load_bar(bar_len: i32, config: &config::Config) {
let cpu_count = match sys_info::cpu_num() {
Ok(c) => c,
Err(e) => panic!("{:?}", e),
};
let la_one: f32 = match sys_info::loadavg() {
Ok(l) => l.one as f32,
Err(e) => panic!("{:?}", e),
};
let len: f32 = la_one as f32 / cpu_count as f32 * bar_len as f32;
to_bar(len as i32, bar_len, 0.3, 0.7, config);
print!("{:.2} LA1#[default]", la_one);
}
pub fn get_player() -> Result<Vec<String>, Box<dyn std::error::Error>> {
let conn = Connection::new_session()?;
let proxy = conn.with_proxy("org.freedesktop.DBus", "/", Duration::from_millis(5000));
let (names,): (Vec<String>,) = proxy.method_call("org.freedesktop.DBus", "ListNames", ())?;
let mut players: Vec<String> = Vec::new();
for name in names {
if name.contains("org.mpris.MediaPlayer2") {
players.push(name);
}
}
Ok(players)
}
pub fn player_info(players: Vec<String>) -> Result<TrackInfo, Box<dyn std::error::Error>> {
let mut players_vec: Vec<TrackInfo> = Vec::new();
for player in players {
let mut track_info = TrackInfo {
artist: "".to_string(),
title: "".to_string(),
position: "".to_string(),
duration: "".to_string(),
status: "".to_string(),
};
let conn = Connection::new_session()?;
let proxy = conn.with_proxy(
player,
"/org/mpris/MediaPlayer2",
Duration::from_millis(5000),
);
let metadata: Box<dyn arg::RefArg> =
proxy.get("org.mpris.MediaPlayer2.Player", "Metadata")?;
let mut iter = metadata.as_iter().unwrap();
while let Some(key) = iter.next() {
if key.as_str() == Some("xesam:title") {
if let Some(title) = iter.next().unwrap().as_str() {
track_info.title = title.to_string();
}
}
if key.as_str() == Some("mpris:length") {
if let Some(length) = iter.next().unwrap().as_i64() {
track_info.duration = format_time(length / 1000000);
}
}
if key.as_str() == Some("xesam:artist") {
if let Some(mut artists) = iter.next().unwrap().as_iter() {
while let Some(artist) = artists.next() {
if let Some(mut line) = artist.as_iter() {
track_info.artist = line.next().unwrap().as_str().unwrap().to_string();
}
}
}
}
}
let position: Box<dyn arg::RefArg> =
proxy.get("org.mpris.MediaPlayer2.Player", "Position")?;
track_info.position = format_time(position.as_i64().unwrap() / 1000000);
// ugly
let _status_text_box: Box<dyn arg::RefArg> =
proxy.get("org.mpris.MediaPlayer2.Player", "PlaybackStatus")?;
let _status_text = _status_text_box.as_str().unwrap();
match _status_text.as_ref() {
"Playing" => track_info.status = "".to_string(),
"Paused" => track_info.status = "".to_string(),
_ => track_info.status = "".to_string(),
};
players_vec.push(track_info);
}
for player in &players_vec {
if player.status == "".to_string() {
return Ok(player.clone());
}
}
Ok(players_vec[players_vec.len() - 1].clone())
}
pub fn format_time(sec: i64) -> String {
let minutes = sec / 60;
let secondes = sec % 60;
let result = format!("{:02}:{:02}", minutes, secondes);
result.to_string()
}
pub fn get_time(utc: bool, format: Option<String>) {
// Format reference: https://docs.rs/chrono/0.4.10/chrono/format/strftime/index.html
let fmt = match format {
Some(format) => format,
None => "%H:%M".to_string(),
};
if utc {
let local_time = Local::now();
let utc_time = DateTime::<Utc>::from_utc(local_time.naive_utc(), Utc);
println!("{}", utc_time.format(&fmt));
} else {
let local_time = Local::now();
println!("{}", local_time.format(&fmt));
}
}
fn format_player(track_info: TrackInfo, config: &config::Config) {
let mut title_len = 30;
let mut artist_len = 30;
let mut artist_line: String = String::new();
let mut title_line: String = String::new();
let mut separator: String = "".to_string();
let max_shift = 6;
if track_info.artist.chars().count() == 0 {
separator = "".to_string();
title_len += artist_len;
}
if artist_len + max_shift >= track_info.artist.chars().count() {
artist_len = track_info.artist.chars().count()
}
if track_info.artist.len() > artist_len {
let mut counter = 0;
for ch in track_info.artist.chars() {
if counter == artist_len {
artist_line.push_str("..");
break;
}
artist_line.push(ch);
counter += 1;
}
}
if title_len + max_shift >= track_info.title.chars().count() {
title_len = track_info.title.chars().count()
}
if track_info.title.len() > title_len {
let mut counter = 0;
for ch in track_info.title.chars() {
if counter == title_len {
title_line.push_str("..");
break;
}
title_line.push(ch);
counter += 1;
}
}
println!(
"#[none]#[bold]{}{}{}#[none]{}{}{}{} {}[{}/{}] {} {}#[default]",
config.color_track_name,
title_line,
config.color_end,
separator,
config.color_track_artist,
artist_line,
config.color_end,
config.color_track_time,
track_info.position,
track_info.duration,
track_info.status,
config.color_end,
);
}
pub fn mpris(config: &config::Config) {
match player_info(get_player().unwrap()) {
Ok(track_info) => format_player(track_info, config),
Err(_e) => println!("No music playing"),
}
}
pub fn mpd(config: &config::Config) {
let mut conn = match Client::connect(&config.mpd_server) {
Ok(conn) => conn,
Err(e) => {println!("Can't connect to MPD server. {}", e); process::exit(0x0001)}
};
let mut track_info = TrackInfo {
title: String::new(),
artist: String::new(),
position: String::new(),
duration: String::new(),
status: String::new(),
};
if let Some(song) = conn.currentsong().unwrap() {
if let Some(title) = song.title {
track_info.title = title
}
if let Some(artist) = song.tags.get("Artist") {
track_info.artist = artist.to_string()
}
}
if let Some(time) = conn.status().unwrap().time {
track_info.position = time.0.num_seconds().to_string();
track_info.duration = time.1.num_seconds().to_string()
}
let status = match conn.status() {
Ok(status) => {
match status.state {
mpd::State::Play => "".to_string(),
mpd::State::Pause => "".to_string(),
mpd::State::Stop => "".to_string(),
}
}
Err(_) => {"".to_string()},
};
track_info.status = status;
format_player(track_info, config)
}