Created the managarr-demo repository and created a Dockerfile for CI/CD builds. Added Docker sections to the README as well

This commit is contained in:
2024-03-16 18:19:53 -06:00
parent 6bdefa6ba5
commit 472eeb43ab
7 changed files with 126 additions and 9 deletions
+7
View File
@@ -0,0 +1,7 @@
.github
.git
/screenshots
/target
README.md
CHANGELOG.md
LICENSE
+26
View File
@@ -0,0 +1,26 @@
FROM clux/muslrust:stable AS builder
WORKDIR /usr/src
# Download and compile Rust dependencies in an empty project and cache as a separate Docker layer
RUN USER=root cargo new --bin managarr-temp
WORKDIR /usr/src/managarr-temp
COPY Cargo.* .
RUN cargo build --release --target x86_64-unknown-linux-musl
# remove src from empty project
RUN rm -r src
COPY src ./src
# remove previous deps
RUN rm ./target/x86_64-unknown-linux-musl/release/deps/managarr*
RUN --mount=type=cache,target=/volume/target \
--mount=type=cache,target=/root/.cargo/registry \
cargo build --release --target x86_64-unknown-linux-musl --bin managarr
RUN mv target/x86_64-unknown-linux-musl/release/managarr .
FROM debian:stable-slim
# Copy the compiled binary from the builder container
COPY --from=builder --chown=nonroot:nonroot /usr/src/managarr-temp/managarr /usr/local/bin
ENTRYPOINT [ "/usr/local/bin/managarr" ]
+7
View File
@@ -1,4 +1,7 @@
#!make
VERSION := latest
IMG_NAME := darkalex17/managarr
IMAGE := ${IMG_NAME}:${VERSION}
default: run
@@ -14,6 +17,9 @@ test-cov:
build: test
@cargo build --release
docker:
@DOCKER_BUILDKIT=1 docker build --rm -t ${IMAGE} .
run:
@CARGO_INCREMENTAL=1 cargo fmt && make lint && cargo run
@@ -35,3 +41,4 @@ release:
delete-tag:
@git tag -d ${V} && git push --delete origin ${V}
+27
View File
@@ -32,6 +32,23 @@ pleasant as possible!
- ![bazarr_logo](logos/bazarr.png) [Bazarr](https://www.bazarr.media/)
- ![tautulli_logo](logos/tautulli.png) [Tautulli](https://tautulli.com/)
## Try Before You Buy
To try out Managarr before linking it to your HTPC, you can use the purpose built [managarr-demo](https://github.com/Dark-Alex-17/managarr-demo) repository.
Simply run the following command to start a demo:
```shell
curl https://raw.githubusercontent.com/Dark-Alex-17/managarr-demo/main/managarr-demo.sh > /tmp/managarr-demo.sh && bash /tmp/managarr-demo.sh
```
**Note**: This demo does download a handful of images to your local machine, so be sure to run the cleanup command from the [cleanup section](https://github.com/Dark-Alex-17/managarr-demo#Cleanup) of the
`managarr-demo` README to free space once you're done trying out Managarr:
```shell
docker image rm lscr.io/linuxserver/radarr &&\
docker image rm lscr.io/linuxserver/prowlarr &&\
rm -rf /tmp/managarr-demo
```
## Features
### Radarr
@@ -79,6 +96,16 @@ pleasant as possible!
- [ ] Support for Tautulli
## Installation
### Docker
Run Managarr as a docker container by mounting your `config.yml` file to `/root/.config/managarr/config.yml`. For example:
```shell
docker run --rm -it -v ~/.config/managarr:/root/.config/managarr darkalex17/managarr
```
You can also clone this repo and run `make docker` to build a docker image locally and run it using the above command.
# Configuration
Managarr assumes reasonable defaults to connect to each service (i.e. Radarr is on localhost:7878),
but all servers will require you to input the API token.
+10 -6
View File
@@ -165,6 +165,8 @@ fn draw_file_info(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
fn draw_movie_details(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
let block = layout_block_top_border();
let is_monitored = app.data.radarr_data.movies.current_selection().monitored;
let status = app.data.radarr_data.movies.current_selection().status.clone();
match app.data.radarr_data.movie_details_modal.as_ref() {
Some(movie_details_modal) if !app.is_loading => {
@@ -183,7 +185,7 @@ fn draw_movie_details(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
.map(|line| {
let split = line.split(':').collect::<Vec<&str>>();
let title = format!("{}:", split[0]);
let style = style_from_download_status(download_status);
let style = style_from_download_status(download_status, is_monitored, status.clone());
Line::from(vec![
title.bold().style(style),
@@ -518,13 +520,15 @@ fn draw_manual_search_confirm_prompt(f: &mut Frame<'_>, app: &mut App<'_>) {
}
}
fn style_from_download_status(download_status: &str) -> Style {
fn style_from_download_status(download_status: &str, is_monitored: bool, status: String) -> Style {
match download_status {
"Downloaded" => Style::new().success(),
"Downloaded" => Style::new().downloaded(),
"Awaiting Import" => Style::new().awaiting_import(),
"Downloading" => Style::new().warning(),
"Missing" => Style::new().failure(),
_ => Style::new().success(),
"Downloading" => Style::new().downloading(),
_ if !is_monitored && download_status == "Missing" => Style::new().unmonitored_missing(),
_ if status != "released" && download_status == "Missing" => Style::new().unreleased(),
"Missing" => Style::new().missing(),
_ => Style::new().downloaded(),
}
}
@@ -1,10 +1,15 @@
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use ratatui::style::Style;
use ratatui::text::Text;
use rstest::rstest;
use strum::IntoEnumIterator;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, MOVIE_DETAILS_BLOCKS};
use crate::ui::radarr_ui::library::movie_details_ui::MovieDetailsUi;
use crate::ui::radarr_ui::library::movie_details_ui::{decorate_peer_style, MovieDetailsUi, style_from_download_status};
use crate::ui::DrawUi;
use crate::ui::styles::ManagarrStyle;
#[test]
fn test_movie_details_ui_accepts() {
@@ -16,4 +21,44 @@ mod tests {
}
});
}
#[rstest]
#[case("Downloading", true, "", Style::new().downloading())]
#[case("Downloaded", true, "", Style::new().downloaded())]
#[case("Awaiting Import", true, "", Style::new().awaiting_import())]
#[case("Missing", false, "", Style::new().unmonitored_missing())]
#[case("Missing", false, "", Style::new().unmonitored_missing())]
#[case("Missing", true, "released", Style::new().missing())]
#[case("", true, "", Style::new().downloaded())]
fn test_style_from_download_status(
#[case] download_status: &str,
#[case] is_monitored: bool,
#[case] movie_status: &str,
#[case] expected_style: Style,
) {
assert_eq!(style_from_download_status(download_status, is_monitored, movie_status.to_owned()), expected_style);
}
#[rstest]
#[case(0, 0, PeerStyle::Failure)]
#[case(1, 2, PeerStyle::Warning)]
#[case(4, 2, PeerStyle::Success)]
fn test_decorate_peer_style(
#[case] seeders: u64,
#[case] leechers: u64,
#[case] expected_style: PeerStyle,
) {
let text = Text::from("test");
match expected_style {
PeerStyle::Failure => assert_eq!(decorate_peer_style(seeders, leechers, text.clone()), text.failure()),
PeerStyle::Warning => assert_eq!(decorate_peer_style(seeders, leechers, text.clone()), text.warning()),
PeerStyle::Success => assert_eq!(decorate_peer_style(seeders, leechers, text.clone()), text.success()),
}
}
enum PeerStyle {
Failure,
Warning,
Success,
}
}
+1
View File
@@ -1,5 +1,6 @@
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use ratatui::widgets::{Cell, Row};
use rstest::rstest;
use strum::IntoEnumIterator;