mirror of
https://github.com/bastienwirtz/homer.git
synced 2026-01-23 10:25:19 +00:00
Compare commits
163 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6367012675 | ||
|
|
d7bee37405 | ||
|
|
4cf69b3a25 | ||
|
|
2e1c7b3d27 | ||
|
|
151c136923 | ||
|
|
2a27bee30e | ||
|
|
d1356c3e6a | ||
|
|
8d82c77630 | ||
|
|
f11c14e764 | ||
|
|
62606e0caf | ||
|
|
184c16d46c | ||
|
|
ee57fa05fb | ||
|
|
8249aa8ae4 | ||
|
|
a4ec46ee35 | ||
|
|
bac62457f1 | ||
|
|
3913c30a56 | ||
|
|
3f49479556 | ||
|
|
6aa29935f6 | ||
|
|
19c5f174e8 | ||
|
|
89a264563a | ||
|
|
d19724b896 | ||
|
|
8a598dbdc0 | ||
|
|
2f4bbee491 | ||
|
|
7bd56d941a | ||
|
|
5a816709e5 | ||
|
|
81c7496264 | ||
|
|
4904717db0 | ||
|
|
92a79ffdfb | ||
|
|
35e49e3d91 | ||
|
|
68fb183c20 | ||
|
|
9054bd8941 | ||
|
|
b821651017 | ||
|
|
5b29bc411c | ||
|
|
06b677ab76 | ||
|
|
843a814ac5 | ||
|
|
1b6c3e6213 | ||
|
|
90ba82de8f | ||
|
|
6f902b78c0 | ||
|
|
9aaef4eaef | ||
|
|
e4588bc634 | ||
|
|
61d5d0b722 | ||
|
|
63647e837a | ||
|
|
2df7d5947b | ||
|
|
8ce2daff4d | ||
|
|
1f2c2058f6 | ||
|
|
a36634c237 | ||
|
|
ee152fd202 | ||
|
|
5eaa479b3c | ||
|
|
11bd5fd9d5 | ||
|
|
da32035841 | ||
|
|
2046d8d30c | ||
|
|
308deb95e0 | ||
|
|
a941e94a3b | ||
|
|
83152453c5 | ||
|
|
b4e20fe8af | ||
|
|
a38514739d | ||
|
|
7ea9b2e882 | ||
|
|
60cc984f12 | ||
|
|
fcf730f610 | ||
|
|
c230392da8 | ||
|
|
adf671772b | ||
|
|
51b4649628 | ||
|
|
6344970eb6 | ||
|
|
3f1d8e01ad | ||
|
|
58a1a0764d | ||
|
|
105937d438 | ||
|
|
abb0cf84bb | ||
|
|
517de68e74 | ||
|
|
1afa0afd00 | ||
|
|
a5eeb1e44e | ||
|
|
acb304adec | ||
|
|
347a3d062b | ||
|
|
15f59b9e36 | ||
|
|
42f3a3ee71 | ||
|
|
ad76093a38 | ||
|
|
9e314c960b | ||
|
|
07207dca55 | ||
|
|
59b0ed7688 | ||
|
|
4684b23a8c | ||
|
|
28ad80369f | ||
|
|
9307f5a926 | ||
|
|
1f6e6e7cce | ||
|
|
cde338a48d | ||
|
|
66e7989e97 | ||
|
|
fef1e8dcbe | ||
|
|
b40d008400 | ||
|
|
f4c026fe2e | ||
|
|
1de57d9423 | ||
|
|
042e4a0529 | ||
|
|
ef95630225 | ||
|
|
68441f2b81 | ||
|
|
5de2344dc2 | ||
|
|
5976f8f561 | ||
|
|
5c4b5e805e | ||
|
|
1ecbef0aca | ||
|
|
4b63b7784f | ||
|
|
deec0aaa68 | ||
|
|
bf531404f5 | ||
|
|
fc10b5c512 | ||
|
|
04164acff3 | ||
|
|
7cc7effd2e | ||
|
|
4a05f0d113 | ||
|
|
d15ebb9d09 | ||
|
|
933e7a0991 | ||
|
|
f0cd8ce91f | ||
|
|
fcf332a31c | ||
|
|
7cb7293abf | ||
|
|
2024297f61 | ||
|
|
a63f9e2c7c | ||
|
|
3f154b07a7 | ||
|
|
6916c2fed3 | ||
|
|
e5bd328d21 | ||
|
|
2a290004b7 | ||
|
|
b11bee7d64 | ||
|
|
234e063d2e | ||
|
|
02ff6a2039 | ||
|
|
e1fdb0069b | ||
|
|
37716c8d42 | ||
|
|
50acb9957e | ||
|
|
76e6c70696 | ||
|
|
c812bda08f | ||
|
|
1b607b6357 | ||
|
|
c546fc1605 | ||
|
|
7dfb3b8faf | ||
|
|
11934c3995 | ||
|
|
60a45191b9 | ||
|
|
4bd449e036 | ||
|
|
a8f7d09bd4 | ||
|
|
2a0387f90e | ||
|
|
12a004a9e1 | ||
|
|
20fb0c2254 | ||
|
|
13fb05696a | ||
|
|
31f7cfa09f | ||
|
|
36d753df58 | ||
|
|
1c09714c43 | ||
|
|
bc0ceee894 | ||
|
|
5a1697a5e6 | ||
|
|
b3e67b5af5 | ||
|
|
cb8a1e992c | ||
|
|
f0bcd50503 | ||
|
|
1d680ab2db | ||
|
|
474dc3ae8c | ||
|
|
1cc724c800 | ||
|
|
986954953b | ||
|
|
6031d57ccb | ||
|
|
3468b9d795 | ||
|
|
45acac744a | ||
|
|
7490a1948f | ||
|
|
741e7f5a1f | ||
|
|
a421a6ba12 | ||
|
|
03cf1c2c42 | ||
|
|
66d4cc36b5 | ||
|
|
aba3b5eed7 | ||
|
|
2f1cbe7328 | ||
|
|
72a5daf705 | ||
|
|
52ac793d45 | ||
|
|
db535442d6 | ||
|
|
47a7831764 | ||
|
|
fa4c10c9a4 | ||
|
|
103168544d | ||
|
|
f150c6c037 | ||
|
|
7909bd1054 | ||
|
|
97bb74a114 |
150 changed files with 9121 additions and 2703 deletions
5
.github/FUNDING.yml
vendored
5
.github/FUNDING.yml
vendored
|
|
@ -1,3 +1,6 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
custom: ['https://www.buymeacoffee.com/bastien']
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [bastienwirtz]
|
||||
buy_me_a_coffee: bastien
|
||||
|
|
|
|||
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
|
@ -9,10 +9,11 @@ Fixes # (issue)
|
|||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] Refactoring
|
||||
|
||||
## Checklist:
|
||||
|
||||
- [ ] I've read & comply with the [contributing guidelines](https://github.com/bastienwirtz/homer/blob/main/CONTRIBUTING.md)
|
||||
- [ ] I have tested my code for new features & regressions on both mobile & desktop devices, using the latest version of major browsers.
|
||||
- [ ] I have made corresponding changes to the documentation (README.md).
|
||||
- [ ] I have tested my code for new features & regressions on both mobile & desktop devices, using the latest version of major browsers.
|
||||
- [ ] I have made corresponding changes to the documentation (`README.md`).
|
||||
- [ ] I've checked my modifications for any breaking changes, especially in the `config.yml` file
|
||||
|
|
|
|||
2
.github/workflows/dockerhub.yml
vendored
2
.github/workflows/dockerhub.yml
vendored
|
|
@ -44,3 +44,5 @@ jobs:
|
|||
ghcr.io/${{ github.repository }}:latest
|
||||
ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm/v6,linux/arm64
|
||||
build-args: |
|
||||
VERSION_TAG=${{ github.ref_name }}
|
||||
|
|
|
|||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -23,4 +23,8 @@ yarn-error.log*
|
|||
# App configuration
|
||||
config.yml
|
||||
|
||||
.drone.yml
|
||||
.drone.yml
|
||||
|
||||
# Specific Agent file
|
||||
CLAUDE.md
|
||||
GEMINI.md
|
||||
|
|
|
|||
8
.jsconfig.json
Normal file
8
.jsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
359
.schema/config-schema.json
Normal file
359
.schema/config-schema.json
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
{
|
||||
"$id": "https://raw.githubusercontent.com/bastienwirtz/homer/main/.schema/config-schema.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"description": "https://github.com/bastienwirtz/homer/blob/main/docs/configuration.md",
|
||||
"examples": [],
|
||||
"title": "Homer Dashboard configuration",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
"Colors": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"light": {
|
||||
"$ref": "#/definitions/ColorSet"
|
||||
},
|
||||
"dark": {
|
||||
"$ref": "#/definitions/ColorSet"
|
||||
}
|
||||
},
|
||||
"title": "Colors"
|
||||
},
|
||||
"ColorSet": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"highlight-primary": {
|
||||
"type": "string"
|
||||
},
|
||||
"highlight-secondary": {
|
||||
"type": "string"
|
||||
},
|
||||
"highlight-hover": {
|
||||
"type": "string"
|
||||
},
|
||||
"background": {
|
||||
"type": "string"
|
||||
},
|
||||
"card-background": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"text-header": {
|
||||
"type": "string"
|
||||
},
|
||||
"text-title": {
|
||||
"type": "string"
|
||||
},
|
||||
"text-subtitle": {
|
||||
"type": "string"
|
||||
},
|
||||
"card-shadow": {
|
||||
"type": "string"
|
||||
},
|
||||
"link": {
|
||||
"type": "string"
|
||||
},
|
||||
"link-hover": {
|
||||
"type": "string"
|
||||
},
|
||||
"background-image": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Defaults": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"layout": {
|
||||
"enum": [
|
||||
"columns",
|
||||
"list"
|
||||
],
|
||||
"description": "Layout of the dashboard, either 'columns' or 'list'"
|
||||
},
|
||||
"colorTheme": {
|
||||
"enum": [
|
||||
"auto",
|
||||
"light",
|
||||
"dark"
|
||||
],
|
||||
"description": "One of 'auto', 'light', or 'dark'"
|
||||
}
|
||||
},
|
||||
"title": "Defaults"
|
||||
},
|
||||
"Hotkey": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"search": {
|
||||
"type": "string",
|
||||
"description": "hotkey for search, e.g. Shift"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"search"
|
||||
]
|
||||
},
|
||||
"Link": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name as seen in the navbar"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"description": "Fontawesome icon"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "Url of the link. When #filename is used, it is a link to another homer page, while 'filename' is the name of the config file"
|
||||
},
|
||||
"target": {
|
||||
"type": "string",
|
||||
"description": "html tag target attribute like _blank for a new page"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"title": "Link"
|
||||
},
|
||||
"Message": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"mapping": {
|
||||
"$ref": "#/definitions/Mapping",
|
||||
"description": "Mapping for the content loaded from the URL"
|
||||
},
|
||||
"refreshInterval": {
|
||||
"type": "integer",
|
||||
"description": "The refresh interval in milliseconds for reloading the message url"
|
||||
},
|
||||
"style": {
|
||||
"type": "string",
|
||||
"description": "See https://bulma.io/documentation/components/message/#colors for styling options"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Title of the message box"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"description": "Fontawesome icon for the message box"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "HTML content for the message box"
|
||||
}
|
||||
},
|
||||
"title": "Messagebox"
|
||||
},
|
||||
"Mapping": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"title": "Mapping"
|
||||
},
|
||||
"Proxy": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"useCredentials": {
|
||||
"type": "boolean",
|
||||
"description": "# send cookies & authorization headers when fetching service specific data. Set to `true` if you use an authentication proxy. Can be overrided on service level. "
|
||||
},
|
||||
"headers": {
|
||||
"$ref": "#/definitions/Headers",
|
||||
"description": "send custom headers when fetching service specific data. Can also be set on a service level."
|
||||
}
|
||||
},
|
||||
"title": "Proxy"
|
||||
},
|
||||
"Headers": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"title": "Headers"
|
||||
},
|
||||
"Service": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Service name"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"description": "Fontawesome icon for the service"
|
||||
},
|
||||
"logo": {
|
||||
"type": "string",
|
||||
"description": "A path to an image can also be provided. Note that icon take precedence if both icon and logo are set."
|
||||
},
|
||||
"class": {
|
||||
"type": "string",
|
||||
"description": "Optional css class to add on the service group. Example 'highlight-purple'"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Item"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"items"
|
||||
],
|
||||
"title": "Service"
|
||||
},
|
||||
"Item": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"logo": {
|
||||
"type": "string",
|
||||
"description": "Path to a logo. Alternatively a fa icon can be provided"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"description": "Fontawesome icon for the item, alternative for logo"
|
||||
},
|
||||
"subtitle": {
|
||||
"type": "string"
|
||||
},
|
||||
"tag": {
|
||||
"type": "string",
|
||||
"description": "Show tag"
|
||||
},
|
||||
"keywords": {
|
||||
"type": "string",
|
||||
"description": "Optional keyword used for searching purpose"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "Url of this item"
|
||||
},
|
||||
"target": {
|
||||
"type": "string",
|
||||
"description": "html tag target attribute like _blank for a new page"
|
||||
},
|
||||
"tagstyle": {
|
||||
"type": "string",
|
||||
"description": "Styleclass for the tag"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Optional, loads a specific component that provides extra features. MUST MATCH a file name (without file extension) available in `src/components/services`"
|
||||
}
|
||||
},
|
||||
"title": "Item"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"externalConfig": {
|
||||
"type": "string",
|
||||
"description": "Use external configuration file. Using this will ignore remaining config in this file externalConfig: https://example.com/server-luci/config.yaml"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Title of the dashboard"
|
||||
},
|
||||
"subtitle": {
|
||||
"type": "string",
|
||||
"description": "Subtitle of the dashboard"
|
||||
},
|
||||
"documentTitle": {
|
||||
"type": "string",
|
||||
"description": "Title of the document. When not filled, title (and subtitle will be used)"
|
||||
},
|
||||
"logo": {
|
||||
"type": "string",
|
||||
"description": "Path to logo image"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"description": "Dashboard icon"
|
||||
},
|
||||
"header": {
|
||||
"type": "boolean",
|
||||
"description": "Show header, default is true"
|
||||
},
|
||||
"hotkey": {
|
||||
"$ref": "#/definitions/Hotkey",
|
||||
"description": "Define hotkeys, for example for search"
|
||||
},
|
||||
"footer": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"description": "footer Line content. HTML is supported. Set false if you want to hide it."
|
||||
},
|
||||
"columns": {
|
||||
"type": "string",
|
||||
"description": "'auto' or number (must be a factor of 12: 1, 2, 3, 4, 6, 12)",
|
||||
"format": "integer"
|
||||
},
|
||||
"connectivityCheck": {
|
||||
"type": "boolean",
|
||||
"description": "# whether you want to display a message when the apps are not accessible anymore (VPN disconnected for example). You should set it to true when using an authentication proxy, it also reloads the page when a redirection is detected when checking connectivity."
|
||||
},
|
||||
"proxy": {
|
||||
"$ref": "#/definitions/Proxy",
|
||||
"description": "Optional: Proxy / hosting option"
|
||||
},
|
||||
"defaults": {
|
||||
"$ref": "#/definitions/Defaults"
|
||||
},
|
||||
"theme": {
|
||||
"type": "string",
|
||||
"description": "'default' or one of the themes available in 'src/assets/themes'"
|
||||
},
|
||||
"stylesheet": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Will load custom CSS files. Especially useful for custom icon sets. Entries are paths to the stylesheets"
|
||||
},
|
||||
"colors": {
|
||||
"$ref": "#/definitions/Colors"
|
||||
},
|
||||
"message": {
|
||||
"$ref": "#/definitions/Message",
|
||||
"description": "Messagebox"
|
||||
},
|
||||
"links": {
|
||||
"description": "Links in the navigation bar",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Link"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"description": "Services",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Service"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
84
AGENTS.md
Normal file
84
AGENTS.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# AGENTS Instructions
|
||||
|
||||
This file provides guidance to AI Agents when working with code in this repository.
|
||||
|
||||
## Development Commands
|
||||
|
||||
```bash
|
||||
pnpm install # Install dependencies (PNPM enforced via packageManager)
|
||||
pnpm dev # Start development server on http://localhost:3000
|
||||
pnpm mock # Start mock API server for testing service integrations
|
||||
pnpm build # Build for production
|
||||
pnpm preview # Preview production build
|
||||
pnpm lint # Run ESLint with auto-fix
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
Homer is a static Vue.js 3 PWA dashboard that loads configuration from YAML files. The architecture is service-oriented with dynamic component loading.
|
||||
|
||||
### Core Application Structure
|
||||
|
||||
- **Entry Point**: `src/main.js` mounts the Vue app
|
||||
- **Root Component**: `src/App.vue` handles layout, configuration loading, and routing
|
||||
- **Configuration System**: YAML-based with runtime merging of defaults (`src/assets/defaults.yml`) and user config (`/assets/config.yml`)
|
||||
- **Service Components**: 53 specialized integrations in `src/components/services/` that extend a Generic component pattern
|
||||
|
||||
### Service Integration Pattern
|
||||
|
||||
All service components follow this architecture:
|
||||
|
||||
- Extend `Generic.vue` using Vue slots (`<template #indicator>`, `<template #content>`, `<template #icon>`)
|
||||
- Use the `service.js` mixin (`src/mixins/service.js`) for common API functionality
|
||||
- Use a custom `fetch` method provided by the service mixin to seamlessly support proxy configuration, custom headers, and credentials.
|
||||
|
||||
### Configuration & Routing
|
||||
|
||||
- **Multi-page Support**: Hash-based routing without Vue Router
|
||||
- **Dynamic Config Loading**: External URLs supported via `config.remote_config`
|
||||
- **Theme System**: CSS layers architecture with three built-in themes in `src/assets/themes/`
|
||||
- **Asset Management**: Static files served from `/assets/` with runtime configuration merging
|
||||
|
||||
### Build System Details
|
||||
|
||||
- **Vite 7**: Modern build tool with Vue plugin
|
||||
- **PWA**: Auto-updating service worker via `vite-plugin-pwa`
|
||||
- **SCSS**: Bulma framework with modular component styling
|
||||
- **Docker**: Multi-stage build (Node.js → Alpine + Lighttpd)
|
||||
|
||||
### Mock Data Creation Pattern
|
||||
|
||||
When creating mock data for service components testing:
|
||||
|
||||
**Structure**: `dummy-data/[component-name]/[api-path]/[endpoint]`
|
||||
|
||||
**Steps**:
|
||||
|
||||
1. **Analyze component**: Read the Vue component file to identify API calls (look for `this.fetch()` calls)
|
||||
2. **Check existing mock**: If mock directory exists, read existing files to check for missing fields
|
||||
3. **Create/update structure**: `mkdir -p dummy-data/[lowercase-component-name]/` and mirror API endpoint paths
|
||||
4. **Create/update JSON files**: Write realistic mock responses matching the expected data structure
|
||||
5. **Verify fields**: Ensure all fields used in the component's computed properties and templates are included
|
||||
6. **Update existing mocks**: If mock files exist but are missing fields, add the missing fields without removing existing data
|
||||
|
||||
**Key Points**:
|
||||
|
||||
- Component directory name should be lowercase version of component name (e.g., `AdGuardHome.vue` → `adguardhome/`)
|
||||
- Directory structure mirrors API endpoints exactly
|
||||
- Files contain JSON responses (no file extension needed)
|
||||
- Mock server serves from `dummy-data/` via `pnpm mock` command
|
||||
- Each component gets isolated directory to prevent API path conflicts
|
||||
- When updating existing mocks, preserve existing data and only add missing fields required by the component
|
||||
- Always read existing mock files first to understand current structure before making changes
|
||||
|
||||
**Example**: For `AdGuardHome.vue`:
|
||||
- API calls: `/control/status`, `/control/stats`
|
||||
- Mock files: `dummy-data/adguardhome/control/status`, `dummy-data/adguardhome/control/stats`
|
||||
|
||||
### Development Notes
|
||||
|
||||
- Use `pnpm mock` to test service integrations with dummy data
|
||||
- Configuration changes require restart in development mode
|
||||
- New service components should follow the Generic component slot pattern
|
||||
- Themes use CSS custom properties for dynamic color switching
|
||||
- The app has no backend dependencies and generates static files only
|
||||
|
|
@ -6,10 +6,10 @@ First off, thank you for considering contributing to Homer!
|
|||
|
||||
### Project philosophy
|
||||
|
||||
Homer is meant to be a light and very simple dashboard that keeps all your useful utilities at hands. The few features implemented in Homer focus on
|
||||
UX and usability. If you are looking for a full featured dashboard, there is tons of great stuff out there like https://heimdall.site/, https://github.com/rmountjoy92/DashMachine or https://organizr.app/.
|
||||
Homer is meant to be a light and very simple dashboard that keeps all your useful utilities at hand. The few features implemented in Homer focus on
|
||||
UX and usability. If you are looking for a full featured dashboard, there are tons of great stuff out there like https://gethomepage.dev/, https://heimdall.site/, https://github.com/rmountjoy92/DashMachine or https://organizr.app/.
|
||||
|
||||
- Configuration is stored in a simple config file, avoiding the need for a backend/database while making possible to use versioning or [config template](https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html).
|
||||
- Configuration is stored in a simple config file, avoiding the need for a backend/database while making it possible to use versioning or [config template](https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html).
|
||||
- Only modern browsers are supported, feel free to use any JS features without any polyfill as soon as the latest version of the major browsers supports them.
|
||||
|
||||
|
||||
|
|
@ -33,10 +33,19 @@ For all contributions, please respect the following guidelines:
|
|||
If you want to add a feature, it's often best to talk about it before starting to work on it and submitting a pull request. It's not mandatory at all, but
|
||||
feel free to open an issue to present your idea.
|
||||
|
||||
### Working with AI Agents
|
||||
|
||||
This repository include an [`AGENTS.md`](https://github.com/bastienwirtz/homer/blob/main/AGENTS.md) instruction file for agents. It use an [open format](https://agents.md/), which most agent should natively use for context. However, for specific agent like Claude Code or Gemini, you will have to specifically ask it to read the file or create symlink:
|
||||
|
||||
```sh
|
||||
ln -s AGENTS.md CLAUDE.md
|
||||
ln -s AGENTS.md GEMINI.md
|
||||
```
|
||||
|
||||
### How to submit a contribution
|
||||
|
||||
The general process to submit a contribution is as follow:
|
||||
1. Take a look to the [development guideline](https://github.com/bastienwirtz/homer/blob/main/docs/development.md).
|
||||
1. Take a look at the [development guideline](https://github.com/bastienwirtz/homer/blob/main/docs/development.md).
|
||||
2. Create your own fork of the code
|
||||
3. Do the changes in your fork
|
||||
4. Make sure to fill the [pull request description](https://github.com/bastienwirtz/homer/blob/main/.github/PULL_REQUEST_TEMPLATE.md) properly.
|
||||
|
|
|
|||
23
Dockerfile
23
Dockerfile
|
|
@ -1,10 +1,10 @@
|
|||
# build stage
|
||||
FROM --platform=$BUILDPLATFORM node:22-alpine3.20 AS build-stage
|
||||
FROM --platform=$BUILDPLATFORM node:22-alpine3.21 AS build-stage
|
||||
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
|
||||
RUN corepack enable && corepack use pnpm@9
|
||||
RUN corepack enable && corepack use pnpm@10
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
@ -15,7 +15,20 @@ COPY . .
|
|||
RUN pnpm build
|
||||
|
||||
# production stage
|
||||
FROM alpine:3.20
|
||||
FROM alpine:3.21
|
||||
|
||||
ARG VERSION_TAG=latest
|
||||
|
||||
LABEL \
|
||||
org.label-schema.schema-version="1.0" \
|
||||
org.label-schema.version="$VERSION_TAG" \
|
||||
org.opencontainers.image.title="Homer Image" \
|
||||
org.opencontainers.image.description="A dead simple static Home-Page for your server to keep your services on hand, from a simple yaml configuration file." \
|
||||
org.opencontainers.image.ref.name="b4bz/homer:${VERSION_TAG}" \
|
||||
org.opencontainers.image.version="$VERSION_TAG" \
|
||||
org.opencontainers.image.licenses="Apache-2.0 license" \
|
||||
org.opencontainers.image.source="https://github.com/bastienwirtz/homer" \
|
||||
org.opencontainers.image.url="https://hub.docker.com/r/b4bz/homer"
|
||||
|
||||
ENV GID=1000 \
|
||||
UID=1000 \
|
||||
|
|
@ -37,8 +50,8 @@ COPY --from=build-stage --chown=${UID}:${GID} /app/dist/assets /www/default-asse
|
|||
|
||||
USER ${UID}:${GID}
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:${PORT}/ || exit 1
|
||||
HEALTHCHECK --start-period=10s --start-interval=1s --interval=30s --timeout=5s --retries=3 \
|
||||
CMD wget --no-verbose -Y off --tries=1 --spider http://127.0.0.1:${PORT}/ || exit 1
|
||||
|
||||
EXPOSE ${PORT}
|
||||
|
||||
|
|
|
|||
13
README.md
13
README.md
|
|
@ -34,7 +34,7 @@
|
|||
•
|
||||
<a href="https://hub.docker.com/r/b4bz/homer">Docker Hub</a>
|
||||
•
|
||||
<a href="#getting-started">Get started</a>
|
||||
<a href="#get-started">Get started</a>
|
||||
</strong>
|
||||
</p>
|
||||
|
||||
|
|
@ -121,17 +121,6 @@ If you would like to change internal port of Homer from default `8080` to your p
|
|||
- **`IPV6_DISABLE`** (default: 0)
|
||||
Set to `1` to disable listening on IPv6.
|
||||
|
||||
#### With docker-compose
|
||||
|
||||
A [`docker-compose.yml`](docker-compose.yml) file is available as an example. It must be edited to match your needs. You probably want to adjust the port mapping and volume binding (equivalent to `-p` and `-v` arguments).
|
||||
|
||||
Then launch the container:
|
||||
|
||||
```sh
|
||||
cd /path/to/docker-compose.yml/
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Using the release tarball (prebuilt, ready to use)
|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Configuration
|
||||
|
||||
Homer rely on a single [yaml](http://yaml.org/) configuration file, located in the `/assets` directory.
|
||||
Homer relies on a single [yaml](http://yaml.org/) configuration file, located in the `/assets` directory.
|
||||
`.dist` sample configuration files are available to help you get started. Alternatively, the example below can be
|
||||
copied into the config file.
|
||||
|
||||
|
|
@ -183,9 +183,9 @@ Empty values (either in `config.yml` or the endpoint data) will hide the element
|
|||
## Connectivity checks
|
||||
|
||||
As a webapp (PWA) the dashboard can still be displayed when your homer server is offline.
|
||||
The connectivity checker periodically send a HEAD request bypassing the PWA cache to the dashbord page to make sure it's still reachable.
|
||||
The connectivity checker periodically sends a HEAD request bypassing the PWA cache to the dashbord page to make sure it's still reachable.
|
||||
|
||||
It can be useful when you access your dashboard through a VPN or ssh tunnel for example, to know is your conection is up. It also helps when using an authentication proxy, it will reloads the page if the authentication expires (when a redirection is send in response to the HEAD request).
|
||||
It can be useful when you access your dashboard through a VPN or ssh tunnel for example, to know if your conection is up. It also helps when using an authentication proxy, it will reload the page if the authentication expires (when a redirect is send in response to the HEAD request).
|
||||
|
||||
## Style Options
|
||||
|
||||
|
|
@ -206,9 +206,10 @@ The `/assets/manifest.json` can also be edited to change the app (pwa) name, des
|
|||
|
||||
### Community theme
|
||||
|
||||
- [Dracula theme](https://draculatheme.com/homer) by [@Tuetenk0pp](https://github.com/Tuetenk0pp)
|
||||
- [Homer Theme v2](https://github.com/walkxcode/homer-theme) by [walkxcode](https://github.com/walkxcode)
|
||||
- [Catppuccin theme](https://github.com/mrpbennett/catppucin-homer) by [@mrpbenett](https://github.com/mrpbennett)
|
||||
- [DietPi theme](https://codeberg.org/Cs137/homer-theme-dietpi) by [@Cs137](https://codeberg.org/Cs137)
|
||||
- [Dracula theme](https://draculatheme.com/homer) by [@Tuetenk0pp](https://github.com/Tuetenk0pp)
|
||||
- [Homer Theme v2](https://github.com/walkxcode/homer-theme) by [@walkxcode](https://github.com/walkxcode)
|
||||
|
||||
## PWA Icons
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -6,7 +6,8 @@ Here is a collection of neat tips and tricks that Homer users have come up with!
|
|||
|
||||
Great source to find service icons
|
||||
|
||||
- <https://github.com/walkxcode/dashboard-icons>
|
||||
- <https://selfh.st/icons/>
|
||||
- <https://github.com/homarr-labs/dashboard-icons>
|
||||
|
||||
## Use Homer as a custom "new tab" page
|
||||
|
||||
|
|
@ -77,6 +78,21 @@ Then when Homer reads your config, it will substitute your anchors automatically
|
|||
The end result is that if you want to update the name or style of any particular tag, just update it once, in the tags section!
|
||||
Great if you have a lot of services or a lot of tags!
|
||||
|
||||
## YAML auto complete with a YAML schema
|
||||
|
||||
A lot of editor support auto completion, see <https://www.schemastore.org/json/>
|
||||
The homer schema is available here: <https://raw.githubusercontent.com/bastienwirtz/homer/main/.schema/config-schema.json>
|
||||
|
||||
For example with IntelliJ you can define:
|
||||
|
||||
```yaml
|
||||
# $schema: https://raw.githubusercontent.com/bastienwirtz/homer/main/.schema/config-schema.json
|
||||
```
|
||||
With VSCode you can define it like this:
|
||||
```yaml
|
||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/bastienwirtz/homer/main/.schema/config-schema.json
|
||||
```
|
||||
|
||||
## Remotely edit your config with Code Server
|
||||
|
||||
#### `by @JamiePhonic`
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ 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.
|
||||
- **Use a proxy** to add the necessary CORS headers (lot of options, some of them described [here](https://enable-cors.org/server.html). Also check [`CORSair`](https://github.com/bastienwirtz/corsair), a light and simple solution)
|
||||
|
||||
## I am using an authentication proxy and homer says I am offline
|
||||
|
||||
|
|
|
|||
51
dummy-data/adguardhome/control/stats
Normal file
51
dummy-data/adguardhome/control/stats
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"time_units": "hours",
|
||||
"num_dns_queries": 28947,
|
||||
"num_blocked_filtering": 12489,
|
||||
"num_replaced_safebrowsing": 0,
|
||||
"num_replaced_safesearch": 0,
|
||||
"num_replaced_parental": 0,
|
||||
"avg_processing_time": 0.34,
|
||||
"top_queried_domains": [
|
||||
{
|
||||
"name": "example.com",
|
||||
"count": 1289
|
||||
},
|
||||
{
|
||||
"name": "api.github.com",
|
||||
"count": 892
|
||||
}
|
||||
],
|
||||
"top_clients": [
|
||||
{
|
||||
"name": "192.168.1.100",
|
||||
"count": 8945
|
||||
},
|
||||
{
|
||||
"name": "192.168.1.101",
|
||||
"count": 6234
|
||||
}
|
||||
],
|
||||
"top_blocked_domains": [
|
||||
{
|
||||
"name": "ads.google.com",
|
||||
"count": 1245
|
||||
},
|
||||
{
|
||||
"name": "tracker.example.com",
|
||||
"count": 987
|
||||
}
|
||||
],
|
||||
"dns_queries": [
|
||||
12450, 13200, 14100, 13800, 12900, 11200, 10800, 9600, 8200, 7800,
|
||||
9200, 10500, 12100, 13600, 14800, 15200, 14900, 13700, 12800, 11900,
|
||||
11200, 10800, 10200, 9800
|
||||
],
|
||||
"blocked_filtering": [
|
||||
5200, 5800, 6100, 5900, 5400, 4800, 4600, 4200, 3600, 3400,
|
||||
4000, 4500, 5200, 5800, 6300, 6500, 6300, 5800, 5400, 5100,
|
||||
4800, 4600, 4300, 4200
|
||||
],
|
||||
"replaced_safebrowsing": [],
|
||||
"replaced_parental": []
|
||||
}
|
||||
16
dummy-data/adguardhome/control/status
Normal file
16
dummy-data/adguardhome/control/status
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"protection_enabled": true,
|
||||
"version": "v0.107.48",
|
||||
"language": "en",
|
||||
"dns_address": "127.0.0.1:53",
|
||||
"dns_port": 53,
|
||||
"protection_disabled_duration": null,
|
||||
"http_port": 80,
|
||||
"https_port": 443,
|
||||
"querylog_enabled": true,
|
||||
"querylog_size": 5000,
|
||||
"querylog_size_memory": 1000,
|
||||
"querylog_interval": 2160,
|
||||
"dhcp_available": true,
|
||||
"running": true
|
||||
}
|
||||
215
dummy-data/dockersocketproxy/containers/json
Normal file
215
dummy-data/dockersocketproxy/containers/json
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
[
|
||||
{
|
||||
"Id": "8dfafdbc3a40",
|
||||
"Names": ["/boring_feynman"],
|
||||
"Image": "nginx:latest",
|
||||
"ImageID": "sha256:f6d0b4767a6c",
|
||||
"Command": "/docker-entrypoint.sh nginx -g 'daemon off;'",
|
||||
"Created": 1640995200,
|
||||
"Ports": [
|
||||
{
|
||||
"IP": "0.0.0.0",
|
||||
"PrivatePort": 80,
|
||||
"PublicPort": 8080,
|
||||
"Type": "tcp"
|
||||
}
|
||||
],
|
||||
"Labels": {
|
||||
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
|
||||
},
|
||||
"State": "running",
|
||||
"Status": "Up 2 hours",
|
||||
"HostConfig": {
|
||||
"NetworkMode": "default"
|
||||
},
|
||||
"NetworkSettings": {
|
||||
"Networks": {
|
||||
"bridge": {
|
||||
"IPAMConfig": null,
|
||||
"Links": null,
|
||||
"Aliases": null,
|
||||
"NetworkID": "f2de39df4171",
|
||||
"EndpointID": "2cdc4edb1ded",
|
||||
"Gateway": "172.17.0.1",
|
||||
"IPAddress": "172.17.0.2",
|
||||
"IPPrefixLen": 16,
|
||||
"IPv6Gateway": "",
|
||||
"GlobalIPv6Address": "",
|
||||
"GlobalIPv6PrefixLen": 0,
|
||||
"MacAddress": "02:42:ac:11:00:02"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Mounts": []
|
||||
},
|
||||
{
|
||||
"Id": "9e87a2b84b8e",
|
||||
"Names": ["/web-app"],
|
||||
"Image": "node:16-alpine",
|
||||
"ImageID": "sha256:c85b8f829d1f",
|
||||
"Command": "npm start",
|
||||
"Created": 1640991600,
|
||||
"Ports": [
|
||||
{
|
||||
"IP": "0.0.0.0",
|
||||
"PrivatePort": 3000,
|
||||
"PublicPort": 3000,
|
||||
"Type": "tcp"
|
||||
}
|
||||
],
|
||||
"Labels": {},
|
||||
"State": "running",
|
||||
"Status": "Up 3 hours",
|
||||
"HostConfig": {
|
||||
"NetworkMode": "default"
|
||||
},
|
||||
"NetworkSettings": {
|
||||
"Networks": {
|
||||
"bridge": {
|
||||
"IPAMConfig": null,
|
||||
"Links": null,
|
||||
"Aliases": null,
|
||||
"NetworkID": "f2de39df4171",
|
||||
"EndpointID": "3edc5fdb2efe",
|
||||
"Gateway": "172.17.0.1",
|
||||
"IPAddress": "172.17.0.3",
|
||||
"IPPrefixLen": 16,
|
||||
"IPv6Gateway": "",
|
||||
"GlobalIPv6Address": "",
|
||||
"GlobalIPv6PrefixLen": 0,
|
||||
"MacAddress": "02:42:ac:11:00:03"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Mounts": [
|
||||
{
|
||||
"Type": "bind",
|
||||
"Source": "/home/user/app",
|
||||
"Destination": "/app",
|
||||
"Mode": "",
|
||||
"RW": true,
|
||||
"Propagation": "rprivate"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "7b9a3c6d2e1f",
|
||||
"Names": ["/database"],
|
||||
"Image": "postgres:13",
|
||||
"ImageID": "sha256:b4ed8d5b4f3a",
|
||||
"Command": "docker-entrypoint.sh postgres",
|
||||
"Created": 1640988000,
|
||||
"Ports": [
|
||||
{
|
||||
"IP": "127.0.0.1",
|
||||
"PrivatePort": 5432,
|
||||
"PublicPort": 5432,
|
||||
"Type": "tcp"
|
||||
}
|
||||
],
|
||||
"Labels": {},
|
||||
"State": "dead",
|
||||
"Status": "Up 4 hours",
|
||||
"HostConfig": {
|
||||
"NetworkMode": "default"
|
||||
},
|
||||
"NetworkSettings": {
|
||||
"Networks": {
|
||||
"bridge": {
|
||||
"IPAMConfig": null,
|
||||
"Links": null,
|
||||
"Aliases": null,
|
||||
"NetworkID": "f2de39df4171",
|
||||
"EndpointID": "4fdc6gdb3gfg",
|
||||
"Gateway": "172.17.0.1",
|
||||
"IPAddress": "172.17.0.4",
|
||||
"IPPrefixLen": 16,
|
||||
"IPv6Gateway": "",
|
||||
"GlobalIPv6Address": "",
|
||||
"GlobalIPv6PrefixLen": 0,
|
||||
"MacAddress": "02:42:ac:11:00:04"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Mounts": [
|
||||
{
|
||||
"Type": "volume",
|
||||
"Name": "postgres_data",
|
||||
"Source": "/var/lib/docker/volumes/postgres_data/_data",
|
||||
"Destination": "/var/lib/postgresql/data",
|
||||
"Driver": "local",
|
||||
"Mode": "rw",
|
||||
"RW": true,
|
||||
"Propagation": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "5c8d1f4e9a2b",
|
||||
"Names": ["/old-service"],
|
||||
"Image": "ubuntu:20.04",
|
||||
"ImageID": "sha256:f643c72bc252",
|
||||
"Command": "/bin/bash",
|
||||
"Created": 1640984400,
|
||||
"Ports": [],
|
||||
"Labels": {},
|
||||
"State": "exited",
|
||||
"Status": "Exited (0) 2 hours ago",
|
||||
"HostConfig": {
|
||||
"NetworkMode": "default"
|
||||
},
|
||||
"NetworkSettings": {
|
||||
"Networks": {
|
||||
"bridge": {
|
||||
"IPAMConfig": null,
|
||||
"Links": null,
|
||||
"Aliases": null,
|
||||
"NetworkID": "",
|
||||
"EndpointID": "",
|
||||
"Gateway": "",
|
||||
"IPAddress": "",
|
||||
"IPPrefixLen": 0,
|
||||
"IPv6Gateway": "",
|
||||
"GlobalIPv6Address": "",
|
||||
"GlobalIPv6PrefixLen": 0,
|
||||
"MacAddress": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"Mounts": []
|
||||
},
|
||||
{
|
||||
"Id": "1a2b3c4d5e6f",
|
||||
"Names": ["/backup-job"],
|
||||
"Image": "alpine:latest",
|
||||
"ImageID": "sha256:c059bfaa849c",
|
||||
"Command": "sh -c 'sleep 3600'",
|
||||
"Created": 1640980800,
|
||||
"Ports": [],
|
||||
"Labels": {},
|
||||
"State": "exited",
|
||||
"Status": "Exited (0) 30 minutes ago",
|
||||
"HostConfig": {
|
||||
"NetworkMode": "default"
|
||||
},
|
||||
"NetworkSettings": {
|
||||
"Networks": {
|
||||
"bridge": {
|
||||
"IPAMConfig": null,
|
||||
"Links": null,
|
||||
"Aliases": null,
|
||||
"NetworkID": "",
|
||||
"EndpointID": "",
|
||||
"Gateway": "",
|
||||
"IPAddress": "",
|
||||
"IPPrefixLen": 0,
|
||||
"IPv6Gateway": "",
|
||||
"GlobalIPv6Address": "",
|
||||
"GlobalIPv6PrefixLen": 0,
|
||||
"MacAddress": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"Mounts": []
|
||||
}
|
||||
]
|
||||
1
dummy-data/docuseal/version
Normal file
1
dummy-data/docuseal/version
Normal file
|
|
@ -0,0 +1 @@
|
|||
1.8.3a
|
||||
24
dummy-data/emby/System/info/public
Normal file
24
dummy-data/emby/System/info/public
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"LocalAddress": "192.168.1.100:8096",
|
||||
"ServerName": "Homer-Emby-Server",
|
||||
"Version": "4.8.8.0",
|
||||
"ProductName": "Emby Server",
|
||||
"OperatingSystem": "Linux",
|
||||
"Id": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
|
||||
"StartupWizardCompleted": true,
|
||||
"SupportsLibraryMonitor": true,
|
||||
"WebSocketPortNumber": 8096,
|
||||
"CompletedInstallations": [],
|
||||
"CanSelfRestart": true,
|
||||
"CanSelfUpdate": true,
|
||||
"CanLaunchWebBrowser": false,
|
||||
"WanAddress": "192.168.1.100:8096",
|
||||
"HasUpdateAvailable": false,
|
||||
"SupportsAutoRunAtStartup": false,
|
||||
"TranscodingTempPath": "/var/lib/emby/transcoding-temp",
|
||||
"CachePath": "/var/lib/emby/cache",
|
||||
"LogPath": "/var/log/emby",
|
||||
"InternalMetadataPath": "/var/lib/emby/metadata",
|
||||
"ItemsByNamePath": "/var/lib/emby/metadata/People",
|
||||
"ProgramDataPath": "/var/lib/emby"
|
||||
}
|
||||
12
dummy-data/emby/items/counts
Normal file
12
dummy-data/emby/items/counts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"MovieCount": 1247,
|
||||
"SeriesCount": 89,
|
||||
"EpisodeCount": 2156,
|
||||
"ArtistCount": 234,
|
||||
"AlbumCount": 567,
|
||||
"SongCount": 8923,
|
||||
"MusicVideoCount": 42,
|
||||
"BoxSetCount": 23,
|
||||
"BookCount": 156,
|
||||
"ItemCount": 13437
|
||||
}
|
||||
211
dummy-data/gatus/api/v1/endpoints/statuses
Normal file
211
dummy-data/gatus/api/v1/endpoints/statuses
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
[
|
||||
{
|
||||
"name": "Gateway",
|
||||
"group": "Services",
|
||||
"key": "services_gateway",
|
||||
"results": [
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "gateway.example.com",
|
||||
"duration": 10000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"condition": "[RESPONSE_TIME] < 500",
|
||||
"success": true
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"timestamp": "2025-05-26T07:35:41.784208588Z"
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "gateway.example.com",
|
||||
"duration": 10000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"condition": "[RESPONSE_TIME] < 500",
|
||||
"success": true
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"timestamp": "2025-05-26T07:40:41.804489793Z"
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "gateway.example.com",
|
||||
"duration": 10000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"condition": "[RESPONSE_TIME] < 500",
|
||||
"success": true
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"timestamp": "2025-05-26T07:45:41.837925713Z"
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "gateway.example.com",
|
||||
"duration": 10000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"condition": "[RESPONSE_TIME] < 500",
|
||||
"success": true
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"timestamp": "2025-05-26T07:50:41.848391366Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Website",
|
||||
"group": "External",
|
||||
"key": "external_website",
|
||||
"results": [
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "www.example.com",
|
||||
"duration": 10000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"condition": "[RESPONSE_TIME] < 500",
|
||||
"success": false
|
||||
}
|
||||
],
|
||||
"success": false,
|
||||
"timestamp": "2025-05-26T07:35:41.784208588Z"
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "gateway.example.com",
|
||||
"duration": 10000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": false
|
||||
},
|
||||
{
|
||||
"condition": "[RESPONSE_TIME] < 500",
|
||||
"success": true
|
||||
}
|
||||
],
|
||||
"success": false,
|
||||
"timestamp": "2025-05-26T07:40:41.804489793Z"
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "gateway.example.com",
|
||||
"duration": 10000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"condition": "[RESPONSE_TIME] < 500",
|
||||
"success": true
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"timestamp": "2025-05-26T07:45:41.837925713Z"
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "gateway.example.com",
|
||||
"duration": 10000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"condition": "[RESPONSE_TIME] < 500",
|
||||
"success": true
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"timestamp": "2025-05-26T07:50:41.848391366Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DNS",
|
||||
"group": "Services",
|
||||
"key": "services_dns",
|
||||
"results": [
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "ns1.example",
|
||||
"duration": 20000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": false
|
||||
}
|
||||
],
|
||||
"success": false,
|
||||
"timestamp": "2025-05-26T07:35:41.784208588Z"
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "ns1.example.com",
|
||||
"duration": 20000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": false
|
||||
}
|
||||
],
|
||||
"success": false,
|
||||
"timestamp": "2025-05-26T07:40:41.804489793Z"
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "ns1.example.com",
|
||||
"duration": 20000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": false
|
||||
}
|
||||
],
|
||||
"success": false,
|
||||
"timestamp": "2025-05-26T07:45:41.837925713Z"
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"hostname": "ns1.example.com",
|
||||
"duration": 20000000,
|
||||
"conditionResults": [
|
||||
{
|
||||
"condition": "[STATUS] == 200",
|
||||
"success": false
|
||||
}
|
||||
],
|
||||
"success": false,
|
||||
"timestamp": "2025-05-26T07:50:41.848391366Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
11
dummy-data/gitea/swagger.v1.json
Normal file
11
dummy-data/gitea/swagger.v1.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"info": {
|
||||
"description": "This documentation describes the Forgejo API.",
|
||||
"title": "Forgejo API",
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "http://opensource.org/licenses/MIT"
|
||||
},
|
||||
"version": "8.0.3+gitea-1.22.0"
|
||||
}
|
||||
}
|
||||
4
dummy-data/gotify/health
Normal file
4
dummy-data/gotify/health
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"health": "green",
|
||||
"database": "green"
|
||||
}
|
||||
65
dummy-data/gotify/message
Normal file
65
dummy-data/gotify/message
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"messages": [
|
||||
{
|
||||
"id": 1,
|
||||
"appid": 1,
|
||||
"message": "System backup completed successfully",
|
||||
"title": "Backup Service",
|
||||
"priority": 2,
|
||||
"date": "2024-01-15T10:30:00Z"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"appid": 2,
|
||||
"message": "Database optimization finished",
|
||||
"title": "Database Manager",
|
||||
"priority": 1,
|
||||
"date": "2024-01-15T09:15:00Z"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"appid": 1,
|
||||
"message": "Server restart scheduled for maintenance",
|
||||
"title": "System Admin",
|
||||
"priority": 5,
|
||||
"date": "2024-01-15T08:45:00Z"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"appid": 3,
|
||||
"message": "New user registration: john.doe@example.com",
|
||||
"title": "User Management",
|
||||
"priority": 1,
|
||||
"date": "2024-01-15T07:20:00Z"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"appid": 2,
|
||||
"message": "Weekly report generated and sent",
|
||||
"title": "Report Generator",
|
||||
"priority": 2,
|
||||
"date": "2024-01-14T18:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"appid": 4,
|
||||
"message": "Security scan completed - no threats detected",
|
||||
"title": "Security Monitor",
|
||||
"priority": 2,
|
||||
"date": "2024-01-14T16:30:00Z"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"appid": 1,
|
||||
"message": "Disk usage is at 85% on /var partition",
|
||||
"title": "System Monitor",
|
||||
"priority": 4,
|
||||
"date": "2024-01-14T14:15:00Z"
|
||||
}
|
||||
],
|
||||
"paging": {
|
||||
"size": 7,
|
||||
"since": 0,
|
||||
"limit": 100
|
||||
}
|
||||
}
|
||||
95
dummy-data/healthchecks/api/v1/checks
Normal file
95
dummy-data/healthchecks/api/v1/checks
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
{
|
||||
"checks": [
|
||||
{
|
||||
"name": "Database Backup",
|
||||
"tags": "backup database",
|
||||
"desc": "Daily database backup job",
|
||||
"grace": 3600,
|
||||
"n_pings": 127,
|
||||
"status": "up",
|
||||
"last_ping": "2024-01-15T10:30:00+00:00",
|
||||
"next_ping": "2024-01-16T10:30:00+00:00",
|
||||
"manual_resume": false,
|
||||
"methods": "",
|
||||
"unique_key": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||
},
|
||||
{
|
||||
"name": "Web Server Monitoring",
|
||||
"tags": "web server nginx",
|
||||
"desc": "Monitor web server health",
|
||||
"grace": 300,
|
||||
"n_pings": 2847,
|
||||
"status": "up",
|
||||
"last_ping": "2024-01-15T10:25:00+00:00",
|
||||
"next_ping": "2024-01-15T10:30:00+00:00",
|
||||
"manual_resume": false,
|
||||
"methods": "",
|
||||
"unique_key": "b2c3d4e5-f6g7-8901-bcde-f23456789012"
|
||||
},
|
||||
{
|
||||
"name": "SSL Certificate Check",
|
||||
"tags": "ssl certificate",
|
||||
"desc": "Weekly SSL certificate expiry check",
|
||||
"grace": 86400,
|
||||
"n_pings": 52,
|
||||
"status": "up",
|
||||
"last_ping": "2024-01-14T12:00:00+00:00",
|
||||
"next_ping": "2024-01-21T12:00:00+00:00",
|
||||
"manual_resume": false,
|
||||
"methods": "",
|
||||
"unique_key": "c3d4e5f6-g7h8-9012-cdef-345678901234"
|
||||
},
|
||||
{
|
||||
"name": "Log Cleanup Service",
|
||||
"tags": "cleanup logs maintenance",
|
||||
"desc": "Weekly log file cleanup",
|
||||
"grace": 7200,
|
||||
"n_pings": 15,
|
||||
"status": "grace",
|
||||
"last_ping": "2024-01-13T02:00:00+00:00",
|
||||
"next_ping": "2024-01-20T02:00:00+00:00",
|
||||
"manual_resume": false,
|
||||
"methods": "",
|
||||
"unique_key": "d4e5f6g7-h8i9-0123-defa-456789012345"
|
||||
},
|
||||
{
|
||||
"name": "Email Service",
|
||||
"tags": "email smtp",
|
||||
"desc": "Email service availability check",
|
||||
"grace": 600,
|
||||
"n_pings": 0,
|
||||
"status": "down",
|
||||
"last_ping": "2024-01-12T08:15:00+00:00",
|
||||
"next_ping": "2024-01-15T08:15:00+00:00",
|
||||
"manual_resume": false,
|
||||
"methods": "",
|
||||
"unique_key": "e5f6g7h8-i9j0-1234-efab-567890123456"
|
||||
},
|
||||
{
|
||||
"name": "API Health Check",
|
||||
"tags": "api health",
|
||||
"desc": "External API endpoint health monitoring",
|
||||
"grace": 180,
|
||||
"n_pings": 1440,
|
||||
"status": "up",
|
||||
"last_ping": "2024-01-15T10:28:00+00:00",
|
||||
"next_ping": "2024-01-15T10:30:00+00:00",
|
||||
"manual_resume": false,
|
||||
"methods": "",
|
||||
"unique_key": "f6g7h8i9-j0k1-2345-fabc-678901234567"
|
||||
},
|
||||
{
|
||||
"name": "Backup Verification",
|
||||
"tags": "backup verify",
|
||||
"desc": "Verify backup integrity",
|
||||
"grace": 1800,
|
||||
"n_pings": 45,
|
||||
"status": "grace",
|
||||
"last_ping": "2024-01-14T22:30:00+00:00",
|
||||
"next_ping": "2024-01-15T22:30:00+00:00",
|
||||
"manual_resume": false,
|
||||
"methods": "",
|
||||
"unique_key": "g7h8i9j0-k1l2-3456-gbcd-789012345678"
|
||||
}
|
||||
]
|
||||
}
|
||||
45
dummy-data/homeassistant/api/config
Normal file
45
dummy-data/homeassistant/api/config
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"location_name": "Home",
|
||||
"latitude": 40.7128,
|
||||
"longitude": -74.0060,
|
||||
"elevation": 10,
|
||||
"unit_system": {
|
||||
"length": "km",
|
||||
"mass": "kg",
|
||||
"pressure": "Pa",
|
||||
"temperature": "°C",
|
||||
"volume": "L"
|
||||
},
|
||||
"time_zone": "America/New_York",
|
||||
"components": [
|
||||
"automation",
|
||||
"climate",
|
||||
"device_tracker",
|
||||
"frontend",
|
||||
"history",
|
||||
"light",
|
||||
"logger",
|
||||
"media_player",
|
||||
"recorder",
|
||||
"script",
|
||||
"sensor",
|
||||
"switch",
|
||||
"system_health",
|
||||
"weather"
|
||||
],
|
||||
"config_dir": "/config",
|
||||
"allowlist_external_dirs": [
|
||||
"/config",
|
||||
"/share"
|
||||
],
|
||||
"allowlist_external_urls": [],
|
||||
"version": "2024.1.5",
|
||||
"config_source": "storage",
|
||||
"recovery_mode": false,
|
||||
"state": "RUNNING",
|
||||
"external_url": null,
|
||||
"internal_url": null,
|
||||
"currency": "USD",
|
||||
"country": "US",
|
||||
"language": "en"
|
||||
}
|
||||
141
dummy-data/homeassistant/api/states
Normal file
141
dummy-data/homeassistant/api/states
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
[
|
||||
{
|
||||
"entity_id": "sensor.living_room_temperature",
|
||||
"state": "22.5",
|
||||
"attributes": {
|
||||
"unit_of_measurement": "°C",
|
||||
"device_class": "temperature",
|
||||
"friendly_name": "Living Room Temperature"
|
||||
},
|
||||
"last_changed": "2024-01-15T10:30:00+00:00",
|
||||
"last_updated": "2024-01-15T10:30:00+00:00",
|
||||
"context": {
|
||||
"id": "01HMV123456789",
|
||||
"parent_id": null,
|
||||
"user_id": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"entity_id": "light.bedroom_ceiling",
|
||||
"state": "on",
|
||||
"attributes": {
|
||||
"brightness": 180,
|
||||
"color_mode": "brightness",
|
||||
"supported_color_modes": ["brightness"],
|
||||
"friendly_name": "Bedroom Ceiling Light"
|
||||
},
|
||||
"last_changed": "2024-01-15T09:15:00+00:00",
|
||||
"last_updated": "2024-01-15T09:15:00+00:00",
|
||||
"context": {
|
||||
"id": "01HMV234567890",
|
||||
"parent_id": null,
|
||||
"user_id": "user123"
|
||||
}
|
||||
},
|
||||
{
|
||||
"entity_id": "switch.coffee_maker",
|
||||
"state": "off",
|
||||
"attributes": {
|
||||
"friendly_name": "Coffee Maker"
|
||||
},
|
||||
"last_changed": "2024-01-14T22:00:00+00:00",
|
||||
"last_updated": "2024-01-14T22:00:00+00:00",
|
||||
"context": {
|
||||
"id": "01HMV345678901",
|
||||
"parent_id": null,
|
||||
"user_id": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"entity_id": "climate.living_room",
|
||||
"state": "heat",
|
||||
"attributes": {
|
||||
"temperature": 21.0,
|
||||
"current_temperature": 20.5,
|
||||
"hvac_modes": ["off", "heat", "cool", "auto"],
|
||||
"min_temp": 7.0,
|
||||
"max_temp": 35.0,
|
||||
"target_temp_step": 0.5,
|
||||
"friendly_name": "Living Room Thermostat"
|
||||
},
|
||||
"last_changed": "2024-01-15T08:00:00+00:00",
|
||||
"last_updated": "2024-01-15T10:25:00+00:00",
|
||||
"context": {
|
||||
"id": "01HMV456789012",
|
||||
"parent_id": null,
|
||||
"user_id": "user123"
|
||||
}
|
||||
},
|
||||
{
|
||||
"entity_id": "sensor.front_door",
|
||||
"state": "closed",
|
||||
"attributes": {
|
||||
"device_class": "door",
|
||||
"friendly_name": "Front Door"
|
||||
},
|
||||
"last_changed": "2024-01-15T07:30:00+00:00",
|
||||
"last_updated": "2024-01-15T07:30:00+00:00",
|
||||
"context": {
|
||||
"id": "01HMV567890123",
|
||||
"parent_id": null,
|
||||
"user_id": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"entity_id": "media_player.living_room_tv",
|
||||
"state": "playing",
|
||||
"attributes": {
|
||||
"volume_level": 0.4,
|
||||
"is_volume_muted": false,
|
||||
"media_content_type": "tvshow",
|
||||
"media_title": "The Office",
|
||||
"app_name": "Netflix",
|
||||
"friendly_name": "Living Room TV"
|
||||
},
|
||||
"last_changed": "2024-01-15T10:00:00+00:00",
|
||||
"last_updated": "2024-01-15T10:20:00+00:00",
|
||||
"context": {
|
||||
"id": "01HMV678901234",
|
||||
"parent_id": null,
|
||||
"user_id": "user123"
|
||||
}
|
||||
},
|
||||
{
|
||||
"entity_id": "automation.morning_routine",
|
||||
"state": "on",
|
||||
"attributes": {
|
||||
"last_triggered": "2024-01-15T07:00:00+00:00",
|
||||
"mode": "single",
|
||||
"current": 0,
|
||||
"friendly_name": "Morning Routine"
|
||||
},
|
||||
"last_changed": "2024-01-14T07:00:00+00:00",
|
||||
"last_updated": "2024-01-15T07:00:00+00:00",
|
||||
"context": {
|
||||
"id": "01HMV789012345",
|
||||
"parent_id": null,
|
||||
"user_id": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"entity_id": "weather.home",
|
||||
"state": "partly-cloudy",
|
||||
"attributes": {
|
||||
"temperature": 18.0,
|
||||
"humidity": 65,
|
||||
"pressure": 1013.2,
|
||||
"wind_speed": 12.5,
|
||||
"wind_bearing": 225,
|
||||
"visibility": 16.0,
|
||||
"forecast": [],
|
||||
"friendly_name": "Home Weather"
|
||||
},
|
||||
"last_changed": "2024-01-15T10:00:00+00:00",
|
||||
"last_updated": "2024-01-15T10:30:00+00:00",
|
||||
"context": {
|
||||
"id": "01HMV890123456",
|
||||
"parent_id": null,
|
||||
"user_id": null
|
||||
}
|
||||
}
|
||||
]
|
||||
3
dummy-data/homeassistant/api_root
Normal file
3
dummy-data/homeassistant/api_root
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"message": "API running."
|
||||
}
|
||||
41
dummy-data/immich/api/server/statistics
Normal file
41
dummy-data/immich/api/server/statistics
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"photos": 12847,
|
||||
"videos": 1523,
|
||||
"usage": 248576851456,
|
||||
"usageByUser": [
|
||||
{
|
||||
"userId": "user-1234-5678-9abc-def0",
|
||||
"userName": "john.doe",
|
||||
"photos": 8945,
|
||||
"videos": 892,
|
||||
"usage": 156789012345
|
||||
},
|
||||
{
|
||||
"userId": "user-2345-6789-abcd-ef01",
|
||||
"userName": "jane.smith",
|
||||
"photos": 2134,
|
||||
"videos": 423,
|
||||
"usage": 67891234567
|
||||
},
|
||||
{
|
||||
"userId": "user-3456-789a-bcde-f012",
|
||||
"userName": "family.shared",
|
||||
"photos": 1768,
|
||||
"videos": 208,
|
||||
"usage": 23896604544
|
||||
}
|
||||
],
|
||||
"usageRaw": 248576851456,
|
||||
"photosGrowth": {
|
||||
"date": "2024-01-15",
|
||||
"value": 42
|
||||
},
|
||||
"videosGrowth": {
|
||||
"date": "2024-01-15",
|
||||
"value": 7
|
||||
},
|
||||
"usageGrowth": {
|
||||
"date": "2024-01-15",
|
||||
"value": 2147483648
|
||||
}
|
||||
}
|
||||
342
dummy-data/jellystat/proxy/getSessions
Normal file
342
dummy-data/jellystat/proxy/getSessions
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
[
|
||||
{
|
||||
"PlayState": {
|
||||
"CanSeek": true,
|
||||
"IsPaused": false,
|
||||
"IsMuted": false,
|
||||
"RepeatMode": "RepeatNone",
|
||||
"ShuffleMode": "Sorted",
|
||||
"VolumeLevel": 85,
|
||||
"AudioStreamIndex": 1,
|
||||
"SubtitleStreamIndex": -1,
|
||||
"MediaSourceId": "12345abcdef",
|
||||
"PlayMethod": "DirectPlay",
|
||||
"PlaySessionId": "session-1-abc123",
|
||||
"PlaylistItemId": "playlist-item-1",
|
||||
"PositionTicks": 18000000000
|
||||
},
|
||||
"AdditionalUsers": [],
|
||||
"Capabilities": {
|
||||
"PlayableMediaTypes": ["Audio", "Video"],
|
||||
"SupportedCommands": ["Play", "Pause", "Stop", "Seek"]
|
||||
},
|
||||
"RemoteEndPoint": "192.168.1.100",
|
||||
"PlayableMediaTypes": ["Audio", "Video"],
|
||||
"Id": "session-1-abc123",
|
||||
"UserId": "user123abc",
|
||||
"UserName": "john_doe",
|
||||
"Client": "Jellyfin Web",
|
||||
"LastActivityDate": "2024-01-15T10:30:00.0000000Z",
|
||||
"LastPlaybackCheckIn": "2024-01-15T10:30:00.0000000Z",
|
||||
"DeviceName": "Chrome on Desktop",
|
||||
"DeviceId": "device-desktop-chrome",
|
||||
"ApplicationVersion": "10.8.13",
|
||||
"IsActive": true,
|
||||
"SupportsMediaControl": true,
|
||||
"SupportsRemoteControl": true,
|
||||
"NowPlayingItem": {
|
||||
"Name": "The Office - S03E01 - Gay Witch Hunt",
|
||||
"OriginalTitle": "Gay Witch Hunt",
|
||||
"Id": "episode123abc",
|
||||
"Etag": "etag123",
|
||||
"SourceType": "Library",
|
||||
"PlaylistItemId": "playlist-item-1",
|
||||
"DateCreated": "2024-01-10T00:00:00.0000000Z",
|
||||
"DateLastMediaAdded": "2024-01-10T00:00:00.0000000Z",
|
||||
"ExtraType": null,
|
||||
"AirsBeforeSeasonNumber": null,
|
||||
"AirsAfterSeasonNumber": null,
|
||||
"AirsBeforeEpisodeNumber": null,
|
||||
"CanDelete": false,
|
||||
"CanDownload": false,
|
||||
"HasSubtitles": true,
|
||||
"Container": "mkv",
|
||||
"SortName": "office s03e01 gay witch hunt",
|
||||
"ForcedSortName": null,
|
||||
"Video3DFormat": null,
|
||||
"PremiereDate": "2006-09-21T00:00:00.0000000Z",
|
||||
"ExternalUrls": [],
|
||||
"MediaSources": [],
|
||||
"CriticRating": null,
|
||||
"ProductionLocations": [],
|
||||
"Path": "/media/tv/The Office/Season 03/S03E01.mkv",
|
||||
"EnableMediaSourceDisplay": true,
|
||||
"OfficialRating": "TV-14",
|
||||
"CustomRating": null,
|
||||
"ChannelId": null,
|
||||
"ChannelName": null,
|
||||
"Overview": "Michael's kiss with Oscar at the Dundies leads to sensitivity training for the office.",
|
||||
"Taglines": [],
|
||||
"Genres": ["Comedy"],
|
||||
"CommunityRating": 8.1,
|
||||
"CumulativeRunTimeTicks": 13050000000,
|
||||
"RunTimeTicks": 13050000000,
|
||||
"PlayAccess": "Full",
|
||||
"AspectRatio": "16:9",
|
||||
"ProductionYear": 2006,
|
||||
"IsPlaceHolder": false,
|
||||
"Number": null,
|
||||
"ChannelNumber": null,
|
||||
"IndexNumber": 1,
|
||||
"IndexNumberEnd": null,
|
||||
"ParentIndexNumber": 3,
|
||||
"RemoteTrailers": [],
|
||||
"ProviderIds": {},
|
||||
"IsHD": true,
|
||||
"IsFolder": false,
|
||||
"ParentId": "season3abc",
|
||||
"Type": "Episode",
|
||||
"People": [],
|
||||
"Studios": [],
|
||||
"GenreItems": [],
|
||||
"ParentLogoItemId": null,
|
||||
"ParentBackdropItemId": "series123",
|
||||
"ParentBackdropImageTags": ["backdrop1"],
|
||||
"LocalTrailerCount": 0,
|
||||
"UserData": {
|
||||
"Rating": null,
|
||||
"PlayedPercentage": 75.5,
|
||||
"UnplayedItemCount": null,
|
||||
"PlaybackPositionTicks": 18000000000,
|
||||
"PlayCount": 1,
|
||||
"IsFavorite": false,
|
||||
"Likes": null,
|
||||
"LastPlayedDate": "2024-01-15T10:30:00.0000000Z",
|
||||
"Played": false,
|
||||
"Key": "episode123abc"
|
||||
},
|
||||
"RecursiveItemCount": 0,
|
||||
"ChildCount": 0,
|
||||
"SeriesName": "The Office",
|
||||
"SeriesId": "series123",
|
||||
"SeasonId": "season3abc",
|
||||
"SpecialFeatureCount": 0,
|
||||
"DisplayPreferencesId": "episode123abc",
|
||||
"Status": null,
|
||||
"AirTime": null,
|
||||
"AirDays": [],
|
||||
"Tags": [],
|
||||
"PrimaryImageAspectRatio": 1.777777777777778,
|
||||
"Artists": [],
|
||||
"ArtistItems": [],
|
||||
"Album": null,
|
||||
"CollectionType": null,
|
||||
"DisplayOrder": null,
|
||||
"AlbumId": null,
|
||||
"AlbumPrimaryImageTag": null,
|
||||
"SeriesPrimaryImageTag": "series-primary",
|
||||
"AlbumArtist": null,
|
||||
"AlbumArtists": [],
|
||||
"SeasonName": "Season 3",
|
||||
"MediaStreams": [],
|
||||
"VideoType": "VideoFile",
|
||||
"PartCount": 1,
|
||||
"MediaSourceCount": 1,
|
||||
"ImageTags": {
|
||||
"Primary": "episode-primary"
|
||||
},
|
||||
"BackdropImageTags": [],
|
||||
"ScreenshotImageTags": [],
|
||||
"ParentLogoImageTag": null,
|
||||
"ParentArtItemId": null,
|
||||
"ParentArtImageTag": null,
|
||||
"SeriesThumbImageTag": null,
|
||||
"ImageBlurHashes": {},
|
||||
"SeriesStudio": "NBC",
|
||||
"ParentThumbItemId": null,
|
||||
"ParentThumbImageTag": null,
|
||||
"ParentPrimaryImageItemId": "series123",
|
||||
"ParentPrimaryImageTag": "series-primary",
|
||||
"Chapters": [],
|
||||
"LocationType": "FileSystem",
|
||||
"IsoType": null,
|
||||
"MediaType": "Video",
|
||||
"EndDate": null,
|
||||
"LockedFields": [],
|
||||
"TrailerCount": 0,
|
||||
"MovieCount": 0,
|
||||
"SeriesCount": 0,
|
||||
"ProgramCount": 0,
|
||||
"EpisodeCount": 0,
|
||||
"SongCount": 0,
|
||||
"AlbumCount": 0,
|
||||
"ArtistCount": 0,
|
||||
"MusicVideoCount": 0,
|
||||
"LockData": false,
|
||||
"Width": 1920,
|
||||
"Height": 1080,
|
||||
"CameraMake": null,
|
||||
"CameraModel": null,
|
||||
"Software": null,
|
||||
"ExposureTime": null,
|
||||
"FocalLength": null,
|
||||
"ImageOrientation": null,
|
||||
"Aperture": null,
|
||||
"ShutterSpeed": null,
|
||||
"Latitude": null,
|
||||
"Longitude": null,
|
||||
"Altitude": null,
|
||||
"IsoSpeedRating": null,
|
||||
"SeriesTimerId": null,
|
||||
"ProgramId": null,
|
||||
"ChannelPrimaryImageTag": null,
|
||||
"StartDate": null,
|
||||
"CompletionPercentage": null,
|
||||
"IsRepeat": null,
|
||||
"EpisodeTitle": "Gay Witch Hunt",
|
||||
"ChannelType": null,
|
||||
"Audio": null,
|
||||
"IsMovie": false,
|
||||
"IsSports": false,
|
||||
"IsNews": false,
|
||||
"IsKids": false,
|
||||
"IsPremiere": false,
|
||||
"TimerId": null,
|
||||
"NormalizationGain": null,
|
||||
"CurrentProgram": null
|
||||
},
|
||||
"FullNowPlayingItem": {},
|
||||
"NowViewingItem": null,
|
||||
"DeviceType": "Desktop",
|
||||
"NowPlayingQueue": [],
|
||||
"NowPlayingQueueFullItems": [],
|
||||
"HasCustomDeviceName": false,
|
||||
"PlaylistItemId": "playlist-item-1",
|
||||
"ServerId": "jellyfin-server-123",
|
||||
"UserPrimaryImageTag": null,
|
||||
"SupportedCommands": []
|
||||
},
|
||||
{
|
||||
"PlayState": {
|
||||
"CanSeek": true,
|
||||
"IsPaused": true,
|
||||
"IsMuted": false,
|
||||
"RepeatMode": "RepeatNone",
|
||||
"ShuffleMode": "Sorted",
|
||||
"VolumeLevel": 65,
|
||||
"AudioStreamIndex": 1,
|
||||
"SubtitleStreamIndex": 2,
|
||||
"MediaSourceId": "67890defghi",
|
||||
"PlayMethod": "DirectPlay",
|
||||
"PlaySessionId": "session-2-def456",
|
||||
"PlaylistItemId": "playlist-item-2",
|
||||
"PositionTicks": 45000000000
|
||||
},
|
||||
"AdditionalUsers": [],
|
||||
"Capabilities": {
|
||||
"PlayableMediaTypes": ["Audio", "Video"],
|
||||
"SupportedCommands": ["Play", "Pause", "Stop", "Seek"]
|
||||
},
|
||||
"RemoteEndPoint": "192.168.1.101",
|
||||
"PlayableMediaTypes": ["Audio", "Video"],
|
||||
"Id": "session-2-def456",
|
||||
"UserId": "user456def",
|
||||
"UserName": "jane_smith",
|
||||
"Client": "Jellyfin Android",
|
||||
"LastActivityDate": "2024-01-15T10:25:00.0000000Z",
|
||||
"LastPlaybackCheckIn": "2024-01-15T10:25:00.0000000Z",
|
||||
"DeviceName": "Samsung Galaxy S21",
|
||||
"DeviceId": "device-android-samsung",
|
||||
"ApplicationVersion": "2.6.2",
|
||||
"IsActive": true,
|
||||
"SupportsMediaControl": true,
|
||||
"SupportsRemoteControl": true,
|
||||
"NowPlayingItem": {
|
||||
"Name": "Inception",
|
||||
"OriginalTitle": "Inception",
|
||||
"Id": "movie456def",
|
||||
"Etag": "etag456",
|
||||
"SourceType": "Library",
|
||||
"PlaylistItemId": "playlist-item-2",
|
||||
"DateCreated": "2024-01-05T00:00:00.0000000Z",
|
||||
"DateLastMediaAdded": "2024-01-05T00:00:00.0000000Z",
|
||||
"Container": "mkv",
|
||||
"SortName": "inception",
|
||||
"PremiereDate": "2010-07-16T00:00:00.0000000Z",
|
||||
"Path": "/media/movies/Inception (2010)/Inception.mkv",
|
||||
"EnableMediaSourceDisplay": true,
|
||||
"OfficialRating": "PG-13",
|
||||
"Overview": "A thief who steals corporate secrets through the use of dream-sharing technology is given the inverse task of planting an idea into the mind of a C.E.O.",
|
||||
"Taglines": ["Your mind is the scene of the crime"],
|
||||
"Genres": ["Action", "Sci-Fi", "Thriller"],
|
||||
"CommunityRating": 8.8,
|
||||
"CumulativeRunTimeTicks": 88800000000,
|
||||
"RunTimeTicks": 88800000000,
|
||||
"PlayAccess": "Full",
|
||||
"AspectRatio": "2.40:1",
|
||||
"ProductionYear": 2010,
|
||||
"IsPlaceHolder": false,
|
||||
"IsHD": true,
|
||||
"IsFolder": false,
|
||||
"Type": "Movie",
|
||||
"LocalTrailerCount": 0,
|
||||
"UserData": {
|
||||
"PlayedPercentage": 50.6,
|
||||
"PlaybackPositionTicks": 45000000000,
|
||||
"PlayCount": 0,
|
||||
"IsFavorite": true,
|
||||
"LastPlayedDate": "2024-01-15T10:25:00.0000000Z",
|
||||
"Played": false,
|
||||
"Key": "movie456def"
|
||||
},
|
||||
"PrimaryImageAspectRatio": 0.6666666666666666,
|
||||
"VideoType": "VideoFile",
|
||||
"PartCount": 1,
|
||||
"MediaSourceCount": 1,
|
||||
"ImageTags": {
|
||||
"Primary": "movie-primary"
|
||||
},
|
||||
"BackdropImageTags": ["backdrop1", "backdrop2"],
|
||||
"LocationType": "FileSystem",
|
||||
"MediaType": "Video",
|
||||
"Width": 1920,
|
||||
"Height": 800,
|
||||
"IsMovie": true,
|
||||
"IsSports": false,
|
||||
"IsNews": false,
|
||||
"IsKids": false,
|
||||
"IsPremiere": false
|
||||
},
|
||||
"FullNowPlayingItem": {},
|
||||
"NowViewingItem": null,
|
||||
"DeviceType": "Phone",
|
||||
"NowPlayingQueue": [],
|
||||
"NowPlayingQueueFullItems": [],
|
||||
"HasCustomDeviceName": false,
|
||||
"PlaylistItemId": "playlist-item-2",
|
||||
"ServerId": "jellyfin-server-123",
|
||||
"UserPrimaryImageTag": null,
|
||||
"SupportedCommands": []
|
||||
},
|
||||
{
|
||||
"PlayState": null,
|
||||
"AdditionalUsers": [],
|
||||
"Capabilities": {
|
||||
"PlayableMediaTypes": ["Audio", "Video"],
|
||||
"SupportedCommands": ["Play", "Pause", "Stop"]
|
||||
},
|
||||
"RemoteEndPoint": "192.168.1.102",
|
||||
"PlayableMediaTypes": ["Audio", "Video"],
|
||||
"Id": "session-3-ghi789",
|
||||
"UserId": "user789ghi",
|
||||
"UserName": "family_user",
|
||||
"Client": "Jellyfin for Roku",
|
||||
"LastActivityDate": "2024-01-15T10:20:00.0000000Z",
|
||||
"LastPlaybackCheckIn": "2024-01-15T10:20:00.0000000Z",
|
||||
"DeviceName": "Roku Ultra",
|
||||
"DeviceId": "device-roku-ultra",
|
||||
"ApplicationVersion": "1.6.8",
|
||||
"IsActive": true,
|
||||
"SupportsMediaControl": true,
|
||||
"SupportsRemoteControl": true,
|
||||
"FullNowPlayingItem": {},
|
||||
"NowViewingItem": null,
|
||||
"DeviceType": "Tv",
|
||||
"NowPlayingQueue": [],
|
||||
"NowPlayingQueueFullItems": [],
|
||||
"HasCustomDeviceName": false,
|
||||
"ServerId": "jellyfin-server-123",
|
||||
"UserPrimaryImageTag": null,
|
||||
"SupportedCommands": []
|
||||
}
|
||||
]
|
||||
35
dummy-data/lidarr/api/v1/health
Normal file
35
dummy-data/lidarr/api/v1/health
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
[
|
||||
{
|
||||
"source": "IndexerStatusCheck",
|
||||
"type": "warning",
|
||||
"message": "Indexer MusicBrainzDB is unavailable due to recent indexer errors: Service temporarily unavailable",
|
||||
"wikiUrl": "https://wiki.servarr.com/lidarr/health#indexers-are-unavailable-due-to-recent-failures"
|
||||
},
|
||||
{
|
||||
"source": "ImportMechanismCheck",
|
||||
"type": "ok",
|
||||
"message": "No issues with import mechanism checks"
|
||||
},
|
||||
{
|
||||
"source": "DownloadClientStatusCheck",
|
||||
"type": "ok",
|
||||
"message": "All download clients are available"
|
||||
},
|
||||
{
|
||||
"source": "RootFolderCheck",
|
||||
"type": "error",
|
||||
"message": "Missing root folder: /music",
|
||||
"wikiUrl": "https://wiki.servarr.com/lidarr/health#missing-root-folder"
|
||||
},
|
||||
{
|
||||
"source": "UpdateCheck",
|
||||
"type": "ok",
|
||||
"message": "Update available: 1.3.6.3557 -> 2.0.7.3849"
|
||||
},
|
||||
{
|
||||
"source": "MetadataProviderCheck",
|
||||
"type": "warning",
|
||||
"message": "Metadata provider Last.fm API key is invalid or expired",
|
||||
"wikiUrl": "https://wiki.servarr.com/lidarr/health#metadata-provider-issues"
|
||||
}
|
||||
]
|
||||
7
dummy-data/lidarr/api/v1/queue/status
Normal file
7
dummy-data/lidarr/api/v1/queue/status
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"totalCount": 4,
|
||||
"count": 4,
|
||||
"unknownCount": 0,
|
||||
"errors": false,
|
||||
"warnings": false
|
||||
}
|
||||
179
dummy-data/lidarr/api/v1/wanted/missing
Normal file
179
dummy-data/lidarr/api/v1/wanted/missing
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
{
|
||||
"page": 1,
|
||||
"pageSize": 20,
|
||||
"sortKey": "releaseDate",
|
||||
"sortDirection": "descending",
|
||||
"totalRecords": 7,
|
||||
"records": [
|
||||
{
|
||||
"artistId": 1,
|
||||
"albumId": 12345,
|
||||
"foreignAlbumId": "mbid-123-456-789",
|
||||
"title": "Dark Side of the Moon",
|
||||
"disambiguation": "",
|
||||
"overview": "The eighth studio album by Pink Floyd, released in 1973.",
|
||||
"artistName": "Pink Floyd",
|
||||
"foreignArtistId": "mbid-artist-123",
|
||||
"monitored": true,
|
||||
"anyReleaseOk": true,
|
||||
"profileId": 1,
|
||||
"duration": 2580000,
|
||||
"albumType": "Album",
|
||||
"secondaryTypes": [],
|
||||
"mediumCount": 1,
|
||||
"releaseDate": "1973-03-01T00:00:00Z",
|
||||
"releases": [
|
||||
{
|
||||
"id": 67890,
|
||||
"albumId": 12345,
|
||||
"foreignReleaseId": "mbid-release-123",
|
||||
"title": "Dark Side of the Moon",
|
||||
"status": "Official",
|
||||
"duration": 2580000,
|
||||
"trackCount": 10,
|
||||
"mediumCount": 1,
|
||||
"disambiguation": "",
|
||||
"country": ["US"],
|
||||
"label": ["Harvest", "Capitol"],
|
||||
"monitored": true
|
||||
}
|
||||
],
|
||||
"genres": ["Progressive Rock", "Psychedelic Rock"],
|
||||
"media": [
|
||||
{
|
||||
"mediumNumber": 1,
|
||||
"mediumName": "",
|
||||
"mediumFormat": "CD"
|
||||
}
|
||||
],
|
||||
"artist": {
|
||||
"artistName": "Pink Floyd",
|
||||
"foreignArtistId": "mbid-artist-123",
|
||||
"nameSlug": "pink-floyd",
|
||||
"overview": "English rock band formed in London in 1965.",
|
||||
"disambiguation": "",
|
||||
"links": [],
|
||||
"images": [],
|
||||
"path": "/music/Pink Floyd",
|
||||
"qualityProfileId": 1,
|
||||
"metadataProfileId": 1,
|
||||
"monitored": true,
|
||||
"monitorNewItems": "all",
|
||||
"genres": ["Progressive Rock", "Psychedelic Rock", "Art Rock"],
|
||||
"cleanName": "pinkfloyd",
|
||||
"sortName": "Pink Floyd",
|
||||
"tags": [],
|
||||
"added": "2024-01-01T00:00:00Z",
|
||||
"ratings": {
|
||||
"votes": 54321,
|
||||
"value": 9.2
|
||||
},
|
||||
"statistics": {
|
||||
"albumCount": 15,
|
||||
"trackFileCount": 142,
|
||||
"trackCount": 149,
|
||||
"totalTrackCount": 149,
|
||||
"sizeOnDisk": 7516192768,
|
||||
"percentOfTracks": 95.3
|
||||
},
|
||||
"id": 1
|
||||
},
|
||||
"images": [],
|
||||
"links": [],
|
||||
"statistics": {
|
||||
"trackFileCount": 0,
|
||||
"trackCount": 10,
|
||||
"totalTrackCount": 10,
|
||||
"sizeOnDisk": 0,
|
||||
"percentOfTracks": 0.0
|
||||
},
|
||||
"grabbed": false,
|
||||
"id": 12345
|
||||
},
|
||||
{
|
||||
"artistId": 2,
|
||||
"albumId": 23456,
|
||||
"foreignAlbumId": "mbid-234-567-890",
|
||||
"title": "OK Computer",
|
||||
"disambiguation": "",
|
||||
"overview": "The third studio album by Radiohead, released in 1997.",
|
||||
"artistName": "Radiohead",
|
||||
"foreignArtistId": "mbid-artist-234",
|
||||
"monitored": true,
|
||||
"anyReleaseOk": true,
|
||||
"profileId": 1,
|
||||
"duration": 3230000,
|
||||
"albumType": "Album",
|
||||
"secondaryTypes": [],
|
||||
"mediumCount": 1,
|
||||
"releaseDate": "1997-06-16T00:00:00Z",
|
||||
"releases": [
|
||||
{
|
||||
"id": 78901,
|
||||
"albumId": 23456,
|
||||
"foreignReleaseId": "mbid-release-234",
|
||||
"title": "OK Computer",
|
||||
"status": "Official",
|
||||
"duration": 3230000,
|
||||
"trackCount": 12,
|
||||
"mediumCount": 1,
|
||||
"disambiguation": "",
|
||||
"country": ["GB"],
|
||||
"label": ["Parlophone", "Capitol"],
|
||||
"monitored": true
|
||||
}
|
||||
],
|
||||
"genres": ["Alternative Rock", "Art Rock"],
|
||||
"media": [
|
||||
{
|
||||
"mediumNumber": 1,
|
||||
"mediumName": "",
|
||||
"mediumFormat": "CD"
|
||||
}
|
||||
],
|
||||
"artist": {
|
||||
"artistName": "Radiohead",
|
||||
"foreignArtistId": "mbid-artist-234",
|
||||
"nameSlug": "radiohead",
|
||||
"overview": "English rock band formed in Abingdon, Oxfordshire, in 1985.",
|
||||
"disambiguation": "",
|
||||
"links": [],
|
||||
"images": [],
|
||||
"path": "/music/Radiohead",
|
||||
"qualityProfileId": 1,
|
||||
"metadataProfileId": 1,
|
||||
"monitored": true,
|
||||
"monitorNewItems": "all",
|
||||
"genres": ["Alternative Rock", "Art Rock", "Electronic"],
|
||||
"cleanName": "radiohead",
|
||||
"sortName": "Radiohead",
|
||||
"tags": [],
|
||||
"added": "2024-01-01T00:00:00Z",
|
||||
"ratings": {
|
||||
"votes": 45678,
|
||||
"value": 8.9
|
||||
},
|
||||
"statistics": {
|
||||
"albumCount": 9,
|
||||
"trackFileCount": 89,
|
||||
"trackCount": 95,
|
||||
"totalTrackCount": 95,
|
||||
"sizeOnDisk": 4831838208,
|
||||
"percentOfTracks": 93.7
|
||||
},
|
||||
"id": 2
|
||||
},
|
||||
"images": [],
|
||||
"links": [],
|
||||
"statistics": {
|
||||
"trackFileCount": 0,
|
||||
"trackCount": 12,
|
||||
"totalTrackCount": 12,
|
||||
"sizeOnDisk": 0,
|
||||
"percentOfTracks": 0.0
|
||||
},
|
||||
"grabbed": false,
|
||||
"id": 23456
|
||||
}
|
||||
]
|
||||
}
|
||||
61
dummy-data/linkding/api/bookmarks
Normal file
61
dummy-data/linkding/api/bookmarks
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"count": 12,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"url": "https://github.com/bastienwirtz/homer",
|
||||
"title": "Homer - A very simple static homepage for your server",
|
||||
"description": "A dead simple static HOMepage for your servER to keep your services on hand, from a simple yaml configuration file.",
|
||||
"notes": "",
|
||||
"website_title": "GitHub",
|
||||
"website_description": "GitHub is where over 100 million developers shape the future of software, together.",
|
||||
"web_archive_snapshot_url": "",
|
||||
"favicon_url": "https://github.githubassets.com/favicons/favicon.svg",
|
||||
"preview_image_url": "",
|
||||
"is_archived": false,
|
||||
"unread": false,
|
||||
"shared": false,
|
||||
"tag_names": ["selfhosted", "dashboard", "yaml"],
|
||||
"date_added": "2024-01-15T10:30:00.123456Z",
|
||||
"date_modified": "2024-01-15T10:30:00.123456Z"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"url": "https://docs.docker.com/",
|
||||
"title": "Docker Documentation",
|
||||
"description": "Official Docker documentation with guides, references, and tutorials for containerization.",
|
||||
"notes": "Essential for container management",
|
||||
"website_title": "Docker Docs",
|
||||
"website_description": "Docker helps developers build, share, run, and verify applications anywhere.",
|
||||
"web_archive_snapshot_url": "",
|
||||
"favicon_url": "https://docs.docker.com/favicons/docs@2x.ico",
|
||||
"preview_image_url": "",
|
||||
"is_archived": false,
|
||||
"unread": false,
|
||||
"shared": false,
|
||||
"tag_names": ["docker", "containers", "documentation"],
|
||||
"date_added": "2024-01-14T15:20:00.123456Z",
|
||||
"date_modified": "2024-01-14T15:20:00.123456Z"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"url": "https://nginx.org/en/docs/",
|
||||
"title": "nginx documentation",
|
||||
"description": "Official nginx web server documentation covering installation, configuration, and modules.",
|
||||
"notes": "",
|
||||
"website_title": "nginx",
|
||||
"website_description": "nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server.",
|
||||
"web_archive_snapshot_url": "",
|
||||
"favicon_url": "https://nginx.org/favicon.ico",
|
||||
"preview_image_url": "",
|
||||
"is_archived": false,
|
||||
"unread": false,
|
||||
"shared": false,
|
||||
"tag_names": ["nginx", "webserver", "proxy"],
|
||||
"date_added": "2024-01-13T09:45:00.123456Z",
|
||||
"date_modified": "2024-01-13T09:45:00.123456Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
6
dummy-data/matrix/_matrix/federation/v1/version
Normal file
6
dummy-data/matrix/_matrix/federation/v1/version
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"server": {
|
||||
"name": "Synapse",
|
||||
"version": "1.99.0"
|
||||
}
|
||||
}
|
||||
18
dummy-data/mealie/api/admin/about/statistics
Normal file
18
dummy-data/mealie/api/admin/about/statistics
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"totalRecipes": 247,
|
||||
"totalUsers": 5,
|
||||
"totalGroups": 2,
|
||||
"totalCategories": 18,
|
||||
"totalTags": 42,
|
||||
"totalTools": 15,
|
||||
"totalMealPlans": 156,
|
||||
"totalShoppingLists": 28,
|
||||
"totalComments": 89,
|
||||
"lastUpdated": "2024-01-15T10:30:00Z",
|
||||
"version": "1.0.0",
|
||||
"demoStatus": false,
|
||||
"allowSignup": true,
|
||||
"defaultGroup": "Home",
|
||||
"buildVersion": "v1.0.0-1234567",
|
||||
"apiVersion": "v1"
|
||||
}
|
||||
64
dummy-data/mealie/api/groups/mealplans/today
Normal file
64
dummy-data/mealie/api/groups/mealplans/today
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
[
|
||||
{
|
||||
"id": "meal-123-abc",
|
||||
"date": "2024-01-15",
|
||||
"entryType": "dinner",
|
||||
"title": "Dinner",
|
||||
"text": "",
|
||||
"recipe": {
|
||||
"id": "recipe-456-def",
|
||||
"name": "Chicken Tikka Masala",
|
||||
"slug": "chicken-tikka-masala",
|
||||
"image": "recipe-456-def.webp",
|
||||
"description": "Creamy tomato-based curry with tender chicken pieces and aromatic spices",
|
||||
"recipeCategory": [
|
||||
{
|
||||
"id": "cat-1",
|
||||
"name": "Indian",
|
||||
"slug": "indian"
|
||||
},
|
||||
{
|
||||
"id": "cat-2",
|
||||
"name": "Main Course",
|
||||
"slug": "main-course"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"id": "tag-1",
|
||||
"name": "Curry",
|
||||
"slug": "curry"
|
||||
},
|
||||
{
|
||||
"id": "tag-2",
|
||||
"name": "Chicken",
|
||||
"slug": "chicken"
|
||||
},
|
||||
{
|
||||
"id": "tag-3",
|
||||
"name": "Spicy",
|
||||
"slug": "spicy"
|
||||
}
|
||||
],
|
||||
"rating": 4.5,
|
||||
"totalTime": "45 minutes",
|
||||
"prepTime": "15 minutes",
|
||||
"cookTime": "30 minutes",
|
||||
"performTime": null,
|
||||
"servings": 4,
|
||||
"dateAdded": "2024-01-10T00:00:00Z",
|
||||
"dateUpdated": "2024-01-14T12:30:00Z",
|
||||
"createdBy": {
|
||||
"id": "user-789",
|
||||
"username": "chef_sarah",
|
||||
"fullName": "Sarah Mitchell"
|
||||
},
|
||||
"updateBy": {
|
||||
"id": "user-789",
|
||||
"username": "chef_sarah",
|
||||
"fullName": "Sarah Mitchell"
|
||||
}
|
||||
},
|
||||
"groupId": "group-default-123"
|
||||
}
|
||||
]
|
||||
108
dummy-data/medusa/api/v2/config
Normal file
108
dummy-data/medusa/api/v2/config
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
{
|
||||
"system": {
|
||||
"news": {
|
||||
"unread": 3,
|
||||
"latest": [
|
||||
{
|
||||
"title": "Medusa v1.0.19 Released",
|
||||
"date": "2024-01-14",
|
||||
"content": "Bug fixes and performance improvements",
|
||||
"read": false
|
||||
},
|
||||
{
|
||||
"title": "New indexer support added",
|
||||
"date": "2024-01-12",
|
||||
"content": "Support for additional torrent indexers",
|
||||
"read": false
|
||||
},
|
||||
{
|
||||
"title": "Database maintenance completed",
|
||||
"date": "2024-01-10",
|
||||
"content": "Weekly database optimization finished",
|
||||
"read": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"version": "1.0.19",
|
||||
"branch": "master",
|
||||
"commit": "abc123def456",
|
||||
"dbVersion": 44,
|
||||
"pythonVersion": "3.11.7"
|
||||
},
|
||||
"os": {
|
||||
"platform": "Linux",
|
||||
"release": "6.5.0-15-generic",
|
||||
"version": "#15~22.04.1-Ubuntu"
|
||||
},
|
||||
"memory": {
|
||||
"used": 512.5,
|
||||
"total": 8192.0,
|
||||
"percent": 6.3
|
||||
}
|
||||
},
|
||||
"main": {
|
||||
"logs": {
|
||||
"numWarnings": 2,
|
||||
"numErrors": 1,
|
||||
"loggingLevels": [
|
||||
"DEBUG",
|
||||
"INFO",
|
||||
"WARNING",
|
||||
"ERROR"
|
||||
],
|
||||
"currentLevel": "INFO"
|
||||
},
|
||||
"general": {
|
||||
"webHost": "0.0.0.0",
|
||||
"webPort": 8081,
|
||||
"webRoot": "",
|
||||
"launchBrowser": false,
|
||||
"versionNotify": true,
|
||||
"autoUpdate": false,
|
||||
"logDir": "/app/Logs",
|
||||
"dataDir": "/app/Data",
|
||||
"configVersion": 12
|
||||
},
|
||||
"showDefaults": {
|
||||
"status": "Skipped/Wanted/Snatched/Downloaded",
|
||||
"statusAfter": "Downloaded",
|
||||
"season_folders": true,
|
||||
"anime": false,
|
||||
"scene": false,
|
||||
"archive_firstmatch": false,
|
||||
"quality_default": "Standard Definition",
|
||||
"subtitles": false,
|
||||
"flatten_folders": false,
|
||||
"indexer_default": "tvdb",
|
||||
"indexer_timeout": 20,
|
||||
"skip_removed_files": false
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"general": {
|
||||
"randomize_providers": false,
|
||||
"download_propers": true,
|
||||
"check_propers_interval": "daily",
|
||||
"propers_search_days": 2,
|
||||
"backlog_days": 7,
|
||||
"cache_trimming": false,
|
||||
"max_cache_age": 30
|
||||
},
|
||||
"nzb": {
|
||||
"nzbs": false,
|
||||
"nzbs_uid": "",
|
||||
"nzbs_hash": ""
|
||||
},
|
||||
"torrent": {
|
||||
"torrent_method": "blackhole",
|
||||
"torrent_path": "",
|
||||
"torrent_seed_time": 0,
|
||||
"torrent_paused": false,
|
||||
"torrent_high_bandwidth": false,
|
||||
"torrent_label": "",
|
||||
"torrent_label_anime": "",
|
||||
"torrent_verify_cert": false
|
||||
}
|
||||
}
|
||||
}
|
||||
36
dummy-data/miniflux/v1/entries
Normal file
36
dummy-data/miniflux/v1/entries
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"total": 42,
|
||||
"entries": [
|
||||
{
|
||||
"id": 888,
|
||||
"user_id": 1,
|
||||
"feed_id": 42,
|
||||
"title": "Example Unread Entry",
|
||||
"url": "http://example.org/article.html",
|
||||
"comments_url": "",
|
||||
"author": "John Doe",
|
||||
"content": "<p>This is an unread RSS entry</p>",
|
||||
"hash": "29f99e4074cdacca1766f47697d03c66070ef6a14770a1fd5a867483c207a1bb",
|
||||
"published_at": "2025-11-11T16:15:19Z",
|
||||
"created_at": "2025-11-11T16:15:19Z",
|
||||
"status": "unread",
|
||||
"share_code": "",
|
||||
"starred": false,
|
||||
"reading_time": 5,
|
||||
"enclosures": null,
|
||||
"feed": {
|
||||
"id": 42,
|
||||
"user_id": 1,
|
||||
"title": "Tech Blog",
|
||||
"site_url": "http://example.org",
|
||||
"feed_url": "http://example.org/feed.atom",
|
||||
"checked_at": "2025-11-11T21:06:03.133839Z",
|
||||
"category": {
|
||||
"id": 22,
|
||||
"user_id": 1,
|
||||
"title": "Technology"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
10
dummy-data/nextcloud/status.php
Normal file
10
dummy-data/nextcloud/status.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"installed": true,
|
||||
"maintenance": false,
|
||||
"needsDbUpgrade": false,
|
||||
"version": "28.0.2.1",
|
||||
"versionstring": "28.0.2",
|
||||
"edition": "",
|
||||
"productname": "Nextcloud",
|
||||
"extendedSupport": false
|
||||
}
|
||||
18
dummy-data/olivetin/webUiSettings.json
Normal file
18
dummy-data/olivetin/webUiSettings.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"Rest": "./api/",
|
||||
"ShowFooter": true,
|
||||
"ShowNavigation": true,
|
||||
"ShowNewVersions": true,
|
||||
"AvailableVersion": "none",
|
||||
"CurrentVersion": "2024.11.24",
|
||||
"PageTitle": "OliveTin",
|
||||
"SectionNavigationStyle": "sidebar",
|
||||
"DefaultIconForBack": "«",
|
||||
"SshFoundKey": "not found at /home/user/.ssh/id_rsa",
|
||||
"SshFoundConfig": "not found at /home/user/.ssh/config",
|
||||
"EnableCustomJs": false,
|
||||
"AuthLoginUrl": "",
|
||||
"AuthLocalLogin": false,
|
||||
"AuthOAuth2Providers": null,
|
||||
"AdditionalLinks": null
|
||||
}
|
||||
88
dummy-data/paperlessng/api/documents
Normal file
88
dummy-data/paperlessng/api/documents
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
{
|
||||
"count": 1847,
|
||||
"next": "http://paperless.local/api/documents/?page=2",
|
||||
"previous": null,
|
||||
"all": [1, 2, 3, 4, 5],
|
||||
"results": [
|
||||
{
|
||||
"id": 1847,
|
||||
"correspondent": 15,
|
||||
"document_type": 12,
|
||||
"storage_path": null,
|
||||
"title": "Bank Statement - January 2024",
|
||||
"content": "Monthly bank statement with account summary and transaction details",
|
||||
"tags": [8, 15, 23],
|
||||
"created": "2024-01-15T10:30:00Z",
|
||||
"created_date": "2024-01-15",
|
||||
"modified": "2024-01-15T10:30:00Z",
|
||||
"added": "2024-01-15T10:30:00Z",
|
||||
"archive_serial_number": "ASN2024001847",
|
||||
"original_file_name": "bank_statement_202401.pdf",
|
||||
"archived_file_name": "0001847.pdf"
|
||||
},
|
||||
{
|
||||
"id": 1846,
|
||||
"correspondent": 23,
|
||||
"document_type": 5,
|
||||
"storage_path": null,
|
||||
"title": "Utility Bill - Electric Company",
|
||||
"content": "Monthly electricity bill for December 2023",
|
||||
"tags": [12, 18],
|
||||
"created": "2024-01-14T16:45:00Z",
|
||||
"created_date": "2024-01-14",
|
||||
"modified": "2024-01-14T16:45:00Z",
|
||||
"added": "2024-01-14T16:45:00Z",
|
||||
"archive_serial_number": "ASN2024001846",
|
||||
"original_file_name": "electric_bill_202312.pdf",
|
||||
"archived_file_name": "0001846.pdf"
|
||||
},
|
||||
{
|
||||
"id": 1845,
|
||||
"correspondent": 7,
|
||||
"document_type": 18,
|
||||
"storage_path": null,
|
||||
"title": "Insurance Policy Renewal Notice",
|
||||
"content": "Annual home insurance policy renewal documentation",
|
||||
"tags": [5, 11, 19],
|
||||
"created": "2024-01-13T14:20:00Z",
|
||||
"created_date": "2024-01-13",
|
||||
"modified": "2024-01-13T14:20:00Z",
|
||||
"added": "2024-01-13T14:20:00Z",
|
||||
"archive_serial_number": "ASN2024001845",
|
||||
"original_file_name": "insurance_renewal_2024.pdf",
|
||||
"archived_file_name": "0001845.pdf"
|
||||
},
|
||||
{
|
||||
"id": 1844,
|
||||
"correspondent": 31,
|
||||
"document_type": 9,
|
||||
"storage_path": null,
|
||||
"title": "Tax Document - W2 Form 2023",
|
||||
"content": "Annual W2 tax form from employer",
|
||||
"tags": [2, 14, 25],
|
||||
"created": "2024-01-12T09:15:00Z",
|
||||
"created_date": "2024-01-12",
|
||||
"modified": "2024-01-12T09:15:00Z",
|
||||
"added": "2024-01-12T09:15:00Z",
|
||||
"archive_serial_number": "ASN2024001844",
|
||||
"original_file_name": "w2_form_2023.pdf",
|
||||
"archived_file_name": "0001844.pdf"
|
||||
},
|
||||
{
|
||||
"id": 1843,
|
||||
"correspondent": 42,
|
||||
"document_type": 21,
|
||||
"storage_path": null,
|
||||
"title": "Medical Records - Annual Checkup",
|
||||
"content": "Annual physical examination results and health summary",
|
||||
"tags": [6, 17, 28],
|
||||
"created": "2024-01-11T11:30:00Z",
|
||||
"created_date": "2024-01-11",
|
||||
"modified": "2024-01-11T11:30:00Z",
|
||||
"added": "2024-01-11T11:30:00Z",
|
||||
"archive_serial_number": "ASN2024001843",
|
||||
"original_file_name": "medical_checkup_2024.pdf",
|
||||
"archived_file_name": "0001843.pdf"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
"domains_being_blocked": 152588,
|
||||
"dns_queries_today": 0,
|
||||
"ads_blocked_today": 0,
|
||||
"ads_percentage_today": 42,
|
||||
"percent_blocked": 42,
|
||||
"unique_domains": 0,
|
||||
"queries_forwarded": 0,
|
||||
"queries_cached": 0,
|
||||
|
|
|
|||
12
dummy-data/plex/library/sections
Normal file
12
dummy-data/plex/library/sections
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MediaContainer size="3" allowSync="1" art="/:/resources/show-fanart.jpg" identifier="com.plexapp.plugins.library" librarySectionID="0" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1705317600" thumb="/:/resources/show.png" title1="Plex Library" viewGroup="secondary" viewMode="458752">
|
||||
<Directory allowSync="1" art="/:/resources/movie-fanart.jpg" composite="/library/sections/1/composite/1705317600" filters="1" refreshing="0" thumb="/:/resources/movie.png" key="1" type="movie" title="Movies" agent="com.plexapp.agents.themoviedb" scanner="Plex Movie" language="en-US" uuid="abcd1234-5678-90ab-cdef-123456789012" updatedAt="1705317600" createdAt="1704067200" scannedAt="1705317000" content="1" directory="1" contentChangedAt="1705316400" hidden="0">
|
||||
<Location id="1" path="/media/movies" />
|
||||
</Directory>
|
||||
<Directory allowSync="1" art="/:/resources/show-fanart.jpg" composite="/library/sections/2/composite/1705317600" filters="1" refreshing="0" thumb="/:/resources/show.png" key="2" type="show" title="TV Shows" agent="com.plexapp.agents.thetvdb" scanner="Plex TV Series" language="en-US" uuid="efgh5678-90ab-cdef-1234-567890abcdef" updatedAt="1705317600" createdAt="1704067200" scannedAt="1705317000" content="1" directory="1" contentChangedAt="1705316400" hidden="0">
|
||||
<Location id="2" path="/media/tv" />
|
||||
</Directory>
|
||||
<Directory allowSync="1" art="/:/resources/artist-fanart.jpg" composite="/library/sections/3/composite/1705317600" filters="1" refreshing="0" thumb="/:/resources/artist.png" key="3" type="artist" title="Music" agent="com.plexapp.agents.lastfm" scanner="Plex Music" language="en-US" uuid="ijkl9012-3456-789a-bcde-f0123456789a" updatedAt="1705317600" createdAt="1704067200" scannedAt="1705317000" content="1" directory="1" contentChangedAt="1705316400" hidden="0">
|
||||
<Location id="3" path="/media/music" />
|
||||
</Directory>
|
||||
</MediaContainer>
|
||||
7
dummy-data/plex/library/sections1all
Normal file
7
dummy-data/plex/library/sections1all
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MediaContainer size="247" allowSync="1" art="/:/resources/movie-fanart.jpg" identifier="com.plexapp.plugins.library" librarySectionID="1" librarySectionTitle="Movies" librarySectionUUID="abcd1234-5678-90ab-cdef-123456789012" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1705317600" mixedParents="0" nocache="1" offset="0" thumb="/:/resources/movie.png" title1="Movies" title2="All Movies" totalSize="247" viewGroup="movie" viewMode="458752">
|
||||
<Video ratingKey="1001" key="/library/metadata/1001" guid="plex://movie/5d9c086fe98e47001e0d5001" type="movie" title="Inception" titleSort="Inception" contentRating="PG-13" summary="A thief who steals corporate secrets through dream-sharing technology." rating="8.8" audienceRating="9.1" year="2010" tagline="Your mind is the scene of the crime" thumb="/library/metadata/1001/thumb/1705317600" art="/library/metadata/1001/art/1705317600" duration="8880000" originallyAvailableAt="2010-07-16" addedAt="1705144800" updatedAt="1705317600">
|
||||
<Media id="2001" duration="8880000" bitrate="12000" width="1920" height="1080" aspectRatio="1.78" audioChannels="6" audioCodec="dts" videoCodec="h264" videoResolution="1080" container="mkv" videoFrameRate="24p" audioProfile="dts" videoProfile="high" />
|
||||
</Video>
|
||||
<!-- 246 more movies would be here, showing just one for brevity -->
|
||||
</MediaContainer>
|
||||
13
dummy-data/plex/library/sections2all
Normal file
13
dummy-data/plex/library/sections2all
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MediaContainer size="89" allowSync="1" art="/:/resources/show-fanart.jpg" identifier="com.plexapp.plugins.library" librarySectionID="2" librarySectionTitle="TV Shows" librarySectionUUID="efgh5678-90ab-cdef-1234-567890abcdef" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1705317600" mixedParents="0" nocache="1" offset="0" thumb="/:/resources/show.png" title1="TV Shows" title2="All Shows" totalSize="89" viewGroup="show" viewMode="458752">
|
||||
<Directory ratingKey="2001" key="/library/metadata/2001" guid="plex://show/5d9c081fe98e47001e0c2001" type="show" title="Breaking Bad" titleSort="Breaking Bad" contentRating="TV-MA" summary="A high school chemistry teacher diagnosed with inoperable lung cancer turns to manufacturing and selling methamphetamine in order to secure his family's future." rating="9.5" year="2008" thumb="/library/metadata/2001/thumb/1705317600" art="/library/metadata/2001/art/1705317600" banner="/library/metadata/2001/banner/1705317600" duration="2820000" originallyAvailableAt="2008-01-20" leafCount="62" viewedLeafCount="62" childCount="5" addedAt="1705144800" updatedAt="1705317600">
|
||||
<Genre tag="Crime" />
|
||||
<Genre tag="Drama" />
|
||||
<Genre tag="Thriller" />
|
||||
</Directory>
|
||||
<Directory ratingKey="2002" key="/library/metadata/2002" guid="plex://show/5d9c081fe98e47001e0c2002" type="show" title="Friends" titleSort="Friends" contentRating="TV-14" summary="Follows the personal and professional lives of six twenty to thirty-something-year-old friends living in Manhattan." rating="8.9" year="1994" thumb="/library/metadata/2002/thumb/1705317600" art="/library/metadata/2002/art/1705317600" banner="/library/metadata/2002/banner/1705317600" duration="1320000" originallyAvailableAt="1994-09-22" leafCount="236" viewedLeafCount="236" childCount="10" addedAt="1705144800" updatedAt="1705317600">
|
||||
<Genre tag="Comedy" />
|
||||
<Genre tag="Romance" />
|
||||
</Directory>
|
||||
<!-- 87 more shows would be here, showing just two for brevity -->
|
||||
</MediaContainer>
|
||||
19
dummy-data/plex/status/sessions
Normal file
19
dummy-data/plex/status/sessions
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MediaContainer size="2" allowCameraUpload="1" allowChannelAccess="1" allowMediaDeletion="1" allowSharing="1" allowSync="1" backgroundProcessing="1" certificateVersion="2" companionProxy="1" countryCode="US" diagnostics="logs,databases,streaminglogs" eventStream="1" friendlyName="Homer-Plex-Server" hubSearch="1" itemClusters="1" livenessTimeout="0" machineIdentifier="abc123def456ghi789jkl012" mediaProviders="1" multiuser="1" myPlex="1" myPlexMappingState="mapped" myPlexSigninState="ok" myPlexSubscription="1" myPlexUsername="homer@example.com" offlineTranscode="1" ownerFeatures="adaptive_bitrate,collections,content_filter,dvr,hardware_transcoding,home,loudness_analysis,music_videos,pass,photo_autotags,premium_music_metadata,session_bandwidth_restrictions,sync,trailers,webhooks" photoAutoTag="1" platform="Linux" platformVersion="6.5.0-15-generic" pluginHost="1" pushNotifications="1" readOnlyLibraries="1" requestParametersInCookie="1" streamingBrainABRVersion="3" streamingBrainVersion="2" sync="1" transcoderActiveVideoSessions="0" transcoderAudio="1" transcoderLyrics="1" transcoderPhoto="1" transcoderSubtitles="1" transcoderVideo="1" transcoderVideoBitrates="64,96,208,320,720,1500,2000,3000,4000,8000,10000,12000,20000" transcoderVideoQualities="0,1,2,3,4,5,6,7,8,9,10,11,12" transcoderVideoResolutions="128,128,160,240,320,480,768,720,720,1080,1080,1080,1080" updatedAt="1705317600" updater="1" version="1.40.1.8227-c0dd5a73e" voiceSearch="1">
|
||||
<Video sessionKey="1" key="/library/metadata/12345" parentKey="/library/metadata/12300" grandparentKey="/library/metadata/12000" guid="plex://episode/5d9c086fe98e47001e0d5c3f" parentGuid="plex://season/602e67d31d3358002d2fb2bd" grandparentGuid="plex://show/5d9c081fe98e47001e0c8382" type="episode" title="The One Where Monica Gets a Roommate" titleSort="One Where Monica Gets a Roommate, The" grandparentTitle="Friends" parentTitle="Season 1" contentRating="TV-14" summary="Monica and the gang introduce Rachel to the real world after she leaves her fiancé at the altar." index="1" parentIndex="1" lastViewedAt="1705315800" year="1994" thumb="/library/metadata/12345/thumb/1705317600" art="/library/metadata/12000/art/1705317600" parentThumb="/library/metadata/12300/thumb/1705317600" grandparentThumb="/library/metadata/12000/thumb/1705317600" grandparentArt="/library/metadata/12000/art/1705317600" duration="1380000" originallyAvailableAt="1994-09-22" addedAt="1705230400" updatedAt="1705317600" chapterSource="media" primaryExtraKey="/library/metadata/12346" ratingKey="12345" viewOffset="420000" skipCount="1">
|
||||
<Media id="67890" duration="1380000" bitrate="8137" width="1920" height="1080" aspectRatio="1.78" audioChannels="2" audioCodec="aac" videoCodec="h264" videoResolution="1080" container="mkv" videoFrameRate="24p" audioProfile="lc" videoProfile="high">
|
||||
<Part accessible="1" exists="1" id="98765" key="/library/parts/98765/1705317600/file.mkv" duration="1380000" file="/media/tv/Friends/Season 01/Friends - S01E01 - The One Where Monica Gets a Roommate.mkv" size="1398101419" audioProfile="lc" container="mkv" indexes="sd" videoProfile="high" />
|
||||
</Media>
|
||||
<User id="1" thumb="https://plex.tv/users/abc123def456/avatar?c=1705317600" title="John Doe" />
|
||||
<Player address="192.168.1.100" device="Chrome" machineIdentifier="browser-chrome-192-168-1-100" model="hosted" platform="Chrome" platformVersion="120" product="Plex Web" profile="Web" remotePublicAddress="203.0.113.1" state="playing" title="Chrome (John's Desktop)" userID="1" vendor="Google" version="4.126.1" />
|
||||
<Session id="session123abc" bandwidth="8000" location="lan" />
|
||||
</Video>
|
||||
<Video sessionKey="2" key="/library/metadata/54321" guid="plex://movie/5d9c086fe98e47001e0d5c4a" type="movie" title="The Matrix" titleSort="Matrix, The" contentRating="R" summary="A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers." rating="8.7" year="1999" tagline="The fight for the future begins" thumb="/library/metadata/54321/thumb/1705317600" art="/library/metadata/54321/art/1705317600" duration="8160000" originallyAvailableAt="1999-03-31" addedAt="1705144800" updatedAt="1705317600" chapterSource="media" ratingKey="54321" viewOffset="2100000">
|
||||
<Media id="11223" duration="8160000" bitrate="15463" width="1920" height="816" aspectRatio="2.35" audioChannels="6" audioCodec="dts" videoCodec="h264" videoResolution="1080" container="mkv" videoFrameRate="24p" audioProfile="dts" videoProfile="high">
|
||||
<Part accessible="1" exists="1" id="33445" key="/library/parts/33445/1705317600/file.mkv" duration="8160000" file="/media/movies/The Matrix (1999)/The Matrix (1999).mkv" size="15758698701" audioProfile="dts" container="mkv" indexes="sd" videoProfile="high" />
|
||||
</Media>
|
||||
<User id="2" thumb="https://plex.tv/users/def456ghi789/avatar?c=1705317600" title="Jane Smith" />
|
||||
<Player address="192.168.1.101" device="Android" machineIdentifier="android-phone-samsung" model="SM-G991B" platform="Android" platformVersion="14" product="Plex for Android" profile="Mobile" remotePublicAddress="203.0.113.2" state="paused" title="Samsung Galaxy S21" userID="2" vendor="Samsung" version="9.8.1" />
|
||||
<Session id="session456def" bandwidth="4000" location="lan" />
|
||||
</Video>
|
||||
</MediaContainer>
|
||||
94
dummy-data/portainer/api/endpoints
Normal file
94
dummy-data/portainer/api/endpoints
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
[
|
||||
{
|
||||
"Id": 1,
|
||||
"Name": "local",
|
||||
"Type": 1,
|
||||
"URL": "unix:///var/run/docker.sock",
|
||||
"GroupId": 1,
|
||||
"PublicURL": "",
|
||||
"Status": 1,
|
||||
"UserAccessPolicies": {},
|
||||
"TeamAccessPolicies": {},
|
||||
"Extensions": [],
|
||||
"TagIds": [],
|
||||
"AssociatedEndpoints": [],
|
||||
"Snapshots": [
|
||||
{
|
||||
"Time": 1705317600,
|
||||
"DockerVersion": "24.0.7",
|
||||
"Swarm": false,
|
||||
"TotalCPU": 8,
|
||||
"TotalMemory": 16777216000,
|
||||
"RunningContainerCount": 12,
|
||||
"StoppedContainerCount": 5,
|
||||
"HealthyContainerCount": 10,
|
||||
"UnhealthyContainerCount": 0,
|
||||
"VolumeCount": 25,
|
||||
"ImageCount": 47,
|
||||
"ServiceCount": 0,
|
||||
"StackCount": 0,
|
||||
"DockerRootDir": "/var/lib/docker"
|
||||
}
|
||||
],
|
||||
"Kubernetes": {
|
||||
"Snapshots": []
|
||||
},
|
||||
"Agent": {
|
||||
"NodeName": "",
|
||||
"ChecklnInterval": 5,
|
||||
"Version": ""
|
||||
},
|
||||
"Edge": {
|
||||
"AsyncMode": false,
|
||||
"PingInterval": 60,
|
||||
"CommandInterval": 5,
|
||||
"SnapshotInterval": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"Id": 2,
|
||||
"Name": "production",
|
||||
"Type": 2,
|
||||
"URL": "tcp://prod-docker:2376",
|
||||
"GroupId": 1,
|
||||
"PublicURL": "https://prod-docker.example.com",
|
||||
"Status": 1,
|
||||
"UserAccessPolicies": {},
|
||||
"TeamAccessPolicies": {},
|
||||
"Extensions": [],
|
||||
"TagIds": [],
|
||||
"AssociatedEndpoints": [],
|
||||
"Snapshots": [
|
||||
{
|
||||
"Time": 1705317600,
|
||||
"DockerVersion": "24.0.7",
|
||||
"Swarm": false,
|
||||
"TotalCPU": 16,
|
||||
"TotalMemory": 33554432000,
|
||||
"RunningContainerCount": 25,
|
||||
"StoppedContainerCount": 3,
|
||||
"HealthyContainerCount": 23,
|
||||
"UnhealthyContainerCount": 2,
|
||||
"VolumeCount": 40,
|
||||
"ImageCount": 75,
|
||||
"ServiceCount": 0,
|
||||
"StackCount": 0,
|
||||
"DockerRootDir": "/var/lib/docker"
|
||||
}
|
||||
],
|
||||
"Kubernetes": {
|
||||
"Snapshots": []
|
||||
},
|
||||
"Agent": {
|
||||
"NodeName": "",
|
||||
"ChecklnInterval": 5,
|
||||
"Version": ""
|
||||
},
|
||||
"Edge": {
|
||||
"AsyncMode": false,
|
||||
"PingInterval": 60,
|
||||
"CommandInterval": 5,
|
||||
"SnapshotInterval": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
94
dummy-data/portainer/api/endpoints.backup
Normal file
94
dummy-data/portainer/api/endpoints.backup
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
[
|
||||
{
|
||||
"Id": 1,
|
||||
"Name": "local",
|
||||
"Type": 1,
|
||||
"URL": "unix:///var/run/docker.sock",
|
||||
"GroupId": 1,
|
||||
"PublicURL": "",
|
||||
"Status": 1,
|
||||
"UserAccessPolicies": {},
|
||||
"TeamAccessPolicies": {},
|
||||
"Extensions": [],
|
||||
"TagIds": [],
|
||||
"AssociatedEndpoints": [],
|
||||
"Snapshots": [
|
||||
{
|
||||
"Time": 1705317600,
|
||||
"DockerVersion": "24.0.7",
|
||||
"Swarm": false,
|
||||
"TotalCPU": 8,
|
||||
"TotalMemory": 16777216000,
|
||||
"RunningContainerCount": 12,
|
||||
"StoppedContainerCount": 5,
|
||||
"HealthyContainerCount": 10,
|
||||
"UnhealthyContainerCount": 0,
|
||||
"VolumeCount": 25,
|
||||
"ImageCount": 47,
|
||||
"ServiceCount": 0,
|
||||
"StackCount": 0,
|
||||
"DockerRootDir": "/var/lib/docker"
|
||||
}
|
||||
],
|
||||
"Kubernetes": {
|
||||
"Snapshots": []
|
||||
},
|
||||
"Agent": {
|
||||
"NodeName": "",
|
||||
"ChecklnInterval": 5,
|
||||
"Version": ""
|
||||
},
|
||||
"Edge": {
|
||||
"AsyncMode": false,
|
||||
"PingInterval": 60,
|
||||
"CommandInterval": 5,
|
||||
"SnapshotInterval": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"Id": 2,
|
||||
"Name": "production",
|
||||
"Type": 2,
|
||||
"URL": "tcp://prod-docker:2376",
|
||||
"GroupId": 1,
|
||||
"PublicURL": "https://prod-docker.example.com",
|
||||
"Status": 1,
|
||||
"UserAccessPolicies": {},
|
||||
"TeamAccessPolicies": {},
|
||||
"Extensions": [],
|
||||
"TagIds": [],
|
||||
"AssociatedEndpoints": [],
|
||||
"Snapshots": [
|
||||
{
|
||||
"Time": 1705317600,
|
||||
"DockerVersion": "24.0.7",
|
||||
"Swarm": false,
|
||||
"TotalCPU": 16,
|
||||
"TotalMemory": 33554432000,
|
||||
"RunningContainerCount": 25,
|
||||
"StoppedContainerCount": 3,
|
||||
"HealthyContainerCount": 23,
|
||||
"UnhealthyContainerCount": 2,
|
||||
"VolumeCount": 40,
|
||||
"ImageCount": 75,
|
||||
"ServiceCount": 0,
|
||||
"StackCount": 0,
|
||||
"DockerRootDir": "/var/lib/docker"
|
||||
}
|
||||
],
|
||||
"Kubernetes": {
|
||||
"Snapshots": []
|
||||
},
|
||||
"Agent": {
|
||||
"NodeName": "",
|
||||
"ChecklnInterval": 5,
|
||||
"Version": ""
|
||||
},
|
||||
"Edge": {
|
||||
"AsyncMode": false,
|
||||
"PingInterval": 60,
|
||||
"CommandInterval": 5,
|
||||
"SnapshotInterval": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
38
dummy-data/portainer/api/status
Normal file
38
dummy-data/portainer/api/status
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"Version": "2.19.4",
|
||||
"APIVersion": "2.19.4",
|
||||
"DatabaseVersion": "34",
|
||||
"Build": {
|
||||
"BuildNumber": "1234567890",
|
||||
"ImageTag": "2.19.4-alpine",
|
||||
"NodejsVersion": "v18.17.1",
|
||||
"YarnVersion": "1.22.19",
|
||||
"WebpackVersion": "5.88.2",
|
||||
"GoVersion": "go1.21.5"
|
||||
},
|
||||
"InstanceID": "portainer-instance-abc123def456",
|
||||
"Edition": "CE",
|
||||
"DemoEnvironment": {
|
||||
"Enabled": false,
|
||||
"URL": ""
|
||||
},
|
||||
"AnalyticsEnabled": false,
|
||||
"AuthenticationMethod": 1,
|
||||
"Users": 3,
|
||||
"ValidLicense": false,
|
||||
"LicenseInfo": {
|
||||
"Company": "",
|
||||
"CreatedAt": 0,
|
||||
"ExpiresAt": 0,
|
||||
"LicenseKey": "",
|
||||
"ProductEdition": "",
|
||||
"Seats": 0,
|
||||
"Valid": false
|
||||
},
|
||||
"RequiredPasswordLength": 12,
|
||||
"UserSessionTimeout": "8h",
|
||||
"Features": {
|
||||
"EdgeDeviceUntrustedMode": false
|
||||
},
|
||||
"EdgeAgentCheckinIntervalSeconds": 5
|
||||
}
|
||||
99
dummy-data/prometheus/api/v1/alerts
Normal file
99
dummy-data/prometheus/api/v1/alerts
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"alerts": [
|
||||
{
|
||||
"labels": {
|
||||
"alertname": "HighCPUUsage",
|
||||
"instance": "localhost:9090",
|
||||
"job": "prometheus",
|
||||
"severity": "warning"
|
||||
},
|
||||
"annotations": {
|
||||
"description": "CPU usage is above 80% for more than 5 minutes",
|
||||
"summary": "High CPU usage detected"
|
||||
},
|
||||
"state": "firing",
|
||||
"activeAt": "2024-01-15T10:30:00.000Z",
|
||||
"value": "85.2"
|
||||
},
|
||||
{
|
||||
"labels": {
|
||||
"alertname": "HighMemoryUsage",
|
||||
"instance": "web-server-01:9090",
|
||||
"job": "node-exporter",
|
||||
"severity": "critical"
|
||||
},
|
||||
"annotations": {
|
||||
"description": "Memory usage is above 90% for more than 10 minutes",
|
||||
"summary": "Critical memory usage detected"
|
||||
},
|
||||
"state": "firing",
|
||||
"activeAt": "2024-01-15T10:25:00.000Z",
|
||||
"value": "92.8"
|
||||
},
|
||||
{
|
||||
"labels": {
|
||||
"alertname": "DiskSpaceLow",
|
||||
"instance": "db-server-01:9090",
|
||||
"job": "node-exporter",
|
||||
"severity": "warning",
|
||||
"device": "/dev/sda1"
|
||||
},
|
||||
"annotations": {
|
||||
"description": "Disk space is below 20% on {{ $labels.device }}",
|
||||
"summary": "Low disk space warning"
|
||||
},
|
||||
"state": "pending",
|
||||
"activeAt": "2024-01-15T11:00:00.000Z",
|
||||
"value": "18.5"
|
||||
},
|
||||
{
|
||||
"labels": {
|
||||
"alertname": "ServiceDown",
|
||||
"instance": "api-server-02:8080",
|
||||
"job": "api-health-check",
|
||||
"severity": "critical",
|
||||
"service": "user-api"
|
||||
},
|
||||
"annotations": {
|
||||
"description": "Service {{ $labels.service }} is not responding",
|
||||
"summary": "Service is down"
|
||||
},
|
||||
"state": "pending",
|
||||
"activeAt": "2024-01-15T11:10:00.000Z",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"labels": {
|
||||
"alertname": "DatabaseConnections",
|
||||
"instance": "db-server-01:5432",
|
||||
"job": "postgres-exporter",
|
||||
"severity": "info"
|
||||
},
|
||||
"annotations": {
|
||||
"description": "Database connection count is normal",
|
||||
"summary": "Database connections stable"
|
||||
},
|
||||
"state": "inactive",
|
||||
"activeAt": "2024-01-15T09:00:00.000Z",
|
||||
"value": "45"
|
||||
},
|
||||
{
|
||||
"labels": {
|
||||
"alertname": "HTTPResponseTime",
|
||||
"instance": "web-server-02:80",
|
||||
"job": "blackbox-exporter",
|
||||
"severity": "info"
|
||||
},
|
||||
"annotations": {
|
||||
"description": "HTTP response time is within acceptable limits",
|
||||
"summary": "Response time normal"
|
||||
},
|
||||
"state": "inactive",
|
||||
"activeAt": "2024-01-15T08:30:00.000Z",
|
||||
"value": "150"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
41
dummy-data/prowlarr/api/v1/health
Normal file
41
dummy-data/prowlarr/api/v1/health
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
[
|
||||
{
|
||||
"source": "IndexerStatusCheck",
|
||||
"type": "warning",
|
||||
"message": "Indexer 1337x has been disabled due to recent failures: Connection timeout after 30 seconds",
|
||||
"wikiUrl": "https://wiki.servarr.com/prowlarr/health#indexers-are-unavailable-due-to-recent-failures"
|
||||
},
|
||||
{
|
||||
"source": "IndexerRSSCheck",
|
||||
"type": "ok",
|
||||
"message": "All indexer RSS feeds are functioning normally"
|
||||
},
|
||||
{
|
||||
"source": "ApplicationStatusCheck",
|
||||
"type": "warning",
|
||||
"message": "Application Sonarr sync failed: Unable to connect to Sonarr at http://sonarr:8989",
|
||||
"wikiUrl": "https://wiki.servarr.com/prowlarr/health#applications-are-unavailable-due-to-recent-failures"
|
||||
},
|
||||
{
|
||||
"source": "UpdateCheck",
|
||||
"type": "ok",
|
||||
"message": "Update available: 1.11.4.4173 -> 1.12.2.4211"
|
||||
},
|
||||
{
|
||||
"source": "IndexerSearchCheck",
|
||||
"type": "error",
|
||||
"message": "Indexer TorrentLeech returned invalid search results: Malformed JSON response",
|
||||
"wikiUrl": "https://wiki.servarr.com/prowlarr/health#indexer-search-failures"
|
||||
},
|
||||
{
|
||||
"source": "ProxyCheck",
|
||||
"type": "ok",
|
||||
"message": "No proxy configuration issues detected"
|
||||
},
|
||||
{
|
||||
"source": "IndexerLongTermStatusCheck",
|
||||
"type": "warning",
|
||||
"message": "Indexer RARBG has been failing for more than 6 hours: HTTP 403 Forbidden",
|
||||
"wikiUrl": "https://wiki.servarr.com/prowlarr/health#indexers-are-unavailable-due-to-recent-failures"
|
||||
}
|
||||
]
|
||||
35
dummy-data/radarr/api/v3/health
Normal file
35
dummy-data/radarr/api/v3/health
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
[
|
||||
{
|
||||
"source": "IndexerStatusCheck",
|
||||
"type": "warning",
|
||||
"message": "Indexer TorrentDay is unavailable due to recent indexer errors: HTTP 503 Service Unavailable",
|
||||
"wikiUrl": "https://wiki.servarr.com/radarr/health#indexers-are-unavailable-due-to-recent-failures"
|
||||
},
|
||||
{
|
||||
"source": "ImportMechanismCheck",
|
||||
"type": "ok",
|
||||
"message": "No issues with import mechanism checks"
|
||||
},
|
||||
{
|
||||
"source": "DownloadClientStatusCheck",
|
||||
"type": "ok",
|
||||
"message": "All download clients are available"
|
||||
},
|
||||
{
|
||||
"source": "RootFolderCheck",
|
||||
"type": "warning",
|
||||
"message": "Missing root folder: /movies",
|
||||
"wikiUrl": "https://wiki.servarr.com/radarr/health#missing-root-folder"
|
||||
},
|
||||
{
|
||||
"source": "UpdateCheck",
|
||||
"type": "ok",
|
||||
"message": "Update available: 4.7.5.7809 -> 5.0.3.8127"
|
||||
},
|
||||
{
|
||||
"source": "DiskSpaceCheck",
|
||||
"type": "error",
|
||||
"message": "Disk space is critically low on /movies: 2.1 GB remaining",
|
||||
"wikiUrl": "https://wiki.servarr.com/radarr/health#disk-space"
|
||||
}
|
||||
]
|
||||
8
dummy-data/radarr/api/v3/queue
Normal file
8
dummy-data/radarr/api/v3/queue
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"page": 1,
|
||||
"pageSize": 20,
|
||||
"sortKey": "progress",
|
||||
"sortDirection": "descending",
|
||||
"totalRecords": 2,
|
||||
"records": []
|
||||
}
|
||||
16
dummy-data/radarr/api/v3/queuedetails
Normal file
16
dummy-data/radarr/api/v3/queuedetails
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
{
|
||||
"movieId": 1,
|
||||
"title": "Inception (2010)",
|
||||
"trackedDownloadStatus": "ok",
|
||||
"trackedDownloadState": "importPending",
|
||||
"id": 1
|
||||
},
|
||||
{
|
||||
"movieId": 2,
|
||||
"title": "The Matrix (1999)",
|
||||
"trackedDownloadStatus": "warning",
|
||||
"trackedDownloadState": "downloading",
|
||||
"id": 2
|
||||
}
|
||||
]
|
||||
161
dummy-data/radarr/api/v3/wanted/missing
Normal file
161
dummy-data/radarr/api/v3/wanted/missing
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
{
|
||||
"page": 1,
|
||||
"pageSize": 20,
|
||||
"sortKey": "digitalRelease",
|
||||
"sortDirection": "descending",
|
||||
"totalRecords": 5,
|
||||
"records": [
|
||||
{
|
||||
"title": "Dune: Part Two",
|
||||
"originalTitle": "Dune: Part Two",
|
||||
"originalLanguage": {
|
||||
"id": 1,
|
||||
"name": "English"
|
||||
},
|
||||
"alternateTitles": [],
|
||||
"secondaryYear": null,
|
||||
"secondaryYearSourceId": 0,
|
||||
"sortTitle": "dune part two",
|
||||
"sizeOnDisk": 0,
|
||||
"status": "released",
|
||||
"overview": "Follow the mythic journey of Paul Atreides as he unites with Chani and the Fremen while on a path of revenge against the conspirators who destroyed his family.",
|
||||
"inCinemas": "2024-02-29T00:00:00Z",
|
||||
"physicalRelease": "2024-05-14T00:00:00Z",
|
||||
"digitalRelease": "2024-04-16T00:00:00Z",
|
||||
"images": [],
|
||||
"website": "",
|
||||
"remotePoster": "",
|
||||
"year": 2024,
|
||||
"hasFile": false,
|
||||
"youTubeTrailerId": "",
|
||||
"studio": "Warner Bros. Pictures",
|
||||
"path": "/movies/Dune Part Two (2024)",
|
||||
"qualityProfileId": 1,
|
||||
"monitored": true,
|
||||
"minimumAvailability": "announced",
|
||||
"isAvailable": true,
|
||||
"folderName": "Dune Part Two (2024)",
|
||||
"runtime": 166,
|
||||
"cleanTitle": "duneparttwo",
|
||||
"imdbId": "tt15239678",
|
||||
"tmdbId": 693134,
|
||||
"titleSlug": "dune-part-two-2024",
|
||||
"certification": "PG-13",
|
||||
"genres": ["Adventure", "Drama", "Science Fiction"],
|
||||
"tags": [],
|
||||
"added": "2024-01-10T00:00:00Z",
|
||||
"ratings": {
|
||||
"votes": 234567,
|
||||
"value": 8.9
|
||||
},
|
||||
"movieFile": null,
|
||||
"collection": {
|
||||
"name": "Dune Collection",
|
||||
"tmdbId": 726871,
|
||||
"images": []
|
||||
},
|
||||
"popularity": 89.245,
|
||||
"id": 3
|
||||
},
|
||||
{
|
||||
"title": "Oppenheimer",
|
||||
"originalTitle": "Oppenheimer",
|
||||
"originalLanguage": {
|
||||
"id": 1,
|
||||
"name": "English"
|
||||
},
|
||||
"alternateTitles": [],
|
||||
"secondaryYear": null,
|
||||
"secondaryYearSourceId": 0,
|
||||
"sortTitle": "oppenheimer",
|
||||
"sizeOnDisk": 0,
|
||||
"status": "released",
|
||||
"overview": "The story of J. Robert Oppenheimer's role in the development of the atomic bomb during World War II.",
|
||||
"inCinemas": "2023-07-21T00:00:00Z",
|
||||
"physicalRelease": "2023-11-21T00:00:00Z",
|
||||
"digitalRelease": "2023-10-31T00:00:00Z",
|
||||
"images": [],
|
||||
"website": "",
|
||||
"remotePoster": "",
|
||||
"year": 2023,
|
||||
"hasFile": false,
|
||||
"youTubeTrailerId": "",
|
||||
"studio": "Universal Pictures",
|
||||
"path": "/movies/Oppenheimer (2023)",
|
||||
"qualityProfileId": 1,
|
||||
"monitored": true,
|
||||
"minimumAvailability": "announced",
|
||||
"isAvailable": true,
|
||||
"folderName": "Oppenheimer (2023)",
|
||||
"runtime": 180,
|
||||
"cleanTitle": "oppenheimer",
|
||||
"imdbId": "tt15398776",
|
||||
"tmdbId": 872585,
|
||||
"titleSlug": "oppenheimer-2023",
|
||||
"certification": "R",
|
||||
"genres": ["Drama", "History"],
|
||||
"tags": [],
|
||||
"added": "2024-01-05T00:00:00Z",
|
||||
"ratings": {
|
||||
"votes": 456789,
|
||||
"value": 8.4
|
||||
},
|
||||
"movieFile": null,
|
||||
"collection": null,
|
||||
"popularity": 92.567,
|
||||
"id": 4
|
||||
},
|
||||
{
|
||||
"title": "Spider-Man: Across the Spider-Verse",
|
||||
"originalTitle": "Spider-Man: Across the Spider-Verse",
|
||||
"originalLanguage": {
|
||||
"id": 1,
|
||||
"name": "English"
|
||||
},
|
||||
"alternateTitles": [],
|
||||
"secondaryYear": null,
|
||||
"secondaryYearSourceId": 0,
|
||||
"sortTitle": "spider man across spider verse",
|
||||
"sizeOnDisk": 0,
|
||||
"status": "released",
|
||||
"overview": "After reuniting with Gwen Stacy, Brooklyn's full-time, friendly neighborhood Spider-Man is catapulted across the Multiverse, where he encounters the Spider-Society.",
|
||||
"inCinemas": "2023-06-02T00:00:00Z",
|
||||
"physicalRelease": "2023-09-05T00:00:00Z",
|
||||
"digitalRelease": "2023-08-08T00:00:00Z",
|
||||
"images": [],
|
||||
"website": "",
|
||||
"remotePoster": "",
|
||||
"year": 2023,
|
||||
"hasFile": false,
|
||||
"youTubeTrailerId": "",
|
||||
"studio": "Sony Pictures Animation",
|
||||
"path": "/movies/Spider-Man Across the Spider-Verse (2023)",
|
||||
"qualityProfileId": 2,
|
||||
"monitored": true,
|
||||
"minimumAvailability": "announced",
|
||||
"isAvailable": true,
|
||||
"folderName": "Spider-Man Across the Spider-Verse (2023)",
|
||||
"runtime": 140,
|
||||
"cleanTitle": "spidermanacrossthespiderverse",
|
||||
"imdbId": "tt9362722",
|
||||
"tmdbId": 569094,
|
||||
"titleSlug": "spider-man-across-the-spider-verse-2023",
|
||||
"certification": "PG",
|
||||
"genres": ["Animation", "Action", "Adventure"],
|
||||
"tags": [],
|
||||
"added": "2024-01-03T00:00:00Z",
|
||||
"ratings": {
|
||||
"votes": 345678,
|
||||
"value": 8.7
|
||||
},
|
||||
"movieFile": null,
|
||||
"collection": {
|
||||
"name": "Spider-Verse Collection",
|
||||
"tmdbId": 573436,
|
||||
"images": []
|
||||
},
|
||||
"popularity": 85.432,
|
||||
"id": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
97
dummy-data/sabnzbd/api
Normal file
97
dummy-data/sabnzbd/api
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
{
|
||||
"queue": {
|
||||
"version": "4.1.0",
|
||||
"paused": false,
|
||||
"pause_int": "0",
|
||||
"paused_all": false,
|
||||
"diskspace1": "465.47",
|
||||
"diskspace2": "465.47",
|
||||
"diskspacetotal1": "931.51",
|
||||
"diskspacetotal2": "931.51",
|
||||
"speedlimit": "",
|
||||
"speedlimit_abs": "",
|
||||
"have_warnings": "0",
|
||||
"finishaction": null,
|
||||
"quota": "",
|
||||
"left_quota": "0 ",
|
||||
"cache_art": "0",
|
||||
"cache_size": "0 B",
|
||||
"kbpersec": "8547.82",
|
||||
"speed": "8.35",
|
||||
"mbleft": "2847.93",
|
||||
"mb": "2847.93",
|
||||
"noofslots": 3,
|
||||
"noofslots_total": 8,
|
||||
"status": "Downloading",
|
||||
"timeleft": "0:05:41",
|
||||
"eta": "22:15:41",
|
||||
"slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"nzo_id": "SABnzbd_nzo_abc123",
|
||||
"unpackopts": "3",
|
||||
"priority": "Normal",
|
||||
"script": "None",
|
||||
"filename": "Ubuntu.22.04.3.Desktop.amd64.iso",
|
||||
"labels": [],
|
||||
"password": "",
|
||||
"cat": "software",
|
||||
"mbleft": "1847.52",
|
||||
"mb": "1847.52",
|
||||
"size": "1.8 GB",
|
||||
"sizeleft": "1.8 GB",
|
||||
"percentage": "0",
|
||||
"mbmissing": "0.00",
|
||||
"direct_unpack": "0",
|
||||
"status": "Downloading",
|
||||
"timeleft": "0:03:41",
|
||||
"eta": "unknown",
|
||||
"avg_age": "4d"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"nzo_id": "SABnzbd_nzo_def456",
|
||||
"unpackopts": "3",
|
||||
"priority": "High",
|
||||
"script": "None",
|
||||
"filename": "Movie.Collection.2023.1080p.BluRay.x264",
|
||||
"labels": ["movie"],
|
||||
"password": "",
|
||||
"cat": "movies",
|
||||
"mbleft": "756.41",
|
||||
"mb": "756.41",
|
||||
"size": "756.4 MB",
|
||||
"sizeleft": "756.4 MB",
|
||||
"percentage": "12",
|
||||
"mbmissing": "0.00",
|
||||
"direct_unpack": "0",
|
||||
"status": "Downloading",
|
||||
"timeleft": "0:01:35",
|
||||
"eta": "unknown",
|
||||
"avg_age": "1d"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"nzo_id": "SABnzbd_nzo_ghi789",
|
||||
"unpackopts": "3",
|
||||
"priority": "Normal",
|
||||
"script": "cleanup.py",
|
||||
"filename": "TV.Show.S05E08.1080p.WEB.H264-GROUP",
|
||||
"labels": ["tv"],
|
||||
"password": "",
|
||||
"cat": "tv",
|
||||
"mbleft": "244.00",
|
||||
"mb": "244.00",
|
||||
"size": "244.0 MB",
|
||||
"sizeleft": "244.0 MB",
|
||||
"percentage": "65",
|
||||
"mbmissing": "0.00",
|
||||
"direct_unpack": "1",
|
||||
"status": "Downloading",
|
||||
"timeleft": "0:00:25",
|
||||
"eta": "unknown",
|
||||
"avg_age": "12h"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
162
dummy-data/scrutiny/api/summary
Normal file
162
dummy-data/scrutiny/api/summary
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"summary": {
|
||||
"0x5000cca264eb01d7": {
|
||||
"device": {
|
||||
"wwn": "0x5000cca264eb01d7",
|
||||
"device_name": "Samsung SSD 980 1TB",
|
||||
"device_uuid": "WWN-0x5000cca264eb01d7",
|
||||
"device_serial_id": "S64HNE0T123456A",
|
||||
"device_label": "",
|
||||
"manufacture": "Samsung",
|
||||
"model_name": "Samsung SSD 980 1TB",
|
||||
"interface_type": "nvme",
|
||||
"interface_speed": "",
|
||||
"serial_number": "S64HNE0T123456A",
|
||||
"firmware": "2B4QGXA7",
|
||||
"rotational_speed": 0,
|
||||
"capacity": 1000204886016,
|
||||
"form_factor": "",
|
||||
"smart_support": true,
|
||||
"device_protocol": "NVMe",
|
||||
"device_type": "",
|
||||
"device_status": 0,
|
||||
"created_at": "2024-01-15T10:30:00Z",
|
||||
"updated_at": "2024-01-15T11:45:00Z",
|
||||
"deleted_at": null
|
||||
},
|
||||
"smart": {
|
||||
"collector_date": "2024-01-15T11:45:00Z",
|
||||
"temp": 35,
|
||||
"power_on_hours": 2847,
|
||||
"power_cycle_count": 1247
|
||||
}
|
||||
},
|
||||
"0x5000cca264eb01d8": {
|
||||
"device": {
|
||||
"wwn": "0x5000cca264eb01d8",
|
||||
"device_name": "Western Digital WD Blue 2TB",
|
||||
"device_uuid": "WWN-0x5000cca264eb01d8",
|
||||
"device_serial_id": "WD-WCC4N7DS2468",
|
||||
"device_label": "",
|
||||
"manufacture": "Western Digital",
|
||||
"model_name": "WDC WD20EZAZ-00GXCB0",
|
||||
"interface_type": "ata",
|
||||
"interface_speed": "",
|
||||
"serial_number": "WD-WCC4N7DS2468",
|
||||
"firmware": "80.00A80",
|
||||
"rotational_speed": 5400,
|
||||
"capacity": 2000398934016,
|
||||
"form_factor": "",
|
||||
"smart_support": true,
|
||||
"device_protocol": "ATA",
|
||||
"device_type": "",
|
||||
"device_status": 0,
|
||||
"created_at": "2024-01-15T10:30:00Z",
|
||||
"updated_at": "2024-01-15T11:45:00Z",
|
||||
"deleted_at": null
|
||||
},
|
||||
"smart": {
|
||||
"collector_date": "2024-01-15T11:45:00Z",
|
||||
"temp": 41,
|
||||
"power_on_hours": 8942,
|
||||
"power_cycle_count": 892
|
||||
}
|
||||
},
|
||||
"0x500a0751e6b8a7c3": {
|
||||
"device": {
|
||||
"wwn": "0x500a0751e6b8a7c3",
|
||||
"device_name": "Seagate Barracuda 4TB",
|
||||
"device_uuid": "WWN-0x500a0751e6b8a7c3",
|
||||
"device_serial_id": "ST4000DM004-2CV104",
|
||||
"device_label": "",
|
||||
"manufacture": "Seagate",
|
||||
"model_name": "ST4000DM004-2CV104",
|
||||
"interface_type": "ata",
|
||||
"interface_speed": "",
|
||||
"serial_number": "ZFN123AB",
|
||||
"firmware": "0001",
|
||||
"rotational_speed": 5400,
|
||||
"capacity": 4000787030016,
|
||||
"form_factor": "",
|
||||
"smart_support": true,
|
||||
"device_protocol": "ATA",
|
||||
"device_type": "",
|
||||
"device_status": 2,
|
||||
"created_at": "2024-01-15T10:30:00Z",
|
||||
"updated_at": "2024-01-15T11:45:00Z",
|
||||
"deleted_at": null
|
||||
},
|
||||
"smart": {
|
||||
"collector_date": "2024-01-15T11:45:00Z",
|
||||
"temp": 47,
|
||||
"power_on_hours": 12456,
|
||||
"power_cycle_count": 456
|
||||
}
|
||||
},
|
||||
"0x5000cca264eb01d9": {
|
||||
"device": {
|
||||
"wwn": "0x5000cca264eb01d9",
|
||||
"device_name": "Kingston NV2 500GB",
|
||||
"device_uuid": "WWN-0x5000cca264eb01d9",
|
||||
"device_serial_id": "50026B7784123456",
|
||||
"device_label": "",
|
||||
"manufacture": "Kingston",
|
||||
"model_name": "KINGSTON SNV2S500G",
|
||||
"interface_type": "nvme",
|
||||
"interface_speed": "",
|
||||
"serial_number": "50026B7784123456",
|
||||
"firmware": "SNV2S2.1.0",
|
||||
"rotational_speed": 0,
|
||||
"capacity": 500107862016,
|
||||
"form_factor": "",
|
||||
"smart_support": true,
|
||||
"device_protocol": "NVMe",
|
||||
"device_type": "",
|
||||
"device_status": 4,
|
||||
"created_at": "2024-01-15T10:30:00Z",
|
||||
"updated_at": "2024-01-15T11:45:00Z",
|
||||
"deleted_at": null
|
||||
},
|
||||
"smart": {
|
||||
"collector_date": "2024-01-15T11:45:00Z",
|
||||
"temp": 52,
|
||||
"power_on_hours": 1247,
|
||||
"power_cycle_count": 89
|
||||
}
|
||||
},
|
||||
"0x5000cca264eb01da": {
|
||||
"device": {
|
||||
"wwn": "0x5000cca264eb01da",
|
||||
"device_name": "Crucial MX500 1TB",
|
||||
"device_uuid": "WWN-0x5000cca264eb01da",
|
||||
"device_serial_id": "194251A12345",
|
||||
"device_label": "",
|
||||
"manufacture": "Crucial",
|
||||
"model_name": "CT1000MX500SSD1",
|
||||
"interface_type": "ata",
|
||||
"interface_speed": "",
|
||||
"serial_number": "194251A12345",
|
||||
"firmware": "M3CR033",
|
||||
"rotational_speed": 0,
|
||||
"capacity": 1000204886016,
|
||||
"form_factor": "",
|
||||
"smart_support": true,
|
||||
"device_protocol": "ATA",
|
||||
"device_type": "",
|
||||
"device_status": 0,
|
||||
"created_at": "2024-01-15T10:30:00Z",
|
||||
"updated_at": "2024-01-15T11:45:00Z",
|
||||
"deleted_at": null
|
||||
},
|
||||
"smart": {
|
||||
"collector_date": "2024-01-15T11:45:00Z",
|
||||
"temp": 39,
|
||||
"power_on_hours": 5642,
|
||||
"power_cycle_count": 1089
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
dummy-data/sonarr/api/v3/health
Normal file
29
dummy-data/sonarr/api/v3/health
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
[
|
||||
{
|
||||
"source": "IndexerStatusCheck",
|
||||
"type": "warning",
|
||||
"message": "Indexer MyIndexer is unavailable due to recent indexer errors: Request timeout",
|
||||
"wikiUrl": "https://wiki.servarr.com/sonarr/health#indexers-are-unavailable-due-to-recent-failures"
|
||||
},
|
||||
{
|
||||
"source": "ImportMechanismCheck",
|
||||
"type": "ok",
|
||||
"message": "No issues with import mechanism checks"
|
||||
},
|
||||
{
|
||||
"source": "DownloadClientStatusCheck",
|
||||
"type": "ok",
|
||||
"message": "All download clients are available"
|
||||
},
|
||||
{
|
||||
"source": "RootFolderCheck",
|
||||
"type": "warning",
|
||||
"message": "Missing root folder: /media/tv",
|
||||
"wikiUrl": "https://wiki.servarr.com/sonarr/health#missing-root-folder"
|
||||
},
|
||||
{
|
||||
"source": "UpdateCheck",
|
||||
"type": "ok",
|
||||
"message": "Update available: 3.0.10.1567 -> 4.0.1.929"
|
||||
}
|
||||
]
|
||||
77
dummy-data/sonarr/api/v3/queue
Normal file
77
dummy-data/sonarr/api/v3/queue
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"page": 1,
|
||||
"pageSize": 20,
|
||||
"sortKey": "progress",
|
||||
"sortDirection": "descending",
|
||||
"totalRecords": 3,
|
||||
"records": [
|
||||
{
|
||||
"seriesId": 1,
|
||||
"episodeId": 12345,
|
||||
"seasonNumber": 5,
|
||||
"episodeNumber": 8,
|
||||
"title": "The Office S05E08 - Business Trip",
|
||||
"size": 1073741824,
|
||||
"sizeleft": 0,
|
||||
"timeleft": "00:00:00",
|
||||
"estimatedCompletionTime": "2024-01-15T10:30:00Z",
|
||||
"status": "completed",
|
||||
"trackedDownloadStatus": "ok",
|
||||
"trackedDownloadState": "importPending",
|
||||
"statusMessages": [],
|
||||
"downloadId": "download123abc",
|
||||
"protocol": "torrent",
|
||||
"downloadClient": "qBittorrent",
|
||||
"indexer": "Prowlarr",
|
||||
"outputPath": "/downloads/complete/The.Office.US.S05E08.720p.WEB.x264-GROUP",
|
||||
"id": 1
|
||||
},
|
||||
{
|
||||
"seriesId": 2,
|
||||
"episodeId": 67890,
|
||||
"seasonNumber": 3,
|
||||
"episodeNumber": 15,
|
||||
"title": "Breaking Bad S03E15 - Half Measures",
|
||||
"size": 2147483648,
|
||||
"sizeleft": 536870912,
|
||||
"timeleft": "00:15:23",
|
||||
"estimatedCompletionTime": "2024-01-15T10:45:23Z",
|
||||
"status": "downloading",
|
||||
"trackedDownloadStatus": "ok",
|
||||
"trackedDownloadState": "downloading",
|
||||
"statusMessages": [],
|
||||
"downloadId": "download456def",
|
||||
"protocol": "torrent",
|
||||
"downloadClient": "qBittorrent",
|
||||
"indexer": "Prowlarr",
|
||||
"outputPath": "/downloads/incomplete/Breaking.Bad.S03E15.1080p.BluRay.x264-GROUP",
|
||||
"id": 2
|
||||
},
|
||||
{
|
||||
"seriesId": 3,
|
||||
"episodeId": 11121,
|
||||
"seasonNumber": 1,
|
||||
"episodeNumber": 3,
|
||||
"title": "Better Call Saul S01E03 - Nacho",
|
||||
"size": 1610612736,
|
||||
"sizeleft": 1073741824,
|
||||
"timeleft": "01:24:15",
|
||||
"estimatedCompletionTime": "2024-01-15T12:09:15Z",
|
||||
"status": "downloading",
|
||||
"trackedDownloadStatus": "warning",
|
||||
"trackedDownloadState": "downloading",
|
||||
"statusMessages": [
|
||||
{
|
||||
"title": "Slow Download Speed",
|
||||
"messages": ["Download speed is below expected threshold"]
|
||||
}
|
||||
],
|
||||
"downloadId": "download789ghi",
|
||||
"protocol": "usenet",
|
||||
"downloadClient": "SABnzbd",
|
||||
"indexer": "NZBgeek",
|
||||
"outputPath": "/downloads/incomplete/Better.Call.Saul.S01E03.720p.WEB.x264-GROUP",
|
||||
"id": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
129
dummy-data/sonarr/api/v3/wanted/missing
Normal file
129
dummy-data/sonarr/api/v3/wanted/missing
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
{
|
||||
"page": 1,
|
||||
"pageSize": 20,
|
||||
"sortKey": "airDateUtc",
|
||||
"sortDirection": "descending",
|
||||
"totalRecords": 15,
|
||||
"records": [
|
||||
{
|
||||
"seriesId": 1,
|
||||
"tvdbId": 73244,
|
||||
"seasonNumber": 9,
|
||||
"episodeNumber": 23,
|
||||
"title": "Finale",
|
||||
"airDate": "2013-05-16",
|
||||
"airDateUtc": "2013-05-17T01:00:00Z",
|
||||
"overview": "One year later, Dunder Mifflin Scranton has thrived, but Jim and Pam are looking to a move to Philadelphia.",
|
||||
"episodeFile": null,
|
||||
"hasFile": false,
|
||||
"monitored": true,
|
||||
"absoluteEpisodeNumber": 201,
|
||||
"series": {
|
||||
"title": "The Office (US)",
|
||||
"sortTitle": "office us",
|
||||
"seasonCount": 9,
|
||||
"status": "ended",
|
||||
"overview": "A mockumentary about a group of typical office workers.",
|
||||
"network": "NBC",
|
||||
"airTime": "21:00",
|
||||
"images": [],
|
||||
"seasons": [],
|
||||
"year": 2005,
|
||||
"path": "/media/tv/The Office (US)",
|
||||
"qualityProfileId": 1,
|
||||
"languageProfileId": 1,
|
||||
"seasonFolder": true,
|
||||
"monitored": true,
|
||||
"useSceneNumbering": false,
|
||||
"runtime": 22,
|
||||
"tvdbId": 73244,
|
||||
"tvRageId": 6061,
|
||||
"tvMazeId": 526,
|
||||
"firstAired": "2005-03-24T00:00:00Z",
|
||||
"lastInfoSync": "2024-01-15T09:00:00Z",
|
||||
"seriesType": "standard",
|
||||
"cleanTitle": "theoffice",
|
||||
"imdbId": "tt0386676",
|
||||
"titleSlug": "the-office-us",
|
||||
"certification": "TV-14",
|
||||
"genres": ["Comedy"],
|
||||
"tags": [],
|
||||
"added": "2024-01-01T00:00:00Z",
|
||||
"ratings": {
|
||||
"votes": 654321,
|
||||
"value": 8.9
|
||||
},
|
||||
"statistics": {
|
||||
"seasonCount": 9,
|
||||
"episodeFileCount": 200,
|
||||
"episodeCount": 201,
|
||||
"totalEpisodeCount": 201,
|
||||
"sizeOnDisk": 107374182400,
|
||||
"percentOfEpisodes": 99.5
|
||||
},
|
||||
"id": 1
|
||||
},
|
||||
"id": 4567
|
||||
},
|
||||
{
|
||||
"seriesId": 2,
|
||||
"tvdbId": 81189,
|
||||
"seasonNumber": 5,
|
||||
"episodeNumber": 16,
|
||||
"title": "Felina",
|
||||
"airDate": "2013-09-29",
|
||||
"airDateUtc": "2013-09-30T01:00:00Z",
|
||||
"overview": "Walt's final confrontation with his past mistakes leads to a climactic conclusion.",
|
||||
"episodeFile": null,
|
||||
"hasFile": false,
|
||||
"monitored": true,
|
||||
"absoluteEpisodeNumber": 62,
|
||||
"series": {
|
||||
"title": "Breaking Bad",
|
||||
"sortTitle": "breaking bad",
|
||||
"seasonCount": 5,
|
||||
"status": "ended",
|
||||
"overview": "A high school chemistry teacher turned methamphetamine manufacturer.",
|
||||
"network": "AMC",
|
||||
"airTime": "21:00",
|
||||
"images": [],
|
||||
"seasons": [],
|
||||
"year": 2008,
|
||||
"path": "/media/tv/Breaking Bad",
|
||||
"qualityProfileId": 1,
|
||||
"languageProfileId": 1,
|
||||
"seasonFolder": true,
|
||||
"monitored": true,
|
||||
"useSceneNumbering": false,
|
||||
"runtime": 47,
|
||||
"tvdbId": 81189,
|
||||
"tvRageId": 18164,
|
||||
"tvMazeId": 169,
|
||||
"firstAired": "2008-01-20T00:00:00Z",
|
||||
"lastInfoSync": "2024-01-15T09:00:00Z",
|
||||
"seriesType": "standard",
|
||||
"cleanTitle": "breakingbad",
|
||||
"imdbId": "tt0903747",
|
||||
"titleSlug": "breaking-bad",
|
||||
"certification": "TV-MA",
|
||||
"genres": ["Crime", "Drama", "Thriller"],
|
||||
"tags": [],
|
||||
"added": "2024-01-01T00:00:00Z",
|
||||
"ratings": {
|
||||
"votes": 1234567,
|
||||
"value": 9.5
|
||||
},
|
||||
"statistics": {
|
||||
"seasonCount": 5,
|
||||
"episodeFileCount": 61,
|
||||
"episodeCount": 62,
|
||||
"totalEpisodeCount": 62,
|
||||
"sizeOnDisk": 161061273600,
|
||||
"percentOfEpisodes": 98.4
|
||||
},
|
||||
"id": 2
|
||||
},
|
||||
"id": 8901
|
||||
}
|
||||
]
|
||||
}
|
||||
185
dummy-data/tautulli/api/v2
Normal file
185
dummy-data/tautulli/api/v2
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
{
|
||||
"response": {
|
||||
"result": "success",
|
||||
"message": null,
|
||||
"data": {
|
||||
"stream_count": 3,
|
||||
"stream_count_direct_play": 1,
|
||||
"stream_count_direct_stream": 1,
|
||||
"stream_count_transcode": 1,
|
||||
"total_bandwidth": 15420,
|
||||
"wan_bandwidth": 8240,
|
||||
"lan_bandwidth": 7180,
|
||||
"sessions": [
|
||||
{
|
||||
"session_key": "425",
|
||||
"session_id": "tautulli_session_425",
|
||||
"media_index": "1",
|
||||
"parent_media_index": "1",
|
||||
"art": "/library/metadata/98765/art/1705317600",
|
||||
"thumb": "/library/metadata/98765/thumb/1705317600",
|
||||
"grandparent_thumb": "/library/metadata/98765/thumb/1705317600",
|
||||
"title": "The One Where Monica Gets a Roommate",
|
||||
"parent_title": "Season 1",
|
||||
"grandparent_title": "Friends",
|
||||
"original_title": "",
|
||||
"year": 1994,
|
||||
"media_type": "episode",
|
||||
"rating_key": "98765",
|
||||
"parent_rating_key": "98764",
|
||||
"grandparent_rating_key": "98763",
|
||||
"state": "playing",
|
||||
"session_progress": 42,
|
||||
"view_offset": 630000,
|
||||
"duration": 1500000,
|
||||
"remaining_time": 870000,
|
||||
"progress_percent": 42,
|
||||
"username": "john_doe",
|
||||
"friendly_name": "John's iPhone",
|
||||
"user_id": 1,
|
||||
"user": "john_doe",
|
||||
"ip_address": "192.168.1.105",
|
||||
"ip_address_public": "203.0.113.45",
|
||||
"location": "lan",
|
||||
"secure": 1,
|
||||
"relayed": 0,
|
||||
"platform": "iOS",
|
||||
"platform_name": "iPhone",
|
||||
"platform_version": "17.2",
|
||||
"product": "Plex for iOS",
|
||||
"product_version": "8.25.1",
|
||||
"profile": "Mobile",
|
||||
"player": "PlexMobile",
|
||||
"machine_id": "abc123def456",
|
||||
"bandwidth": 4820,
|
||||
"quality_profile": "4 Mbps 720p",
|
||||
"video_resolution": "720p",
|
||||
"video_framerate": "24p",
|
||||
"video_codec": "h264",
|
||||
"video_bitrate": 4200,
|
||||
"video_width": 1280,
|
||||
"video_height": 720,
|
||||
"audio_codec": "aac",
|
||||
"audio_bitrate": 128,
|
||||
"audio_channels": 2,
|
||||
"transcode_decision": "transcode",
|
||||
"stream_container": "mkv",
|
||||
"stream_video_codec": "h264",
|
||||
"stream_audio_codec": "aac"
|
||||
},
|
||||
{
|
||||
"session_key": "426",
|
||||
"session_id": "tautulli_session_426",
|
||||
"media_index": "3",
|
||||
"parent_media_index": "2",
|
||||
"art": "/library/metadata/45678/art/1705317600",
|
||||
"thumb": "/library/metadata/45678/thumb/1705317600",
|
||||
"grandparent_thumb": "/library/metadata/45678/thumb/1705317600",
|
||||
"title": "The One with the Sonogram at the End",
|
||||
"parent_title": "Season 1",
|
||||
"grandparent_title": "Friends",
|
||||
"original_title": "",
|
||||
"year": 1994,
|
||||
"media_type": "episode",
|
||||
"rating_key": "45678",
|
||||
"parent_rating_key": "45677",
|
||||
"grandparent_rating_key": "45676",
|
||||
"state": "playing",
|
||||
"session_progress": 18,
|
||||
"view_offset": 270000,
|
||||
"duration": 1500000,
|
||||
"remaining_time": 1230000,
|
||||
"progress_percent": 18,
|
||||
"username": "sarah_smith",
|
||||
"friendly_name": "Sarah's TV",
|
||||
"user_id": 2,
|
||||
"user": "sarah_smith",
|
||||
"ip_address": "192.168.1.110",
|
||||
"ip_address_public": "203.0.113.45",
|
||||
"location": "lan",
|
||||
"secure": 1,
|
||||
"relayed": 0,
|
||||
"platform": "Roku",
|
||||
"platform_name": "Roku Ultra",
|
||||
"platform_version": "12.5.0",
|
||||
"product": "Plex for Roku",
|
||||
"product_version": "6.8.0",
|
||||
"profile": "Roku",
|
||||
"player": "Roku",
|
||||
"machine_id": "def456ghi789",
|
||||
"bandwidth": 2360,
|
||||
"quality_profile": "2 Mbps 480p",
|
||||
"video_resolution": "480p",
|
||||
"video_framerate": "24p",
|
||||
"video_codec": "h264",
|
||||
"video_bitrate": 2000,
|
||||
"video_width": 720,
|
||||
"video_height": 480,
|
||||
"audio_codec": "aac",
|
||||
"audio_bitrate": 128,
|
||||
"audio_channels": 2,
|
||||
"transcode_decision": "direct_stream",
|
||||
"stream_container": "mkv",
|
||||
"stream_video_codec": "h264",
|
||||
"stream_audio_codec": "aac"
|
||||
},
|
||||
{
|
||||
"session_key": "427",
|
||||
"session_id": "tautulli_session_427",
|
||||
"media_index": null,
|
||||
"parent_media_index": null,
|
||||
"art": "/library/metadata/12345/art/1705317600",
|
||||
"thumb": "/library/metadata/12345/thumb/1705317600",
|
||||
"grandparent_thumb": "",
|
||||
"title": "Inception",
|
||||
"parent_title": "",
|
||||
"grandparent_title": "",
|
||||
"original_title": "Inception",
|
||||
"year": 2010,
|
||||
"media_type": "movie",
|
||||
"rating_key": "12345",
|
||||
"parent_rating_key": "",
|
||||
"grandparent_rating_key": "",
|
||||
"state": "playing",
|
||||
"session_progress": 67,
|
||||
"view_offset": 5952000,
|
||||
"duration": 8880000,
|
||||
"remaining_time": 2928000,
|
||||
"progress_percent": 67,
|
||||
"username": "movie_buff",
|
||||
"friendly_name": "Living Room TV",
|
||||
"user_id": 3,
|
||||
"user": "movie_buff",
|
||||
"ip_address": "10.0.0.15",
|
||||
"ip_address_public": "198.51.100.25",
|
||||
"location": "wan",
|
||||
"secure": 1,
|
||||
"relayed": 1,
|
||||
"platform": "Android TV",
|
||||
"platform_name": "NVIDIA Shield TV",
|
||||
"platform_version": "11",
|
||||
"product": "Plex for Android TV",
|
||||
"product_version": "9.12.0",
|
||||
"profile": "Android TV",
|
||||
"player": "AndroidTV",
|
||||
"machine_id": "ghi789jkl012",
|
||||
"bandwidth": 8240,
|
||||
"quality_profile": "8 Mbps 1080p",
|
||||
"video_resolution": "1080p",
|
||||
"video_framerate": "24p",
|
||||
"video_codec": "h264",
|
||||
"video_bitrate": 8000,
|
||||
"video_width": 1920,
|
||||
"video_height": 1080,
|
||||
"audio_codec": "ac3",
|
||||
"audio_bitrate": 640,
|
||||
"audio_channels": 6,
|
||||
"transcode_decision": "direct_play",
|
||||
"stream_container": "mkv",
|
||||
"stream_video_codec": "h264",
|
||||
"stream_audio_codec": "ac3"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
5
dummy-data/traefik/api/version
Normal file
5
dummy-data/traefik/api/version
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Version": "3.1.7",
|
||||
"Codename": "comte",
|
||||
"startDate": "2024-11-20T05:55:46.259506879Z"
|
||||
}
|
||||
1
dummy-data/truenasscale/api/v2.0/system/version
Normal file
1
dummy-data/truenasscale/api/v2.0/system/version
Normal file
|
|
@ -0,0 +1 @@
|
|||
"TrueNAS-SCALE-22.12.4.2"
|
||||
64
dummy-data/uptimekuma/api/status-page/default
Normal file
64
dummy-data/uptimekuma/api/status-page/default
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"config": {
|
||||
"title": "Homer Dashboard Status",
|
||||
"description": "Status page for all monitored services",
|
||||
"icon": "/icon.svg",
|
||||
"theme": "light",
|
||||
"published": true,
|
||||
"showTags": true,
|
||||
"domainNames": [
|
||||
"status.homer.local"
|
||||
],
|
||||
"customCSS": "",
|
||||
"footerText": null,
|
||||
"showPoweredBy": true,
|
||||
"googleAnalyticsId": null,
|
||||
"showCertificateExpiry": false,
|
||||
"certExpiryDays": 14
|
||||
},
|
||||
"incident": null,
|
||||
"publicGroupList": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Web Services",
|
||||
"weight": 1,
|
||||
"monitorList": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Main Website",
|
||||
"url": "https://example.com",
|
||||
"type": "http",
|
||||
"interval": 60
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "API Server",
|
||||
"url": "https://api.example.com",
|
||||
"type": "http",
|
||||
"interval": 60
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Infrastructure",
|
||||
"weight": 2,
|
||||
"monitorList": [
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Database Server",
|
||||
"url": "postgresql://db.example.com:5432",
|
||||
"type": "postgres",
|
||||
"interval": 120
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Redis Cache",
|
||||
"url": "redis://cache.example.com:6379",
|
||||
"type": "redis",
|
||||
"interval": 60
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
114
dummy-data/uptimekuma/api/status-page/heartbeat/default
Normal file
114
dummy-data/uptimekuma/api/status-page/heartbeat/default
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
{
|
||||
"heartbeatList": {
|
||||
"1": [
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:00:00",
|
||||
"msg": "200 - OK",
|
||||
"ping": 45,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
},
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:01:00",
|
||||
"msg": "200 - OK",
|
||||
"ping": 52,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
},
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:02:00",
|
||||
"msg": "200 - OK",
|
||||
"ping": 38,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
}
|
||||
],
|
||||
"2": [
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:00:00",
|
||||
"msg": "200 - OK",
|
||||
"ping": 67,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
},
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:01:00",
|
||||
"msg": "200 - OK",
|
||||
"ping": 71,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
},
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:02:00",
|
||||
"msg": "200 - OK",
|
||||
"ping": 63,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
}
|
||||
],
|
||||
"3": [
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:00:00",
|
||||
"msg": "Connected successfully",
|
||||
"ping": 12,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
},
|
||||
{
|
||||
"status": 0,
|
||||
"time": "2024-01-15 10:02:00",
|
||||
"msg": "Connection timeout",
|
||||
"ping": null,
|
||||
"important": true,
|
||||
"duration": 5000
|
||||
},
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:04:00",
|
||||
"msg": "Connected successfully",
|
||||
"ping": 15,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
}
|
||||
],
|
||||
"4": [
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:00:00",
|
||||
"msg": "PONG received",
|
||||
"ping": 3,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
},
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:01:00",
|
||||
"msg": "PONG received",
|
||||
"ping": 2,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
},
|
||||
{
|
||||
"status": 1,
|
||||
"time": "2024-01-15 10:02:00",
|
||||
"msg": "PONG received",
|
||||
"ping": 4,
|
||||
"important": false,
|
||||
"duration": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"uptimeList": {
|
||||
"1": 1.0,
|
||||
"2": 1.0,
|
||||
"3": 0.95,
|
||||
"4": 1.0
|
||||
}
|
||||
}
|
||||
1
dummy-data/vaultwarden/api/version
Normal file
1
dummy-data/vaultwarden/api/version
Normal file
|
|
@ -0,0 +1 @@
|
|||
"1.30.3"
|
||||
1
dummy-data/wallabag/api/version
Normal file
1
dummy-data/wallabag/api/version
Normal file
|
|
@ -0,0 +1 @@
|
|||
"2.6.10"
|
||||
182
dummy-data/wud/api/containers
Normal file
182
dummy-data/wud/api/containers
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
[
|
||||
{
|
||||
"id": "nginx-proxy",
|
||||
"name": "nginx-proxy",
|
||||
"watcher": "docker",
|
||||
"image": {
|
||||
"registry": {
|
||||
"name": "hub.docker.com",
|
||||
"url": "https://registry-1.docker.io/v2"
|
||||
},
|
||||
"name": "nginx",
|
||||
"tag": {
|
||||
"value": "1.25.3",
|
||||
"semver": true
|
||||
},
|
||||
"digest": {
|
||||
"watch": false,
|
||||
"repo": "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
|
||||
},
|
||||
"architecture": "amd64",
|
||||
"os": "linux",
|
||||
"created": "2023-12-15T10:30:00Z"
|
||||
},
|
||||
"result": {
|
||||
"tag": "1.25.4"
|
||||
},
|
||||
"updateAvailable": true,
|
||||
"status": "running",
|
||||
"created": "2024-01-10T08:15:00Z",
|
||||
"updated": "2024-01-15T11:30:00Z"
|
||||
},
|
||||
{
|
||||
"id": "postgres-db",
|
||||
"name": "postgres-db",
|
||||
"watcher": "docker",
|
||||
"image": {
|
||||
"registry": {
|
||||
"name": "hub.docker.com",
|
||||
"url": "https://registry-1.docker.io/v2"
|
||||
},
|
||||
"name": "postgres",
|
||||
"tag": {
|
||||
"value": "15.5-alpine",
|
||||
"semver": true
|
||||
},
|
||||
"digest": {
|
||||
"watch": false,
|
||||
"repo": "sha256:2345678901abcdef2345678901abcdef2345678901abcdef2345678901abcdef"
|
||||
},
|
||||
"architecture": "amd64",
|
||||
"os": "linux",
|
||||
"created": "2023-11-28T14:22:00Z"
|
||||
},
|
||||
"result": {
|
||||
"tag": "16.1-alpine"
|
||||
},
|
||||
"updateAvailable": true,
|
||||
"status": "running",
|
||||
"created": "2024-01-08T12:45:00Z",
|
||||
"updated": "2024-01-15T11:30:00Z"
|
||||
},
|
||||
{
|
||||
"id": "redis-cache",
|
||||
"name": "redis-cache",
|
||||
"watcher": "docker",
|
||||
"image": {
|
||||
"registry": {
|
||||
"name": "hub.docker.com",
|
||||
"url": "https://registry-1.docker.io/v2"
|
||||
},
|
||||
"name": "redis",
|
||||
"tag": {
|
||||
"value": "7.2.4-alpine",
|
||||
"semver": true
|
||||
},
|
||||
"digest": {
|
||||
"watch": false,
|
||||
"repo": "sha256:3456789012abcdef3456789012abcdef3456789012abcdef3456789012abcdef"
|
||||
},
|
||||
"architecture": "amd64",
|
||||
"os": "linux",
|
||||
"created": "2024-01-12T09:18:00Z"
|
||||
},
|
||||
"result": {
|
||||
"tag": "7.2.4-alpine"
|
||||
},
|
||||
"updateAvailable": false,
|
||||
"status": "running",
|
||||
"created": "2024-01-12T16:20:00Z",
|
||||
"updated": "2024-01-15T11:30:00Z"
|
||||
},
|
||||
{
|
||||
"id": "portainer-agent",
|
||||
"name": "portainer-agent",
|
||||
"watcher": "docker",
|
||||
"image": {
|
||||
"registry": {
|
||||
"name": "hub.docker.com",
|
||||
"url": "https://registry-1.docker.io/v2"
|
||||
},
|
||||
"name": "portainer/agent",
|
||||
"tag": {
|
||||
"value": "2.19.4",
|
||||
"semver": true
|
||||
},
|
||||
"digest": {
|
||||
"watch": false,
|
||||
"repo": "sha256:4567890123abcdef4567890123abcdef4567890123abcdef4567890123abcdef"
|
||||
},
|
||||
"architecture": "amd64",
|
||||
"os": "linux",
|
||||
"created": "2024-01-05T07:42:00Z"
|
||||
},
|
||||
"result": {
|
||||
"tag": "2.19.4"
|
||||
},
|
||||
"updateAvailable": false,
|
||||
"status": "running",
|
||||
"created": "2024-01-05T14:30:00Z",
|
||||
"updated": "2024-01-15T11:30:00Z"
|
||||
},
|
||||
{
|
||||
"id": "app-backend",
|
||||
"name": "app-backend",
|
||||
"watcher": "docker",
|
||||
"image": {
|
||||
"registry": {
|
||||
"name": "hub.docker.com",
|
||||
"url": "https://registry-1.docker.io/v2"
|
||||
},
|
||||
"name": "node",
|
||||
"tag": {
|
||||
"value": "18.19.0-alpine",
|
||||
"semver": true
|
||||
},
|
||||
"digest": {
|
||||
"watch": false,
|
||||
"repo": "sha256:5678901234abcdef5678901234abcdef5678901234abcdef5678901234abcdef"
|
||||
},
|
||||
"architecture": "amd64",
|
||||
"os": "linux",
|
||||
"created": "2023-12-28T11:15:00Z"
|
||||
},
|
||||
"result": {
|
||||
"tag": "20.11.0-alpine"
|
||||
},
|
||||
"updateAvailable": true,
|
||||
"status": "running",
|
||||
"created": "2024-01-07T09:12:00Z",
|
||||
"updated": "2024-01-15T11:30:00Z"
|
||||
},
|
||||
{
|
||||
"id": "prometheus",
|
||||
"name": "prometheus",
|
||||
"watcher": "docker",
|
||||
"image": {
|
||||
"registry": {
|
||||
"name": "quay.io",
|
||||
"url": "https://quay.io/v2"
|
||||
},
|
||||
"name": "prometheus/prometheus",
|
||||
"tag": {
|
||||
"value": "v2.48.1",
|
||||
"semver": true
|
||||
},
|
||||
"digest": {
|
||||
"watch": false,
|
||||
"repo": "sha256:6789012345abcdef6789012345abcdef6789012345abcdef6789012345abcdef"
|
||||
},
|
||||
"architecture": "amd64",
|
||||
"os": "linux",
|
||||
"created": "2023-12-20T16:33:00Z"
|
||||
},
|
||||
"result": {
|
||||
"tag": "v2.49.1"
|
||||
},
|
||||
"updateAvailable": true,
|
||||
"status": "running",
|
||||
"created": "2024-01-03T13:55:00Z",
|
||||
"updated": "2024-01-15T11:30:00Z"
|
||||
}
|
||||
]
|
||||
|
|
@ -14,4 +14,5 @@ if [[ "${INIT_ASSETS}" == "1" ]] && [[ ! -f "/www/assets/config.yml" ]]; then
|
|||
fi
|
||||
|
||||
echo "Starting webserver"
|
||||
exec 3>&1
|
||||
exec lighttpd -D -f /lighttpd.conf
|
||||
|
|
|
|||
|
|
@ -1,21 +1,30 @@
|
|||
import globals from "globals";
|
||||
import pluginJs from "@eslint/js";
|
||||
import pluginVue from "eslint-plugin-vue";
|
||||
import eslintConfigPrettier from "@vue/eslint-config-prettier";
|
||||
|
||||
import js from "@eslint/js";
|
||||
import pluginVue from 'eslint-plugin-vue'
|
||||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
...pluginVue.configs['flat/recommended'],
|
||||
{ files: ["**/*.{js,mjs,cjs,vue}"] },
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
__APP_VERSION__: "readable",
|
||||
},
|
||||
},
|
||||
},
|
||||
pluginJs.configs.recommended,
|
||||
...pluginVue.configs["flat/recommended"],
|
||||
eslintConfigPrettier,
|
||||
{
|
||||
files: ['**/*.{vue,js,jsx,mjs,cjs}'],
|
||||
rules: {
|
||||
"vue/multi-word-component-names": "off",
|
||||
"vue/require-default-prop": "off",
|
||||
"vue/no-v-html": "off",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ["**/dist/"],
|
||||
}
|
||||
ignores: ["**/dist/**", "**/dist-ssr/**", "**/coverage/**"],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="assets/icons/favicon.ico" />
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ include "/etc/lighttpd/mime-types.conf"
|
|||
include_shell "/etc/lighttpd/ipv6.sh"
|
||||
|
||||
server.port = env.PORT
|
||||
server.modules = ( "mod_alias" )
|
||||
server.modules = ( "mod_alias", "mod_accesslog" )
|
||||
server.username = "lighttpd"
|
||||
server.groupname = "lighttpd"
|
||||
server.document-root = "/www"
|
||||
|
|
@ -10,3 +10,9 @@ alias.url = ( env.SUBFOLDER => "/www" )
|
|||
server.indexfiles = ("index.html")
|
||||
server.follow-symlink = "enable"
|
||||
server.feature-flags += ( "server.clock-jump-restart" => 0 )
|
||||
server.max-request-field-size = 65535
|
||||
accesslog.filename = "/dev/fd/3"
|
||||
|
||||
# Avoid logging docker healthcheck request
|
||||
$HTTP["remote-ip"] == "127.0.0.1" { accesslog.filename = "" }
|
||||
$HTTP["remote-ip"] == "[::1]" { accesslog.filename = "" }
|
||||
|
|
|
|||
33
package.json
33
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "homer",
|
||||
"version": "24.11.5",
|
||||
"version": "25.11.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
|
@ -10,23 +10,28 @@
|
|||
"lint": "eslint . --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.7.0",
|
||||
"bulma": "^1.0.2",
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"bulma": "^1.0.4",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"vue": "^3.5.13",
|
||||
"yaml": "^2.6.1"
|
||||
"vue": "^3.5.26",
|
||||
"yaml": "^2.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.0",
|
||||
"@vue/eslint-config-prettier": "^10.0.0",
|
||||
"eslint": "^9.15.0",
|
||||
"eslint-plugin-vue": "^9.31.0",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@vitejs/plugin-vue": "^6.0.3",
|
||||
"@vue/eslint-config-prettier": "^10.2.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-vue": "^9.33.0",
|
||||
"globals": "^17.0.0",
|
||||
"http-server": "^14.1.1",
|
||||
"prettier": "^3.3.3",
|
||||
"sass-embedded": "^1.81.0",
|
||||
"vite": "^5.4.11",
|
||||
"vite-plugin-pwa": "^0.21.0"
|
||||
"prettier": "^3.8.0",
|
||||
"sass-embedded": "^1.97.2",
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-pwa": "^1.2.0"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"packageManager": "pnpm@9.14.2+sha512.6e2baf77d06b9362294152c851c4f278ede37ab1eba3a55fda317a4a17b209f4dbb973fb250a77abc463a341fcb1f17f17cfa24091c4eb319cda0d9b84278387"
|
||||
"packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48",
|
||||
"pnpm": {
|
||||
"neverBuiltDependencies": []
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4386
pnpm-lock.yaml
generated
4386
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
|
@ -51,7 +51,7 @@ services:
|
|||
icon: "fa-solid fa-download"
|
||||
subtitle: "Start using Homer in a few minutes"
|
||||
tag: "setup"
|
||||
url: "https://github.com/bastienwirtz/homer?tab=readme-ov-file#getting-started"
|
||||
url: "https://github.com/bastienwirtz/homer?tab=readme-ov-file#get-started"
|
||||
- name: "Configuration"
|
||||
icon: "fa-solid fa-sliders"
|
||||
subtitle: "Configuration options documentation"
|
||||
|
|
@ -66,12 +66,20 @@ services:
|
|||
icon: "fa-solid fa-palette"
|
||||
subtitle: "Displays dynamic information or actions."
|
||||
tag: "setup"
|
||||
url: "https://github.com/bastienwirtz/homer/blob/main/docs/theming.md"
|
||||
url: "https://github.com/bastienwirtz/homer/blob/main/docs/customservices.md"
|
||||
- name: "Dashboard icons"
|
||||
icon: "fa-solid fa-icons"
|
||||
subtitle: "Dashboard icons"
|
||||
tag: "setup"
|
||||
url: "https://github.com/walkxcode/dashboard-icons"
|
||||
url: ""
|
||||
quick:
|
||||
- name: "selfh.st"
|
||||
url: "https://selfh.st/icons/"
|
||||
icon: "fa-solid fa-arrow-up-right-from-square"
|
||||
target: "_blank"
|
||||
- name: "homarr-labs"
|
||||
url: "https://github.com/homarr-labs/dashboard-icons"
|
||||
icon: "fa-solid fa-arrow-up-right-from-square"
|
||||
target: "_blank"
|
||||
- name: "Buy me a coffee!"
|
||||
subtitle: "Sponsor this project"
|
||||
icon: "fa-solid fa-mug-hot"
|
||||
|
|
@ -116,18 +124,19 @@ services:
|
|||
icon: "fa-regular fa-bookmark"
|
||||
class: highlight-inverted
|
||||
items:
|
||||
- name: "r/selfhosted"
|
||||
- name: "Selfhosted community"
|
||||
icon: "fa-brands fa-reddit-alien"
|
||||
subtitle: "selfhosted community on Reddit"
|
||||
tag: "community"
|
||||
url: "https://www.reddit.com/r/selfhosted/"
|
||||
target: "_blank"
|
||||
- name: "c/selfhosted"
|
||||
logo: "https://icons.iconarchive.com/icons/simpleicons-team/simple/256/lemmy-icon.png"
|
||||
subtitle: "selfhosted community on Lemmy"
|
||||
tag: "community"
|
||||
url: "https://lemmy.world/c/selfhosted"
|
||||
target: "_blank"
|
||||
url: ""
|
||||
quick:
|
||||
- name: "r/selfhosted"
|
||||
url: "https://www.reddit.com/r/selfhosted/"
|
||||
icon: "fa-solid fa-arrow-up-right-from-square"
|
||||
target: "_blank"
|
||||
- name: "c/selfhosted"
|
||||
url: "https://lemmy.world/c/selfhosted"
|
||||
icon: "fa-solid fa-arrow-up-right-from-square"
|
||||
target: "_blank"
|
||||
- name: "Awesome selfhosted"
|
||||
icon: "fa-solid fa-star"
|
||||
subtitle: "Another application"
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ services:
|
|||
icon: "fa-solid fa-download"
|
||||
subtitle: "Start using Homer in a few minutes"
|
||||
tag: "setup"
|
||||
url: "https://github.com/bastienwirtz/homer?tab=readme-ov-file#getting-started"
|
||||
url: "https://github.com/bastienwirtz/homer?tab=readme-ov-file#get-started"
|
||||
- name: "Configuration"
|
||||
icon: "fa-solid fa-sliders"
|
||||
subtitle: "Configuration options documentation"
|
||||
|
|
@ -93,7 +93,7 @@ services:
|
|||
icon: "fa-solid fa-palette"
|
||||
subtitle: "Displays dynamic information or actions."
|
||||
tag: "setup"
|
||||
url: "https://github.com/bastienwirtz/homer/blob/main/docs/theming.md"
|
||||
url: "https://github.com/bastienwirtz/homer/blob/main/docs/customservices.md"
|
||||
- name: "Dashboard icons"
|
||||
icon: "fa-solid fa-icons"
|
||||
subtitle: "Dashboard icons"
|
||||
|
|
|
|||
81
src/App.vue
81
src/App.vue
|
|
@ -54,7 +54,6 @@
|
|||
/>
|
||||
</Navbar>
|
||||
</div>
|
||||
|
||||
<section id="main-section" class="section">
|
||||
<div v-cloak class="container">
|
||||
<ConnectivityChecker
|
||||
|
|
@ -68,64 +67,23 @@
|
|||
<!-- Optional messages -->
|
||||
<Message :item="config.message" />
|
||||
|
||||
<!-- Horizontal layout -->
|
||||
<div v-if="!vlayout || filter" class="columns is-multiline">
|
||||
<template v-for="(group, groupIndex) in services">
|
||||
<h2
|
||||
v-if="group.name"
|
||||
:key="`header-${groupIndex}`"
|
||||
class="column is-full group-title"
|
||||
:class="group.class"
|
||||
>
|
||||
<i v-if="group.icon" :class="['fa-fw', group.icon]"></i>
|
||||
<div v-else-if="group.logo" class="group-logo media-left">
|
||||
<figure class="image is-48x48">
|
||||
<img :src="group.logo" :alt="`${group.name} logo`" />
|
||||
</figure>
|
||||
</div>
|
||||
{{ group.name }}
|
||||
</h2>
|
||||
<Service
|
||||
v-for="(item, index) in group.items"
|
||||
:key="`service-${groupIndex}-${index}`"
|
||||
:item="item"
|
||||
:proxy="config.proxy"
|
||||
:class="[
|
||||
'column',
|
||||
`is-${12 / config.columns}`,
|
||||
`${item.class || group.class || ''}`,
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Vertical layout -->
|
||||
<!-- Unified layout -->
|
||||
<div
|
||||
v-if="!filter && vlayout"
|
||||
class="columns is-multiline layout-vertical"
|
||||
:class="[
|
||||
'columns',
|
||||
'is-multiline',
|
||||
{ 'layout-vertical': vlayout && !filter },
|
||||
]"
|
||||
>
|
||||
<div
|
||||
<ServiceGroup
|
||||
v-for="(group, groupIndex) in services"
|
||||
:key="groupIndex"
|
||||
:class="['column', `is-${12 / config.columns}`]"
|
||||
>
|
||||
<h2 v-if="group.name" class="group-title" :class="group.class">
|
||||
<i v-if="group.icon" :class="['fa-fw', group.icon]"></i>
|
||||
<div v-else-if="group.logo" class="group-logo media-left">
|
||||
<figure class="image is-48x48">
|
||||
<img :src="group.logo" :alt="`${group.name} logo`" />
|
||||
</figure>
|
||||
</div>
|
||||
{{ group.name }}
|
||||
</h2>
|
||||
<Service
|
||||
v-for="(item, index) in group.items"
|
||||
:key="index"
|
||||
:item="item"
|
||||
:proxy="config.proxy"
|
||||
:class="item.class || group.class"
|
||||
/>
|
||||
</div>
|
||||
:key="`${currentPage}-${groupIndex}`"
|
||||
:group="group"
|
||||
:is-vertical="vlayout && !filter"
|
||||
:proxy="config.proxy"
|
||||
:columns="config.columns"
|
||||
:group-index="groupIndex"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -150,7 +108,7 @@ import merge from "lodash.merge";
|
|||
import Navbar from "./components/Navbar.vue";
|
||||
import GetStarted from "./components/GetStarted.vue";
|
||||
import ConnectivityChecker from "./components/ConnectivityChecker.vue";
|
||||
import Service from "./components/Service.vue";
|
||||
import ServiceGroup from "./components/ServiceGroup.vue";
|
||||
import Message from "./components/Message.vue";
|
||||
import SearchInput from "./components/SearchInput.vue";
|
||||
import SettingToggle from "./components/SettingToggle.vue";
|
||||
|
|
@ -165,7 +123,7 @@ export default {
|
|||
Navbar,
|
||||
GetStarted,
|
||||
ConnectivityChecker,
|
||||
Service,
|
||||
ServiceGroup,
|
||||
Message,
|
||||
SearchInput,
|
||||
SettingToggle,
|
||||
|
|
@ -195,6 +153,10 @@ export default {
|
|||
this.buildDashboard();
|
||||
window.onhashchange = this.buildDashboard;
|
||||
this.loaded = true;
|
||||
console.info(`Homer v${__APP_VERSION__}`);
|
||||
},
|
||||
beforeUnmount() {
|
||||
window.onhashchange = null;
|
||||
},
|
||||
methods: {
|
||||
searchHotkey() {
|
||||
|
|
@ -224,7 +186,8 @@ export default {
|
|||
|
||||
document.title =
|
||||
this.config.documentTitle ||
|
||||
`${this.config.title} | ${this.config.subtitle}`;
|
||||
[this.config.title, this.config.subtitle].filter(Boolean).join(" | ");
|
||||
|
||||
if (this.config.stylesheet) {
|
||||
let stylesheet = "";
|
||||
let addtionnal_styles = this.config.stylesheet;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@
|
|||
background-color: var(--card-background);
|
||||
}
|
||||
}
|
||||
.component-error .card {
|
||||
border: 1px solid rgba(255, 33, 33, 0.664);
|
||||
background-color: rgba(255, 58, 58, 0.24);
|
||||
}
|
||||
|
||||
.message {
|
||||
.message-body {
|
||||
|
|
@ -171,9 +175,9 @@
|
|||
|
||||
.title {
|
||||
font-size: 1.1em;
|
||||
line-height: 1.2em;
|
||||
line-height: 1.3em;
|
||||
font-weight: 500;
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 3px;
|
||||
@include ellipsis();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
--text: #eaeaea;
|
||||
--text-header: #ffffff;
|
||||
--text-title: #fafafa;
|
||||
--text-subtitle: #b6b6b6;
|
||||
--text-subtitle: #b6b6b6;
|
||||
--card-shadow: rgba(0, 0, 0, 0.4);
|
||||
--link: #3273dc;
|
||||
--link-hover: #144aa2;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
--link: #b5ff57;
|
||||
--link-hover: #8cce36;
|
||||
--background-image: none;
|
||||
--highlight-variant-inverted: #2d2d2d;
|
||||
}
|
||||
|
||||
.theme-neon.dark {
|
||||
|
|
@ -29,6 +30,7 @@
|
|||
--link: #b5ff57;
|
||||
--link-hover: #aeff45;
|
||||
--background-image: none;
|
||||
--highlight-variant-inverted: #696969;
|
||||
}
|
||||
|
||||
// theme
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
--card-shadow: rgba(0, 0, 0, 0.5);
|
||||
--link: #3273dc;
|
||||
--link-hover: #2e4053;
|
||||
--background-image: url("assets/themes/walkxcode/wallpaper-light.webp");
|
||||
--background-image: url("/assets/themes/walkxcode/wallpaper-light.webp");
|
||||
}
|
||||
|
||||
.theme-walkxcode.dark {
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
--card-shadow: rgba(0, 0, 0, 0.5);
|
||||
--link: #ffffff;
|
||||
--link-hover: #fafafa;
|
||||
--background-image: url("assets/themes/walkxcode/wallpaper.webp");
|
||||
--background-image: url("/assets/themes/walkxcode/wallpaper.webp");
|
||||
}
|
||||
|
||||
// theme
|
||||
|
|
|
|||
|
|
@ -1,12 +1,26 @@
|
|||
<template>
|
||||
<div v-if="offline" class="offline-message mb-4">
|
||||
<div
|
||||
v-if="offline"
|
||||
class="offline-message mb-4"
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
>
|
||||
<i class="fa-solid fa-triangle-exclamation"></i>
|
||||
<h1>
|
||||
Network unreachable
|
||||
<span @click="checkOffline"> <i class="fas fa-redo-alt"></i></span>
|
||||
Network unreachable
|
||||
<button
|
||||
aria-label="Retry connection check"
|
||||
class="retry-button"
|
||||
@click="checkOffline"
|
||||
>
|
||||
<i class="fas fa-redo-alt"></i>
|
||||
</button>
|
||||
</h1>
|
||||
<p>
|
||||
<a href="https://github.com/bastienwirtz/homer/blob/main/docs/configuration.md#connectivity-checks">More information →</a>
|
||||
<a
|
||||
href="https://github.com/bastienwirtz/homer/blob/main/docs/configuration.md#connectivity-checks"
|
||||
>More information →</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -23,46 +37,49 @@ export default {
|
|||
if (/t=\d+/.test(window.location.href)) {
|
||||
window.history.replaceState({}, document.title, window.location.pathname);
|
||||
}
|
||||
let that = this;
|
||||
this.checkOffline();
|
||||
|
||||
document.addEventListener(
|
||||
"visibilitychange",
|
||||
function () {
|
||||
if (document.visibilityState == "visible") {
|
||||
that.checkOffline();
|
||||
}
|
||||
},
|
||||
this.handleVisibilityChange,
|
||||
false,
|
||||
);
|
||||
window.addEventListener(
|
||||
"online",
|
||||
function () {
|
||||
that.checkOffline();
|
||||
},
|
||||
false,
|
||||
);
|
||||
window.addEventListener(
|
||||
"offline",
|
||||
function () {
|
||||
this.offline = true;
|
||||
},
|
||||
false,
|
||||
window.addEventListener("online", this.handleOnline, false);
|
||||
window.addEventListener("offline", this.handleOffline, false);
|
||||
},
|
||||
beforeUnmount: function () {
|
||||
document.removeEventListener(
|
||||
"visibilitychange",
|
||||
this.handleVisibilityChange,
|
||||
);
|
||||
window.removeEventListener("online", this.handleOnline);
|
||||
window.removeEventListener("offline", this.handleOffline);
|
||||
},
|
||||
methods: {
|
||||
handleVisibilityChange: function () {
|
||||
if (document.visibilityState === "visible") {
|
||||
this.checkOffline();
|
||||
}
|
||||
},
|
||||
handleOnline: function () {
|
||||
this.checkOffline();
|
||||
},
|
||||
handleOffline: function () {
|
||||
this.offline = true;
|
||||
},
|
||||
checkOffline: function () {
|
||||
// Global online check
|
||||
if (!navigator.onLine) {
|
||||
this.offline = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// extra check to make sure we're not offline
|
||||
// Check if the current URL is reachable
|
||||
let that = this;
|
||||
const urlPath = window.location.pathname.replace(/\/+$/, "");
|
||||
const aliveCheckUrl = `${
|
||||
window.location.origin
|
||||
}${urlPath}/index.html?t=${new Date().valueOf()}`;
|
||||
|
||||
const aliveCheckUrl = new URL(window.location);
|
||||
aliveCheckUrl.searchParams.set("t", new Date().valueOf());
|
||||
|
||||
return fetch(aliveCheckUrl, {
|
||||
method: "HEAD",
|
||||
cache: "no-store",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default {
|
|||
props: {
|
||||
defaultValue: String,
|
||||
},
|
||||
emits: ['updated'],
|
||||
emits: ["updated"],
|
||||
data: function () {
|
||||
return {
|
||||
isDark: null,
|
||||
|
|
|
|||
23
src/components/GroupHeader.vue
Normal file
23
src/components/GroupHeader.vue
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<template>
|
||||
<h2 :class="group.class">
|
||||
<i v-if="group.icon" :class="['fa-fw', group.icon]"></i>
|
||||
<div v-else-if="group.logo" class="group-logo media-left">
|
||||
<figure class="image is-48x48">
|
||||
<img :src="group.logo" :alt="`${group.name} logo`" />
|
||||
</figure>
|
||||
</div>
|
||||
{{ group.name }}
|
||||
</h2>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "GroupHeader",
|
||||
props: {
|
||||
group: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -73,7 +73,7 @@ export default {
|
|||
return;
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,7 @@
|
|||
:href="link.url"
|
||||
:target="link.target"
|
||||
>
|
||||
<i
|
||||
v-if="link.icon"
|
||||
:class="['fa-fw', link.icon, { 'mr-2': link.name }]"
|
||||
></i>
|
||||
<i v-if="link.icon" :class="['fa-fw', link.icon]"></i>
|
||||
{{ link.name }}
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -52,7 +49,7 @@ export default {
|
|||
},
|
||||
links: Array,
|
||||
},
|
||||
emits: ['navbar-toggle'],
|
||||
emits: ["navbar-toggle"],
|
||||
computed: {
|
||||
showMenu: function () {
|
||||
return this.open && this.isSmallScreen();
|
||||
|
|
@ -65,3 +62,11 @@ export default {
|
|||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@media (min-width: 1023px) {
|
||||
i.fa-fw {
|
||||
width: 0.8em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export default {
|
|||
emits: ["search-open", "search-focus", "search-cancel", "input"],
|
||||
mounted() {
|
||||
this._keyListener = function (event) {
|
||||
if (event.key === this.hotkey) {
|
||||
if (!this.hasFocus() && event.key === this.hotkey) {
|
||||
event.preventDefault();
|
||||
this.focus();
|
||||
}
|
||||
|
|
@ -63,6 +63,9 @@ export default {
|
|||
this.$refs.search.focus();
|
||||
});
|
||||
},
|
||||
hasFocus: function () {
|
||||
return document.activeElement == this.$refs.search;
|
||||
},
|
||||
setSearchURL: function (value) {
|
||||
const url = new URL(window.location);
|
||||
if (value === "") {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
<template>
|
||||
<component :is="component" :item="item" :proxy="proxy"></component>
|
||||
<Generic v-if="isGeneric" :item="item"></Generic>
|
||||
<component :is="component" v-else :item="item" :proxy="proxy"></component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineAsyncComponent } from "vue";
|
||||
import Generic from "./services/Generic.vue";
|
||||
import errorComponent from "./services/_error.vue";
|
||||
const defaultService = "Generic";
|
||||
|
||||
export default {
|
||||
name: "Service",
|
||||
|
|
@ -13,12 +15,15 @@ export default {
|
|||
proxy: Object,
|
||||
},
|
||||
computed: {
|
||||
isGeneric() {
|
||||
return defaultService === (this.item.type || defaultService);
|
||||
},
|
||||
component() {
|
||||
const type = this.item.type || "Generic";
|
||||
if (type === "Generic") {
|
||||
return Generic;
|
||||
}
|
||||
return defineAsyncComponent(() => import(`./services/${type}.vue`));
|
||||
return defineAsyncComponent({
|
||||
loader: () => import(`./services/${this.item.type}.vue`),
|
||||
errorComponent: errorComponent,
|
||||
timeout: 3000,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
69
src/components/ServiceGroup.vue
Normal file
69
src/components/ServiceGroup.vue
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<template>
|
||||
<!-- Vertical layout: Group container wrapper -->
|
||||
<div v-if="isVertical" :class="['column', `is-${12 / columns}`]">
|
||||
<GroupHeader v-if="group.name" :group="group" class="group-title" />
|
||||
<Service
|
||||
v-for="(item, index) in group.items"
|
||||
:key="`srv-${groupIndex}-${index}-${item.name || item.type}`"
|
||||
:item="item"
|
||||
:proxy="proxy"
|
||||
:class="item.class || group.class"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Horizontal layout: Direct rendering -->
|
||||
<template v-else>
|
||||
<GroupHeader
|
||||
v-if="group.name"
|
||||
:key="`header-${groupIndex}`"
|
||||
:group="group"
|
||||
class="column is-full group-title"
|
||||
/>
|
||||
<Service
|
||||
v-for="(item, index) in group.items"
|
||||
:key="`srv-${groupIndex}-${index}-${item.name || item.type}`"
|
||||
:item="item"
|
||||
:proxy="proxy"
|
||||
:class="[
|
||||
'column',
|
||||
`is-${12 / columns}`,
|
||||
`${item.class || group.class || ''}`,
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Service from "./Service.vue";
|
||||
import GroupHeader from "./GroupHeader.vue";
|
||||
|
||||
export default {
|
||||
name: "ServiceGroup",
|
||||
components: {
|
||||
Service,
|
||||
GroupHeader,
|
||||
},
|
||||
props: {
|
||||
group: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isVertical: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
proxy: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
columns: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
groupIndex: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -21,13 +21,9 @@
|
|||
|
||||
<script>
|
||||
import service from "@/mixins/service.js";
|
||||
import Generic from "./Generic.vue";
|
||||
|
||||
export default {
|
||||
name: "AdGuardHome",
|
||||
components: {
|
||||
Generic,
|
||||
},
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
|
|
|
|||
|
|
@ -15,13 +15,9 @@
|
|||
|
||||
<script>
|
||||
import service from "@/mixins/service.js";
|
||||
import Generic from "./Generic.vue";
|
||||
|
||||
export default {
|
||||
name: "CopyToClipboard",
|
||||
components: {
|
||||
Generic,
|
||||
},
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
|
|
|
|||
109
src/components/services/DockerSocketProxy.vue
Normal file
109
src/components/services/DockerSocketProxy.vue
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
<template>
|
||||
<Generic :item="item">
|
||||
<template #indicator>
|
||||
<div class="notifs">
|
||||
<strong
|
||||
v-if="running > 0"
|
||||
class="notif running"
|
||||
title="Running Containers"
|
||||
>
|
||||
{{ running }}
|
||||
</strong>
|
||||
<strong
|
||||
v-if="stopped > 0"
|
||||
class="notif stopped"
|
||||
title="Stopped Containers"
|
||||
>
|
||||
{{ stopped }}
|
||||
</strong>
|
||||
<strong v-if="errors > 0" class="notif errors" title="Error">
|
||||
{{ errors }}
|
||||
</strong>
|
||||
<strong
|
||||
v-if="serverError"
|
||||
class="notif errors"
|
||||
title="Connection error to Docker Socket Proxy API"
|
||||
>
|
||||
Unavailable
|
||||
</strong>
|
||||
</div>
|
||||
</template>
|
||||
</Generic>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import service from "@/mixins/service.js";
|
||||
export default {
|
||||
name: "DockerSocketProxy",
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
},
|
||||
data: () => {
|
||||
return {
|
||||
running: null,
|
||||
stopped: null,
|
||||
errors: null,
|
||||
serverError: false,
|
||||
};
|
||||
},
|
||||
created: function () {
|
||||
const checkInterval = parseInt(this.item.checkInterval, 10) || 0;
|
||||
if (checkInterval > 0) {
|
||||
setInterval(() => this.fetchData(), checkInterval);
|
||||
}
|
||||
this.fetchData();
|
||||
},
|
||||
methods: {
|
||||
fetchData: function () {
|
||||
const handleError = (e) => {
|
||||
console.error(e);
|
||||
this.serverError = true;
|
||||
};
|
||||
|
||||
// Fetch all containers (including stopped) from Docker Socket Proxy
|
||||
this.fetch("/containers/json?all=true") // Docker endpoint for container statuses
|
||||
.then((containers) => {
|
||||
this.running = containers.filter(
|
||||
(container) => container.State === "running",
|
||||
).length;
|
||||
this.stopped = containers.filter(
|
||||
(container) => container.State === "exited",
|
||||
).length;
|
||||
})
|
||||
.catch(handleError);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.notifs {
|
||||
position: absolute;
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
top: 0.3em;
|
||||
right: 0.5em;
|
||||
|
||||
.notif {
|
||||
display: inline-block;
|
||||
padding: 0.2em 0.35em;
|
||||
border-radius: 0.25em;
|
||||
position: relative;
|
||||
margin-left: 0.3em;
|
||||
font-size: 0.8em;
|
||||
|
||||
&.running {
|
||||
background-color: #4fb5d6;
|
||||
}
|
||||
|
||||
&.stopped {
|
||||
background-color: #d08d2e;
|
||||
}
|
||||
|
||||
&.errors {
|
||||
background-color: #e51111;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
86
src/components/services/Docuseal.vue
Normal file
86
src/components/services/Docuseal.vue
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<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-if="versionstring">
|
||||
Version {{ versionstring }}
|
||||
</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";
|
||||
|
||||
export default {
|
||||
name: "Docuseal",
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
},
|
||||
data: () => ({
|
||||
status: null,
|
||||
versionstring: null,
|
||||
}),
|
||||
created() {
|
||||
this.fetchStatus();
|
||||
},
|
||||
methods: {
|
||||
fetchStatus: async function () {
|
||||
const params = {
|
||||
cache: "no-cache",
|
||||
};
|
||||
this.fetch("/version", params, false)
|
||||
.then((response) => {
|
||||
this.status = "online";
|
||||
this.versionstring = response;
|
||||
})
|
||||
.catch((e) => {
|
||||
this.status = "offline";
|
||||
console.log(e);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.status {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-title);
|
||||
white-space: nowrap;
|
||||
margin-left: 0.25rem;
|
||||
|
||||
&.online:before {
|
||||
background-color: #94e185;
|
||||
border-color: #78d965;
|
||||
box-shadow: 0 0 5px 1px #94e185;
|
||||
}
|
||||
|
||||
&.offline: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>
|
||||
|
|
@ -21,13 +21,9 @@
|
|||
|
||||
<script>
|
||||
import service from "@/mixins/service.js";
|
||||
import Generic from "./Generic.vue";
|
||||
|
||||
export default {
|
||||
name: "Emby",
|
||||
components: {
|
||||
Generic,
|
||||
},
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
|
|
|
|||
|
|
@ -2,29 +2,32 @@
|
|||
<Generic :item="item">
|
||||
<template #indicator>
|
||||
<div class="notifs">
|
||||
<strong v-if="subscriptions > 0" class="notif subscriptions" title="Subscriptions">
|
||||
<strong
|
||||
v-if="subscriptions > 0"
|
||||
class="notif subscriptions"
|
||||
title="Subscriptions"
|
||||
>
|
||||
{{ subscriptions }}
|
||||
</strong>
|
||||
<strong v-if="unread > 0" class="notif unread" title="Unread">
|
||||
{{ unread }}
|
||||
</strong>
|
||||
<strong
|
||||
v-if="serverError" class="notif errors"
|
||||
title="Connection error to the FreshRSS API, check url username and password in config.yml">?</strong>
|
||||
v-if="serverError"
|
||||
class="notif errors"
|
||||
title="Connection error to the FreshRSS API, check url username and password in config.yml"
|
||||
>?</strong
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</Generic>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import service from "@/mixins/service.js";
|
||||
import Generic from "./Generic.vue";
|
||||
|
||||
export default {
|
||||
name: "FreshRSS",
|
||||
components: {
|
||||
Generic,
|
||||
},
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
|
|
@ -45,20 +48,25 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
fetchConfig: async function () {
|
||||
|
||||
if (!this.auth) {
|
||||
const match = await this.fetch(`/api/greader.php/accounts/ClientLogin?Email=${this.item.username}&Passwd=${this.item.password}`, { method: 'GET', cache: "no-cache" }, false)
|
||||
.then(response => { return response.text(); })
|
||||
.then(body => { return body.match(/Auth=(([([a-z0-9]+)\/([([a-z0-9]+))/i); });
|
||||
if (match !== null)
|
||||
this.auth = match[1];
|
||||
const match = await this.fetch(
|
||||
`/api/greader.php/accounts/ClientLogin?Email=${this.item.username}&Passwd=${this.item.password}`,
|
||||
{ method: "GET", cache: "no-cache" },
|
||||
false,
|
||||
).then((body) => {
|
||||
return body.match(/Auth=(([([a-z0-9]+)\/([([a-z0-9]+))/i);
|
||||
});
|
||||
if (match !== null) this.auth = match[1];
|
||||
}
|
||||
|
||||
const headers = {
|
||||
"Authorization": `GoogleLogin auth=${this.auth}`,
|
||||
Authorization: `GoogleLogin auth=${this.auth}`,
|
||||
};
|
||||
|
||||
this.fetch(`/api/greader.php/reader/api/0/subscription/list?output=json`, { headers })
|
||||
this.fetch(
|
||||
`/api/greader.php/reader/api/0/subscription/list?output=json`,
|
||||
{ headers },
|
||||
)
|
||||
.then((subscription) => {
|
||||
this.subscriptions = subscription.subscriptions.length;
|
||||
})
|
||||
|
|
@ -66,7 +74,9 @@ export default {
|
|||
console.error(e);
|
||||
this.serverError = true;
|
||||
});
|
||||
this.fetch(`/api/greader.php/reader/api/0/unread-count?output=json`, { headers })
|
||||
this.fetch(`/api/greader.php/reader/api/0/unread-count?output=json`, {
|
||||
headers,
|
||||
})
|
||||
.then((unreadcount) => {
|
||||
this.unread = unreadcount.max;
|
||||
})
|
||||
|
|
@ -78,7 +88,7 @@ export default {
|
|||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped lang="scss">
|
||||
.notifs {
|
||||
position: absolute;
|
||||
|
|
@ -104,4 +114,4 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
153
src/components/services/Gatus.vue
Normal file
153
src/components/services/Gatus.vue
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<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>
|
||||
<i class="fa-solid fa-signal"></i> {{ up }}/{{ total }}
|
||||
<template v-if="avgRespTime > 0">
|
||||
<span class="separator"> | </span>
|
||||
<i class="fa-solid fa-stopwatch"></i> {{ avgRespTime }} ms avg.
|
||||
</template>
|
||||
</p>
|
||||
</template>
|
||||
<template #indicator>
|
||||
<div v-if="status !== false" class="status" :class="status">
|
||||
{{ percentageGood }}%
|
||||
</div>
|
||||
</template>
|
||||
</Generic>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import service from "@/mixins/service.js";
|
||||
|
||||
export default {
|
||||
name: "Gatus",
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
},
|
||||
data: () => ({
|
||||
up: 0,
|
||||
down: 0,
|
||||
total: 0,
|
||||
avgRespTime: NaN,
|
||||
percentageGood: NaN,
|
||||
status: false,
|
||||
statusMessage: false,
|
||||
}),
|
||||
created() {
|
||||
const updateInterval = parseInt(this.item.updateInterval, 10) || 0;
|
||||
if (updateInterval > 0) {
|
||||
setInterval(() => this.fetchStatus(), updateInterval);
|
||||
}
|
||||
this.fetchStatus();
|
||||
},
|
||||
methods: {
|
||||
fetchStatus: async function () {
|
||||
this.fetch("/api/v1/endpoints/statuses", {
|
||||
method: "GET",
|
||||
cache: "no-cache",
|
||||
})
|
||||
.then((response) => {
|
||||
// Apply filtering by groups, if defined
|
||||
if (this.item.groups) {
|
||||
response = response?.filter((job) => {
|
||||
return this.item.groups.includes(job.group) === true;
|
||||
});
|
||||
}
|
||||
|
||||
// Initialise counts, avg times
|
||||
this.total = response.length;
|
||||
this.up = 0;
|
||||
|
||||
let totalrestime = 0;
|
||||
let totalresults = 0;
|
||||
|
||||
response.forEach((job) => {
|
||||
if (job.results[job.results.length - 1].success === true) {
|
||||
this.up++;
|
||||
}
|
||||
|
||||
if (!this.item.hideaverages) {
|
||||
// Update array of average times
|
||||
let totalduration = 0;
|
||||
let rescounter = 0;
|
||||
job.results.forEach((res) => {
|
||||
totalduration += parseInt(res.duration, 10) / 1000000;
|
||||
rescounter++;
|
||||
});
|
||||
|
||||
totalrestime += totalduration;
|
||||
totalresults += rescounter;
|
||||
} else {
|
||||
totalrestime = 0;
|
||||
totalresults = 1;
|
||||
}
|
||||
});
|
||||
|
||||
// Rest are down
|
||||
this.down = this.total - this.up;
|
||||
|
||||
// Calculate overall average response time
|
||||
this.avgRespTime = (totalrestime / totalresults).toFixed(2);
|
||||
|
||||
// Update representations
|
||||
if (this.up == 0 || this.total == 0) {
|
||||
this.percentageGood = 0;
|
||||
} else {
|
||||
this.percentageGood = Math.round((this.up / this.total) * 100);
|
||||
}
|
||||
|
||||
// Status flag
|
||||
if (this.up == 0 && this.down == 0) {
|
||||
this.status = false;
|
||||
} else if (this.down == this.total) {
|
||||
this.status = "bad";
|
||||
} else if (this.up == this.total) {
|
||||
this.status = "good";
|
||||
} else {
|
||||
this.status = "warn";
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.status {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-title);
|
||||
&.good:before {
|
||||
background-color: #94e185;
|
||||
border-color: #78d965;
|
||||
box-shadow: 0 0 5px 1px #94e185;
|
||||
}
|
||||
&.warn:before {
|
||||
background-color: #f8a306;
|
||||
border-color: #e1b35e;
|
||||
box-shadow: 0 0 5px 1px #f8a306;
|
||||
}
|
||||
&.bad: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>
|
||||
|
|
@ -19,6 +19,24 @@
|
|||
<div class="media-content">
|
||||
<slot name="content">
|
||||
<p class="title">{{ item.name }}</p>
|
||||
<p v-if="item.quick" class="quicklinks">
|
||||
<a
|
||||
v-for="(link, linkIndex) in item.quick"
|
||||
:key="linkIndex"
|
||||
:style="`background-color:${link.color};`"
|
||||
:href="link.url"
|
||||
:target="link.target"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<span v-if="link.icon"
|
||||
><i
|
||||
style="font-size: 12px"
|
||||
:class="['fa-fw', link.icon]"
|
||||
></i
|
||||
></span>
|
||||
{{ link.name }}
|
||||
</a>
|
||||
</p>
|
||||
<p v-if="item.subtitle" class="subtitle">
|
||||
{{ item.subtitle }}
|
||||
</p>
|
||||
|
|
@ -61,4 +79,22 @@ export default {
|
|||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
a[href=""] {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.quicklinks {
|
||||
float: right;
|
||||
a {
|
||||
font-size: 0.75rem;
|
||||
padding: 3px 6px;
|
||||
margin-left: 6px;
|
||||
border-radius: 100px;
|
||||
background-color: var(--background);
|
||||
z-index: 9999;
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@
|
|||
<template #content>
|
||||
<p class="title is-4">{{ item.name }}</p>
|
||||
<p class="subtitle is-6">
|
||||
<template v-if="versionstring">
|
||||
<template v-if="item.subtitle">
|
||||
{{ item.subtitle }}
|
||||
</template>
|
||||
<template v-else-if="versionstring">
|
||||
Version {{ versionstring }}
|
||||
</template>
|
||||
</p>
|
||||
|
|
@ -18,13 +21,9 @@
|
|||
|
||||
<script>
|
||||
import service from "@/mixins/service.js";
|
||||
import Generic from "./Generic.vue";
|
||||
|
||||
export default {
|
||||
name: "Gitea",
|
||||
components: {
|
||||
Generic,
|
||||
},
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue