forked from extern/homer
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
a4c1f6a37d | |||
76d30be8e3 | |||
240e3f0e87 | |||
33f75a798a | |||
9c370d3c5e | |||
7341d7634b | |||
b2a4140054 | |||
9e1e82b0f3 | |||
000a46ee88 | |||
1275a8cce5 | |||
cd1fc28f51 | |||
5c42d50d47 | |||
31027f4791 | |||
abfe72b9cf | |||
6dc8fa2026 | |||
345dd6c194 | |||
585844394d | |||
a25f317bee | |||
e2ebf9973b | |||
6e6efc7d29 |
16
.github/workflows/docs.yml
vendored
16
.github/workflows/docs.yml
vendored
@ -1,16 +0,0 @@
|
||||
name: docs
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: '3.x'
|
||||
cache: 'pip'
|
||||
- run: pip install -r requirements.txt
|
||||
- run: mkdocs gh-deploy --force
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -23,10 +23,4 @@ yarn-error.log*
|
||||
# App configuration
|
||||
config.yml
|
||||
|
||||
.drone.yml
|
||||
|
||||
# Python venv
|
||||
venv
|
||||
|
||||
# MkDocs
|
||||
site
|
||||
.drone.yml
|
90
README.md
90
README.md
@ -2,7 +2,7 @@
|
||||
<img
|
||||
width="180"
|
||||
alt="Homer's donut"
|
||||
src="public/logo.png">
|
||||
src="https://raw.githubusercontent.com//bastienwirtz/homer/main/public/logo.png">
|
||||
<br/>
|
||||
Homer
|
||||
</h1>
|
||||
@ -36,18 +36,18 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/images/screenshot.png" width="100%">
|
||||
<img src="https://raw.github.com/bastienwirtz/homer/main/docs/screenshot.png" width="100%">
|
||||
</p>
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Features](#features)
|
||||
- [Getting started](#getting-started)
|
||||
- [Configuration](https://bastienwirtz.github.io/homer/configuration)
|
||||
- [Custom services](https://bastienwirtz.github.io/homer/custom_services)
|
||||
- [Tips & tricks](https://bastienwirtz.github.io/homer/tips_and_tricks)
|
||||
- [Development](https://bastienwirtz.github.io/homer/development)
|
||||
- [Troubleshooting](https://bastienwirtz.github.io/homer/troubleshooting)
|
||||
- [Configuration](docs/configuration.md)
|
||||
- [Custom services](docs/customservices.md)
|
||||
- [Tips & tricks](docs/tips-and-tricks.md)
|
||||
- [Development](docs/development.md)
|
||||
- [Troubleshooting](docs/troubleshooting.md)
|
||||
|
||||
## Features
|
||||
|
||||
@ -65,58 +65,34 @@
|
||||
|
||||
## Getting started
|
||||
|
||||
### Using Docker
|
||||
Homer is a full static html/js dashboard, generated from the source in `/src` using webpack. It's meant to be served by an HTTP server, **it will not work if you open dist/index.html directly over file:// protocol**.
|
||||
|
||||
The fastest and recommended way to get your Homer instance up and running is
|
||||
with Docker. The Docker image comes with a web server built-in so that all you
|
||||
need to worry about is your config file.
|
||||
See [documentation](docs/configuration.md) for information about the configuration (`assets/config.yml`) options.
|
||||
|
||||
Internally, the Docker image looks for the assets in the `/www/assets` directory
|
||||
so you can bind a volume from your host machine to that directory in order to
|
||||
modify and persist the configuration files. The web server serves the dashboard
|
||||
on port 8080, but using a port binding will let you expose that to whatever
|
||||
external port you like.
|
||||
|
||||
#### docker
|
||||
### Using docker
|
||||
|
||||
To launch container:
|
||||
|
||||
```sh
|
||||
docker run -d \
|
||||
-p 8080:8080 \
|
||||
-v </your/local/assets>:/www/assets \
|
||||
-v </your/local/assets/>:/www/assets \
|
||||
--restart=always \
|
||||
b4bz/homer:latest
|
||||
```
|
||||
|
||||
Use `UID` and/or `GID` env var to change the assets owner:
|
||||
Default assets will be automatically installed in the `/www/assets` directory. Use `UID` and/or `GID` env var to change the assets owner (`docker run -e "UID=1000" -e "GID=1000" [...]`).
|
||||
|
||||
```sh
|
||||
docker run -d \
|
||||
-p 8080:8080 \
|
||||
-v </your/local/assets>:/www/assets \
|
||||
-e "UID=1000" -e "GID=1000" \
|
||||
--restart=always \
|
||||
b4bz/homer:latest
|
||||
```
|
||||
### Using docker-compose
|
||||
|
||||
#### docker-compose
|
||||
|
||||
It is recommended to use docker-compose to manage your Docker containers, and
|
||||
below you can find a simple compose yaml file. Copy the contents into a
|
||||
`docker-compose.yaml` and modify the volume binding to your desired directory to
|
||||
get started:
|
||||
The `docker-compose.yml` file must be edited to match your needs.
|
||||
Set the port and volume (equivalent to `-p` and `-v` arguments):
|
||||
|
||||
```yaml
|
||||
version: '3.3'
|
||||
services:
|
||||
homer:
|
||||
restart: always
|
||||
volumes:
|
||||
- /your/local/assets:/www/assets
|
||||
ports:
|
||||
- 8080:8080
|
||||
image: b4bz/homer
|
||||
volumes:
|
||||
- /your/local/assets/:/www/assets
|
||||
ports:
|
||||
- 8080:8080
|
||||
```
|
||||
|
||||
To launch container:
|
||||
@ -126,31 +102,17 @@ cd /path/to/docker-compose.yml
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Use `UID` and/or `GID` env var to change the assets owner:
|
||||
Default assets will be automatically installed in the `/www/assets` directory. Use `UID` and/or `GID` env var to change the assets owner, also in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: '3.3'
|
||||
services:
|
||||
homer:
|
||||
restart: always
|
||||
volumes:
|
||||
- /your/local/assets:/www/assets
|
||||
ports:
|
||||
- 8080:8080
|
||||
environment:
|
||||
- UID=1000
|
||||
- GID=1000
|
||||
image: b4bz/homer
|
||||
environment:
|
||||
- UID=1000
|
||||
- GID=1000
|
||||
```
|
||||
|
||||
### Shipping your own web server
|
||||
### Using the release tarball (prebuilt, ready to use)
|
||||
|
||||
#### Prebuilt release tarball
|
||||
|
||||
Download and extract the latest release (`homer.zip`) from the [release page]
|
||||
(https://github.com/bastienwirtz/homer/releases), rename the
|
||||
`assets/config.yml.dist` file to `assets/config.yml`, and put it behind a web
|
||||
server.
|
||||
Download and extract the latest release (`homer.zip`) from the [release page](https://github.com/bastienwirtz/homer/releases), rename the `assets/config.yml.dist` file to `assets/config.yml`, and put it behind a web server.
|
||||
|
||||
```sh
|
||||
wget https://github.com/bastienwirtz/homer/releases/latest/download/homer.zip
|
||||
@ -160,7 +122,7 @@ cp assets/config.yml.dist assets/config.yml
|
||||
npx serve # or python -m http.server 8010 or apache, nginx ...
|
||||
```
|
||||
|
||||
#### Building from source
|
||||
### Build manually
|
||||
|
||||
```sh
|
||||
# Using yarn (recommended)
|
||||
|
@ -1,25 +0,0 @@
|
||||
# Homer docs
|
||||
|
||||
Live on github pages: [https://bastienwirtz.github.io/homer/](https://bastienwirtz.github.io/homer/)
|
||||
|
||||
## Local development
|
||||
|
||||
### Install Python dependencies
|
||||
|
||||
Homer's documentation is built using [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/). To get started, you'll need Python 3 installed on your machine and set up your local environment.
|
||||
|
||||
```sh
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Preview local copy
|
||||
|
||||
MkDocs comes with a command-line utility for building and serving the static documentation site every time you save a file. To launch it, run the `serve` command.
|
||||
|
||||
```sh
|
||||
mkdocs serve
|
||||
```
|
||||
|
||||
Your local version of the docs site will now be available at http://localhost:8000/.
|
@ -1,8 +1,6 @@
|
||||
# Configuration
|
||||
|
||||
Title, icons, links, colors, and services can be configured in the `config.yml`
|
||||
file (located in `/assets` directory once built, or in the `public/assets`
|
||||
directory in development mode), using [yaml](http://yaml.org/) format.
|
||||
Title, icons, links, colors, and services can be configured in the `config.yml` file (located in `/assets` directory once built, or in the `public/assets` directory in development mode), using [yaml](http://yaml.org/) format.
|
||||
|
||||
```yaml
|
||||
---
|
||||
@ -15,57 +13,40 @@ directory in development mode), using [yaml](http://yaml.org/) format.
|
||||
|
||||
title: "App dashboard"
|
||||
subtitle: "Homer"
|
||||
# Customize the browser tab text
|
||||
# documentTitle: "Welcome"
|
||||
# documentTitle: "Welcome" # Customize the browser tab text
|
||||
logo: "assets/logo.png"
|
||||
# Alternatively a Font Awesome icon can be provided
|
||||
# Alternatively a fa icon can be provided:
|
||||
# icon: "fas fa-skull-crossbones"
|
||||
|
||||
# Set to false to hide the header
|
||||
header: true
|
||||
# Set to false to hide the footer
|
||||
footer: >
|
||||
<p>Created with <span class="has-text-danger">❤️</span> with
|
||||
<a href="https://bulma.io/">bulma</a>,
|
||||
<a href="https://vuejs.org/">vuejs</a>, &
|
||||
<a href="https://fontawesome.com/">font awesome</a>
|
||||
// Fork me on <a href="https://github.com/bastienwirtz/homer">
|
||||
<i class="fab fa-github-alt"></i></a></p>
|
||||
|
||||
# Use "auto" or number (must be a factor of 12: 1, 2, 3, 4, 6, 12)
|
||||
columns: "3"
|
||||
# Whether you want to display a message when the apps are not accessible
|
||||
# anymore (VPN disconnected for example)
|
||||
connectivityCheck: true
|
||||
|
||||
# Optional: Set a different hotkey for search, defaults to "/"
|
||||
header: true # Set to false to hide the header
|
||||
# Optional: Different hotkey for search, defaults to "/"
|
||||
# hotkey:
|
||||
# search: "Shift"
|
||||
footer: '<p>Created with <span class="has-text-danger">❤️</span> with <a href="https://bulma.io/">bulma</a>, <a href="https://vuejs.org/">vuejs</a> & <a href="https://fontawesome.com/">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>' # set false if you want to hide it.
|
||||
|
||||
columns: "3" # "auto" or number (must be a factor of 12: 1, 2, 3, 4, 6, 12)
|
||||
connectivityCheck: true # whether you want to display a message when the apps are not accessible anymore (VPN disconnected for example)
|
||||
|
||||
# Optional: Proxy / hosting option
|
||||
proxy:
|
||||
# Send cookies & authorization headers when fetching service specific data.
|
||||
# Set to `true` if you use an authentication proxy. Can be overrided on
|
||||
# service level.
|
||||
useCredentials: false
|
||||
useCredentials: false # send cookies & authorization headers when fetching service specific data. Set to `true` if you use an authentication proxy. Can be overrided on service level.
|
||||
|
||||
# Set the default layout and color scheme
|
||||
defaults:
|
||||
layout: columns # Either 'columns', or 'list'
|
||||
colorTheme: auto # One of 'auto', 'light', or 'dark'
|
||||
|
||||
# Optional theming: 'default' or one of the themes available in
|
||||
# 'src/assets/themes'.
|
||||
theme: default
|
||||
# Optional theming
|
||||
theme: default # 'default' or one of the themes available in 'src/assets/themes'.
|
||||
|
||||
# Optional custom stylesheet
|
||||
# Will load custom CSS files. Especially useful for custom icon sets.
|
||||
# stylesheet:
|
||||
# - "assets/custom.css"
|
||||
|
||||
# Here is the exhaustive list of customization parameters, however all values
|
||||
# are optional and will fallback to default if not set. If you want to change
|
||||
# only some of the colors, feel free to remove all unused keys.
|
||||
# Here is the exhaustive list of customization parameters
|
||||
# However all value are optional and will fallback to default if not set.
|
||||
# if you want to change only some of the colors, feel free to remove all unused key.
|
||||
colors:
|
||||
light:
|
||||
highlight-primary: "#3367d6"
|
||||
@ -98,30 +79,25 @@ colors:
|
||||
|
||||
# Optional message
|
||||
message:
|
||||
# Uses Bulma. See https://bulma.io/documentation/components/message/#colors
|
||||
# for styling options.
|
||||
style: "is-warning"
|
||||
title: "Optional message!"
|
||||
icon: "fa fa-exclamation-triangle"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
|
||||
|
||||
# Can optionally fetch information from an endpoint to override value below.
|
||||
# url: "https://<my-api-endpoint>"
|
||||
# mapping: # Select the appropriate fields from the response object.
|
||||
# title: 'id' # Use value from field 'id' as title
|
||||
# content: 'value' # Use value from field 'value' as content
|
||||
# url: "https://<my-api-endpoint>" # Can fetch information from an endpoint to override value below.
|
||||
# mapping: # allows to map fields from the remote format to the one expected by Homer
|
||||
# title: 'id' # use value from field 'id' as title
|
||||
# content: 'value' # value from field 'value' as content
|
||||
# refreshInterval: 10000 # Optional: time interval to refresh message
|
||||
#
|
||||
# Real example using chucknorris.io for showing Chuck Norris facts:
|
||||
# Real example using chucknorris.io for showing Chuck Norris facts as messages:
|
||||
# url: https://api.chucknorris.io/jokes/random
|
||||
# mapping:
|
||||
# title: 'id'
|
||||
# content: 'value'
|
||||
# refreshInterval: 10000
|
||||
style: "is-warning"
|
||||
title: "Optional message!"
|
||||
icon: "fa fa-exclamation-triangle"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
|
||||
|
||||
# Optional navbar
|
||||
# Specify [] for navbar (dark mode, layout, and search) without any links
|
||||
# links: []
|
||||
# links: [] # Allows for navbar (dark mode, layout, and search) without any links
|
||||
links:
|
||||
- name: "Link 1"
|
||||
icon: "fab fa-github"
|
||||
@ -130,22 +106,19 @@ links:
|
||||
- name: "link 2"
|
||||
icon: "fas fa-book"
|
||||
url: "https://github.com/bastienwirtz/homer"
|
||||
# Urls starting with # will link to additional Homer pages. Passing "#page2"
|
||||
# will load config from page2.yml as overrides on top of the default values
|
||||
# set in this config.yml.
|
||||
# this will link to a second homer page that will load config from page2.yml and keep default config values as in config.yml file
|
||||
# see url field and assets/page.yml used in this example:
|
||||
- name: "Second Page"
|
||||
icon: "fas fa-file-alt"
|
||||
url: "#page2"
|
||||
|
||||
# Services
|
||||
# First level array represents a group. Use only an "items" key if not using
|
||||
# groups (name, icon, & tagstyle are optional; section separation will not be
|
||||
# displayed).
|
||||
# First level array represents a group.
|
||||
# Leave only a "items" key if not using group (group name, icon & tagstyle are optional, section separation will not be displayed).
|
||||
services:
|
||||
- name: "Application"
|
||||
icon: "fas fa-code-branch"
|
||||
# A path to an image can also be provided. Note that icon will take
|
||||
# precedence if both icon and logo are set.
|
||||
# A path to an image can also be provided. Note that icon take precedence if both icon and logo are set.
|
||||
# logo: "path/to/logo"
|
||||
items:
|
||||
- name: "Awesome app"
|
||||
@ -155,8 +128,7 @@ services:
|
||||
subtitle: "Bookmark example"
|
||||
tag: "app"
|
||||
url: "https://www.reddit.com/r/selfhosted/"
|
||||
# Optional: HTML <a> tag target attribute
|
||||
target: "_blank"
|
||||
target: "_blank" # optional html tag target attribute
|
||||
- name: "Another one"
|
||||
logo: "assets/tools/sample2.png"
|
||||
subtitle: "Another application"
|
||||
@ -169,28 +141,18 @@ services:
|
||||
items:
|
||||
- name: "Pi-hole"
|
||||
logo: "assets/tools/sample.png"
|
||||
# Optional: If no subtitle is defined, PiHole statistics will be shown.
|
||||
# subtitle: "Network-wide Ad Blocking"
|
||||
# subtitle: "Network-wide Ad Blocking" # optional, if no subtitle is defined, PiHole statistics will be shown
|
||||
tag: "other"
|
||||
url: "http://192.168.0.151/admin"
|
||||
# Optional: Loads a specific component that provides extra features.
|
||||
# MUST MATCH a file name (without file extension) available in
|
||||
# `src/components/services`
|
||||
type: "PiHole"
|
||||
# Optional: HTML <a> tag target attribute
|
||||
target: "_blank"
|
||||
# Optional: Custom CSS class for card, useful with custom stylesheet
|
||||
# class: "green"
|
||||
# Optional: Set background color directly without custom stylesheet
|
||||
# background: red
|
||||
type: "PiHole" # optional, loads a specific component that provides extra features. MUST MATCH a file name (without file extension) available in `src/components/services`
|
||||
target: "_blank" # optional html a tag target attribute
|
||||
# class: "green" # optional custom CSS class for card, useful with custom stylesheet
|
||||
# background: red # optional color for card to set color directly without custom stylesheet
|
||||
```
|
||||
|
||||
View [Custom Services](custom_services.md) for details about all available
|
||||
custom services (like PiHole) and how to configure them.
|
||||
View [Custom Services](customservices.md) for details about all available custom services (like PiHole) and how to configure them.
|
||||
|
||||
If you choose to fetch message information from an endpoint, the output format
|
||||
should be as follows (or you can
|
||||
[custom map fields as shown in tips and tricks](tips_and_tricks#mapping-fields)):
|
||||
If you choose to fetch message information from an endpoint, the output format should be as follows (or you can [custom map fields as shown in tips-and-tricks](./tips-and-tricks.md#mapping-fields)):
|
||||
|
||||
```json
|
||||
{
|
||||
@ -200,31 +162,43 @@ should be as follows (or you can
|
||||
}
|
||||
```
|
||||
|
||||
`null` value or missing keys will be ignored and value from the `config.yml`
|
||||
will be used if available. Empty values (either in `config.yml` or the endpoint
|
||||
data) will hide the element (ex: set `"title": ""` to hide the title bar).
|
||||
`null` value or missing keys will be ignored and value from the `config.yml` will be used if available.
|
||||
Empty values (either in `config.yml` or the endpoint data) will hide the element (ex: set `"title": ""` to hide the title bar).
|
||||
|
||||
## Style Options
|
||||
|
||||
Homer uses [Bulma CSS](https://bulma.io/), which provides a
|
||||
[modifiers syntax](https://bulma.io/documentation/modifiers/syntax/). You'll
|
||||
notice in the config there is a `tagstyle` option. It can be set to any of the
|
||||
bulma modifiers. You'll probably want to use one of these 4 main colors:
|
||||
Homer uses [bulma CSS](https://bulma.io/), which provides a [modifiers syntax](https://bulma.io/documentation/modifiers/syntax/). You'll notice in the config there is a `tagstyle` option. It can be set to any of the bulma modifiers. You'll probably want to use one of these 4 main colors:
|
||||
|
||||
- `is-info` (blue)
|
||||
- `is-success` (green)
|
||||
- `is-warning` (yellow)
|
||||
- `is-danger` (red)
|
||||
|
||||
You can read the [bulma modifiers page](https://bulma.io/documentation/modifiers/syntax/)
|
||||
for other options regarding size, style, or state.
|
||||
You can read the [bulma modifiers page](https://bulma.io/documentation/modifiers/syntax/) for other options regarding size, style, or state.
|
||||
|
||||
## PWA Icons
|
||||
|
||||
In order to easily generate all required icon preset for the PWA to work, a tool
|
||||
like [vue-pwa-asset-generator](https://www.npmjs.com/package/vue-pwa-asset-generator)
|
||||
can be used:
|
||||
In order to easily generate all required icon preset for the PWA to work, a tool like [vue-pwa-asset-generator](https://www.npmjs.com/package/vue-pwa-asset-generator) can be used:
|
||||
|
||||
```bash
|
||||
npx vue-pwa-asset-generator -a {your_512x512_source_png} -o {your_output_folder}
|
||||
```
|
||||
|
||||
## Supported services
|
||||
|
||||
Currently the following services are supported for showing quick infos on the card. They can be used by setting the type to one of the following values at the item.
|
||||
|
||||
- PiHole
|
||||
- AdGuardHome
|
||||
- PaperlessNG
|
||||
- Mealie
|
||||
|
||||
## Additional configuration
|
||||
|
||||
### Paperless
|
||||
|
||||
For Paperless you need an API-Key which you have to store at the item in the field `apikey`.
|
||||
|
||||
### Mealie
|
||||
|
||||
First off make sure to remove an existing `subtitle` as it will take precedence if set. Setting `type: "Mealie"` will then show the number of recipes Mealie is keeping organized or the planned meal for today if one is planned. You will have to set an API key in the field `apikey` which can be created in your Mealie installation.
|
||||
|
@ -17,8 +17,6 @@ within Homer:
|
||||
+ [AdGuard Home](#adguard-home)
|
||||
+ [Portainer](#portainer)
|
||||
+ [Emby](#emby)
|
||||
+ [Uptime Kuma](#uptime-kuma)
|
||||
+ [Tautulli](#tautulli)
|
||||
|
||||
If you experiencing any issue, please have a look to the [troubleshooting](troubleshooting.md) page.
|
||||
|
||||
@ -181,45 +179,3 @@ You need to set the type to Emby, provide an api key and choose which stats to s
|
||||
apikey: "MY-SUPER-SECRET-API-KEY"
|
||||
libraryType: "music" #Choose which stats to show. Can be one of: music, series or movies.
|
||||
```
|
||||
|
||||
## Uptime Kuma
|
||||
|
||||
Using the Uptime Kuma service you can display info about your instance uptime right on your Homer dashboard.
|
||||
|
||||
The following configuration is available for the UptimeKuma service. Needs v1.13.1 or later because of the change in APIs due to [multiple status pages support](https://github.com/louislam/uptime-kuma/releases/tag/1.13.1).
|
||||
|
||||
```yaml
|
||||
- name: "Uptime Kuma"
|
||||
logo: "assets/tools/sample.png"
|
||||
# subtitle: "A fancy self-hosted monitoring tool" # optional, if no subtitle is defined, Uptime Kuma incidents, if any, will be shown
|
||||
url: "http://192.168.0.151:3001"
|
||||
slug: "myCustomDashboard" # Defaults to "default" if not provided.
|
||||
type: "UptimeKuma"
|
||||
```
|
||||
|
||||
## Tautulli
|
||||
|
||||
The Tautulli service can allow you to show the number of currently active
|
||||
streams on you Plex instance. An API key is required, and can be obtained from
|
||||
the "Web Interface" section of settings on the Tautulli web UI.
|
||||
|
||||
```yaml
|
||||
- name: "Tautulli"
|
||||
logo: "assets/tools/sample.png"
|
||||
url: "http://192.168.0.151:8181"
|
||||
type: "Tautulli"
|
||||
apikey: "MY-SUPER-SECRET-API-KEY"
|
||||
```
|
||||
|
||||
Because the service type and link don't necessarily have to match, you could
|
||||
even make the service type Tautulli on your Plex card and provide a separate
|
||||
endpoint pointing to Tautulli!
|
||||
|
||||
```yaml
|
||||
- name: "Plex"
|
||||
logo: "assets/tools/sample.png"
|
||||
url: "http://192.168.0.151:32400/web" # Plex
|
||||
endpoint: "http://192.168.0.151:8181" # Tautulli
|
||||
type: "Tautulli"
|
||||
apikey: "MY-SUPER-SECRET-API-KEY"
|
||||
```
|
@ -72,32 +72,3 @@ body #app.theme-my-awesome-theme. { ... }
|
||||
...
|
||||
@import "./themes/my-awesome-theme.scss";
|
||||
```
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
### Install Python dependencies
|
||||
|
||||
Homer's documentation is built using
|
||||
[Material for MkDocs](https://squidfunk.github.io/mkdocs-material/). To get
|
||||
started, you'll need Python 3 installed on your machine and set up your local
|
||||
environment.
|
||||
|
||||
```sh
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Preview local copy
|
||||
|
||||
MkDocs comes with a command-line utility for building and serving the static
|
||||
documentation site every time you save a file. To launch it, run the `serve`
|
||||
command.
|
||||
|
||||
```sh
|
||||
mkdocs serve
|
||||
```
|
||||
|
||||
Your local version of the docs site will now be available at
|
||||
http://localhost:8000/.
|
||||
|
@ -1,105 +0,0 @@
|
||||
## Using Docker
|
||||
|
||||
The fastest and recommended way to get your Homer instance up and running is
|
||||
with Docker. The Docker image comes with a web server built-in so that all you
|
||||
need to worry about is your config file.
|
||||
|
||||
Internally, the Docker image looks for the assets in the `/www/assets` directory
|
||||
so you can bind a volume from your host machine to that directory in order to
|
||||
modify and persist the configuration files. The web server serves the dashboard
|
||||
on port 8080, but using a port binding will let you expose that to whatever
|
||||
external port you like.
|
||||
|
||||
### docker
|
||||
|
||||
To launch container:
|
||||
|
||||
```sh
|
||||
docker run -d \
|
||||
-p 8080:8080 \
|
||||
-v </your/local/assets>:/www/assets \
|
||||
--restart=always \
|
||||
b4bz/homer:latest
|
||||
```
|
||||
|
||||
Use `UID` and/or `GID` env var to change the assets owner:
|
||||
|
||||
```sh
|
||||
docker run -d \
|
||||
-p 8080:8080 \
|
||||
-v </your/local/assets>:/www/assets \
|
||||
-e "UID=1000" -e "GID=1000" \
|
||||
--restart=always \
|
||||
b4bz/homer:latest
|
||||
```
|
||||
|
||||
### docker-compose
|
||||
|
||||
It is recommended to use docker-compose to manage your Docker containers, and
|
||||
below you can find a simple compose yaml file. Copy the contents into a
|
||||
`docker-compose.yaml` and modify the volume binding to your desired directory to
|
||||
get started:
|
||||
|
||||
```yaml
|
||||
version: '3.3'
|
||||
services:
|
||||
homer:
|
||||
restart: always
|
||||
volumes:
|
||||
- /your/local/assets:/www/assets
|
||||
ports:
|
||||
- 8080:8080
|
||||
image: b4bz/homer
|
||||
```
|
||||
|
||||
To launch container:
|
||||
|
||||
```sh
|
||||
cd /path/to/docker-compose.yml
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Use `UID` and/or `GID` env var to change the assets owner:
|
||||
|
||||
```yaml
|
||||
version: '3.3'
|
||||
services:
|
||||
homer:
|
||||
restart: always
|
||||
volumes:
|
||||
- /your/local/assets:/www/assets
|
||||
ports:
|
||||
- 8080:8080
|
||||
environment:
|
||||
- UID=1000
|
||||
- GID=1000
|
||||
image: b4bz/homer
|
||||
```
|
||||
|
||||
## Shipping your own web server
|
||||
|
||||
### Prebuilt release tarball
|
||||
|
||||
Download and extract the latest release (`homer.zip`) from the [release page](https://github.com/bastienwirtz/homer/releases), rename the `assets/config.yml.dist` file to `assets/config.yml`, and put it behind a web server.
|
||||
|
||||
```sh
|
||||
wget https://github.com/bastienwirtz/homer/releases/latest/download/homer.zip
|
||||
unzip homer.zip
|
||||
cd homer
|
||||
cp assets/config.yml.dist assets/config.yml
|
||||
npx serve # or python -m http.server 8010 or apache, nginx ...
|
||||
```
|
||||
|
||||
### Building from source
|
||||
|
||||
```sh
|
||||
# Using yarn (recommended)
|
||||
yarn install
|
||||
yarn build
|
||||
|
||||
# **OR** Using npm
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
Then your dashboard is ready to use in the `/dist` directory.
|
Binary file not shown.
Before Width: | Height: | Size: 36 KiB |
@ -1,34 +0,0 @@
|
||||
<img class="hero-image" src="images/screenshot.png" draggable="false" />
|
||||
|
||||
## High-level overview
|
||||
|
||||
Homer is web-based dashboard that simplifies your home page management. Designed
|
||||
for home labs, corporate internal networks, and anyone looking to organize their
|
||||
web-based work. It is built with [Vue](https://vuejs.org/) and uses `yaml`
|
||||
configuration files to provide you with a home page that is dead simple to build
|
||||
and serve!
|
||||
|
||||
## Ease of use & customizability
|
||||
|
||||
[Get up and running](/getting_started) in seconds using Docker and customize to
|
||||
your hearts content using the long list of [configuration](/configuration)
|
||||
options available! Add links to all your relevant services and web apps,
|
||||
categorize them in groups, and in some cases,
|
||||
[get live status data](/custom_services) right there on your home page.
|
||||
Customize your home page with your own images and CSS to make it fit your style!
|
||||
|
||||
## Features
|
||||
|
||||
- [yaml](http://yaml.org/) file configuration
|
||||
- Installable (pwa)
|
||||
- Search
|
||||
- Grouping
|
||||
- Theme customization
|
||||
- Offline health check
|
||||
- keyboard shortcuts:
|
||||
- `/` Start searching.
|
||||
- `Escape` Stop searching.
|
||||
- `Enter` Open the first matching result (respects the bookmark's `_target` property).
|
||||
- `Alt`/`Option` + `Enter` Open the first matching result in a new tab.
|
||||
|
||||
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
1
docs/stylesheets/open-props.1.3.16.min.css
vendored
1
docs/stylesheets/open-props.1.3.16.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1,71 +0,0 @@
|
||||
/* Set some CSS variables for use throughout the page */
|
||||
|
||||
:root>* {
|
||||
--md-hue: 208; /* blue-7 hue */
|
||||
--md-footer-bg-color: var(--md-code-bg-color);
|
||||
--md-footer-fg-color: var(--md-code-fg-color);
|
||||
}
|
||||
|
||||
[data-md-color-scheme="default"] {
|
||||
--md-primary-fg-color: var(--blue-7);
|
||||
--md-accent-fg-color: var(--violet-6);
|
||||
--md-code-bg-color: var(--gray-2);
|
||||
--md-default-fg-color--lightest: var(--gray-4);
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] {
|
||||
--md-primary-fg-color: var(--blue-5);
|
||||
--md-accent-fg-color: var(--violet-4);
|
||||
}
|
||||
|
||||
/* Override some default material styles */
|
||||
|
||||
[dir=ltr] .md-header__title,
|
||||
[dir=rtl] .md-header__title {
|
||||
margin-inline: 0.3rem;
|
||||
}
|
||||
|
||||
.md-nav__title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.md-footer__link {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding-top: 0.7rem;
|
||||
}
|
||||
|
||||
.md-footer__link:is(:focus,:hover) {
|
||||
opacity: unset;
|
||||
}
|
||||
|
||||
.md-footer__title {
|
||||
line-height: unset;
|
||||
margin-top: 0.65rem;
|
||||
padding-inline: 0.6rem;
|
||||
}
|
||||
|
||||
.md-footer__direction {
|
||||
padding-inline: 0.6rem;
|
||||
}
|
||||
|
||||
.md-footer-meta {
|
||||
background-color: hsla(var(--md-hue), 15%, 10%, 1);
|
||||
}
|
||||
|
||||
html .md-footer .md-footer-meta a:focus,
|
||||
html .md-footer .md-footer-meta a:hover,
|
||||
html .md-footer a:focus,
|
||||
html .md-footer a:hover {
|
||||
color: var(--md-accent-fg-color);
|
||||
}
|
||||
|
||||
/* Our custom styles */
|
||||
|
||||
.hero-image {
|
||||
width: 65%;
|
||||
margin-inline-start: 17.5%;
|
||||
border-radius: var(--radius-2);
|
||||
box-shadow: var(--shadow-3);
|
||||
}
|
@ -2,29 +2,18 @@
|
||||
|
||||
## My custom service card doesn't work, nothing appears or offline status is displayed (pi-hole, sonarr, ping, ...)
|
||||
|
||||
You might by facing a [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
|
||||
(Cross Origin Request Sharing) issue. It happens when the targeted service is
|
||||
hosted on a different domain or port. Web browsers will not allow to fetch
|
||||
information from a different site without explicit permissions (the targeted
|
||||
service must include a special `Access-Control-Allow-Origin: *` HTTP headers).
|
||||
If this happens your web console (`ctrl+shift+i` or `F12`) will be filled with
|
||||
this kind of errors:
|
||||
You might by facing a [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) (Cross Origin Request Sharing) issue.
|
||||
It happens when the targeted service is hosted on a different domain or port.
|
||||
Web browsers will not allow to fetch information from a different site without explicit permissions (the targeted service
|
||||
must include a special `Access-Control-Allow-Origin: *` HTTP headers).
|
||||
If this happens your web console (`ctrl+shift+i` or `F12`) will be filled with this kind of errors:
|
||||
|
||||
```text
|
||||
Access to fetch at 'https://<target-service>' from origin 'https://<homer>' has
|
||||
been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
|
||||
on the requested resource. If an opaque response serves your needs, set the
|
||||
request's mode to 'no-cors' to fetch the resource with CORS disabled.
|
||||
Access to fetch at 'https://<target-service>' from origin 'https://<homer>' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
|
||||
```
|
||||
|
||||
To resolve this, you can either:
|
||||
|
||||
* Host all your target service under the same domain & port.
|
||||
* Modify the target server configuration so that the response of the server
|
||||
included following header- `Access-Control-Allow-Origin: *`
|
||||
(<https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests>). It
|
||||
might be an option in the targeted service, otherwise depending on how the
|
||||
service is hosted, the proxy or web server can seamlessly add it.
|
||||
* Use a cors proxy server like
|
||||
[`cors-container`](https://github.com/imjacobclark/cors-container),
|
||||
[`cors-anywhere`](https://github.com/Rob--W/cors-anywhere) or many others.
|
||||
* Modify the target server configuration so that the response of the server included following header- `Access-Control-Allow-Origin: *` (<https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests>). It might be an option in the targeted service, otherwise depending on how the service is hosted, the proxy or web server can seamlessly add it.
|
||||
* Use a cors proxy server like [`cors-container`](https://github.com/imjacobclark/cors-container), [`cors-anywhere`](https://github.com/Rob--W/cors-anywhere) or many others.
|
||||
|
87
mkdocs.yml
87
mkdocs.yml
@ -1,87 +0,0 @@
|
||||
# Project information
|
||||
site_name: Homer
|
||||
site_url: https://bastienwirtz.github.io/
|
||||
|
||||
# Repository
|
||||
repo_name: bastienwirtz/homer
|
||||
repo_url: https://github.com/bastienwirtz/homer
|
||||
edit_uri: ""
|
||||
|
||||
# Custom CSS
|
||||
extra_css:
|
||||
- stylesheets/open-props.1.3.16.min.css
|
||||
- stylesheets/styles.css
|
||||
|
||||
# Theme
|
||||
theme:
|
||||
favicon: images/logo.png
|
||||
logo: images/logo.png
|
||||
name: material
|
||||
# custom_dir: docs/overrides/
|
||||
icon:
|
||||
repo: fontawesome/brands/github
|
||||
language: en
|
||||
palette:
|
||||
- media: "(prefers-color-scheme: light)"
|
||||
scheme: default
|
||||
toggle:
|
||||
icon: fontawesome/solid/sun
|
||||
name: Switch to dark mode
|
||||
- media: "(prefers-color-scheme: dark)"
|
||||
scheme: slate
|
||||
toggle:
|
||||
icon: fontawesome/solid/moon
|
||||
name: Switch to light mode
|
||||
features:
|
||||
- content.code.annotate
|
||||
- navigation.indexes
|
||||
- navigation.sections
|
||||
- navigation.top
|
||||
- navigation.tracking
|
||||
- search.highlight
|
||||
- search.share
|
||||
- search.suggest
|
||||
- toc.follow
|
||||
# Don't include MkDocs' JavaScript
|
||||
include_search_page: false
|
||||
search_index_only: true
|
||||
|
||||
# Copyright - name for footer text
|
||||
copyright: Homer
|
||||
|
||||
# Socials
|
||||
extra:
|
||||
social:
|
||||
- icon: fontawesome/brands/github
|
||||
link: https://github.com/bastienwirtz/homer
|
||||
- icon: fontawesome/brands/gitter
|
||||
link: https://gitter.im/homer-dashboard/community
|
||||
- icon: fontawesome/brands/docker
|
||||
link: https://hub.docker.com/r/b4bz/homer
|
||||
|
||||
# Extensions
|
||||
markdown_extensions:
|
||||
- abbr
|
||||
- admonition
|
||||
- attr_list
|
||||
- def_list
|
||||
- footnotes
|
||||
- meta
|
||||
- md_in_html
|
||||
- toc:
|
||||
permalink: true
|
||||
- pymdownx.highlight:
|
||||
anchor_linenums: true
|
||||
- pymdownx.inlinehilite
|
||||
- pymdownx.snippets
|
||||
- pymdownx.superfences
|
||||
|
||||
# Page tree
|
||||
nav:
|
||||
- What is Homer: index.md
|
||||
- Getting started: getting_started.md
|
||||
- Configuration: configuration.md
|
||||
- Custom services: custom_services.md
|
||||
- Tips & tricks: tips_and_tricks.md
|
||||
- Development: development.md
|
||||
- Troubleshooting: troubleshooting.md
|
@ -1,23 +0,0 @@
|
||||
bracex==2.2.1
|
||||
click==8.0.4
|
||||
ghp-import==2.0.2
|
||||
importlib-metadata==4.11.3
|
||||
Jinja2==3.0.3
|
||||
Markdown==3.3.6
|
||||
MarkupSafe==2.1.1
|
||||
mergedeep==1.3.4
|
||||
mkdocs==1.2.3
|
||||
mkdocs-awesome-pages-plugin==2.7.0
|
||||
mkdocs-material==8.2.5
|
||||
mkdocs-material-extensions==1.0.3
|
||||
packaging==21.3
|
||||
Pygments==2.11.2
|
||||
pymdown-extensions==9.3
|
||||
pyparsing==3.0.7
|
||||
python-dateutil==2.8.2
|
||||
PyYAML==6.0
|
||||
pyyaml-env-tag==0.1
|
||||
six==1.16.0
|
||||
watchdog==2.1.6
|
||||
wcmatch==8.3
|
||||
zipp==3.7.0
|
@ -84,6 +84,7 @@
|
||||
:key="index"
|
||||
:item="item"
|
||||
:proxy="config.proxy"
|
||||
:forwarder="config.forwarder"
|
||||
:class="['column', `is-${12 / config.columns}`]"
|
||||
/>
|
||||
</template>
|
||||
@ -113,6 +114,7 @@
|
||||
:key="index"
|
||||
:item="item"
|
||||
:proxy="config.proxy"
|
||||
:forwarder="config.forwarder"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -52,4 +52,5 @@ links: []
|
||||
services: []
|
||||
|
||||
|
||||
proxy: ~
|
||||
proxy: ~
|
||||
forwarder: ~
|
||||
|
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<component v-bind:is="component" :item="item" :proxy="proxy"></component>
|
||||
<component
|
||||
v-bind:is="component"
|
||||
:item="item"
|
||||
:proxy="proxy"
|
||||
:forwarder="forwarder"
|
||||
></component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -10,6 +15,7 @@ export default {
|
||||
props: {
|
||||
item: Object,
|
||||
proxy: Object,
|
||||
forwarder: Object,
|
||||
},
|
||||
computed: {
|
||||
component() {
|
||||
|
118
src/components/services/Emby.vue
Normal file
118
src/components/services/Emby.vue
Normal file
@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<Generic :item="item">
|
||||
<template #content>
|
||||
<p class="title is-4">{{ item.name }}</p>
|
||||
<p class="subtitle is-6">
|
||||
<template v-if="item.subtitle">
|
||||
{{ item.subtitle }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ embyCount }}
|
||||
</template>
|
||||
</p>
|
||||
</template>
|
||||
<template #indicator>
|
||||
<div v-if="status" class="status" :class="status">
|
||||
{{ status }}
|
||||
</div>
|
||||
</template>
|
||||
</Generic>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import service from "@/mixins/service.js";
|
||||
import Generic from "./Generic.vue";
|
||||
|
||||
export default {
|
||||
name: "Emby",
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
},
|
||||
components: {
|
||||
Generic,
|
||||
},
|
||||
data: () => ({
|
||||
status: "",
|
||||
albumCount: 0,
|
||||
songCount: 0,
|
||||
movieCount: 0,
|
||||
seriesCount: 0,
|
||||
episodeCount: 0,
|
||||
}),
|
||||
computed: {
|
||||
embyCount: function () {
|
||||
if (this.item.libraryType === "music")
|
||||
return `${this.songCount} songs, ${this.albumCount} albums`;
|
||||
else if (this.item.libraryType === "movies")
|
||||
return `${this.movieCount} movies`;
|
||||
else if (this.item.libraryType === "series")
|
||||
return `${this.episodeCount} eps, ${this.seriesCount} series`;
|
||||
else return `wrong library type 💀`;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.fetchServerStatus();
|
||||
|
||||
if (!this.item.subtitle && this.status !== "dead")
|
||||
this.fetchServerMediaStats();
|
||||
},
|
||||
methods: {
|
||||
fetchServerStatus: async function () {
|
||||
this.fetch("/System/info/public")
|
||||
.then((response) => {
|
||||
if (response.Id) this.status = "running";
|
||||
else throw new Error();
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
this.status = "dead";
|
||||
});
|
||||
},
|
||||
fetchServerMediaStats: async function () {
|
||||
const headers = {
|
||||
"X-Emby-Token": this.item.apikey,
|
||||
};
|
||||
|
||||
var data = await this.fetch("/items/counts", { headers }).catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
this.albumCount = data.AlbumCount;
|
||||
this.songCount = data.SongCount;
|
||||
this.movieCount = data.MovieCount;
|
||||
this.seriesCount = data.SeriesCount;
|
||||
this.episodeCount = data.EpisodeCount;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.status {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-title);
|
||||
|
||||
&.running:before {
|
||||
background-color: #94e185;
|
||||
border-color: #78d965;
|
||||
box-shadow: 0 0 5px 1px #94e185;
|
||||
}
|
||||
|
||||
&.dead:before {
|
||||
background-color: #c9404d;
|
||||
border-color: #c42c3b;
|
||||
box-shadow: 0 0 5px 1px #c9404d;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: " ";
|
||||
display: inline-block;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
margin-right: 10px;
|
||||
border: 1px solid #000;
|
||||
border-radius: 7px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -83,6 +83,12 @@ export default {
|
||||
|
||||
let containers = [];
|
||||
for (let endpoint of this.endpoints) {
|
||||
if (
|
||||
this.item.environments &&
|
||||
!this.item.environments.includes(endpoint.Name)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const uri = `/api/endpoints/${endpoint.Id}/docker/containers/json?all=1`;
|
||||
const endpointContainers = await this.fetch(uri, { headers }).catch(
|
||||
(e) => {
|
||||
|
@ -1,6 +1,9 @@
|
||||
const merge = require("lodash.merge");
|
||||
|
||||
export default {
|
||||
props: {
|
||||
proxy: Object,
|
||||
forwarder: Object,
|
||||
},
|
||||
created: function () {
|
||||
// custom service often consume info from an API using the item link (url) as a base url,
|
||||
@ -25,18 +28,28 @@ export default {
|
||||
this.item.useCredentials === true ? "include" : "omit";
|
||||
}
|
||||
|
||||
options = Object.assign(options, init);
|
||||
if (this.forwarder?.apikey) {
|
||||
options.headers = {
|
||||
"X-Homer-Forwarder-Api-Key": this.forwarder.apikey,
|
||||
};
|
||||
}
|
||||
|
||||
if (path.startsWith("/")) {
|
||||
path = path.slice(1);
|
||||
}
|
||||
|
||||
let url = this.endpoint;
|
||||
let url = path ? `${this.endpoint}/${path}` : this.endpoint;
|
||||
|
||||
if (path) {
|
||||
url = `${this.endpoint}/${path}`;
|
||||
if (this.forwarder?.url) {
|
||||
options.headers = {
|
||||
...(options.headers || {}),
|
||||
"X-Homer-Forwarder-Url": url,
|
||||
};
|
||||
url = this.forwarder.url;
|
||||
}
|
||||
|
||||
options = merge(options, init);
|
||||
|
||||
return fetch(url, options).then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Not 2xx response");
|
||||
|
@ -5590,9 +5590,9 @@ minimatch@^3.0.4:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@^1.2.0, minimist@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
||||
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
|
||||
|
||||
minipass@^3.1.1:
|
||||
version "3.1.3"
|
||||
|
Reference in New Issue
Block a user