├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ └── suggestion.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── pnpm-lock.yaml ├── public ├── CNAME └── v4 │ ├── apps │ ├── bazarr.yml │ ├── flaresolverr.yml │ ├── imgproxy.yml │ ├── photoview.yml │ ├── plex-media-server.yml │ ├── prowlarr.yml │ ├── radarr.yml │ ├── sonarr.yml │ └── vaultwarden.yml │ └── logos │ ├── bazarr.png │ ├── flaresolverr.png │ ├── imgproxy.png │ ├── photoview.png │ ├── plex-media-server.png │ ├── prowlarr.png │ ├── radarr.png │ ├── sonarr.png │ └── vaultwarden.png └── scripts ├── build-one-click-apps-from-v4.js ├── build-one-click-apps.js ├── migrate-v2-to-v4.js └── validate-apps.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | trim_trailing_whitespace = false 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/suggestion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: SUGGESTION 3 | about: Suggest a new one-click app 4 | title: 'App Suggestion: [APPNAME]' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Please tell us what app you'd like to see on CapRover as a one-click app.** 11 | 12 | 13 | **Do you know if there is any official Docker image for the app?** 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | First of all, thank you for your contribution! 😄 2 | 3 | 4 | ### ☑️ Self Check before Merge 5 | 6 | - [ ] I have tested the template using the method described in README.md thoroughly 7 | - [ ] I have ensured that I put as much default values as possible (except passwords) to ensure minimum effort required for end users to get started. 8 | - [ ] I have ensured that I am not using the "latest" tag as this tag is dynamically changing and might break the one-click app. Use a fixed version. 9 | - [ ] I have made sure that instructions.start and instructions.end are clear and self-explanatory. 10 | - [ ] Icon is added as a png file to the logos directory. 11 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Validate, Build & Deploy 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | validate-build-deploy: 12 | runs-on: ubuntu-latest 13 | steps: 14 | 15 | - name: Checkout 🛎️ 16 | uses: actions/checkout@v2 17 | 18 | - name: Restore Cache ♻ 19 | uses: actions/cache@v2 20 | with: 21 | path: ~/.pnpm-store 22 | key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} 23 | restore-keys: | 24 | ${{ runner.os }}- 25 | 26 | - name: Setup 🔧 27 | uses: pnpm/action-setup@v2.0.1 28 | with: 29 | version: 6.22.2 30 | run_install: true 31 | 32 | - name: Validate 🔎 33 | run: pnpm run validate 34 | 35 | - name: Build 🏗 36 | if: ${{ github.event_name == 'push' }} 37 | run: pnpm run build 38 | 39 | - name: Deploy 🚀 40 | if: ${{ github.event_name == 'push' }} 41 | uses: JamesIves/github-pages-deploy-action@4.1.5 42 | with: 43 | branch: gh-pages 44 | folder: dist 45 | git-config-name: SkayoBot 46 | git-config-email: frederike.gnampf@gmail.com 47 | clean: true 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | dist/* 3 | node_modules 4 | .DS_Store 5 | .idea/ 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Skayo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Skayo's CapRover One-Click-Apps 2 | 3 | This is my personal collection of one-click-apps that I use on my [CapRover](https://caprover.com/) instance. 4 | 5 | Feel free to use my them on your own server! 6 | Just add `https://caprover-oneclickapps.skayo.dev` to your 3rd party repositories at the bottom of the one-click-app page. 7 | 8 | Some of the apps in my collection are improved or modified versions from the original repo. 9 | You can identify my personal apps with the `(Skayo)` suffix. 10 | Maybe I will propose some of my changes to the original one-click-app repo, but it's not my priority. 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@skayo/caprover-one-click-apps", 3 | "version": "1.0.0", 4 | "description": "My Personal One-Click-App Repository for CapRover", 5 | "scripts": { 6 | "build": "rimraf ./dist && node ./scripts/build-one-click-apps.js && node ./scripts/build-one-click-apps-from-v4.js", 7 | "validate": "node ./scripts/validate-apps.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/SkayoCapRover-One-Click-Apps.git" 12 | }, 13 | "author": "Skayo (https://skayo.dev)", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/Skayo/CapRover-One-Click-Apps/issues" 17 | }, 18 | "homepage": "https://github.com/Skayo/CapRover-One-Click-Apps", 19 | "devDependencies": { 20 | "fs-extra": "^10.0.0", 21 | "rimraf": "^3.0.2", 22 | "yaml": "^1.10.2" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.3 2 | 3 | specifiers: 4 | fs-extra: ^10.0.0 5 | rimraf: ^3.0.2 6 | yaml: ^1.10.2 7 | 8 | devDependencies: 9 | fs-extra: 10.0.0 10 | rimraf: 3.0.2 11 | yaml: 1.10.2 12 | 13 | packages: 14 | 15 | /balanced-match/1.0.2: 16 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 17 | dev: true 18 | 19 | /brace-expansion/1.1.11: 20 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 21 | dependencies: 22 | balanced-match: 1.0.2 23 | concat-map: 0.0.1 24 | dev: true 25 | 26 | /concat-map/0.0.1: 27 | resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} 28 | dev: true 29 | 30 | /fs-extra/10.0.0: 31 | resolution: {integrity: sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==} 32 | engines: {node: '>=12'} 33 | dependencies: 34 | graceful-fs: 4.2.8 35 | jsonfile: 6.1.0 36 | universalify: 2.0.0 37 | dev: true 38 | 39 | /fs.realpath/1.0.0: 40 | resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} 41 | dev: true 42 | 43 | /glob/7.2.0: 44 | resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} 45 | dependencies: 46 | fs.realpath: 1.0.0 47 | inflight: 1.0.6 48 | inherits: 2.0.4 49 | minimatch: 3.0.4 50 | once: 1.4.0 51 | path-is-absolute: 1.0.1 52 | dev: true 53 | 54 | /graceful-fs/4.2.8: 55 | resolution: {integrity: sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==} 56 | dev: true 57 | 58 | /inflight/1.0.6: 59 | resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=} 60 | dependencies: 61 | once: 1.4.0 62 | wrappy: 1.0.2 63 | dev: true 64 | 65 | /inherits/2.0.4: 66 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 67 | dev: true 68 | 69 | /jsonfile/6.1.0: 70 | resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} 71 | dependencies: 72 | universalify: 2.0.0 73 | optionalDependencies: 74 | graceful-fs: 4.2.8 75 | dev: true 76 | 77 | /minimatch/3.0.4: 78 | resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} 79 | dependencies: 80 | brace-expansion: 1.1.11 81 | dev: true 82 | 83 | /once/1.4.0: 84 | resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} 85 | dependencies: 86 | wrappy: 1.0.2 87 | dev: true 88 | 89 | /path-is-absolute/1.0.1: 90 | resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=} 91 | engines: {node: '>=0.10.0'} 92 | dev: true 93 | 94 | /rimraf/3.0.2: 95 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 96 | hasBin: true 97 | dependencies: 98 | glob: 7.2.0 99 | dev: true 100 | 101 | /universalify/2.0.0: 102 | resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} 103 | engines: {node: '>= 10.0.0'} 104 | dev: true 105 | 106 | /wrappy/1.0.2: 107 | resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} 108 | dev: true 109 | 110 | /yaml/1.10.2: 111 | resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} 112 | engines: {node: '>= 6'} 113 | dev: true 114 | -------------------------------------------------------------------------------- /public/CNAME: -------------------------------------------------------------------------------- 1 | caprover-oneclickapps.skayo.dev 2 | -------------------------------------------------------------------------------- /public/v4/apps/bazarr.yml: -------------------------------------------------------------------------------- 1 | # Use schema version 4 2 | captainVersion: 4 3 | 4 | 5 | # One-click-app options 6 | caproverOneClickApp: 7 | 8 | # App name 9 | displayName: Bazarr (Skayo) 10 | 11 | # Description displayed on the app list 12 | description: |- 13 | Bazarr is a companion application to Sonarr and Radarr that manages and downloads subtitles based on your requirements 14 | 15 | # Define instructions 16 | instructions: 17 | 18 | # Displayed one the app config page, where you enter all variable values 19 | start: |- 20 | ![Bazarr Logo](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/bazarr.png) 21 | 22 | 🌐 [Website](https://www.bazarr.media/) 23 | 📖 [Documentation](https://wiki.bazarr.media/) 24 | 📁 [GitHub](https://github.com/morpheus65535/bazarr) 25 | 🐳 [DockerHub](https://hub.docker.com/r/linuxserver/bazarr) 26 | 👛 [Donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XHHRWXT9YB7WE&source=url) 27 | 28 | Bazarr is a companion application to Sonarr and Radarr. 29 | It manages and downloads subtitles based on your requirements. 30 | You define your preferences by TV show or movie and Bazarr takes care of everything for you. 31 | 32 | Be aware that Bazarr doesn't scan disk to detect series and movies: It only takes care of the series and movies that are indexed in Sonarr and Radarr. 33 | 34 | # Displayed after deployment 35 | end: |- 36 | 🎉🎉🎉 Successfully deployed! 37 | Check it out at: http://$$cap_appname.$$cap_root_domain 38 | 39 | # Documentation Link 40 | documentation: https://wiki.bazarr.media/ 41 | 42 | # Whether this one-click-app uses the official image or a trusted source 43 | isOfficial: true 44 | 45 | # Define variables 46 | variables: 47 | 48 | # Variable for version 49 | - id: $$cap_appversion 50 | label: App Version 51 | description: |- 52 | Specify the version tag to install. 53 | Click [here](https://hub.docker.com/r/linuxserver/bazarr/tags) for a list of available tags. 54 | defaultValue: 1.0.1 55 | validRegex: /^(?:(?:arm|amd)(?:64|32)(?:v\d+)?-)?(?:develop(?:ment)?-?|nightly-?)?(?:version-)?v?\d+\.\d+\.\d+(?:-beta\.\d+)?(?:-ls\d+)?$/ 56 | 57 | # Variable for media path 58 | - id: $$cap_media_path 59 | label: Media Path 60 | description: |- 61 | Specify the location of all your media (movies, TV shows, music, etc.). 62 | validRegex: /^(?:[a-zA-Z]:)?[\/\\]{0,2}(?:[.\/\\ ](?![.\/\\\n])|[^<>:"|?*.\/\\ \n])+$/ 63 | 64 | # Variable for time zone 65 | - id: $$cap_tz 66 | label: Time Zone 67 | description: |- 68 | Specify your system's time zone. 69 | Click [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for a list of available time zones. 70 | defaultValue: Europe/Vienna 71 | validRegex: /^\w+\/\w+$/ 72 | 73 | # Variable for Process User ID 74 | - id: $$cap_puid 75 | label: User ID 76 | description: |- 77 | Specify the User ID that the process should use. 78 | Run `id ` on the host system to see your UID. 79 | defaultValue: 1000 80 | validRegex: /^-?\d+$/ 81 | 82 | # Variable for Process Group ID 83 | - id: $$cap_pgid 84 | label: Group ID 85 | description: |- 86 | Specify the Group ID that the process should use. 87 | Run `id ` on the host system to see your GID. 88 | defaultValue: 1000 89 | validRegex: /^-?\d+$/ 90 | 91 | 92 | # Define services 93 | services: 94 | 95 | # Bazarr service 96 | $$cap_appname: 97 | 98 | # Use image by linuxserver.io 99 | image: lscr.io/linuxserver/bazarr:$$cap_appversion 100 | 101 | # Set hostname (f.e. bazarr.demo.caprover.com) 102 | hostname: $$cap_appname.$$cap_root_domain 103 | 104 | # Define environment variables 105 | environment: 106 | 107 | # Process User ID 108 | PUID: $$cap_puid 109 | 110 | # Process Group ID 111 | PGID: $$cap_pgid 112 | 113 | # Timezone 114 | TZ: $$cap_tz 115 | 116 | # Define volumes 117 | volumes: 118 | 119 | # Volume containing database data and config 120 | - $$cap_appname-config:/config 121 | 122 | # Volume containing media like movies and TV shows 123 | - $$cap_media_path:/data/media 124 | 125 | # CapRover's special options 126 | caproverExtra: 127 | 128 | # Bazarr uses port 6767 129 | containerHttpPort: 6767 130 | -------------------------------------------------------------------------------- /public/v4/apps/flaresolverr.yml: -------------------------------------------------------------------------------- 1 | # Use schema version 4 2 | captainVersion: 4 3 | 4 | 5 | # One-click-app options 6 | caproverOneClickApp: 7 | 8 | # App name 9 | displayName: FlareSolverr (Skayo) 10 | 11 | # Description displayed on the app list 12 | description: |- 13 | FlareSolverr is a proxy server to bypass Cloudflare protection 14 | 15 | # Define instructions 16 | instructions: 17 | 18 | # Displayed one the app config page, where you enter all variable values 19 | start: |- 20 | 📁 [GitHub](https://github.com/FlareSolverr/FlareSolverr) 21 | 🐳 [DockerHub](https://hub.docker.com/r/flaresolverr/flaresolverr) 22 | 👛 [Donate](https://www.buymeacoffee.com/ngosang) 23 | 24 | FlareSolverr starts a proxy server and it waits for user requests in an idle state using few resources. 25 | When some request arrives, it uses puppeteer with the stealth plugin to create a headless browser (Firefox). 26 | It opens the URL with user parameters and waits until the Cloudflare challenge is solved (or timeout). 27 | The HTML code and the cookies are sent back to the user, and those cookies can be used to bypass Cloudflare using other HTTP clients. 28 | 29 | Very useful for [Jackett](https://github.com/Jackett/Jackett) or [Prowlarr](https://prowlarr.com/). 30 | 31 | # Displayed after deployment 32 | end: |- 33 | 🎉🎉🎉 Successfully deployed! 34 | Check it out at: http://$$cap_appname.$$cap_root_domain 35 | 36 | # Documentation Link 37 | documentation: https://github.com/FlareSolverr/FlareSolverr 38 | 39 | # Whether this one-click-app uses the official image or a trusted source 40 | isOfficial: true 41 | 42 | # Define variables 43 | variables: 44 | 45 | # Variable for version 46 | - id: $$cap_appversion 47 | label: App Version 48 | description: |- 49 | Specify the version tag to install. 50 | Click [here](https://hub.docker.com/r/flaresolverr/flaresolverr/tags) for a list of available tags. 51 | defaultValue: v2.0.2 52 | validRegex: /^v\d+\.\d+\.\d+$/ 53 | 54 | # Variable for time zone 55 | - id: $$cap_tz 56 | label: Time Zone 57 | description: |- 58 | Specify your system's time zone. 59 | Click [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for a list of available time zones. 60 | defaultValue: Europe/Vienna 61 | validRegex: /^\w+\/\w+$/ 62 | 63 | 64 | # Define services 65 | services: 66 | 67 | # FlareSolverr service 68 | $$cap_appname: 69 | 70 | # Use official image 71 | image: ghcr.io/flaresolverr/flaresolverr:$$cap_appversion 72 | 73 | # Set hostname (f.e. flaresolverr.demo.caprover.com) 74 | hostname: $$cap_appname.$$cap_root_domain 75 | 76 | # Define environment variables 77 | environment: 78 | 79 | # Timezone 80 | TZ: $$cap_tz 81 | 82 | # Port, we set it to 80, so we don't have to specify containerHttpPort 83 | PORT: 80 84 | -------------------------------------------------------------------------------- /public/v4/apps/imgproxy.yml: -------------------------------------------------------------------------------- 1 | # Use schema version 4 2 | captainVersion: 4 3 | 4 | 5 | # One-click-app options 6 | caproverOneClickApp: 7 | 8 | # App name 9 | displayName: imgproxy (Skayo) 10 | 11 | # Description displayed on the app list 12 | description: |- 13 | Fast and secure standalone server for resizing and converting remote images 14 | 15 | # Define instructions 16 | instructions: 17 | 18 | # Displayed one the app config page, where you enter all variable values 19 | start: |- 20 | ![imgproxy logo](https://github.com/imgproxy/imgproxy/blob/master/docs/assets/favicon-128.png?raw=true) 21 | 22 | 🌐 [Website](https://imgproxy.net/) 23 | 📖 [Documentation](https://docs.imgproxy.net/) 24 | 📁 [GitHub](https://github.com/imgproxy/imgproxy) 25 | 🐳 [DockerHub](https://hub.docker.com/r/darthsim/imgproxy/) 26 | 👛 [Go Pro](https://imgproxy.net/#pro) 27 | 28 | imgproxy is a fast and secure standalone server for resizing and converting remote images. 29 | The main principles of imgproxy are simplicity, speed, and security. 30 | 31 | imgproxy can be used to provide a fast and secure way to replace all the image resizing code of your web application (like calling ImageMagick or GraphicsMagick, or using libraries), 32 | while also being able to resize everything on the fly, fast and easy. 33 | imgproxy is also indispensable when handling lots of image resizing, especially when images come from a remote source. 34 | 35 | imgproxy does one thing — resizing remote images — and does it well. 36 | It works great when you need to resize multiple images on the fly to make them match your application design without preparing a ton of cached resized images or re-doing it every time the design changes. 37 | 38 | # Displayed after deployment 39 | end: |- 40 | 🎉🎉🎉 Successfully deployed! 41 | Check it out at: http://$$cap_appname.$$cap_root_domain 42 | 43 | > *NOTE*: There's a lot of environment variables you can set. 44 | > Click [here](https://docs.imgproxy.net/configuration) for a complete list. 45 | 46 | # Documentation Link 47 | documentation: https://docs.imgproxy.net/ 48 | 49 | # Whether this one-click-app uses the official image or a trusted source 50 | isOfficial: true 51 | 52 | # Define variables 53 | variables: 54 | 55 | # Variable for version 56 | - id: $$cap_appversion 57 | label: App Version 58 | description: |- 59 | Specify the version tag to install. 60 | Click [here](https://hub.docker.com/r/darthsim/imgproxy/tags) for a list of available tags. 61 | defaultValue: v2.17.0 62 | validRegex: /^v\d+(?:\.\d+(?:\.\d+)?)?(?:\.beta\d+|\.rc\d+)?$/ 63 | 64 | 65 | # Define services 66 | services: 67 | 68 | # imgproxy service 69 | $$cap_appname: 70 | 71 | # Use official image 72 | image: darthsim/imgproxy:$$cap_appversion 73 | 74 | # Set hostname (f.e. imgproxy.demo.caprover.com) 75 | hostname: $$cap_appname.$$cap_root_domain 76 | 77 | # Define environment variables 78 | environment: 79 | 80 | # Address and Port, we set port to 80, so we don't have to specify containerHttpPort 81 | IMGPROXY_BIND: 0.0.0.0:80 82 | -------------------------------------------------------------------------------- /public/v4/apps/photoview.yml: -------------------------------------------------------------------------------- 1 | # Use schema version 4 2 | captainVersion: 4 3 | 4 | 5 | # One-click-app options 6 | caproverOneClickApp: 7 | 8 | # App name 9 | displayName: Photoview (Skayo) 10 | 11 | # Description displayed on the app list 12 | description: |- 13 | Photo gallery for self-hosted personal servers 14 | 15 | # Define instructions 16 | instructions: 17 | 18 | # Displayed one the app config page, where you enter all variable values 19 | start: |- 20 | ![Photoview Logo](https://github.com/photoview/photoview/raw/master/screenshots/photoview-logo.svg) 21 | 22 | 🌐 [Website](https://photoview.github.io/) 23 | 📖 [Documentation](https://photoview.github.io/docs) 24 | 📁 [GitHub](https://github.com/photoview/photoview) 25 | 🐳 [DockerHub](https://hub.docker.com/r/viktorstrate/photoview) 26 | 👛 [Donate](https://github.com/sponsors/viktorstrate) 27 | 28 | Photoview is a simple and user-friendly photo gallery that's made for photographers and aims to provide an easy and fast way to navigate directories, with thousands of high-resolution photos. 29 | 30 | You configure Photoview to look for photos and videos within a directory on your file system. 31 | The scanner automatically picks up your media and start to generate thumbnail images to make browsing super fast. 32 | 33 | When your media has been scanned they show up on the website, organised in the same way as on the filesystem. 34 | 35 | # Displayed after deployment 36 | end: |- 37 | 🎉🎉🎉 Successfully deployed! 38 | Check it out at: http://$$cap_appname.$$cap_root_domain 39 | 40 | # Documentation Link 41 | documentation: https://photoview.github.io/docs 42 | 43 | # Whether this one-click-app uses the official image or a trusted source 44 | isOfficial: true 45 | 46 | # Define variables 47 | variables: 48 | 49 | # Variable for Photoview Version 50 | - id: $$cap_appversion 51 | label: App Version 52 | description: |- 53 | Specify the version tag of Photoview to install. 54 | Click [here](https://hub.docker.com/r/linuxserver/sonarr/tags) for a list of available tags. 55 | defaultValue: 2.0.1 56 | validRegex: /^(?:\d+(?:\.\d+(?:\.\d+)?)?|linux)(?:-(?:arm|amd)(?:64|32)?(?:-v\d+)?(?:-[a-z0-9]+-push)?)?$/ 57 | 58 | # Variable for Media Path 59 | - id: $$cap_media_path 60 | label: Media Path 61 | description: |- 62 | Specify the location of all your photos and videos. 63 | validRegex: /^(?:[a-zA-Z]:)?[\/\\]{0,2}(?:[.\/\\ ](?![.\/\\\n])|[^<>:"|?*.\/\\ \n])+$/ 64 | 65 | # Variable for Mapbox Token 66 | - id: $$cap_mapbox_token 67 | label: Mapbox Token (OPTIONAL) 68 | description: |- 69 | To enable map related features, you need to create a mapbox token. 70 | A token can be generated for free [here](https://account.mapbox.com/access-tokens/). 71 | It's a good idea to limit the scope of the token to your own domain, to prevent others from using it. 72 | Leave empty to disable map related features. 73 | 74 | # Variable for MariaDB Version 75 | - id: $$cap_mariadb_appversion 76 | label: MariaDB Version 77 | description: |- 78 | Specify the version tag of MariaDB to install. 79 | Click [here](https://hub.docker.com/r/library/mariadb/tags) for a list of available tags. 80 | defaultValue: 10.5 81 | validRegex: /^(?:\d+(?:\.\d+(?:\.\d+)?)?|rc|alpha)(?:-\w+)?$/ 82 | 83 | # Variable for MariaDB Database Name 84 | - id: $$cap_mariadb_db 85 | label: MariaDB Database Name 86 | description: |- 87 | Name of the Database used by Photoview. 88 | Normally, you won't need to change this. 89 | defaultValue: photoview 90 | 91 | # Variable for MariaDB Username 92 | - id: $$cap_mariadb_user 93 | label: MariaDB Username 94 | description: |- 95 | Username for the Database used by Photoview. 96 | Normally, you won't need to change this. 97 | defaultValue: photoview 98 | 99 | # Variable for MariaDB Password 100 | - id: $$cap_mariadb_pass 101 | label: MariaDB Password 102 | description: |- 103 | Password for the Database used by Photoview. 104 | Normally, you won't need to change this. 105 | defaultValue: $$cap_gen_random_hex(16) 106 | 107 | 108 | # Define services 109 | services: 110 | 111 | # Photoview service 112 | $$cap_appname: 113 | 114 | # Use official image 115 | image: viktorstrate/photoview:$$cap_appversion 116 | 117 | # Define the services this service depends on 118 | depends_on: 119 | 120 | # Start the database first, then photoview 121 | - $$cap_appname-db 122 | 123 | # Set hostname (f.e. photoview.demo.caprover.com) 124 | hostname: $$cap_appname.$$cap_root_domain 125 | 126 | # Define environment variables 127 | environment: 128 | 129 | # We use a MySQL database, because it works much better for photoview 130 | PHOTOVIEW_DATABASE_DRIVER: mysql 131 | 132 | # Database Connection URL 133 | PHOTOVIEW_MYSQL_URL: $$cap_mariadb_user:$$cap_mariadb_pass@tcp(srv-captain--$$cap_appname-db)/$$cap_mariadb_db 134 | 135 | # Listen to 0.0.0.0 136 | PHOTOVIEW_LISTEN_IP: 0.0.0.0 137 | 138 | # Listen to port 80, so we don't have to specify containerHttpPort 139 | PHOTOVIEW_LISTEN_PORT: 80 140 | 141 | # Location of media cache 142 | PHOTOVIEW_MEDIA_CACHE: /app/cache 143 | 144 | # MapBox token for map related features 145 | MAPBOX_TOKEN: $$cap_mapbox_token 146 | 147 | # Define volumes 148 | volumes: 149 | 150 | # Volume containing media cache 151 | - $$cap_appname-media-cache:/app/cache 152 | 153 | # Volume containing photos and videos 154 | - $$cap_media_path:/data/media 155 | 156 | # MariaDB service 157 | $$cap_appname-db: 158 | 159 | # Use official image 160 | image: mariadb:$$cap_mariadb_appversion 161 | 162 | # Set hostname (f.e. photoview-db.demo.caprover.com) 163 | hostname: $$cap_appname-db.$$cap_root_domain 164 | 165 | # Define environment variables 166 | environment: 167 | 168 | # Use a random root password, because we don't need root access 169 | MYSQL_RANDOM_ROOT_PASSWORD: 1 170 | 171 | # Database Name 172 | MYSQL_DATABASE: $$cap_mariadb_db 173 | 174 | # Username 175 | MYSQL_USER: $$cap_mariadb_user 176 | 177 | # Password 178 | MYSQL_PASSWORD: $$cap_mariadb_pass 179 | 180 | # Define volumes 181 | volumes: 182 | 183 | # Persist database data 184 | - $$cap_appname-db-data:/var/lib/mysql 185 | 186 | # CapRover's special options 187 | caproverExtra: 188 | 189 | # Database, so don't expose as web app 190 | notExposeAsWebApp: true 191 | -------------------------------------------------------------------------------- /public/v4/apps/plex-media-server.yml: -------------------------------------------------------------------------------- 1 | # Use schema version 4 2 | captainVersion: 4 3 | 4 | 5 | # One-click-app options 6 | caproverOneClickApp: 7 | 8 | # App name 9 | displayName: Plex Media Server (Skayo) 10 | 11 | # Description displayed on the app list 12 | description: |- 13 | Plex organizes all of your personal media so you can enjoy it no matter where you are 14 | 15 | # Define instructions 16 | instructions: 17 | 18 | # Displayed one the app config page, where you enter all variable values 19 | start: |- 20 | ![Plex Logo](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/plex-banner.png) 21 | 22 | 🌐 [Website](https://www.plex.tv/) 23 | 📖 [Documentation](https://support.plex.tv/articles/) 24 | 📁 [GitHub](https://github.com/plexinc/pms-docker) 25 | 🐳 [DockerHub](https://hub.docker.com/r/linuxserver/plex) 26 | 🎫 [Go Premium](https://www.plex.tv/plex-pass/) 27 | 28 | With the easy-to-install Plex Media Server software and your Plex apps, available on all your favorite phones, tablets, streaming devices, gaming consoles, and smart TVs, you can stream your video, music, and photo collections any time, anywhere, to any device. 29 | 30 | # Displayed after deployment 31 | end: |- 32 | 🎉🎉🎉 Successfully deployed! 33 | Check it out at: http://$$cap_appname.$$cap_root_domain 34 | 35 | > *NOTE*: Make sure to allow all the required ports through your firewall! 36 | > Click [here](https://support.plex.tv/articles/201543147-what-network-ports-do-i-need-to-allow-through-my-firewall/) for a detailed description about each port. 37 | > This one-click-app template only makes the container expose the `32400` port. 38 | > Add others on the app config page if you need them. 39 | 40 | # Documentation Link 41 | documentation: https://support.plex.tv/articles/ 42 | 43 | # Whether this one-click-app uses the official image or a trusted source 44 | isOfficial: true 45 | 46 | # Define variables 47 | variables: 48 | 49 | # Variable for version 50 | - id: $$cap_appversion 51 | label: App Version 52 | description: |- 53 | Specify the version tag to install. 54 | Click [here](https://hub.docker.com/r/linuxserver/plex/tags) for a list of available tags. 55 | defaultValue: 1.24.5.5173-8dcc73a59-ls86 56 | validRegex: /^(?:(?:arm|amd)(?:64|32)(?:v\d+)?-)?(?:develop-?)?(?:version-)?(?:\d+)(?:\.\d+\.\d+(?:\.\d+)?)?(?:-[a-z0-9]+)?(?:-ls\d+)?$/ 57 | 58 | # Variable for media path 59 | - id: $$cap_media_path 60 | label: Media Path 61 | description: |- 62 | Specify the location of all your media (movies, TV shows, music, etc.). 63 | validRegex: /^(?:[a-zA-Z]:)?[\/\\]{0,2}(?:[.\/\\ ](?![.\/\\\n])|[^<>:"|?*.\/\\ \n])+$/ 64 | 65 | # Variable for claim token 66 | - id: $$cap_plex_claim 67 | label: Plex Claim Token (OPTIONAL) 68 | description: |- 69 | Optionally, you can obtain a claim token from [here](https://plex.tv/claim) and input it below. 70 | Keep in mind that claim tokens expire within 4 minutes. 71 | validRegex: /^(?:claim-[a-zA-Z0-9]+)?$/ 72 | 73 | # Variable for time zone 74 | - id: $$cap_tz 75 | label: Time Zone 76 | description: |- 77 | Specify your system's time zone. 78 | Click [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for a list of available time zones. 79 | defaultValue: Europe/Vienna 80 | validRegex: /^\w+\/\w+$/ 81 | 82 | # Variable for Process User ID 83 | - id: $$cap_puid 84 | label: User ID 85 | description: |- 86 | Specify the User ID that the process should use. 87 | Run `id ` on the host system to see your UID. 88 | defaultValue: 1000 89 | validRegex: /^-?\d+$/ 90 | 91 | # Variable for Process Group ID 92 | - id: $$cap_pgid 93 | label: Group ID 94 | description: |- 95 | Specify the Group ID that the process should use. 96 | Run `id ` on the host system to see your GID. 97 | defaultValue: 1000 98 | validRegex: /^-?\d+$/ 99 | 100 | 101 | # Define services 102 | services: 103 | 104 | # Plex service 105 | $$cap_appname: 106 | 107 | # Use image by linuxserver.io 108 | image: lscr.io/linuxserver/plex:$$cap_appversion 109 | 110 | # Set hostname (f.e. plex.demo.caprover.com) 111 | hostname: $$cap_appname.$$cap_root_domain 112 | 113 | # Define environment variables 114 | environment: 115 | 116 | # Process User ID 117 | PUID: $$cap_puid 118 | 119 | # Process Group ID 120 | PGID: $$cap_pgid 121 | 122 | # Timezone 123 | TZ: $$cap_tz 124 | 125 | # Plex Claim Token 126 | PLEX_CLAIM: $$cap_plex_claim 127 | 128 | # Define volumes 129 | volumes: 130 | 131 | # Volume containing database data and config 132 | - $$cap_appname-config:/config 133 | 134 | # Volume containing media like movies and TV shows 135 | - $$cap_media_path:/data/media 136 | 137 | # Define ports 138 | ports: 139 | 140 | # This is the only required port - allows access to the Plex Media Server 141 | - 32400:32400 142 | 143 | # CapRover's special options 144 | caproverExtra: 145 | 146 | # Plex uses port 32400 for the web interface 147 | containerHttpPort: 32400 148 | -------------------------------------------------------------------------------- /public/v4/apps/prowlarr.yml: -------------------------------------------------------------------------------- 1 | # Use schema version 4 2 | captainVersion: 4 3 | 4 | 5 | # One-click-app options 6 | caproverOneClickApp: 7 | 8 | # App name 9 | displayName: Prowlarr (Skayo) 10 | 11 | # Description displayed on the app list 12 | description: |- 13 | An indexer manager/proxy built on the popular *arr base stack that integrates seamlessly with Radarr, Sonarr and similar 14 | 15 | # Define instructions 16 | instructions: 17 | 18 | # Displayed one the app config page, where you enter all variable values 19 | start: |- 20 | ![Prowlarr Logo](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/prowlarr-banner.png) 21 | 22 | 📖 [Documentation](https://wiki.servarr.com/prowlarr) 23 | 📁 [GitHub](https://github.com/Prowlarr/Prowlarr) 24 | 🐳 [DockerHub](https://hub.docker.com/r/linuxserver/prowlarr) 25 | 👛 [Donate](https://github.com/sponsors/Prowlarr) 26 | 27 | Prowlarr is an indexer manager/proxy built on the popular *arr base stack (.NET/React.js) to integrate with your various PVR apps. 28 | Prowlarr supports management of both Torrent trackers and Usenet indexers. 29 | It integrates seamlessly with Lidarr, Mylar3, Radarr, Readarr, and Sonarr offering complete management of your indexers with no per-app indexer setup required (we do it all). 30 | 31 | # Displayed after deployment 32 | end: |- 33 | 🎉🎉🎉 Successfully deployed! 34 | Check it out at: http://$$cap_appname.$$cap_root_domain 35 | 36 | # Documentation Link 37 | documentation: https://wiki.servarr.com/prowlarr 38 | 39 | # Whether this one-click-app uses the official image or a trusted source 40 | isOfficial: true 41 | 42 | # Define variables 43 | variables: 44 | 45 | # Variable for version 46 | - id: $$cap_appversion 47 | label: App Version 48 | description: |- 49 | Specify the version tag to install. 50 | Click [here](https://hub.docker.com/r/linuxserver/prowlarr/tags) for a list of available tags. 51 | defaultValue: 1.4.1120 52 | validRegex: /^(?:(?:arm|amd)(?:64|32)(?:v\d+)?-)?(?:develop-?|nightly-?)?(?:version-)?\d+\.\d+\.\d+(?:\.\d+)?(?:-ls\d+)?$/ 53 | 54 | # Variable for time zone 55 | - id: $$cap_tz 56 | label: Time Zone 57 | description: |- 58 | Specify your system's time zone. 59 | Click [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for a list of available time zones. 60 | defaultValue: Europe/Vienna 61 | validRegex: /^\w+\/\w+$/ 62 | 63 | # Variable for Process User ID 64 | - id: $$cap_puid 65 | label: User ID 66 | description: |- 67 | Specify the User ID that the process should use. 68 | Run `id ` on the host system to see your UID. 69 | defaultValue: 1000 70 | validRegex: /^-?\d+$/ 71 | 72 | # Variable for Process Group ID 73 | - id: $$cap_pgid 74 | label: Group ID 75 | description: |- 76 | Specify the Group ID that the process should use. 77 | Run `id ` on the host system to see your GID. 78 | defaultValue: 1000 79 | validRegex: /^-?\d+$/ 80 | 81 | 82 | # Define services 83 | services: 84 | 85 | # Prowlarr service 86 | $$cap_appname: 87 | 88 | # Use image by linuxserver.io 89 | image: lscr.io/linuxserver/prowlarr:$$cap_appversion 90 | 91 | # Set hostname (f.e. prowlarr.demo.caprover.com) 92 | hostname: $$cap_appname.$$cap_root_domain 93 | 94 | # Define environment variables 95 | environment: 96 | 97 | # Process User ID 98 | PUID: $$cap_puid 99 | 100 | # Process Group ID 101 | PGID: $$cap_pgid 102 | 103 | # Timezone 104 | TZ: $$cap_tz 105 | 106 | # Define volumes 107 | volumes: 108 | 109 | # Volume containing database data and config 110 | - $$cap_appname-config:/config 111 | 112 | # CapRover's special options 113 | caproverExtra: 114 | 115 | # Prowlarr uses port 9696 116 | containerHttpPort: 9696 117 | -------------------------------------------------------------------------------- /public/v4/apps/radarr.yml: -------------------------------------------------------------------------------- 1 | # Use schema version 4 2 | captainVersion: 4 3 | 4 | 5 | # One-click-app options 6 | caproverOneClickApp: 7 | 8 | # App name 9 | displayName: Radarr (Skayo) 10 | 11 | # Description displayed on the app list 12 | description: |- 13 | A fork of Sonarr to work with movies à la Couchpotato - Automatically downloads Movies for you 14 | 15 | # Define instructions 16 | instructions: 17 | 18 | # Displayed one the app config page, where you enter all variable values 19 | start: |- 20 | ![Radarr Logo](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/radarr.png) 21 | 22 | 🌐 [Website](https://radarr.video) 23 | 📖 [Documentation](https://wiki.servarr.com/radarr) 24 | 📁 [GitHub](https://github.com/Radarr/Radarr) 25 | 🐳 [DockerHub](https://hub.docker.com/r/linuxserver/radarr) 26 | 👛 [Donate](https://opencollective.com/radarr) 27 | 28 | Radarr is a movie collection manager for Usenet and BitTorrent users. 29 | It can monitor multiple RSS feeds for new movies and will interface with clients and indexers to grab, sort, and rename them. 30 | It can also be configured to automatically upgrade the quality of existing files in the library when a better quality format becomes available. 31 | 32 | # Displayed after deployment 33 | end: |- 34 | 🎉🎉🎉 Successfully deployed! 35 | Check it out at: http://$$cap_appname.$$cap_root_domain 36 | 37 | # Documentation Link 38 | documentation: https://wiki.servarr.com/radarr 39 | 40 | # Whether this one-click-app uses the official image or a trusted source 41 | isOfficial: true 42 | 43 | # Define variables 44 | variables: 45 | 46 | # Variable for version 47 | - id: $$cap_appversion 48 | label: App Version 49 | description: |- 50 | Specify the version tag to install. 51 | Click [here](https://hub.docker.com/r/linuxserver/radarr/tags) for a list of available tags. 52 | defaultValue: 3.2.2.5080-ls121 53 | validRegex: /^(?:(?:arm|amd)(?:64|32)(?:v\d+)?-)?(?:develop-?)?(?:version-)?(?:\d+)(?:\.\d+\.\d+(?:\.\d+)?)?(?:-ls\d+)?$/ 54 | 55 | # Variable for data path 56 | - id: $$cap_data_path 57 | label: Data Path 58 | description: |- 59 | Specify the location of all your movies and downloads. 60 | > *NOTE*: It's best to use a single volume for movies and downloads, otherwise import will take **MUCH** longer! 61 | > If you still want two different volumes, just change it on the app config page later on. 62 | validRegex: /^(?:[a-zA-Z]:)?[\/\\]{0,2}(?:[.\/\\ ](?![.\/\\\n])|[^<>:"|?*.\/\\ \n])+$/ 63 | 64 | # Variable for time zone 65 | - id: $$cap_tz 66 | label: Time Zone 67 | description: |- 68 | Specify your system's time zone. 69 | Click [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for a list of available time zones. 70 | defaultValue: Europe/Vienna 71 | validRegex: /^\w+\/\w+$/ 72 | 73 | # Variable for Process User ID 74 | - id: $$cap_puid 75 | label: User ID 76 | description: |- 77 | Specify the User ID that the process should use. 78 | Run `id ` on the host system to see your UID. 79 | defaultValue: 1000 80 | validRegex: /^-?\d+$/ 81 | 82 | # Variable for Process Group ID 83 | - id: $$cap_pgid 84 | label: Group ID 85 | description: |- 86 | Specify the Group ID that the process should use. 87 | Run `id ` on the host system to see your GID. 88 | defaultValue: 1000 89 | validRegex: /^-?\d+$/ 90 | 91 | 92 | # Define services 93 | services: 94 | 95 | # Radarr service 96 | $$cap_appname: 97 | 98 | # Use image by linuxserver.io 99 | image: lscr.io/linuxserver/radarr:$$cap_appversion 100 | 101 | # Set hostname (f.e. radarr.demo.caprover.com) 102 | hostname: $$cap_appname.$$cap_root_domain 103 | 104 | # Define environment variables 105 | environment: 106 | 107 | # Process User ID 108 | PUID: $$cap_puid 109 | 110 | # Process Group ID 111 | PGID: $$cap_pgid 112 | 113 | # Timezone 114 | TZ: $$cap_tz 115 | 116 | # Define volumes 117 | volumes: 118 | 119 | # Volume containing database data and config 120 | - $$cap_appname-config:/config 121 | 122 | # Volume containing movies and downloads 123 | - $$cap_data_path:/data 124 | 125 | # CapRover's special options 126 | caproverExtra: 127 | 128 | # Radarr uses port 7878 129 | containerHttpPort: 7878 130 | -------------------------------------------------------------------------------- /public/v4/apps/sonarr.yml: -------------------------------------------------------------------------------- 1 | # Use schema version 4 2 | captainVersion: 4 3 | 4 | 5 | # One-click-app options 6 | caproverOneClickApp: 7 | 8 | # App name 9 | displayName: Sonarr (Skayo) 10 | 11 | # Description displayed on the app list 12 | description: |- 13 | A smart PVR for Usenet and BitTorrent users - Automatically downloads TV Shows for you 14 | 15 | # Define instructions 16 | instructions: 17 | 18 | # Displayed one the app config page, where you enter all variable values 19 | start: |- 20 | ![Sonarr Logo](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/sonarr-banner.png) 21 | 22 | 🌐 [Website](https://sonarr.tv/) 23 | 📖 [Documentation](https://wiki.servarr.com/sonarr) 24 | 📁 [GitHub](https://github.com/Sonarr/Sonarr) 25 | 🐳 [DockerHub](https://hub.docker.com/r/linuxserver/sonarr) 26 | 👛 [Donate](https://sonarr.tv/donate) 27 | 28 | Sonarr is a PVR for Usenet and BitTorrent users. 29 | It can monitor multiple RSS feeds for new episodes of your favorite shows and will grab, sort and rename them. 30 | It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available. 31 | 32 | # Displayed after deployment 33 | end: |- 34 | 🎉🎉🎉 Successfully deployed! 35 | Check it out at: http://$$cap_appname.$$cap_root_domain 36 | 37 | # Documentation Link 38 | documentation: https://wiki.servarr.com/sonarr 39 | 40 | # Whether this one-click-app uses the official image or a trusted source 41 | isOfficial: true 42 | 43 | # Define variables 44 | variables: 45 | 46 | # Variable for version 47 | - id: $$cap_appversion 48 | label: App Version 49 | description: |- 50 | Specify the version tag to install. 51 | Click [here](https://hub.docker.com/r/linuxserver/sonarr/tags) for a list of available tags. 52 | defaultValue: 3.0.6.1342-ls128 53 | validRegex: /^(?:(?:arm|amd)(?:64|32)(?:v\d+)?-)?(?:develop-?)?(?:version-)?(?:\d+)(?:\.\d+\.\d+(?:\.\d+)?)?(?:-ls\d+)?$/ 54 | 55 | # Variable for data path 56 | - id: $$cap_data_path 57 | label: Data Path 58 | description: |- 59 | Specify the location of all your TV shows and downloads. 60 | > *NOTE*: It's best to use a single volume for TV shows and downloads, otherwise imports will take **MUCH** longer! 61 | > If you still want two different volumes, just change it on the app config page later on. 62 | validRegex: /^(?:[a-zA-Z]:)?[\/\\]{0,2}(?:[.\/\\ ](?![.\/\\\n])|[^<>:"|?*.\/\\ \n])+$/ 63 | 64 | # Variable for time zone 65 | - id: $$cap_tz 66 | label: Time Zone 67 | description: |- 68 | Specify your system's time zone. 69 | Click [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for a list of available time zones. 70 | defaultValue: Europe/Vienna 71 | validRegex: /^\w+\/\w+$/ 72 | 73 | # Variable for Process User ID 74 | - id: $$cap_puid 75 | label: User ID 76 | description: |- 77 | Specify the User ID that the process should use. 78 | Run `id ` on the host system to see your UID. 79 | defaultValue: 1000 80 | validRegex: /^-?\d+$/ 81 | 82 | # Variable for Process Group ID 83 | - id: $$cap_pgid 84 | label: Group ID 85 | description: |- 86 | Specify the Group ID that the process should use. 87 | Run `id ` on the host system to see your GID. 88 | defaultValue: 1000 89 | validRegex: /^-?\d+$/ 90 | 91 | 92 | # Define services 93 | services: 94 | 95 | # Sonarr service 96 | $$cap_appname: 97 | 98 | # Use image by linuxserver.io 99 | image: lscr.io/linuxserver/sonarr:$$cap_appversion 100 | 101 | # Set hostname (f.e. sonarr.demo.caprover.com) 102 | hostname: $$cap_appname.$$cap_root_domain 103 | 104 | # Define environment variables 105 | environment: 106 | 107 | # Process User ID 108 | PUID: $$cap_puid 109 | 110 | # Process Group ID 111 | PGID: $$cap_pgid 112 | 113 | # Timezone 114 | TZ: $$cap_tz 115 | 116 | # Define volumes 117 | volumes: 118 | 119 | # Volume containing database data and config 120 | - $$cap_appname-config:/config 121 | 122 | # Volume containing TV shows and downloads 123 | - $$cap_data_path:/data 124 | 125 | # CapRover's special options 126 | caproverExtra: 127 | 128 | # Sonarr uses port 8989 129 | containerHttpPort: 8989 130 | -------------------------------------------------------------------------------- /public/v4/apps/vaultwarden.yml: -------------------------------------------------------------------------------- 1 | # Use schema version 4 2 | captainVersion: 4 3 | 4 | 5 | # One-click-app options 6 | caproverOneClickApp: 7 | 8 | # App name 9 | displayName: vaultwarden (Skayo) 10 | 11 | # Description displayed on the app list 12 | description: |- 13 | Unofficial Bitwarden compatible server written in Rust, formerly known as bitwarden_rs 14 | 15 | # Define instructions 16 | instructions: 17 | 18 | # Displayed one the app config page, where you enter all variable values 19 | start: |- 20 | ![Vaultwarden Logo](https://raw.githubusercontent.com/dani-garcia/vaultwarden/main/resources/vaultwarden-logo.svg) 21 | 22 | 📖 [Documentation](https://github.com/dani-garcia/vaultwarden/wiki) 23 | 📁 [GitHub](https://github.com/dani-garcia/vaultwarden) 24 | 🐳 [DockerHub](https://hub.docker.com/r/vaultwarden/server) 25 | 👛 [Donate](https://github.com/sponsors/dani-garcia) 26 | 27 | Alternative implementation of the Bitwarden server API written in Rust and compatible with upstream Bitwarden clients*, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal. 28 | 29 | > *NOTE*: This project was known as Bitwarden_RS and has been renamed to separate itself from the official Bitwarden server in the hopes of avoiding confusion and trademark/branding issues. 30 | 31 | # Displayed after deployment 32 | end: |- 33 | 🎉🎉🎉 Successfully deployed! 34 | Check it out at: http://$$cap_appname.$$cap_root_domain 35 | 36 | > *NOTE*: Enable WebSocket Support in the app's HTTP settings. 37 | > Also make sure to allow port `3012` through your firewall. 38 | > Also enable HTTPS. 39 | 40 | > *NOTE*: There's a lot of environment variables you can set. 41 | > Click [here](https://github.com/dani-garcia/vaultwarden/blob/main/.env.template) for a complete list. 42 | 43 | # Documentation Link 44 | documentation: https://github.com/dani-garcia/vaultwarden/wiki 45 | 46 | # Whether this one-click-app uses the official image or a trusted source 47 | isOfficial: true 48 | 49 | # Define variables 50 | variables: 51 | 52 | # Variable for version 53 | - id: $$cap_appversion 54 | label: App Version 55 | description: |- 56 | Specify the version tag to install. 57 | Click [here](https://hub.docker.com/r/vaultwarden/server/tags) for a list of available tags. 58 | defaultValue: 1.23.0-alpine 59 | validRegex: /^(?:\d+\.\d+\.\d+(?:\.\d+)?)(?:-alpine)?(?:-(?:arm|amd)(?:64|32)(?:v\d+)?)?$/ 60 | 61 | # Variable for time zone 62 | - id: $$cap_tz 63 | label: Time Zone 64 | description: |- 65 | Specify your system's time zone. 66 | Click [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for a list of available time zones. 67 | defaultValue: Europe/Vienna 68 | validRegex: /^\w+\/\w+$/ 69 | 70 | # Variable for user signups enabled/disabled 71 | - id: $$cap_user_signups 72 | label: Enable User Sign-Ups? 73 | description: |- 74 | Controls if new users can register. 75 | > *NOTE*: You should probably disable this after you sign-up. 76 | defaultValue: "true" 77 | validRegex: /^(true|false)$/ 78 | 79 | 80 | # Define services 81 | services: 82 | 83 | # Bitwarden service 84 | $$cap_appname: 85 | 86 | # Use official image 87 | image: vaultwarden/server:$$cap_appversion 88 | 89 | # Set hostname (f.e. vaultwarden.demo.caprover.com) 90 | hostname: $$cap_appname.$$cap_root_domain 91 | 92 | # Define environment variables 93 | environment: 94 | 95 | # The domain which vaultwarden runs on, I use https because I doubt anyone will run vaultwarden on non-https 96 | DOMAIN: https://$$cap_appname.$$cap_root_domain 97 | 98 | # Timezone 99 | TZ: $$cap_tz 100 | 101 | # Enable websocket notifications 102 | WEBSOCKET_ENABLED: true 103 | 104 | # Disable user sign-ups 105 | SIGNUPS_ALLOWED: $$cap_user_signups 106 | 107 | # Define ports 108 | ports: 109 | 110 | # WebSocket port 111 | - 3012:3012 112 | 113 | # Define volumes 114 | volumes: 115 | 116 | # Volume containing database data and config 117 | - $$cap_appname-data:/data 118 | -------------------------------------------------------------------------------- /public/v4/logos/bazarr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasgeiler/caprover-one-click-apps/f4bfa8490d48c5b30199cb916a1aba1277715296/public/v4/logos/bazarr.png -------------------------------------------------------------------------------- /public/v4/logos/flaresolverr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasgeiler/caprover-one-click-apps/f4bfa8490d48c5b30199cb916a1aba1277715296/public/v4/logos/flaresolverr.png -------------------------------------------------------------------------------- /public/v4/logos/imgproxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasgeiler/caprover-one-click-apps/f4bfa8490d48c5b30199cb916a1aba1277715296/public/v4/logos/imgproxy.png -------------------------------------------------------------------------------- /public/v4/logos/photoview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasgeiler/caprover-one-click-apps/f4bfa8490d48c5b30199cb916a1aba1277715296/public/v4/logos/photoview.png -------------------------------------------------------------------------------- /public/v4/logos/plex-media-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasgeiler/caprover-one-click-apps/f4bfa8490d48c5b30199cb916a1aba1277715296/public/v4/logos/plex-media-server.png -------------------------------------------------------------------------------- /public/v4/logos/prowlarr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasgeiler/caprover-one-click-apps/f4bfa8490d48c5b30199cb916a1aba1277715296/public/v4/logos/prowlarr.png -------------------------------------------------------------------------------- /public/v4/logos/radarr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasgeiler/caprover-one-click-apps/f4bfa8490d48c5b30199cb916a1aba1277715296/public/v4/logos/radarr.png -------------------------------------------------------------------------------- /public/v4/logos/sonarr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasgeiler/caprover-one-click-apps/f4bfa8490d48c5b30199cb916a1aba1277715296/public/v4/logos/sonarr.png -------------------------------------------------------------------------------- /public/v4/logos/vaultwarden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasgeiler/caprover-one-click-apps/f4bfa8490d48c5b30199cb916a1aba1277715296/public/v4/logos/vaultwarden.png -------------------------------------------------------------------------------- /scripts/build-one-click-apps-from-v4.js: -------------------------------------------------------------------------------- 1 | /*jshint esversion: 6 */ 2 | const path = require('path'); 3 | const yaml = require('yaml'); 4 | const fs = require('fs-extra'); 5 | 6 | const pathOfPublic = path.join(__dirname, '..', `public`); 7 | 8 | const pathOfDist = path.join(__dirname, '..', `dist`); 9 | 10 | const pathOfDistV2 = path.join(pathOfDist, 'v2'); 11 | const pathOfDistV3 = path.join(pathOfDist, 'v3'); 12 | const pathOfDistV4 = path.join(pathOfDist, 'v4'); 13 | 14 | const pathOfSourceDirectory = path.join(pathOfPublic, 'v4'); 15 | const pathOfSourceDirectoryApps = path.join(pathOfSourceDirectory, 'apps'); 16 | const pathOfSourceDirectoryLogos = path.join(pathOfSourceDirectory, 'logos'); 17 | 18 | /** 19 | * Creates a listing of apps for GET http://oneclickapps.caprover.com/v4 20 | * { 21 | "oneClickApps": [ 22 | { 23 | "name": "adminer", 24 | "displayName": "Adminer", 25 | "description": "Adminer (formerly phpMinAdmin) is a full-featured database management tool written in PHP", 26 | "isOfficial": true, 27 | "logoUrl": "adminer.png" 28 | },.....]} 29 | */ 30 | function createAppList(appsFileNames, pathOfApps) { 31 | const apps = appsFileNames.filter(v => `${v}`.endsWith('.yml')); 32 | 33 | if (apps.length !== appsFileNames.length) { 34 | throw new Error('All files in v4 must end with .yml extension!'); 35 | } 36 | 37 | const appDetails = []; 38 | 39 | for (var i = 0; i < apps.length; i++) { 40 | const contentString = fs.readFileSync(path.join(pathOfApps, apps[i]), 'utf-8'); 41 | const content = yaml.parse(contentString); 42 | const captainVersion = `${content.captainVersion}`; 43 | 44 | apps[i] = apps[i].replace('.yml', ''); 45 | const caproverOneClickApp = content.caproverOneClickApp; 46 | 47 | if (captainVersion === '4') { 48 | if (!caproverOneClickApp.displayName) { 49 | caproverOneClickApp.displayName = apps[i]; 50 | caproverOneClickApp.displayName = caproverOneClickApp.displayName.substr(0, 1).toUpperCase() + 51 | caproverOneClickApp.displayName.substring(1, caproverOneClickApp.displayName.length); 52 | } 53 | if (!caproverOneClickApp.description) caproverOneClickApp.description = ''; 54 | 55 | appDetails[i] = { 56 | name: apps[i], 57 | displayName: caproverOneClickApp.displayName, 58 | description: caproverOneClickApp.description, 59 | isOfficial: `${caproverOneClickApp.isOfficial}`.toLowerCase().trim() === 'true', 60 | logoUrl: apps[i] + '.png' 61 | }; 62 | } else { 63 | throw new Error('Unknown captain-version: ' + captainVersion); 64 | } 65 | 66 | } 67 | 68 | return { 69 | appList: apps, 70 | appDetails: appDetails 71 | }; 72 | } 73 | 74 | function convertV4toV2(v4String) { 75 | const parsed = JSON.parse(v4String); 76 | if (`${parsed.captainVersion}` !== '4') { 77 | throw new Error('CaptainVersion must be 4 for this conversion'); 78 | } 79 | 80 | function moveProperty(propertyName) { 81 | parsed[propertyName] = parsed.caproverOneClickApp[propertyName]; 82 | } 83 | 84 | parsed.dockerCompose = { 85 | services: parsed.services 86 | }; 87 | parsed.services = undefined; 88 | 89 | parsed.captainVersion = 2; 90 | 91 | 92 | moveProperty('variables'); 93 | moveProperty('instructions'); 94 | moveProperty('displayName'); 95 | moveProperty('isOfficial'); 96 | moveProperty('description'); 97 | moveProperty('documentation'); 98 | 99 | Object.keys(parsed.dockerCompose.services).forEach(serviceName => { 100 | const service = parsed.dockerCompose.services[serviceName]; 101 | 102 | if (!service.caproverExtra) { 103 | return; 104 | } 105 | 106 | if (service.caproverExtra.containerHttpPort) { 107 | service.containerHttpPort = service.caproverExtra.containerHttpPort; 108 | } 109 | if (service.caproverExtra.dockerfileLines) { 110 | service.dockerfileLines = service.caproverExtra.dockerfileLines; 111 | } 112 | if (service.caproverExtra.notExposeAsWebApp) { 113 | service.notExposeAsWebApp = service.caproverExtra.notExposeAsWebApp; 114 | } 115 | 116 | service.caproverExtra = undefined; 117 | }); 118 | 119 | parsed.caproverOneClickApp = undefined; 120 | return parsed; 121 | } 122 | 123 | 124 | function buildDist() { 125 | return fs.readdir(pathOfSourceDirectoryApps) 126 | .then(function (appsFileNames) { // [ app1.yml app2.yml .... ] 127 | 128 | appsFileNames.forEach(appFileName => { 129 | 130 | console.log('Building dist for ' + appFileName); 131 | 132 | const pathOfAppFileInSource = path.join(pathOfSourceDirectoryApps, appFileName); 133 | const contentParsed = yaml.parse(fs.readFileSync(pathOfAppFileInSource, 'utf-8')); 134 | 135 | //v4 136 | fs.outputJsonSync(path.join(pathOfDistV4, `apps`, appFileName.split('.')[0]), contentParsed); 137 | 138 | //v3 139 | fs.outputJsonSync(path.join(pathOfDistV3, `apps`, appFileName.split('.')[0]), convertV4toV2(JSON.stringify(contentParsed))); 140 | 141 | //v2 142 | fs.outputJsonSync(path.join(pathOfDistV2, `apps`, appFileName.split('.')[0] + '.json'), convertV4toV2(JSON.stringify(contentParsed))); 143 | }); 144 | 145 | fs.copySync(pathOfSourceDirectoryLogos, path.join(pathOfDistV2, `logos`)); 146 | fs.copySync(pathOfSourceDirectoryLogos, path.join(pathOfDistV3, `logos`)); 147 | fs.copySync(pathOfSourceDirectoryLogos, path.join(pathOfDistV4, `logos`)); 148 | 149 | const allAppsList = createAppList(appsFileNames, pathOfSourceDirectoryApps); 150 | const v3List = { 151 | oneClickApps: allAppsList.appDetails 152 | }; 153 | 154 | // Remove once we are fully on V4 155 | if (fs.existsSync(path.join(pathOfDistV3, 'list'))) { 156 | const v3ListExisting = fs.readFileSync(path.join(pathOfDistV3, 'list'), 'utf-8'); 157 | if (v3ListExisting && JSON.parse(v3ListExisting).oneClickApps) { 158 | v3List.oneClickApps = [...v3List.oneClickApps, ...JSON.parse(v3ListExisting).oneClickApps]; 159 | const names = {}; 160 | const list = []; 161 | v3List.oneClickApps.forEach(a => { 162 | if (!names[a.name]) { 163 | list.push(a); 164 | names[a.name] = true; 165 | } 166 | }); 167 | v3List.oneClickApps = list.sort(function (a, b) { 168 | return `${a.name}`.localeCompare(b.name); 169 | }); 170 | 171 | allAppsList.appList = list.map(l => l.name); 172 | allAppsList.appDetails = v3List.oneClickApps; 173 | } 174 | } 175 | 176 | 177 | fs.outputJsonSync(path.join(pathOfDistV2, 'autoGeneratedList.json'), allAppsList); 178 | fs.outputJsonSync(path.join(pathOfDistV2, 'list'), v3List); 179 | fs.outputJsonSync(path.join(pathOfDistV3, 'list'), v3List); 180 | fs.outputJsonSync(path.join(pathOfDistV4, 'list'), v3List); 181 | }) 182 | .then(function () { 183 | return fs.copySync(path.join(pathOfPublic, 'CNAME'), path.join(pathOfDist, 'CNAME')); 184 | }); 185 | } 186 | 187 | 188 | Promise.resolve() 189 | .then(function () { 190 | return buildDist(); 191 | }) 192 | .catch(function (err) { 193 | console.error(err); 194 | process.exit(127); 195 | }); -------------------------------------------------------------------------------- /scripts/build-one-click-apps.js: -------------------------------------------------------------------------------- 1 | /*jshint esversion: 6 */ 2 | const path = require('path'); 3 | const yaml = require('yaml'); 4 | const fs = require('fs-extra'); 5 | 6 | // Next, for V4: 7 | // ============================================================================ 8 | // ============================================================================ 9 | // *********** THIS IS ONLY TO BE DONE AFTER CAPROVER 1.8 RELEASE ************* 10 | // ============================================================================ 11 | // ============================================================================ 12 | // 13 | // 1- DUPLICATE this script. The new script is to ONLY read from /public/v4/*.yaml 14 | // 2- Test with a new YAML file 15 | // 3- Write script to convert all v2 JSON to V4 yaml and place them in /public/v4/*.yaml 16 | // 4- Update readme!!!! 17 | // 5- Push all 3 steps above at the same time to GITHUB 18 | 19 | const pathOfPublic = path.join(__dirname, '..', `public`); 20 | 21 | const pathOfDist = path.join(__dirname, '..', `dist`); 22 | 23 | const pathOfDistV2 = path.join(pathOfDist, 'v2'); 24 | const pathOfDistV3 = path.join(pathOfDist, 'v3'); 25 | const pathOfDistV4 = path.join(pathOfDist, 'v4'); 26 | 27 | const pathOfSourceDirectory = path.join(pathOfPublic, 'v2'); 28 | const pathOfSourceDirectoryApps = path.join(pathOfSourceDirectory, 'apps'); 29 | const pathOfSourceDirectoryLogos = path.join(pathOfSourceDirectory, 'logos'); 30 | 31 | 32 | function createAppList(appsList, pathOfApps) { 33 | const apps = appsList.filter(v => v.includes('.json')); 34 | const appDetails = []; 35 | 36 | for (var i = 0; i < apps.length; i++) { 37 | const contentString = fs.readFileSync(path.join(pathOfApps, apps[i])); 38 | const content = JSON.parse(contentString); 39 | const captainVersion = (content.captainVersion + ''); 40 | 41 | apps[i] = apps[i].replace('.json', ''); 42 | 43 | if (captainVersion + '' === '2') { 44 | if (!content.displayName) { 45 | content.displayName = apps[i]; 46 | content.displayName = content.displayName.substr(0, 1).toUpperCase() + content.displayName.substring(1, content.displayName.length); 47 | } 48 | if (!content.description) content.description = ''; 49 | 50 | appDetails[i] = { 51 | name: apps[i], 52 | displayName: content.displayName, 53 | description: content.description, 54 | isOfficial: `${content.isOfficial}`.toLowerCase() === 'true', 55 | logoUrl: apps[i] + '.png' 56 | }; 57 | } else { 58 | throw new Error('Unknown captain-version: ' + captainVersion); 59 | } 60 | 61 | } 62 | 63 | return { 64 | appList: apps, 65 | appDetails: appDetails 66 | }; 67 | } 68 | 69 | function convertV2toV4(v2String) { 70 | const parsed = JSON.parse(v2String); 71 | if (`${parsed.captainVersion}` !== '2') { 72 | throw new Error('CaptainVersion must be 2 for this conversion'); 73 | } 74 | 75 | function moveProperty(propertyName) { 76 | parsed.caproverOneClickApp[propertyName] = parsed[propertyName]; 77 | parsed[propertyName] = undefined; 78 | } 79 | 80 | parsed.services = parsed.dockerCompose.services; 81 | parsed.dockerCompose = undefined; 82 | 83 | parsed.captainVersion = 4; 84 | parsed.caproverOneClickApp = {}; 85 | 86 | moveProperty('variables'); 87 | moveProperty('instructions'); 88 | moveProperty('displayName'); 89 | moveProperty('isOfficial'); 90 | moveProperty('description'); 91 | moveProperty('documentation'); 92 | 93 | Object.keys(parsed.services).forEach(serviceName => { 94 | const service = parsed.services[serviceName]; 95 | if (service.containerHttpPort) { 96 | service.caproverExtra = service.caproverExtra || {}; 97 | service.caproverExtra.containerHttpPort = service.containerHttpPort; 98 | } 99 | if (service.dockerfileLines) { 100 | service.caproverExtra = service.caproverExtra || {}; 101 | service.caproverExtra.dockerfileLines = service.dockerfileLines; 102 | } 103 | if (service.notExposeAsWebApp) { 104 | service.caproverExtra = service.caproverExtra || {}; 105 | service.caproverExtra.notExposeAsWebApp = service.notExposeAsWebApp; 106 | } 107 | service.containerHttpPort = undefined; 108 | service.dockerfileLines = undefined; 109 | service.notExposeAsWebApp = undefined; 110 | }); 111 | 112 | return parsed; 113 | } 114 | 115 | 116 | function buildDist() { 117 | return Promise.resolve() 118 | .then(function () { 119 | if (!fs.existsSync(pathOfSourceDirectoryApps)) { 120 | return []; 121 | } 122 | return fs.readdir(pathOfSourceDirectoryApps); 123 | }) 124 | .then(function (appsFileNames) { // [ app1.json app2.json .... ] 125 | 126 | if (appsFileNames.length === 0) { 127 | return; 128 | } 129 | 130 | appsFileNames.forEach(appFileName => { 131 | const pathOfAppFileInSource = path.join(pathOfSourceDirectoryApps, appFileName); 132 | 133 | //v2 134 | fs.copySync(pathOfAppFileInSource, path.join(pathOfDistV2, `apps`, appFileName)); 135 | 136 | //v3 137 | fs.copySync(pathOfAppFileInSource, path.join(pathOfDistV3, `apps`, appFileName.split('.')[0])); 138 | 139 | //v4 140 | const contentString = fs.readFileSync(pathOfAppFileInSource); 141 | fs.outputJsonSync(path.join(pathOfDistV4, `apps`, appFileName.split('.')[0]), convertV2toV4(contentString)); 142 | }); 143 | 144 | fs.copySync(pathOfSourceDirectoryLogos, path.join(pathOfDistV2, `logos`)); 145 | fs.copySync(pathOfSourceDirectoryLogos, path.join(pathOfDistV3, `logos`)); 146 | fs.copySync(pathOfSourceDirectoryLogos, path.join(pathOfDistV4, `logos`)); 147 | 148 | const allAppsList = createAppList(appsFileNames, pathOfSourceDirectoryApps); 149 | const v3List = { 150 | oneClickApps: allAppsList.appDetails 151 | }; 152 | fs.outputJsonSync(path.join(pathOfDistV2, 'autoGeneratedList.json'), allAppsList); 153 | fs.outputJsonSync(path.join(pathOfDistV2, 'list'), v3List); // TODO delete oneClickApps: 154 | fs.outputJsonSync(path.join(pathOfDistV3, 'list'), v3List); 155 | fs.outputJsonSync(path.join(pathOfDistV4, 'list'), v3List); 156 | return fs.copySync(path.join(pathOfPublic, 'CNAME'), path.join(pathOfDist, 'CNAME')); 157 | }); 158 | } 159 | 160 | 161 | Promise.resolve() 162 | .then(function () { 163 | return buildDist(); 164 | }) 165 | .catch(function (err) { 166 | console.error(err); 167 | process.exit(127); 168 | }); -------------------------------------------------------------------------------- /scripts/migrate-v2-to-v4.js: -------------------------------------------------------------------------------- 1 | /*jshint esversion: 6 */ 2 | const path = require('path'); 3 | const yaml = require('yaml'); 4 | const types = require('yaml/types'); 5 | const fs = require('fs-extra'); 6 | types.strOptions.fold.lineWidth = 0; 7 | 8 | // Next, for V4: 9 | // ============================================================================ 10 | // ============================================================================ 11 | // *********** THIS IS ONLY TO BE DONE AFTER CAPROVER 1.8 RELEASE ************* 12 | // ============================================================================ 13 | // ============================================================================ 14 | // 15 | // 1- DUPLICATE this script. The new script is to ONLY read from /public/v4/*.yaml 16 | // 2- Test with a new YAML file 17 | // 3- Write script to convert all v2 JSON to V4 yaml and place them in /public/v4/*.yaml 18 | // 4- Update readme!!!! 19 | // 5- Push all 3 steps above at the same time to GITHUB 20 | 21 | const pathOfPublic = path.join(__dirname, '..', `public`); 22 | 23 | const pathOfDist = path.join(__dirname, '..', `dist`); 24 | 25 | const pathOfDistV2 = path.join(pathOfDist, 'v2'); 26 | const pathOfDistV3 = path.join(pathOfDist, 'v3'); 27 | const pathOfDistV4 = path.join(pathOfDist, 'v4'); 28 | 29 | const pathOfSourceDirectoryV2 = path.join(pathOfPublic, 'v2'); 30 | const pathOfSourceDirectoryAppsV2 = path.join(pathOfSourceDirectoryV2, 'apps'); 31 | const pathOfSourceDirectoryLogosV2 = path.join(pathOfSourceDirectoryV2, 'logos'); 32 | 33 | 34 | 35 | function convertV2toV4(v2String) { 36 | const parsed = JSON.parse(v2String); 37 | if (`${parsed.captainVersion}` !== '2') { 38 | throw new Error('CaptainVersion must be 2 for this conversion'); 39 | } 40 | 41 | function moveProperty(propertyName) { 42 | parsed.caproverOneClickApp[propertyName] = parsed[propertyName]; 43 | parsed[propertyName] = undefined; 44 | } 45 | 46 | parsed.services = parsed.dockerCompose.services; 47 | parsed.dockerCompose = undefined; 48 | 49 | parsed.captainVersion = 4; 50 | parsed.caproverOneClickApp = {}; 51 | 52 | moveProperty('variables'); 53 | moveProperty('instructions'); 54 | moveProperty('displayName'); 55 | moveProperty('isOfficial'); 56 | moveProperty('description'); 57 | moveProperty('documentation'); 58 | 59 | Object.keys(parsed.services).forEach(serviceName => { 60 | const service = parsed.services[serviceName]; 61 | if (service.containerHttpPort) { 62 | service.caproverExtra = service.caproverExtra || {}; 63 | service.caproverExtra.containerHttpPort = service.containerHttpPort; 64 | } 65 | if (service.dockerfileLines) { 66 | service.caproverExtra = service.caproverExtra || {}; 67 | service.caproverExtra.dockerfileLines = service.dockerfileLines; 68 | } 69 | if (service.notExposeAsWebApp) { 70 | service.caproverExtra = service.caproverExtra || {}; 71 | service.caproverExtra.notExposeAsWebApp = service.notExposeAsWebApp; 72 | } 73 | service.containerHttpPort = undefined; 74 | service.dockerfileLines = undefined; 75 | service.notExposeAsWebApp = undefined; 76 | }); 77 | 78 | 79 | return JSON.parse(JSON.stringify(parsed)); 80 | } 81 | 82 | 83 | function buildDist() { 84 | return fs.readdir(pathOfSourceDirectoryAppsV2) 85 | .then(function (appsFileNames) { // [ app1.json app2.json .... ] 86 | 87 | appsFileNames.forEach(appFileName => { 88 | const pathOfAppFileInSource = path.join(pathOfSourceDirectoryAppsV2, appFileName); 89 | 90 | //v4 91 | const pathOfSourceDirectoryV4 = path.join(pathOfPublic, 'v4'); 92 | const contentString = fs.readFileSync(pathOfAppFileInSource); 93 | 94 | fs.outputFileSync(path.join(pathOfSourceDirectoryV4, `apps`, appFileName.split('.')[0] + '.yml'), yaml.stringify(convertV2toV4(contentString))); 95 | fs.moveSync(path.join(pathOfSourceDirectoryV2, `logos`, appFileName.split('.')[0] + '.png'), 96 | path.join(pathOfSourceDirectoryV4, `logos`, appFileName.split('.')[0] + '.png')); 97 | fs.removeSync(path.join(pathOfSourceDirectoryV2, `apps`, appFileName.split('.')[0] + '.json')); 98 | }); 99 | 100 | }); 101 | } 102 | 103 | 104 | Promise.resolve() 105 | .then(function () { 106 | return buildDist(); 107 | }) 108 | .catch(function (err) { 109 | console.error(err); 110 | process.exit(127); 111 | }); -------------------------------------------------------------------------------- /scripts/validate-apps.js: -------------------------------------------------------------------------------- 1 | /*jshint esversion: 6 */ 2 | const path = require('path'); 3 | const yaml = require('yaml'); 4 | const fs = require('fs-extra'); 5 | 6 | const PUBLIC = `public`; 7 | const pathOfPublic = path.join(__dirname, '..', PUBLIC); 8 | 9 | 10 | // validating version 4 11 | function validateV4() { 12 | 13 | const version = '4'; 14 | const pathOfVersion = path.join(pathOfPublic, 'v' + version); 15 | const pathOfApps = path.join(pathOfVersion, 'apps'); 16 | 17 | return fs.readdir(pathOfApps) 18 | .then(function (items) { 19 | 20 | const apps = items.filter(v => v.includes('.yml')); 21 | 22 | if (items.length !== apps.length) { 23 | throw new Error('All files in v4 must end with .yml'); 24 | } 25 | 26 | for (var i = 0; i < apps.length; i++) { 27 | const contentString = fs.readFileSync(path.join(pathOfApps, apps[i]), 'utf-8'); 28 | const content = yaml.parse(contentString); 29 | const captainVersion = (content.captainVersion + ''); 30 | const versionString = (version + ''); 31 | if (versionString !== captainVersion) 32 | throw new Error(`unmatched versions ${versionString} ${captainVersion} for ${apps[i]}`); 33 | 34 | apps[i] = apps[i].replace('.yml', ''); 35 | 36 | if (!content.caproverOneClickApp) { 37 | throw new Error(`Cannot find caproverOneClickApp for ${apps[i]}`); 38 | } 39 | 40 | if (!content.caproverOneClickApp.description) { 41 | throw new Error(`Cannot find description for ${apps[i]}`); 42 | } 43 | 44 | if (content.caproverOneClickApp.description.length > 200) { 45 | throw new Error(`Description too long for ${apps[i]} - keep it below 200 chars`); 46 | } 47 | 48 | if (!content.caproverOneClickApp.instructions || 49 | !content.caproverOneClickApp.instructions.start || 50 | !content.caproverOneClickApp.instructions.end) { 51 | throw new Error(`Cannot find instructions.start or instructions.end for ${apps[i]}`); 52 | } 53 | 54 | if (!content.services) { 55 | throw new Error(`Cannot find services for ${apps[i]}`); 56 | } 57 | 58 | Object.keys(content.services).forEach( 59 | (serviceName) => { // jshint ignore:line 60 | const s = content.services[serviceName]; 61 | if (s.image && s.image.endsWith(':latest')) { 62 | // throw new Error(`"latest" tag is not allowed as it can change and break the setup, see ${apps[i]}`); 63 | } 64 | }); 65 | 66 | const logoFileName = apps[i] + '.png'; 67 | 68 | const logoFullPath = path.join(pathOfVersion, 'logos', logoFileName); 69 | 70 | if (!fs.existsSync(logoFullPath) || 71 | !fs.statSync(logoFullPath).isFile()) { 72 | let printablePath = logoFullPath; 73 | printablePath = printablePath.substr(printablePath.indexOf(`/${PUBLIC}`)); 74 | throw new Error(`Cannot find logo for ${apps[i]} ${printablePath}`); 75 | } 76 | 77 | console.log(`Validated ${apps[i]}`); 78 | 79 | } 80 | 81 | }); 82 | } 83 | 84 | // validating version 2 85 | function validateV2() { 86 | 87 | const version = '2'; 88 | const pathOfVersion = path.join(pathOfPublic, 'v' + version); 89 | const pathOfApps = path.join(pathOfVersion, 'apps'); 90 | 91 | if (!fs.existsSync(pathOfApps)) { 92 | return; 93 | } 94 | 95 | return fs.readdir(pathOfApps) 96 | .then(function (items) { 97 | 98 | const apps = items.filter(v => v.includes('.json')); 99 | 100 | if (items.length !== apps.length) { 101 | throw new Error('All files in v2 must end with .json'); 102 | } 103 | 104 | for (var i = 0; i < apps.length; i++) { 105 | const contentString = fs.readFileSync(path.join(pathOfApps, apps[i])); 106 | const content = JSON.parse(contentString); 107 | const captainVersion = (content.captainVersion + ''); 108 | const versionString = (version + ''); 109 | if (versionString !== captainVersion) 110 | throw new Error(`unmatched versions ${versionString} ${captainVersion} for ${apps[i]}`); 111 | 112 | apps[i] = apps[i].replace('.json', ''); 113 | 114 | if (!content.description) { 115 | throw new Error(`Cannot find description for ${apps[i]}`); 116 | } 117 | if (content.description.length > 200) { 118 | throw new Error(`Description too long for ${apps[i]} - keep it below 200 chars`); 119 | } 120 | 121 | const logoFileName = apps[i] + '.png'; 122 | 123 | const logoFullPath = path.join(pathOfVersion, 'logos', logoFileName); 124 | 125 | if (!fs.existsSync(logoFullPath) || 126 | !fs.statSync(logoFullPath).isFile()) { 127 | let printablePath = logoFullPath; 128 | printablePath = printablePath.substr(printablePath.indexOf(`/${PUBLIC}`)); 129 | throw new Error(`Cannot find logo for ${apps[i]} ${printablePath}`); 130 | } 131 | 132 | console.log(`Validated ${apps[i]}`); 133 | 134 | } 135 | 136 | }); 137 | } 138 | 139 | Promise.resolve() 140 | .then(function () { 141 | return validateV2(); 142 | }) 143 | .then(function () { 144 | return validateV4(); 145 | }) 146 | .catch(function (err) { 147 | console.error(err); 148 | process.exit(127); 149 | }); --------------------------------------------------------------------------------