Actually apply the pre-commit fixers to the codebase.

This can be redone manually with
`pre-commit run --all`

While the pre-commit hook could be merged to run locally,
it is much cleaner to align all the files to best-practice
syntax in a single commit. It is also required for server-side
validation.
This commit is contained in:
Nick Farrell 2022-12-17 18:22:37 +11:00
parent 108ad3c7c3
commit b218e62ffc
No known key found for this signature in database
GPG key ID: 740D3A86CF435835
151 changed files with 42251 additions and 31034 deletions

View file

@ -4,21 +4,17 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- - name: Install Go
name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: '1.18.x' go-version: "1.18.x"
- - name: Install node
name: Install node
uses: actions/setup-node@v2 uses: actions/setup-node@v2
with: with:
node-version: '17' node-version: "17"
- - name: Checkout code
name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
- - name: Cache Go and npm modules
name: Cache Go and npm modules
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
path: | path: |
@ -28,12 +24,9 @@ jobs:
web/node_modules web/node_modules
key: ${{ runner.os }}-ntfy-${{ hashFiles('**/go.sum', '**/package.lock') }} key: ${{ runner.os }}-ntfy-${{ hashFiles('**/go.sum', '**/package.lock') }}
restore-keys: ${{ runner.os }}-ntfy- restore-keys: ${{ runner.os }}-ntfy-
- - name: Install dependencies
name: Install dependencies
run: make build-deps-ubuntu run: make build-deps-ubuntu
- - name: Build all the things
name: Build all the things
run: make build run: make build
- - name: Print build results and checksums
name: Print build results and checksums
run: make cli-build-results run: make cli-build-results

View file

@ -7,11 +7,9 @@ jobs:
publish-docs: publish-docs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- - name: Checkout ntfy code
name: Checkout ntfy code
uses: actions/checkout@v3 uses: actions/checkout@v3
- - name: Checkout docs pages code
name: Checkout docs pages code
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
repository: binwiederhier/ntfy-docs.github.io repository: binwiederhier/ntfy-docs.github.io
@ -19,18 +17,15 @@ jobs:
token: ${{secrets.NTFY_DOCS_PUSH_TOKEN}} token: ${{secrets.NTFY_DOCS_PUSH_TOKEN}}
# Expires after 1 year, re-generate via # Expires after 1 year, re-generate via
# User -> Settings -> Developer options -> Personal Access Tokens -> Fine Grained Token # User -> Settings -> Developer options -> Personal Access Tokens -> Fine Grained Token
- - name: Build docs
name: Build docs
run: make docs run: make docs
- - name: Copy generated docs
name: Copy generated docs
run: rsync -av --exclude CNAME --delete server/docs/ build/ntfy-docs.github.io/docs/ run: rsync -av --exclude CNAME --delete server/docs/ build/ntfy-docs.github.io/docs/
- - name: Publish docs
name: Publish docs
run: | run: |
cd build/ntfy-docs.github.io cd build/ntfy-docs.github.io
git config user.name "GitHub Actions Bot" git config user.name "GitHub Actions Bot"
git config user.email "<>" git config user.email "<>"
git add docs/ git add docs/
git commit -m "Updated docs" git commit -m "Updated docs"
git push origin main git push origin main

View file

@ -2,26 +2,22 @@ name: release
on: on:
push: push:
tags: tags:
- 'v[0-9]+.[0-9]+.[0-9]+' - "v[0-9]+.[0-9]+.[0-9]+"
jobs: jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- - name: Install Go
name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: '1.18.x' go-version: "1.18.x"
- - name: Install node
name: Install node
uses: actions/setup-node@v2 uses: actions/setup-node@v2
with: with:
node-version: '17' node-version: "17"
- - name: Checkout code
name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
- - name: Cache Go and npm modules
name: Cache Go and npm modules
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
path: | path: |
@ -31,20 +27,16 @@ jobs:
web/node_modules web/node_modules
key: ${{ runner.os }}-ntfy-${{ hashFiles('**/go.sum', '**/package.lock') }} key: ${{ runner.os }}-ntfy-${{ hashFiles('**/go.sum', '**/package.lock') }}
restore-keys: ${{ runner.os }}-ntfy- restore-keys: ${{ runner.os }}-ntfy-
- - name: Docker login
name: Docker login
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.DOCKER_HUB_TOKEN }} password: ${{ secrets.DOCKER_HUB_TOKEN }}
- - name: Install dependencies
name: Install dependencies
run: make build-deps-ubuntu run: make build-deps-ubuntu
- - name: Build and publish
name: Build and publish
run: make release run: make release
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Print build results and checksums
name: Print build results and checksums
run: make cli-build-results run: make cli-build-results

View file

@ -4,21 +4,17 @@ jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- - name: Install Go
name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: '1.18.x' go-version: "1.18.x"
- - name: Install node
name: Install node
uses: actions/setup-node@v2 uses: actions/setup-node@v2
with: with:
node-version: '17' node-version: "17"
- - name: Checkout code
name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
- - name: Cache Go and npm modules
name: Cache Go and npm modules
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
path: | path: |
@ -28,21 +24,15 @@ jobs:
web/node_modules web/node_modules
key: ${{ runner.os }}-ntfy-${{ hashFiles('**/go.sum', '**/package.lock') }} key: ${{ runner.os }}-ntfy-${{ hashFiles('**/go.sum', '**/package.lock') }}
restore-keys: ${{ runner.os }}-ntfy- restore-keys: ${{ runner.os }}-ntfy-
- - name: Install dependencies
name: Install dependencies
run: make build-deps-ubuntu run: make build-deps-ubuntu
- - name: Build docs (required for tests)
name: Build docs (required for tests)
run: make docs run: make docs
- - name: Build web app (required for tests)
name: Build web app (required for tests)
run: make web run: make web
- - name: Run tests, formatting, vetting and linting
name: Run tests, formatting, vetting and linting
run: make check run: make check
- - name: Run coverage
name: Run coverage
run: make coverage run: make coverage
- - name: Upload coverage to codecov.io
name: Upload coverage to codecov.io
run: make coverage-upload run: make coverage-upload

View file

@ -25,4 +25,4 @@ ports:
- name: binary - name: binary
port: 2586 port: 2586
- name: web - name: web
port: 3000 port: 3000

View file

@ -3,12 +3,11 @@ before:
- go mod download - go mod download
- go mod tidy - go mod tidy
builds: builds:
- - id: ntfy_linux_amd64
id: ntfy_linux_amd64
binary: ntfy binary: ntfy
env: env:
- CGO_ENABLED=1 # required for go-sqlite3 - CGO_ENABLED=1 # required for go-sqlite3
tags: [sqlite_omit_load_extension,osusergo,netgo] tags: [sqlite_omit_load_extension, osusergo, netgo]
ldflags: ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}" - "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux] goos: [linux]
@ -16,46 +15,42 @@ builds:
hooks: hooks:
post: post:
- upx "{{ .Path }}" # apt install upx - upx "{{ .Path }}" # apt install upx
- - id: ntfy_linux_armv6
id: ntfy_linux_armv6
binary: ntfy binary: ntfy
env: env:
- CGO_ENABLED=1 # required for go-sqlite3 - CGO_ENABLED=1 # required for go-sqlite3
- CC=arm-linux-gnueabi-gcc # apt install gcc-arm-linux-gnueabi - CC=arm-linux-gnueabi-gcc # apt install gcc-arm-linux-gnueabi
tags: [sqlite_omit_load_extension,osusergo,netgo] tags: [sqlite_omit_load_extension, osusergo, netgo]
ldflags: ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}" - "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux] goos: [linux]
goarch: [arm] goarch: [arm]
goarm: [6] goarm: [6]
# No "upx" for ARM, see https://github.com/binwiederhier/ntfy/issues/191#issuecomment-1083406546 # No "upx" for ARM, see https://github.com/binwiederhier/ntfy/issues/191#issuecomment-1083406546
- - id: ntfy_linux_armv7
id: ntfy_linux_armv7
binary: ntfy binary: ntfy
env: env:
- CGO_ENABLED=1 # required for go-sqlite3 - CGO_ENABLED=1 # required for go-sqlite3
- CC=arm-linux-gnueabi-gcc # apt install gcc-arm-linux-gnueabi - CC=arm-linux-gnueabi-gcc # apt install gcc-arm-linux-gnueabi
tags: [sqlite_omit_load_extension,osusergo,netgo] tags: [sqlite_omit_load_extension, osusergo, netgo]
ldflags: ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}" - "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux] goos: [linux]
goarch: [arm] goarch: [arm]
goarm: [7] goarm: [7]
# No "upx" for ARM, see https://github.com/binwiederhier/ntfy/issues/191#issuecomment-1083406546 # No "upx" for ARM, see https://github.com/binwiederhier/ntfy/issues/191#issuecomment-1083406546
- - id: ntfy_linux_arm64
id: ntfy_linux_arm64
binary: ntfy binary: ntfy
env: env:
- CGO_ENABLED=1 # required for go-sqlite3 - CGO_ENABLED=1 # required for go-sqlite3
- CC=aarch64-linux-gnu-gcc # apt install gcc-aarch64-linux-gnu - CC=aarch64-linux-gnu-gcc # apt install gcc-aarch64-linux-gnu
tags: [sqlite_omit_load_extension,osusergo,netgo] tags: [sqlite_omit_load_extension, osusergo, netgo]
ldflags: ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}" - "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux] goos: [linux]
goarch: [arm64] goarch: [arm64]
# No "upx" for ARM, see https://github.com/binwiederhier/ntfy/issues/191#issuecomment-1083406546 # No "upx" for ARM, see https://github.com/binwiederhier/ntfy/issues/191#issuecomment-1083406546
- - id: ntfy_windows_amd64
id: ntfy_windows_amd64
binary: ntfy binary: ntfy
env: env:
- CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3 - CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3
@ -65,8 +60,7 @@ builds:
goos: [windows] goos: [windows]
goarch: [amd64] goarch: [amd64]
# No "upx" for Windows to hopefully avoid Virus warnings # No "upx" for Windows to hopefully avoid Virus warnings
- - id: ntfy_darwin_all
id: ntfy_darwin_all
binary: ntfy binary: ntfy
env: env:
- CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3 - CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3
@ -76,8 +70,7 @@ builds:
goos: [darwin] goos: [darwin]
goarch: [amd64, arm64] # will be combined to "universal binary" (see below) goarch: [amd64, arm64] # will be combined to "universal binary" (see below)
nfpms: nfpms:
- - package_name: ntfy
package_name: ntfy
homepage: https://heckel.io/ntfy homepage: https://heckel.io/ntfy
maintainer: Philipp C. Heckel <philipp.heckel@gmail.com> maintainer: Philipp C. Heckel <philipp.heckel@gmail.com>
description: Simple pub-sub notification service description: Simple pub-sub notification service
@ -111,8 +104,7 @@ nfpms:
preremove: "scripts/prerm.sh" preremove: "scripts/prerm.sh"
postremove: "scripts/postrm.sh" postremove: "scripts/postrm.sh"
archives: archives:
- - id: ntfy_linux
id: ntfy_linux
builds: builds:
- ntfy_linux_amd64 - ntfy_linux_amd64
- ntfy_linux_armv6 - ntfy_linux_armv6
@ -128,8 +120,7 @@ archives:
- client/ntfy-client.service - client/ntfy-client.service
replacements: replacements:
amd64: x86_64 amd64: x86_64
- - id: ntfy_windows
id: ntfy_windows
builds: builds:
- ntfy_windows_amd64 - ntfy_windows_amd64
format: zip format: zip
@ -140,8 +131,7 @@ archives:
- client/client.yml - client/client.yml
replacements: replacements:
amd64: x86_64 amd64: x86_64
- - id: ntfy_darwin
id: ntfy_darwin
builds: builds:
- ntfy_darwin_all - ntfy_darwin_all
wrap_in_directory: true wrap_in_directory: true
@ -152,20 +142,19 @@ archives:
replacements: replacements:
darwin: macOS darwin: macOS
universal_binaries: universal_binaries:
- - id: ntfy_darwin_all
id: ntfy_darwin_all
replace: true replace: true
name_template: ntfy name_template: ntfy
checksum: checksum:
name_template: 'checksums.txt' name_template: "checksums.txt"
snapshot: snapshot:
name_template: "{{ .Tag }}-next" name_template: "{{ .Tag }}-next"
changelog: changelog:
sort: asc sort: asc
filters: filters:
exclude: exclude:
- '^docs:' - "^docs:"
- '^test:' - "^test:"
dockers: dockers:
- image_templates: - image_templates:
- &amd64_image "binwiederhier/ntfy:{{ .Tag }}-amd64" - &amd64_image "binwiederhier/ntfy:{{ .Tag }}-amd64"

View file

@ -1,8 +1,9 @@
repos: repos:
- repo: https://github.com/pre-commit/mirrors-prettier - repo: https://github.com/pre-commit/mirrors-prettier
rev: "v2.7.1" rev: "v3.0.0-alpha.4"
hooks: hooks:
- id: prettier - id: prettier
exclude_types: [markdown]
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0 rev: v4.4.0
hooks: hooks:
@ -12,14 +13,13 @@ repos:
stages: ["commit"] stages: ["commit"]
- repo: https://github.com/Bahjat/pre-commit-golang - repo: https://github.com/Bahjat/pre-commit-golang
rev: v1.0.2 rev: v1.0.3
hooks: hooks:
- id: go-fmt-import - id: go-fmt-import
- id: go-vet - id: go-vet
- id: go-lint - id: go-lint
- id: go-unit-tests - id: go-unit-tests
stages: ["push"] stages: ["push"]
- id: gofumpt # requires github.com/mvdan/gofumpt
- id: golangci-lint # requires github.com/golangci/golangci-lint - id: golangci-lint # requires github.com/golangci/golangci-lint
args: [--config=.github/linters/.golangci.yml] # optional args: [--config=.github/linters/.golangci.yml] # optional
- id: go-ruleguard # requires https://github.com/quasilyte/go-ruleguard - id: go-ruleguard # requires https://github.com/quasilyte/go-ruleguard

View file

@ -60,7 +60,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement via Discord/Matrix (binwiederhier), reported to the community leaders responsible for enforcement via Discord/Matrix (binwiederhier),
or email (ntfy@heckel.io). All complaints will be reviewed and investigated promptly or email (ntfy@heckel.io). All complaints will be reviewed and investigated promptly
and fairly. and fairly.
All community leaders are obligated to respect the privacy and security of the All community leaders are obligated to respect the privacy and security of the
@ -130,4 +130,3 @@ For answers to common questions about this code of conduct, see the FAQ at
[Mozilla CoC]: https://github.com/mozilla/diversity [Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq [FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations [translations]: https://www.contributor-covenant.org/translations

View file

@ -337,4 +337,3 @@ proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. Public License instead of this License.

View file

@ -47,13 +47,13 @@ works best for you:
* [Email](https://heckel.io/about) - reach me directly (_I usually prefer the other methods_) * [Email](https://heckel.io/about) - reach me directly (_I usually prefer the other methods_)
## Announcements / beta testers ## Announcements / beta testers
For announcements of new releases and cutting-edge beta versions, please subscribe to the [ntfy.sh/announcements](https://ntfy.sh/announcements) For announcements of new releases and cutting-edge beta versions, please subscribe to the [ntfy.sh/announcements](https://ntfy.sh/announcements)
topic. If you'd like to test the iOS app, join [TestFlight](https://testflight.apple.com/join/P1fFnAm9). For Android betas, topic. If you'd like to test the iOS app, join [TestFlight](https://testflight.apple.com/join/P1fFnAm9). For Android betas,
join Discord/Matrix (I'll eventually make a testing channel in Google Play). join Discord/Matrix (I'll eventually make a testing channel in Google Play).
## Contributing ## Contributing
I welcome any and all contributions. Just create a PR or an issue. For larger features/ideas, please reach out I welcome any and all contributions. Just create a PR or an issue. For larger features/ideas, please reach out
on Discord/Matrix first to see if I'd accept them. To contribute code, check out the [build instructions](https://ntfy.sh/docs/develop/) on Discord/Matrix first to see if I'd accept them. To contribute code, check out the [build instructions](https://ntfy.sh/docs/develop/)
for the server and the Android app. Or, if you'd like to help translate 🇩🇪 🇺🇸 🇧🇬, you can start immediately in for the server and the Android app. Or, if you'd like to help translate 🇩🇪 🇺🇸 🇧🇬, you can start immediately in
[Hosted Weblate](https://hosted.weblate.org/projects/ntfy/). [Hosted Weblate](https://hosted.weblate.org/projects/ntfy/).
@ -62,8 +62,8 @@ for the server and the Android app. Or, if you'd like to help translate 🇩🇪
</a> </a>
## Sponsors ## Sponsors
I have just very recently started accepting donations via [GitHub Sponsors](https://github.com/sponsors/binwiederhier). I have just very recently started accepting donations via [GitHub Sponsors](https://github.com/sponsors/binwiederhier).
I would be humbled if you helped me carry the server and developer account costs. Even small donations are very much I would be humbled if you helped me carry the server and developer account costs. Even small donations are very much
appreciated. A big fat **Thank You** to the folks already sponsoring ntfy: appreciated. A big fat **Thank You** to the folks already sponsoring ntfy:
<a href="https://github.com/neutralinsomniac"><img src="https://github.com/neutralinsomniac.png" width="40px" /></a> <a href="https://github.com/neutralinsomniac"><img src="https://github.com/neutralinsomniac.png" width="40px" /></a>
@ -114,10 +114,10 @@ We as members, contributors, and leaders pledge to make participation in our com
**We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.** **We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.**
_Please be sure to read the complete [Code of Conduct](CODE_OF_CONDUCT.md)._ _Please be sure to read the complete [Code of Conduct](CODE_OF_CONDUCT.md)._
## License ## License
Made with ❤️ by [Philipp C. Heckel](https://heckel.io). Made with ❤️ by [Philipp C. Heckel](https://heckel.io).
The project is dual licensed under the [Apache License 2.0](LICENSE) and the [GPLv2 License](LICENSE.GPLv2). The project is dual licensed under the [Apache License 2.0](LICENSE) and the [GPLv2 License](LICENSE.GPLv2).
Third party libraries and resources: Third party libraries and resources:
@ -135,7 +135,7 @@ Third party libraries and resources:
* [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) (MIT) is used to provide the persistent message cache * [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) (MIT) is used to provide the persistent message cache
* [Firebase Admin SDK](https://github.com/firebase/firebase-admin-go) (Apache 2.0) is used to send FCM messages * [Firebase Admin SDK](https://github.com/firebase/firebase-admin-go) (Apache 2.0) is used to send FCM messages
* [github/gemoji](https://github.com/github/gemoji) (MIT) is used for emoji support (specifically the [emoji.json](https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json) file) * [github/gemoji](https://github.com/github/gemoji) (MIT) is used for emoji support (specifically the [emoji.json](https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json) file)
* [Lightbox with vanilla JS](https://yossiabramov.com/blog/vanilla-js-lightbox) as a lightbox on the landing page * [Lightbox with vanilla JS](https://yossiabramov.com/blog/vanilla-js-lightbox) as a lightbox on the landing page
* [HTTP middleware for gzip compression](https://gist.github.com/CJEnright/bc2d8b8dc0c1389a9feeddb110f822d7) (MIT) is used for serving static files * [HTTP middleware for gzip compression](https://gist.github.com/CJEnright/bc2d8b8dc0c1389a9feeddb110f822d7) (MIT) is used for serving static files
* [Regex for auto-linking](https://github.com/bryanwoods/autolink-js) (MIT) is used to highlight links (the library is not used) * [Regex for auto-linking](https://github.com/bryanwoods/autolink-js) (MIT) is used to highlight links (the library is not used)
* [Statically linking go-sqlite3](https://www.arp242.net/static-go.html) * [Statically linking go-sqlite3](https://www.arp242.net/static-go.html)

View file

@ -4,9 +4,10 @@ import (
"database/sql" "database/sql"
"errors" "errors"
"fmt" "fmt"
"strings"
_ "github.com/mattn/go-sqlite3" // SQLite driver _ "github.com/mattn/go-sqlite3" // SQLite driver
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"strings"
) )
const ( const (
@ -24,7 +25,7 @@ const (
role TEXT NOT NULL role TEXT NOT NULL
); );
CREATE TABLE IF NOT EXISTS access ( CREATE TABLE IF NOT EXISTS access (
user TEXT NOT NULL, user TEXT NOT NULL,
topic TEXT NOT NULL, topic TEXT NOT NULL,
read INT NOT NULL, read INT NOT NULL,
write INT NOT NULL, write INT NOT NULL,
@ -38,8 +39,8 @@ const (
` `
selectUserQuery = `SELECT pass, role FROM user WHERE user = ?` selectUserQuery = `SELECT pass, role FROM user WHERE user = ?`
selectTopicPermsQuery = ` selectTopicPermsQuery = `
SELECT read, write SELECT read, write
FROM access FROM access
WHERE user IN ('*', ?) AND ? LIKE topic WHERE user IN ('*', ?) AND ? LIKE topic
ORDER BY user DESC ORDER BY user DESC
` `
@ -54,7 +55,7 @@ const (
deleteUserQuery = `DELETE FROM user WHERE user = ?` deleteUserQuery = `DELETE FROM user WHERE user = ?`
upsertUserAccessQuery = ` upsertUserAccessQuery = `
INSERT INTO access (user, topic, read, write) INSERT INTO access (user, topic, read, write)
VALUES (?, ?, ?, ?) VALUES (?, ?, ?, ?)
ON CONFLICT (user, topic) DO UPDATE SET read=excluded.read, write=excluded.write ON CONFLICT (user, topic) DO UPDATE SET read=excluded.read, write=excluded.write
` `

View file

@ -1,12 +1,13 @@
package auth_test package auth_test
import ( import (
"github.com/stretchr/testify/require"
"heckel.io/ntfy/auth"
"path/filepath" "path/filepath"
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require"
"heckel.io/ntfy/auth"
) )
const minBcryptTimingMillis = int64(50) // Ideally should be >100ms, but this should also run on a Raspberry Pi without massive resources const minBcryptTimingMillis = int64(50) // Ideally should be >100ms, but this should also run on a Raspberry Pi without massive resources

View file

@ -7,13 +7,14 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
"io" "io"
"net/http" "net/http"
"strings" "strings"
"sync" "sync"
"time" "time"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
) )
// Event type constants // Event type constants

View file

@ -2,11 +2,12 @@ package client_test
import ( import (
"fmt" "fmt"
"testing"
"time"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"heckel.io/ntfy/client" "heckel.io/ntfy/client"
"heckel.io/ntfy/test" "heckel.io/ntfy/test"
"testing"
"time"
) )
func TestClient_Publish_Subscribe(t *testing.T) { func TestClient_Publish_Subscribe(t *testing.T) {

View file

@ -1,8 +1,9 @@
package client package client
import ( import (
"gopkg.in/yaml.v2"
"os" "os"
"gopkg.in/yaml.v2"
) )
const ( const (

View file

@ -1,11 +1,12 @@
package client_test package client_test
import ( import (
"github.com/stretchr/testify/require"
"heckel.io/ntfy/client"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/stretchr/testify/require"
"heckel.io/ntfy/client"
) )
func TestConfig_Load(t *testing.T) { func TestConfig_Load(t *testing.T) {

View file

@ -2,10 +2,11 @@ package client
import ( import (
"fmt" "fmt"
"heckel.io/ntfy/util"
"net/http" "net/http"
"strings" "strings"
"time" "time"
"heckel.io/ntfy/util"
) )
// RequestOption is a generic request option that can be added to Client calls // RequestOption is a generic request option that can be added to Client calls

View file

@ -5,6 +5,7 @@ package cmd
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"heckel.io/ntfy/auth" "heckel.io/ntfy/auth"
"heckel.io/ntfy/util" "heckel.io/ntfy/util"
@ -50,7 +51,7 @@ Arguments:
to define access rules for anonymous/unauthenticated clients to define access rules for anonymous/unauthenticated clients
TOPIC name of a topic with optional wildcards, e.g. "mytopic*" TOPIC name of a topic with optional wildcards, e.g. "mytopic*"
PERMISSION one of the following: PERMISSION one of the following:
- read-write (alias: rw) - read-write (alias: rw)
- read-only (aliases: read, ro) - read-only (aliases: read, ro)
- write-only (aliases: write, wo) - write-only (aliases: write, wo)
- deny (alias: none) - deny (alias: none)
@ -60,7 +61,7 @@ Examples:
ntfy access phil # Shows access for user phil ntfy access phil # Shows access for user phil
ntfy access phil mytopic rw # Allow read-write access to mytopic for user phil ntfy access phil mytopic rw # Allow read-write access to mytopic for user phil
ntfy access everyone mytopic rw # Allow anonymous read-write access to mytopic ntfy access everyone mytopic rw # Allow anonymous read-write access to mytopic
ntfy access everyone "up*" write # Allow anonymous write-only access to topics "up..." ntfy access everyone "up*" write # Allow anonymous write-only access to topics "up..."
ntfy access --reset # Reset entire access control list ntfy access --reset # Reset entire access control list
ntfy access --reset phil # Reset all access for user phil ntfy access --reset phil # Reset all access for user phil
ntfy access --reset phil mytopic # Reset access for user phil and topic mytopic ntfy access --reset phil mytopic # Reset access for user phil and topic mytopic

View file

@ -2,11 +2,12 @@ package cmd
import ( import (
"fmt" "fmt"
"testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"heckel.io/ntfy/server" "heckel.io/ntfy/server"
"heckel.io/ntfy/test" "heckel.io/ntfy/test"
"testing"
) )
func TestCLI_Access_Show(t *testing.T) { func TestCLI_Access_Show(t *testing.T) {

View file

@ -2,10 +2,11 @@
package cmd package cmd
import ( import (
"os"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc" "github.com/urfave/cli/v2/altsrc"
"heckel.io/ntfy/log" "heckel.io/ntfy/log"
"os"
) )
const ( const (

View file

@ -3,11 +3,12 @@ package cmd
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/client"
"os" "os"
"strings" "strings"
"testing" "testing"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/client"
) )
// This only contains helpers so far // This only contains helpers so far

View file

@ -2,11 +2,12 @@ package cmd
import ( import (
"fmt" "fmt"
"os"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc" "github.com/urfave/cli/v2/altsrc"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"heckel.io/ntfy/util" "heckel.io/ntfy/util"
"os"
) )
// initConfigFileInputSourceFunc is like altsrc.InitInputSourceWithContext and altsrc.NewYamlSourceFromFlagFunc, but checks // initConfigFileInputSourceFunc is like altsrc.InitInputSourceWithContext and altsrc.NewYamlSourceFromFlagFunc, but checks

View file

@ -1,10 +1,11 @@
package cmd package cmd
import ( import (
"github.com/stretchr/testify/require"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestNewYamlSourceFromFile(t *testing.T) { func TestNewYamlSourceFromFile(t *testing.T) {

View file

@ -3,16 +3,17 @@ package cmd
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/client"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
"io" "io"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/client"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
) )
func init() { func init() {
@ -72,11 +73,11 @@ Examples:
ntfy pub --wait-pid 1234 mytopic # Wait for process 1234 to exit before publishing ntfy pub --wait-pid 1234 mytopic # Wait for process 1234 to exit before publishing
ntfy pub --wait-cmd mytopic rsync -av ./ /tmp/a # Run command and publish after it completes ntfy pub --wait-cmd mytopic rsync -av ./ /tmp/a # Run command and publish after it completes
NTFY_USER=phil:mypass ntfy pub secret Psst # Use env variables to set username/password NTFY_USER=phil:mypass ntfy pub secret Psst # Use env variables to set username/password
NTFY_TOPIC=mytopic ntfy pub "some message" # Use NTFY_TOPIC variable as topic NTFY_TOPIC=mytopic ntfy pub "some message" # Use NTFY_TOPIC variable as topic
cat flower.jpg | ntfy pub --file=- flowers 'Nice!' # Same as above, send image.jpg as attachment cat flower.jpg | ntfy pub --file=- flowers 'Nice!' # Same as above, send image.jpg as attachment
ntfy trigger mywebhook # Sending without message, useful for webhooks ntfy trigger mywebhook # Sending without message, useful for webhooks
Please also check out the docs on publishing messages. Especially for the --tags and --delay options, Please also check out the docs on publishing messages. Especially for the --tags and --delay options,
it has incredibly useful information: https://ntfy.sh/docs/publish/. it has incredibly useful information: https://ntfy.sh/docs/publish/.
` + clientCommandDescriptionSuffix, ` + clientCommandDescriptionSuffix,

View file

@ -2,14 +2,15 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/stretchr/testify/require"
"heckel.io/ntfy/test"
"heckel.io/ntfy/util"
"os" "os"
"os/exec" "os/exec"
"strconv" "strconv"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require"
"heckel.io/ntfy/test"
"heckel.io/ntfy/util"
) )
func TestCLI_Publish_Subscribe_Poll_Real_Server(t *testing.T) { func TestCLI_Publish_Subscribe_Poll_Real_Server(t *testing.T) {

View file

@ -86,7 +86,7 @@ var cmdServe = &cli.Command{
Before: initConfigFileInputSourceFunc("config", flagsServe, initLogFunc), Before: initConfigFileInputSourceFunc("config", flagsServe, initLogFunc),
Description: `Run the ntfy server and listen for incoming requests Description: `Run the ntfy server and listen for incoming requests
The command will load the configuration from /etc/ntfy/server.yml. Config options can The command will load the configuration from /etc/ntfy/server.yml. Config options can
be overridden using the command line options. be overridden using the command line options.
Examples: Examples:

View file

@ -3,16 +3,17 @@ package cmd
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/client"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
"os" "os"
"os/exec" "os/exec"
"os/user" "os/user"
"path/filepath" "path/filepath"
"sort" "sort"
"strings" "strings"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/client"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
) )
func init() { func init() {
@ -44,20 +45,20 @@ var cmdSubscribe = &cli.Command{
Category: categoryClient, Category: categoryClient,
Flags: flagsSubscribe, Flags: flagsSubscribe,
Before: initLogFunc, Before: initLogFunc,
Description: `Subscribe to a topic from a ntfy server, and either print or execute a command for Description: `Subscribe to a topic from a ntfy server, and either print or execute a command for
every arriving message. There are 3 modes in which the command can be run: every arriving message. There are 3 modes in which the command can be run:
ntfy subscribe TOPIC ntfy subscribe TOPIC
This prints the JSON representation of every incoming message. It is useful when you This prints the JSON representation of every incoming message. It is useful when you
have a command that wants to stream-read incoming JSON messages. Unless --poll is passed, have a command that wants to stream-read incoming JSON messages. Unless --poll is passed,
this command stays open forever. this command stays open forever.
Examples: Examples:
ntfy subscribe mytopic # Prints JSON for incoming messages for ntfy.sh/mytopic ntfy subscribe mytopic # Prints JSON for incoming messages for ntfy.sh/mytopic
ntfy sub home.lan/backups # Subscribe to topic on different server ntfy sub home.lan/backups # Subscribe to topic on different server
ntfy sub --poll home.lan/backups # Just query for latest messages and exit ntfy sub --poll home.lan/backups # Just query for latest messages and exit
ntfy sub -u phil:mypass secret # Subscribe with username/password ntfy sub -u phil:mypass secret # Subscribe with username/password
ntfy subscribe TOPIC COMMAND ntfy subscribe TOPIC COMMAND
This executes COMMAND for every incoming messages. The message fields are passed to the This executes COMMAND for every incoming messages. The message fields are passed to the
command as environment variables: command as environment variables:
@ -78,10 +79,10 @@ ntfy subscribe TOPIC COMMAND
ntfy sub topic1 myscript.sh # Execute script for incoming messages ntfy sub topic1 myscript.sh # Execute script for incoming messages
ntfy subscribe --from-config ntfy subscribe --from-config
Service mode (used in ntfy-client.service). This reads the config file and sets up Service mode (used in ntfy-client.service). This reads the config file and sets up
subscriptions for every topic in the "subscribe:" block (see config file). subscriptions for every topic in the "subscribe:" block (see config file).
Examples: Examples:
ntfy sub --from-config # Read topics from config file ntfy sub --from-config # Read topics from config file
ntfy sub --config=myclient.yml --from-config # Read topics from alternate config file ntfy sub --config=myclient.yml --from-config # Read topics from alternate config file

View file

@ -50,11 +50,11 @@ granted otherwise by the auth-default-access setting). An admin user has read an
topics. topics.
Examples: Examples:
ntfy user add phil # Add regular user phil ntfy user add phil # Add regular user phil
ntfy user add --role=admin phil # Add admin user phil ntfy user add --role=admin phil # Add admin user phil
NTFY_PASSWORD=... ntfy user add phil # Add user, using env variable to set password (for scripts) NTFY_PASSWORD=... ntfy user add phil # Add user, using env variable to set password (for scripts)
You may set the NTFY_PASSWORD environment variable to pass the password. This is useful if You may set the NTFY_PASSWORD environment variable to pass the password. This is useful if
you are creating users via scripts. you are creating users via scripts.
`, `,
}, },
@ -79,13 +79,13 @@ Example:
Description: `Change the password for the given user. Description: `Change the password for the given user.
The new password will be read from STDIN, and it'll be confirmed by typing The new password will be read from STDIN, and it'll be confirmed by typing
it twice. it twice.
Example: Example:
ntfy user change-pass phil ntfy user change-pass phil
NTFY_PASSWORD=.. ntfy user change-pass phil NTFY_PASSWORD=.. ntfy user change-pass phil
You may set the NTFY_PASSWORD environment variable to pass the new password. This is You may set the NTFY_PASSWORD environment variable to pass the new password. This is
useful if you are updating users via scripts. useful if you are updating users via scripts.
`, `,
@ -104,12 +104,12 @@ to an admin user, or the other way around:
- admin: an admin has read/write access to all topics - admin: an admin has read/write access to all topics
- user: a regular user only has access to what was explicitly granted via 'ntfy access' - user: a regular user only has access to what was explicitly granted via 'ntfy access'
When changing the role of a user to "admin", all access control entries for that When changing the role of a user to "admin", all access control entries for that
user are removed, since they are no longer necessary. user are removed, since they are no longer necessary.
Example: Example:
ntfy user change-role phil admin # Make user phil an admin ntfy user change-role phil admin # Make user phil an admin
ntfy user change-role phil user # Remove admin role from user phil ntfy user change-role phil user # Remove admin role from user phil
`, `,
}, },
{ {
@ -120,7 +120,7 @@ Example:
Description: `Shows a list of all configured users, including the everyone ('*') user. Description: `Shows a list of all configured users, including the everyone ('*') user.
This is a server-only command. It directly reads from the user.db as defined in the server config This is a server-only command. It directly reads from the user.db as defined in the server config
file server.yml. The command only works if 'auth-file' is properly defined. file server.yml. The command only works if 'auth-file' is properly defined.
This command is an alias to calling 'ntfy access' (display access control list). This command is an alias to calling 'ntfy access' (display access control list).
`, `,
@ -132,18 +132,18 @@ This is a server-only command. It directly manages the user.db as defined in the
file server.yml. The command only works if 'auth-file' is properly defined. Please also refer file server.yml. The command only works if 'auth-file' is properly defined. Please also refer
to the related command 'ntfy access'. to the related command 'ntfy access'.
The command allows you to add/remove/change users in the ntfy user database, as well as change The command allows you to add/remove/change users in the ntfy user database, as well as change
passwords or roles. passwords or roles.
Examples: Examples:
ntfy user list # Shows list of users (alias: 'ntfy access') ntfy user list # Shows list of users (alias: 'ntfy access')
ntfy user add phil # Add regular user phil ntfy user add phil # Add regular user phil
NTFY_PASSWORD=... ntfy user add phil # As above, using env variable to set password (for scripts) NTFY_PASSWORD=... ntfy user add phil # As above, using env variable to set password (for scripts)
ntfy user add --role=admin phil # Add admin user phil ntfy user add --role=admin phil # Add admin user phil
ntfy user del phil # Delete user phil ntfy user del phil # Delete user phil
ntfy user change-pass phil # Change password for user phil ntfy user change-pass phil # Change password for user phil
NTFY_PASSWORD=.. ntfy user change-pass phil # As above, using env variable to set password (for scripts) NTFY_PASSWORD=.. ntfy user change-pass phil # As above, using env variable to set password (for scripts)
ntfy user change-role phil admin # Make user phil an admin ntfy user change-role phil admin # Make user phil an admin
For the 'ntfy user add' and 'ntfy user change-pass' commands, you may set the NTFY_PASSWORD environment For the 'ntfy user add' and 'ntfy user change-pass' commands, you may set the NTFY_PASSWORD environment
variable to pass the new password. This is useful if you are creating/updating users via scripts. variable to pass the new password. This is useful if you are creating/updating users via scripts.

View file

@ -1,12 +1,13 @@
package cmd package cmd
import ( import (
"path/filepath"
"testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"heckel.io/ntfy/server" "heckel.io/ntfy/server"
"heckel.io/ntfy/test" "heckel.io/ntfy/test"
"path/filepath"
"testing"
) )
func TestCLI_User_Add(t *testing.T) { func TestCLI_User_Add(t *testing.T) {

View file

@ -6,7 +6,7 @@ services:
command: command:
- serve - serve
environment: environment:
- TZ=UTC # optional: Change to your desired timezone - TZ=UTC # optional: Change to your desired timezone
user: UID:GID # optional: Set custom user/group or uid/gid user: UID:GID # optional: Set custom user/group or uid/gid
volumes: volumes:
- /var/cache/ntfy:/var/cache/ntfy - /var/cache/ntfy:/var/cache/ntfy
@ -14,4 +14,3 @@ services:
ports: ports:
- 80:80 - 80:80
restart: unless-stopped restart: unless-stopped

View file

@ -1,10 +1,10 @@
# Configuring the ntfy server # Configuring the ntfy server
The ntfy server can be configured in three ways: using a config file (typically at `/etc/ntfy/server.yml`, The ntfy server can be configured in three ways: using a config file (typically at `/etc/ntfy/server.yml`,
see [server.yml](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml)), via command line arguments see [server.yml](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml)), via command line arguments
or using environment variables. or using environment variables.
## Quick start ## Quick start
By default, simply running `ntfy serve` will start the server at port 80. No configuration needed. Batteries included 😀. By default, simply running `ntfy serve` will start the server at port 80. No configuration needed. Batteries included 😀.
If everything works as it should, you'll see something like this: If everything works as it should, you'll see something like this:
``` ```
$ ntfy serve $ ntfy serve
@ -12,7 +12,7 @@ $ ntfy serve
``` ```
You can immediately start [publishing messages](publish.md), or subscribe via the [Android app](subscribe/phone.md), You can immediately start [publishing messages](publish.md), or subscribe via the [Android app](subscribe/phone.md),
[the web UI](subscribe/web.md), or simply via [curl or your favorite HTTP client](subscribe/api.md). To configure [the web UI](subscribe/web.md), or simply via [curl or your favorite HTTP client](subscribe/api.md). To configure
the server further, check out the [config options table](#config-options) or simply type `ntfy serve --help` to the server further, check out the [config options table](#config-options) or simply type `ntfy serve --help` to
get a list of [command line options](#command-line-options). get a list of [command line options](#command-line-options).
@ -46,7 +46,7 @@ Here are a few working sample configs:
=== "server.yml (ntfy.sh config)" === "server.yml (ntfy.sh config)"
``` yaml ``` yaml
# All the things: Behind a proxy, Firebase, cache, attachments, # All the things: Behind a proxy, Firebase, cache, attachments,
# SMTP publishing & receiving # SMTP publishing & receiving
base-url: "https://ntfy.sh" base-url: "https://ntfy.sh"
@ -68,14 +68,14 @@ Here are a few working sample configs:
## Message cache ## Message cache
If desired, ntfy can temporarily keep notifications in an in-memory or an on-disk cache. Caching messages for a short period If desired, ntfy can temporarily keep notifications in an in-memory or an on-disk cache. Caching messages for a short period
of time is important to allow [phones](subscribe/phone.md) and other devices with brittle Internet connections to be able to retrieve of time is important to allow [phones](subscribe/phone.md) and other devices with brittle Internet connections to be able to retrieve
notifications that they may have missed. notifications that they may have missed.
By default, ntfy keeps messages **in-memory for 12 hours**, which means that **cached messages do not survive an application By default, ntfy keeps messages **in-memory for 12 hours**, which means that **cached messages do not survive an application
restart**. You can override this behavior using the following config settings: restart**. You can override this behavior using the following config settings:
* `cache-file`: if set, ntfy will store messages in a SQLite based cache (default is empty, which means in-memory cache). * `cache-file`: if set, ntfy will store messages in a SQLite based cache (default is empty, which means in-memory cache).
**This is required if you'd like messages to be retained across restarts**. **This is required if you'd like messages to be retained across restarts**.
* `cache-duration`: defines the duration for which messages are stored in the cache (default is `12h`). * `cache-duration`: defines the duration for which messages are stored in the cache (default is `12h`).
You can also entirely disable the cache by setting `cache-duration` to `0`. When the cache is disabled, messages are only You can also entirely disable the cache by setting `cache-duration` to `0`. When the cache is disabled, messages are only
passed on to the connected subscribers, but never stored on disk or even kept in memory longer than is needed to forward passed on to the connected subscribers, but never stored on disk or even kept in memory longer than is needed to forward
@ -86,11 +86,11 @@ Subscribers can retrieve cached messaging using the [`poll=1` parameter](subscri
## Attachments ## Attachments
If desired, you may allow users to upload and [attach files to notifications](publish.md#attachments). To enable If desired, you may allow users to upload and [attach files to notifications](publish.md#attachments). To enable
this feature, you have to simply configure an attachment cache directory and a base URL (`attachment-cache-dir`, `base-url`). this feature, you have to simply configure an attachment cache directory and a base URL (`attachment-cache-dir`, `base-url`).
Once these options are set and the directory is writable by the server user, you can upload attachments via PUT. Once these options are set and the directory is writable by the server user, you can upload attachments via PUT.
By default, attachments are stored in the disk-cache **for only 3 hours**. The main reason for this is to avoid legal issues By default, attachments are stored in the disk-cache **for only 3 hours**. The main reason for this is to avoid legal issues
and such when hosting user controlled content. Typically, this is more than enough time for the user (or the auto download and such when hosting user controlled content. Typically, this is more than enough time for the user (or the auto download
feature) to download the file. The following config options are relevant to attachments: feature) to download the file. The following config options are relevant to attachments:
* `base-url` is the root URL for the ntfy server; this is needed for the generated attachment URLs * `base-url` is the root URL for the ntfy server; this is needed for the generated attachment URLs
@ -99,7 +99,7 @@ feature) to download the file. The following config options are relevant to atta
* `attachment-file-size-limit` is the per-file attachment size limit (e.g. 300k, 2M, 100M, default: 15M) * `attachment-file-size-limit` is the per-file attachment size limit (e.g. 300k, 2M, 100M, default: 15M)
* `attachment-expiry-duration` is the duration after which uploaded attachments will be deleted (e.g. 3h, 20h, default: 3h) * `attachment-expiry-duration` is the duration after which uploaded attachments will be deleted (e.g. 3h, 20h, default: 3h)
Here's an example config using mostly the defaults (except for the cache directory, which is empty by default): Here's an example config using mostly the defaults (except for the cache directory, which is empty by default):
=== "/etc/ntfy/server.yml (minimal)" === "/etc/ntfy/server.yml (minimal)"
``` yaml ``` yaml
@ -123,27 +123,27 @@ and `visitor-attachment-daily-bandwidth-limit`. Setting these conservatively is
## Access control ## Access control
By default, the ntfy server is open for everyone, meaning **everyone can read and write to any topic** (this is how By default, the ntfy server is open for everyone, meaning **everyone can read and write to any topic** (this is how
ntfy.sh is configured). To restrict access to your own server, you can optionally configure authentication and authorization. ntfy.sh is configured). To restrict access to your own server, you can optionally configure authentication and authorization.
ntfy's auth is implemented with a simple [SQLite](https://www.sqlite.org/)-based backend. It implements two roles ntfy's auth is implemented with a simple [SQLite](https://www.sqlite.org/)-based backend. It implements two roles
(`user` and `admin`) and per-topic `read` and `write` permissions using an [access control list (ACL)](https://en.wikipedia.org/wiki/Access-control_list). (`user` and `admin`) and per-topic `read` and `write` permissions using an [access control list (ACL)](https://en.wikipedia.org/wiki/Access-control_list).
Access control entries can be applied to users as well as the special everyone user (`*`), which represents anonymous API access. Access control entries can be applied to users as well as the special everyone user (`*`), which represents anonymous API access.
To set up auth, simply **configure the following two options**: To set up auth, simply **configure the following two options**:
* `auth-file` is the user/access database; it is created automatically if it doesn't already exist; suggested * `auth-file` is the user/access database; it is created automatically if it doesn't already exist; suggested
location `/var/lib/ntfy/user.db` (easiest if deb/rpm package is used) location `/var/lib/ntfy/user.db` (easiest if deb/rpm package is used)
* `auth-default-access` defines the default/fallback access if no access control entry is found; it can be * `auth-default-access` defines the default/fallback access if no access control entry is found; it can be
set to `read-write` (default), `read-only`, `write-only` or `deny-all`. set to `read-write` (default), `read-only`, `write-only` or `deny-all`.
Once configured, you can use the `ntfy user` command to [add or modify users](#users-and-roles), and the `ntfy access` command Once configured, you can use the `ntfy user` command to [add or modify users](#users-and-roles), and the `ntfy access` command
lets you [modify the access control list](#access-control-list-acl) for specific users and topic patterns. Both of these lets you [modify the access control list](#access-control-list-acl) for specific users and topic patterns. Both of these
commands **directly edit the auth database** (as defined in `auth-file`), so they only work on the server, and only if the user commands **directly edit the auth database** (as defined in `auth-file`), so they only work on the server, and only if the user
accessing them has the right permissions. accessing them has the right permissions.
### Users and roles ### Users and roles
The `ntfy user` command allows you to add/remove/change users in the ntfy user database, as well as change The `ntfy user` command allows you to add/remove/change users in the ntfy user database, as well as change
passwords or roles (`user` or `admin`). In practice, you'll often just create one admin passwords or roles (`user` or `admin`). In practice, you'll often just create one admin
user with `ntfy user add --role=admin ...` and be done with all this (see [example below](#example-private-instance)). user with `ntfy user add --role=admin ...` and be done with all this (see [example below](#example-private-instance)).
**Roles:** **Roles:**
@ -156,7 +156,7 @@ user with `ntfy user add --role=admin ...` and be done with all this (see [examp
``` ```
ntfy user list # Shows list of users (alias: 'ntfy access') ntfy user list # Shows list of users (alias: 'ntfy access')
ntfy user add phil # Add regular user phil ntfy user add phil # Add regular user phil
ntfy user add --role=admin phil # Add admin user phil ntfy user add --role=admin phil # Add admin user phil
ntfy user del phil # Delete user phil ntfy user del phil # Delete user phil
ntfy user change-pass phil # Change password for user phil ntfy user change-pass phil # Change password for user phil
@ -165,7 +165,7 @@ ntfy user change-role phil admin # Make user phil an admin
### Access control list (ACL) ### Access control list (ACL)
The access control list (ACL) **manages access to topics for non-admin users, and for anonymous access (`everyone`/`*`)**. The access control list (ACL) **manages access to topics for non-admin users, and for anonymous access (`everyone`/`*`)**.
Each entry represents the access permissions for a user to a specific topic or topic pattern. Each entry represents the access permissions for a user to a specific topic or topic pattern.
The ACL can be displayed or modified with the `ntfy access` command: The ACL can be displayed or modified with the `ntfy access` command:
@ -175,20 +175,20 @@ ntfy access USERNAME # Shows access control entries for USERNA
ntfy access USERNAME TOPIC PERMISSION # Allow/deny access for USERNAME to TOPIC ntfy access USERNAME TOPIC PERMISSION # Allow/deny access for USERNAME to TOPIC
``` ```
A `USERNAME` is an existing user, as created with `ntfy user add` (see [users and roles](#users-and-roles)), or the A `USERNAME` is an existing user, as created with `ntfy user add` (see [users and roles](#users-and-roles)), or the
anonymous user `everyone` or `*`, which represents clients that access the API without username/password. anonymous user `everyone` or `*`, which represents clients that access the API without username/password.
A `TOPIC` is either a specific topic name (e.g. `mytopic`, or `phil_alerts`), or a wildcard pattern that matches any A `TOPIC` is either a specific topic name (e.g. `mytopic`, or `phil_alerts`), or a wildcard pattern that matches any
number of topics (e.g. `alerts_*` or `ben-*`). Only the wildcard character `*` is supported. It stands for zero to any number of topics (e.g. `alerts_*` or `ben-*`). Only the wildcard character `*` is supported. It stands for zero to any
number of characters. number of characters.
A `PERMISSION` is any of the following supported permissions: A `PERMISSION` is any of the following supported permissions:
* `read-write` (alias: `rw`): Allows [publishing messages](publish.md) to the given topic, as well as * `read-write` (alias: `rw`): Allows [publishing messages](publish.md) to the given topic, as well as
[subscribing](subscribe/api.md) and reading messages [subscribing](subscribe/api.md) and reading messages
* `read-only` (aliases: `read`, `ro`): Allows only subscribing and reading messages, but not publishing to the topic * `read-only` (aliases: `read`, `ro`): Allows only subscribing and reading messages, but not publishing to the topic
* `write-only` (aliases: `write`, `wo`): Allows only publishing to the topic, but not subscribing to it * `write-only` (aliases: `write`, `wo`): Allows only publishing to the topic, but not subscribing to it
* `deny` (alias: `none`): Allows neither publishing nor subscribing to a topic * `deny` (alias: `none`): Allows neither publishing nor subscribing to a topic
**Example commands** (type `ntfy access --help` for more details): **Example commands** (type `ntfy access --help` for more details):
``` ```
@ -237,10 +237,10 @@ After that, simply create an `admin` user:
$ ntfy user add --role=admin phil $ ntfy user add --role=admin phil
password: mypass password: mypass
confirm: mypass confirm: mypass
user phil added with role admin user phil added with role admin
``` ```
Once you've done that, you can publish and subscribe using [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication) Once you've done that, you can publish and subscribe using [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication)
with the given username/password. Be sure to use HTTPS to avoid eavesdropping and exposing your password. Here's a simple example: with the given username/password. Be sure to use HTTPS to avoid eavesdropping and exposing your password. Here's a simple example:
=== "Command line (curl)" === "Command line (curl)"
@ -301,7 +301,7 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
file_get_contents('https://ntfy.example.com/mysecrets', false, stream_context_create([ file_get_contents('https://ntfy.example.com/mysecrets', false, stream_context_create([
'http' => [ 'http' => [
'method' => 'POST', // PUT also works 'method' => 'POST', // PUT also works
'header' => 'header' =>
'Content-Type: text/plain\r\n' . 'Content-Type: text/plain\r\n' .
'Authorization: Basic cGhpbDpteXBhc3M=', 'Authorization: Basic cGhpbDpteXBhc3M=',
'content' => 'Look ma, with auth' 'content' => 'Look ma, with auth'
@ -310,12 +310,12 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
``` ```
### Example: UnifiedPush ### Example: UnifiedPush
[UnifiedPush](https://unifiedpush.org) requires that the [application server](https://unifiedpush.org/spec/definitions/#application-server) (e.g. Synapse, Fediverse Server, …) [UnifiedPush](https://unifiedpush.org) requires that the [application server](https://unifiedpush.org/spec/definitions/#application-server) (e.g. Synapse, Fediverse Server, …)
has anonymous write access to the [topic](https://unifiedpush.org/spec/definitions/#endpoint) used for push messages. has anonymous write access to the [topic](https://unifiedpush.org/spec/definitions/#endpoint) used for push messages.
The topic names used by UnifiedPush all start with the `up*` prefix. Please refer to the The topic names used by UnifiedPush all start with the `up*` prefix. Please refer to the
**[UnifiedPush documentation](https://unifiedpush.org/users/distributors/ntfy/#limit-access-to-some-users)** for more details. **[UnifiedPush documentation](https://unifiedpush.org/users/distributors/ntfy/#limit-access-to-some-users)** for more details.
To enable support for UnifiedPush for private servers (i.e. `auth-default-access: "deny-all"`), you should either To enable support for UnifiedPush for private servers (i.e. `auth-default-access: "deny-all"`), you should either
allow anonymous write access for the entire prefix or explicitly per topic: allow anonymous write access for the entire prefix or explicitly per topic:
=== "Prefix" === "Prefix"
@ -329,11 +329,11 @@ allow anonymous write access for the entire prefix or explicitly per topic:
``` ```
## E-mail notifications ## E-mail notifications
To allow forwarding messages via e-mail, you can configure an **SMTP server for outgoing messages**. Once configured, To allow forwarding messages via e-mail, you can configure an **SMTP server for outgoing messages**. Once configured,
you can set the `X-Email` header to [send messages via e-mail](publish.md#e-mail-notifications) (e.g. you can set the `X-Email` header to [send messages via e-mail](publish.md#e-mail-notifications) (e.g.
`curl -d "hi there" -H "X-Email: phil@example.com" ntfy.sh/mytopic`). `curl -d "hi there" -H "X-Email: phil@example.com" ntfy.sh/mytopic`).
As of today, only SMTP servers with PLAIN auth and STARTLS are supported. To enable e-mail sending, you must set the As of today, only SMTP servers with PLAIN auth and STARTLS are supported. To enable e-mail sending, you must set the
following settings: following settings:
* `base-url` is the root URL for the ntfy server; this is needed for e-mail footer * `base-url` is the root URL for the ntfy server; this is needed for e-mail footer
@ -341,7 +341,7 @@ following settings:
* `smtp-sender-user` and `smtp-sender-pass` are the username and password of the SMTP user * `smtp-sender-user` and `smtp-sender-pass` are the username and password of the SMTP user
* `smtp-sender-from` is the e-mail address of the sender * `smtp-sender-from` is the e-mail address of the sender
Here's an example config using [Amazon SES](https://aws.amazon.com/ses/) for outgoing mail (this is how it is Here's an example config using [Amazon SES](https://aws.amazon.com/ses/) for outgoing mail (this is how it is
configured for `ntfy.sh`): configured for `ntfy.sh`):
=== "/etc/ntfy/server.yml" === "/etc/ntfy/server.yml"
@ -353,13 +353,13 @@ configured for `ntfy.sh`):
smtp-sender-from: "ntfy@ntfy.sh" smtp-sender-from: "ntfy@ntfy.sh"
``` ```
Please also refer to the [rate limiting](#rate-limiting) settings below, specifically `visitor-email-limit-burst` Please also refer to the [rate limiting](#rate-limiting) settings below, specifically `visitor-email-limit-burst`
and `visitor-email-limit-burst`. Setting these conservatively is necessary to avoid abuse. and `visitor-email-limit-burst`. Setting these conservatively is necessary to avoid abuse.
## E-mail publishing ## E-mail publishing
To allow publishing messages via e-mail, ntfy can run a lightweight **SMTP server for incoming messages**. Once configured, To allow publishing messages via e-mail, ntfy can run a lightweight **SMTP server for incoming messages**. Once configured,
users can [send emails to a topic e-mail address](publish.md#e-mail-publishing) (e.g. `mytopic@ntfy.sh` or users can [send emails to a topic e-mail address](publish.md#e-mail-publishing) (e.g. `mytopic@ntfy.sh` or
`myprefix-mytopic@ntfy.sh`) to publish messages to a topic. This is useful for e-mail based integrations such as for `myprefix-mytopic@ntfy.sh`) to publish messages to a topic. This is useful for e-mail based integrations such as for
statuspage.io (though these days most services also support webhooks and HTTP calls). statuspage.io (though these days most services also support webhooks and HTTP calls).
To configure the SMTP server, you must at least set `smtp-server-listen` and `smtp-server-domain`: To configure the SMTP server, you must at least set `smtp-server-listen` and `smtp-server-domain`:
@ -379,8 +379,8 @@ Here's an example config (this is how it is configured for `ntfy.sh`):
smtp-server-addr-prefix: "ntfy-" smtp-server-addr-prefix: "ntfy-"
``` ```
In addition to configuring the ntfy server, you have to create two DNS records (an [MX record](https://en.wikipedia.org/wiki/MX_record) In addition to configuring the ntfy server, you have to create two DNS records (an [MX record](https://en.wikipedia.org/wiki/MX_record)
and a corresponding A record), so incoming mail will find its way to your server. Here's an example of how `ntfy.sh` is and a corresponding A record), so incoming mail will find its way to your server. Here's an example of how `ntfy.sh` is
configured (in [Amazon Route 53](https://aws.amazon.com/route53/)): configured (in [Amazon Route 53](https://aws.amazon.com/route53/)):
<figure markdown> <figure markdown>
@ -388,7 +388,7 @@ configured (in [Amazon Route 53](https://aws.amazon.com/route53/)):
<figcaption>DNS records for incoming mail</figcaption> <figcaption>DNS records for incoming mail</figcaption>
</figure> </figure>
You can check if everything is working correctly by sending an email as raw SMTP via `nc`. Create a text file, e.g. You can check if everything is working correctly by sending an email as raw SMTP via `nc`. Create a text file, e.g.
`email.txt` `email.txt`
``` ```
@ -403,7 +403,7 @@ Hello from 🇩🇪
. .
``` ```
And then send the mail via `nc` like this. If you see any lines starting with `451`, those are errors from the And then send the mail via `nc` like this. If you see any lines starting with `451`, those are errors from the
ntfy server. Read them carefully. ntfy server. Read them carefully.
``` ```
@ -418,9 +418,9 @@ $ cat email.txt | nc -N ntfy.sh 25
As for the DNS setup, be sure to verify that `dig MX` and `dig A` are returning results similar to this: As for the DNS setup, be sure to verify that `dig MX` and `dig A` are returning results similar to this:
``` ```
$ dig MX ntfy.sh +short $ dig MX ntfy.sh +short
10 mx1.ntfy.sh. 10 mx1.ntfy.sh.
$ dig A mx1.ntfy.sh +short $ dig A mx1.ntfy.sh +short
3.139.215.220 3.139.215.220
``` ```
@ -429,12 +429,12 @@ $ dig A mx1.ntfy.sh +short
If you are running ntfy behind a proxy, you must set the `behind-proxy` flag. Otherwise, all visitors are If you are running ntfy behind a proxy, you must set the `behind-proxy` flag. Otherwise, all visitors are
[rate limited](#rate-limiting) as if they are one. [rate limited](#rate-limiting) as if they are one.
It may be desirable to run ntfy behind a proxy (e.g. nginx, HAproxy or Apache), so you can provide TLS certificates It may be desirable to run ntfy behind a proxy (e.g. nginx, HAproxy or Apache), so you can provide TLS certificates
using Let's Encrypt using certbot, or simply because you'd like to share the ports (80/443) with other services. using Let's Encrypt using certbot, or simply because you'd like to share the ports (80/443) with other services.
Whatever your reasons may be, there are a few things to consider. Whatever your reasons may be, there are a few things to consider.
If you are running ntfy behind a proxy, you should set the `behind-proxy` flag. This will instruct the If you are running ntfy behind a proxy, you should set the `behind-proxy` flag. This will instruct the
[rate limiting](#rate-limiting) logic to use the `X-Forwarded-For` header as the primary identifier for a visitor, [rate limiting](#rate-limiting) logic to use the `X-Forwarded-For` header as the primary identifier for a visitor,
as opposed to the remote IP address. If the `behind-proxy` flag is not set, all visitors will as opposed to the remote IP address. If the `behind-proxy` flag is not set, all visitors will
be counted as one, because from the perspective of the ntfy server, they all share the proxy's IP address. be counted as one, because from the perspective of the ntfy server, they all share the proxy's IP address.
@ -445,17 +445,17 @@ be counted as one, because from the perspective of the ntfy server, they all sha
``` ```
### TLS/SSL ### TLS/SSL
ntfy supports HTTPS/TLS by setting the `listen-https` [config option](#config-options). However, if you ntfy supports HTTPS/TLS by setting the `listen-https` [config option](#config-options). However, if you
are behind a proxy, it is recommended that TLS/SSL termination is done by the proxy itself (see below). are behind a proxy, it is recommended that TLS/SSL termination is done by the proxy itself (see below).
I highly recommend using [certbot](https://certbot.eff.org/). I use it with the [dns-route53 plugin](https://certbot-dns-route53.readthedocs.io/en/stable/), I highly recommend using [certbot](https://certbot.eff.org/). I use it with the [dns-route53 plugin](https://certbot-dns-route53.readthedocs.io/en/stable/),
which lets you use [AWS Route 53](https://aws.amazon.com/route53/) as the challenge. That's much easier than using the which lets you use [AWS Route 53](https://aws.amazon.com/route53/) as the challenge. That's much easier than using the
HTTP challenge. I've found [this guide](https://nandovieira.com/using-lets-encrypt-in-development-with-nginx-and-aws-route53) to HTTP challenge. I've found [this guide](https://nandovieira.com/using-lets-encrypt-in-development-with-nginx-and-aws-route53) to
be incredibly helpful. be incredibly helpful.
### nginx/Apache2/caddy ### nginx/Apache2/caddy
For your convenience, here's a working config that'll help configure things behind a proxy. Be sure to **enable WebSockets** For your convenience, here's a working config that'll help configure things behind a proxy. Be sure to **enable WebSockets**
by forwarding the `Connection` and `Upgrade` headers accordingly. by forwarding the `Connection` and `Upgrade` headers accordingly.
In this example, ntfy runs on `:2586` and we proxy traffic to it. We also redirect HTTP to HTTPS for GET requests against a topic In this example, ntfy runs on `:2586` and we proxy traffic to it. We also redirect HTTP to HTTPS for GET requests against a topic
or the root domain: or the root domain:
@ -474,7 +474,7 @@ or the root domain:
server_name ntfy.sh; server_name ntfy.sh;
location / { location / {
# Redirect HTTP to HTTPS, but only for GET topic addresses, since we want # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want
# it to work with curl without the annoying https:// prefix # it to work with curl without the annoying https:// prefix
set $redirect_https ""; set $redirect_https "";
if ($request_method = GET) { if ($request_method = GET) {
@ -489,16 +489,16 @@ or the root domain:
proxy_pass http://127.0.0.1:2586; proxy_pass http://127.0.0.1:2586;
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_buffering off; proxy_buffering off;
proxy_request_buffering off; proxy_request_buffering off;
proxy_redirect off; proxy_redirect off;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 3m; proxy_connect_timeout 3m;
proxy_send_timeout 3m; proxy_send_timeout 3m;
proxy_read_timeout 3m; proxy_read_timeout 3m;
@ -506,19 +506,19 @@ or the root domain:
client_max_body_size 20m; # Must be >= attachment-file-size-limit in /etc/ntfy/server.yml client_max_body_size 20m; # Must be >= attachment-file-size-limit in /etc/ntfy/server.yml
} }
} }
server { server {
listen 443 ssl; listen 443 ssl;
server_name ntfy.sh; server_name ntfy.sh;
ssl_session_cache builtin:1000 shared:SSL:10m; ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1.2 TLSv1.3; ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on; ssl_prefer_server_ciphers on;
ssl_certificate /etc/letsencrypt/live/ntfy.sh/fullchain.pem; ssl_certificate /etc/letsencrypt/live/ntfy.sh/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ntfy.sh/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/ntfy.sh/privkey.pem;
location / { location / {
proxy_pass http://127.0.0.1:2586; proxy_pass http://127.0.0.1:2586;
proxy_http_version 1.1; proxy_http_version 1.1;
@ -526,16 +526,16 @@ or the root domain:
proxy_buffering off; proxy_buffering off;
proxy_request_buffering off; proxy_request_buffering off;
proxy_redirect off; proxy_redirect off;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 3m; proxy_connect_timeout 3m;
proxy_send_timeout 3m; proxy_send_timeout 3m;
proxy_read_timeout 3m; proxy_read_timeout 3m;
client_max_body_size 20m; # Must be >= attachment-file-size-limit in /etc/ntfy/server.yml client_max_body_size 20m; # Must be >= attachment-file-size-limit in /etc/ntfy/server.yml
} }
} }
@ -547,7 +547,7 @@ or the root domain:
# #
# This config requires the use of the -L flag in curl to redirect to HTTPS, and it keeps nginx output buffering # This config requires the use of the -L flag in curl to redirect to HTTPS, and it keeps nginx output buffering
# enabled. While recommended, I have had issues with that in the past. # enabled. While recommended, I have had issues with that in the past.
server { server {
listen 80; listen 80;
server_name ntfy.sh; server_name ntfy.sh;
@ -570,19 +570,19 @@ or the root domain:
client_max_body_size 20m; # Must be >= attachment-file-size-limit in /etc/ntfy/server.yml client_max_body_size 20m; # Must be >= attachment-file-size-limit in /etc/ntfy/server.yml
} }
} }
server { server {
listen 443 ssl; listen 443 ssl;
server_name ntfy.sh; server_name ntfy.sh;
ssl_session_cache builtin:1000 shared:SSL:10m; ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1.2 TLSv1.3; ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on; ssl_prefer_server_ciphers on;
ssl_certificate /etc/letsencrypt/live/ntfy.sh/fullchain.pem; ssl_certificate /etc/letsencrypt/live/ntfy.sh/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ntfy.sh/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/ntfy.sh/privkey.pem;
location / { location / {
proxy_pass http://127.0.0.1:2586; proxy_pass http://127.0.0.1:2586;
proxy_http_version 1.1; proxy_http_version 1.1;
@ -625,16 +625,16 @@ or the root domain:
RewriteCond %{HTTP:Upgrade} websocket [NC] RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC] RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://127.0.0.1:2586/$1" [P,L] RewriteRule ^/?(.*) "ws://127.0.0.1:2586/$1" [P,L]
# Redirect HTTP to HTTPS, but only for GET topic addresses, since we want # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want
# it to work with curl without the annoying https:// prefix # it to work with curl without the annoying https:// prefix
RewriteCond %{REQUEST_METHOD} GET RewriteCond %{REQUEST_METHOD} GET
RewriteRule ^/([-_A-Za-z0-9]{0,64})$ https://%{SERVER_NAME}/$1 [R,L] RewriteRule ^/([-_A-Za-z0-9]{0,64})$ https://%{SERVER_NAME}/$1 [R,L]
</VirtualHost> </VirtualHost>
<VirtualHost *:443> <VirtualHost *:443>
ServerName ntfy.sh ServerName ntfy.sh
SSLEngine on SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/ntfy.sh/fullchain.pem SSLCertificateFile /etc/letsencrypt/live/ntfy.sh/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/ntfy.sh/privkey.pem SSLCertificateKeyFile /etc/letsencrypt/live/ntfy.sh/privkey.pem
@ -647,7 +647,7 @@ or the root domain:
SetEnv proxy-nokeepalive 1 SetEnv proxy-nokeepalive 1
SetEnv proxy-sendchunked 1 SetEnv proxy-sendchunked 1
# Higher than the max message size of 4096 bytes # Higher than the max message size of 4096 bytes
LimitRequestBody 102400 LimitRequestBody 102400
# Enable mod_rewrite (requires "a2enmod rewrite") # Enable mod_rewrite (requires "a2enmod rewrite")
@ -656,7 +656,7 @@ or the root domain:
# WebSockets support (requires "a2enmod rewrite proxy_wstunnel") # WebSockets support (requires "a2enmod rewrite proxy_wstunnel")
RewriteCond %{HTTP:Upgrade} websocket [NC] RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC] RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://127.0.0.1:2586/$1" [P,L] RewriteRule ^/?(.*) "ws://127.0.0.1:2586/$1" [P,L]
</VirtualHost> </VirtualHost>
``` ```
@ -707,10 +707,10 @@ firebase-key-file: "/etc/ntfy/ntfy-sh-firebase-adminsdk-ahnce-9f4d6f14b5.json"
``` ```
## iOS instant notifications ## iOS instant notifications
Unlike Android, iOS heavily restricts background processing, which sadly makes it impossible to implement instant Unlike Android, iOS heavily restricts background processing, which sadly makes it impossible to implement instant
push notifications without a central server. push notifications without a central server.
To still support instant notifications on iOS through your self-hosted ntfy server, you have to forward so called `poll_request` To still support instant notifications on iOS through your self-hosted ntfy server, you have to forward so called `poll_request`
messages to the main ntfy.sh server (or any upstream server that's APNS/Firebase connected, if you build your own iOS app), messages to the main ntfy.sh server (or any upstream server that's APNS/Firebase connected, if you build your own iOS app),
which will then forward it to Firebase/APNS. which will then forward it to Firebase/APNS.
@ -726,12 +726,12 @@ the message ID of the original message, instructing the iOS app to poll this ser
If `upstream-base-url` is not set, notifications will still eventually get to your device, but delivery can take hours, If `upstream-base-url` is not set, notifications will still eventually get to your device, but delivery can take hours,
depending on the state of the phone. If you are using your phone, it shouldn't take more than 20-30 minutes though. depending on the state of the phone. If you are using your phone, it shouldn't take more than 20-30 minutes though.
In case you're curious, here's an example of the entire flow: In case you're curious, here's an example of the entire flow:
- In the iOS app, you subscribe to `https://ntfy.example.com/mytopic` - In the iOS app, you subscribe to `https://ntfy.example.com/mytopic`
- The app subscribes to the Firebase topic `6de73be8dfb7d69e...` (the SHA256 of the topic URL) - The app subscribes to the Firebase topic `6de73be8dfb7d69e...` (the SHA256 of the topic URL)
- When you publish a message to `https://ntfy.example.com/mytopic`, your ntfy server will publish a - When you publish a message to `https://ntfy.example.com/mytopic`, your ntfy server will publish a
poll request to `https://ntfy.sh/6de73be8dfb7d69e...`. The request from your server to the upstream server poll request to `https://ntfy.sh/6de73be8dfb7d69e...`. The request from your server to the upstream server
contains only the message ID (in the `X-Poll-ID` header), and the SHA256 checksum of the topic URL (as upstream topic). contains only the message ID (in the `X-Poll-ID` header), and the SHA256 checksum of the topic URL (as upstream topic).
- The ntfy.sh server publishes the poll request message to Firebase, which forwards it to APNS, which forwards it to your iOS device - The ntfy.sh server publishes the poll request message to Firebase, which forwards it to APNS, which forwards it to your iOS device
- Your iOS device receives the poll request, and fetches the actual message from your server, and then displays it - Your iOS device receives the poll request, and fetches the actual message from your server, and then displays it
@ -743,21 +743,21 @@ curl -X POST -H "X-Poll-ID: s4PdJozxM8na" https://ntfy.sh/6de73be8dfb7d69e32fb2c
{"id":"4HsClFEuCIcs","time":1654087955,"event":"poll_request","topic":"6de73be8dfb7d69e32fb2c00c23fe7adbd8b5504406e3068c273aa24cef4055b","message":"New message","poll_id":"s4PdJozxM8na"} {"id":"4HsClFEuCIcs","time":1654087955,"event":"poll_request","topic":"6de73be8dfb7d69e32fb2c00c23fe7adbd8b5504406e3068c273aa24cef4055b","message":"New message","poll_id":"s4PdJozxM8na"}
``` ```
Note that the self-hosted server literally sends the message `New message` for every message, even if your message Note that the self-hosted server literally sends the message `New message` for every message, even if your message
may be `Some other message`. This is so that if iOS cannot talk to the self-hosted server (in time, or at all), may be `Some other message`. This is so that if iOS cannot talk to the self-hosted server (in time, or at all),
it'll show `New message` as a popup. it'll show `New message` as a popup.
## Rate limiting ## Rate limiting
!!! info !!! info
Be aware that if you are running ntfy behind a proxy, you must set the `behind-proxy` flag. Be aware that if you are running ntfy behind a proxy, you must set the `behind-proxy` flag.
Otherwise, all visitors are rate limited as if they are one. Otherwise, all visitors are rate limited as if they are one.
By default, ntfy runs without authentication, so it is vitally important that we protect the server from abuse or overload. By default, ntfy runs without authentication, so it is vitally important that we protect the server from abuse or overload.
There are various limits and rate limits in place that you can use to configure the server: There are various limits and rate limits in place that you can use to configure the server:
* **Global limit**: A global limit applies across all visitors (IPs, clients, users) * **Global limit**: A global limit applies across all visitors (IPs, clients, users)
* **Visitor limit**: A visitor limit only applies to a certain visitor. A **visitor** is identified by its IP address * **Visitor limit**: A visitor limit only applies to a certain visitor. A **visitor** is identified by its IP address
(or the `X-Forwarded-For` header if `behind-proxy` is set). All config options that start with the word `visitor` apply (or the `X-Forwarded-For` header if `behind-proxy` is set). All config options that start with the word `visitor` apply
only on a per-visitor basis. only on a per-visitor basis.
During normal usage, you shouldn't encounter these limits at all, and even if you burst a few requests or emails During normal usage, you shouldn't encounter these limits at all, and even if you burst a few requests or emails
@ -773,39 +773,39 @@ Let's do the easy limits first:
In addition to the limits above, there is a requests/second limit per visitor for all sensitive GET/PUT/POST requests. In addition to the limits above, there is a requests/second limit per visitor for all sensitive GET/PUT/POST requests.
This limit uses a [token bucket](https://en.wikipedia.org/wiki/Token_bucket) (using Go's [rate package](https://pkg.go.dev/golang.org/x/time/rate)): This limit uses a [token bucket](https://en.wikipedia.org/wiki/Token_bucket) (using Go's [rate package](https://pkg.go.dev/golang.org/x/time/rate)):
Each visitor has a bucket of 60 requests they can fire against the server (defined by `visitor-request-limit-burst`). Each visitor has a bucket of 60 requests they can fire against the server (defined by `visitor-request-limit-burst`).
After the 60, new requests will encounter a `429 Too Many Requests` response. The visitor request bucket is refilled at a rate of one After the 60, new requests will encounter a `429 Too Many Requests` response. The visitor request bucket is refilled at a rate of one
request every 5s (defined by `visitor-request-limit-replenish`) request every 5s (defined by `visitor-request-limit-replenish`)
* `visitor-request-limit-burst` is the initial bucket of requests each visitor has. This defaults to 60. * `visitor-request-limit-burst` is the initial bucket of requests each visitor has. This defaults to 60.
* `visitor-request-limit-replenish` is the rate at which the bucket is refilled (one request per x). Defaults to 5s. * `visitor-request-limit-replenish` is the rate at which the bucket is refilled (one request per x). Defaults to 5s.
* `visitor-request-limit-exempt-hosts` is a comma-separated list of hostnames and IPs to be exempt from request rate * `visitor-request-limit-exempt-hosts` is a comma-separated list of hostnames and IPs to be exempt from request rate
limiting; hostnames are resolved at the time the server is started. Defaults to an empty list. limiting; hostnames are resolved at the time the server is started. Defaults to an empty list.
### Attachment limits ### Attachment limits
Aside from the global file size and total attachment cache limits (see [above](#attachments)), there are two relevant Aside from the global file size and total attachment cache limits (see [above](#attachments)), there are two relevant
per-visitor limits: per-visitor limits:
* `visitor-attachment-total-size-limit` is the total storage limit used for attachments per visitor. It defaults to 100M. * `visitor-attachment-total-size-limit` is the total storage limit used for attachments per visitor. It defaults to 100M.
The per-visitor storage is automatically decreased as attachments expire. External attachments (attached via `X-Attach`, The per-visitor storage is automatically decreased as attachments expire. External attachments (attached via `X-Attach`,
see [publishing docs](publish.md#attachments)) do not count here. see [publishing docs](publish.md#attachments)) do not count here.
* `visitor-attachment-daily-bandwidth-limit` is the total daily attachment download/upload bandwidth limit per visitor, * `visitor-attachment-daily-bandwidth-limit` is the total daily attachment download/upload bandwidth limit per visitor,
including PUT and GET requests. This is to protect your precious bandwidth from abuse, since egress costs money in including PUT and GET requests. This is to protect your precious bandwidth from abuse, since egress costs money in
most cloud providers. This defaults to 500M. most cloud providers. This defaults to 500M.
### E-mail limits ### E-mail limits
Similarly to the request limit, there is also an e-mail limit (only relevant if [e-mail notifications](#e-mail-notifications) Similarly to the request limit, there is also an e-mail limit (only relevant if [e-mail notifications](#e-mail-notifications)
are enabled): are enabled):
* `visitor-email-limit-burst` is the initial bucket of emails each visitor has. This defaults to 16. * `visitor-email-limit-burst` is the initial bucket of emails each visitor has. This defaults to 16.
* `visitor-email-limit-replenish` is the rate at which the bucket is refilled (one email per x). Defaults to 1h. * `visitor-email-limit-replenish` is the rate at which the bucket is refilled (one email per x). Defaults to 1h.
### Firebase limits ### Firebase limits
If [Firebase is configured](#firebase-fcm), all messages are also published to a Firebase topic (unless `Firebase: no` If [Firebase is configured](#firebase-fcm), all messages are also published to a Firebase topic (unless `Firebase: no`
is set). Firebase enforces [its own limits](https://firebase.google.com/docs/cloud-messaging/concept-options#topics_throttling) is set). Firebase enforces [its own limits](https://firebase.google.com/docs/cloud-messaging/concept-options#topics_throttling)
on how many messages can be published. Unfortunately these limits are a little vague and can change depending on the time on how many messages can be published. Unfortunately these limits are a little vague and can change depending on the time
of day. In practice, I have only ever observed `429 Quota exceeded` responses from Firebase if **too many messages are published to of day. In practice, I have only ever observed `429 Quota exceeded` responses from Firebase if **too many messages are published to
the same topic**. the same topic**.
In ntfy, if Firebase responds with a 429 after publishing to a topic, the visitor (= IP address) who published the message In ntfy, if Firebase responds with a 429 after publishing to a topic, the visitor (= IP address) who published the message
is **banned from publishing to Firebase for 10 minutes** (not configurable). Because publishing to Firebase happens asynchronously, is **banned from publishing to Firebase for 10 minutes** (not configurable). Because publishing to Firebase happens asynchronously,
@ -828,7 +828,7 @@ Depending on *how you run it*, here are a few limits that are relevant:
### Message cache ### Message cache
By default, the [message cache](#message-cache) (defined by `cache-file`) uses the SQLite default settings, which means it By default, the [message cache](#message-cache) (defined by `cache-file`) uses the SQLite default settings, which means it
syncs to disk on every write. For personal servers, this is perfectly adequate. For larger installations, such as ntfy.sh, syncs to disk on every write. For personal servers, this is perfectly adequate. For larger installations, such as ntfy.sh,
the [write-ahead log (WAL)](https://sqlite.org/wal.html) should be enabled, and the sync mode should be adjusted. the [write-ahead log (WAL)](https://sqlite.org/wal.html) should be enabled, and the sync mode should be adjusted.
See [this article](https://phiresky.github.io/blog/2020/sqlite-performance-tuning/) for details. See [this article](https://phiresky.github.io/blog/2020/sqlite-performance-tuning/) for details.
In addition to that, for very high load servers (such as ntfy.sh), it may be beneficial to write messages to the cache In addition to that, for very high load servers (such as ntfy.sh), it may be beneficial to write messages to the cache
@ -900,7 +900,7 @@ If you put stuff on the Internet, bad actors will try to break them or break in.
and nginx's [ngx_http_limit_req_module module](http://nginx.org/en/docs/http/ngx_http_limit_req_module.html) can be used and nginx's [ngx_http_limit_req_module module](http://nginx.org/en/docs/http/ngx_http_limit_req_module.html) can be used
to ban client IPs if they misbehave. This is on top of the [rate limiting](#rate-limiting) inside the ntfy server. to ban client IPs if they misbehave. This is on top of the [rate limiting](#rate-limiting) inside the ntfy server.
Here's an example for how ntfy.sh is configured, following the instructions from two tutorials ([here](https://easyengine.io/tutorials/nginx/fail2ban/) Here's an example for how ntfy.sh is configured, following the instructions from two tutorials ([here](https://easyengine.io/tutorials/nginx/fail2ban/)
and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-attack/)): and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-attack/)):
=== "/etc/nginx/nginx.conf" === "/etc/nginx/nginx.conf"
@ -933,7 +933,7 @@ and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-a
location / { location / {
limit_req zone=one burst=1000 nodelay; limit_req zone=one burst=1000 nodelay;
} }
} }
``` ```
=== "/etc/fail2ban/filter.d/nginx-req-limit.conf" === "/etc/fail2ban/filter.d/nginx-req-limit.conf"
@ -957,15 +957,15 @@ and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-a
## Debugging/tracing ## Debugging/tracing
If something's not working right, you can debug/trace through what the ntfy server is doing by setting the `log-level` If something's not working right, you can debug/trace through what the ntfy server is doing by setting the `log-level`
to `DEBUG` or `TRACE`. The `DEBUG` setting will output information about each published message, but not the message to `DEBUG` or `TRACE`. The `DEBUG` setting will output information about each published message, but not the message
contents. The `TRACE` setting will also print the message contents. contents. The `TRACE` setting will also print the message contents.
!!! warning !!! warning
Both options are very verbose and should only be enabled in production for short periods of time. Otherwise, Both options are very verbose and should only be enabled in production for short periods of time. Otherwise,
you're going to run out of disk space pretty quickly. you're going to run out of disk space pretty quickly.
You can also hot-reload the `log-level` by sending the `SIGHUP` signal to the process after editing the `server.yml` file. You can also hot-reload the `log-level` by sending the `SIGHUP` signal to the process after editing the `server.yml` file.
You can do so by calling `systemctl reload ntfy` (if ntfy is running inside systemd), or by calling `kill -HUP $(pidof ntfy)`. You can do so by calling `systemctl reload ntfy` (if ntfy is running inside systemd), or by calling `kill -HUP $(pidof ntfy)`.
If successful, you'll see something like this: If successful, you'll see something like this:
``` ```
@ -981,8 +981,8 @@ CLI option (e.g. `--listen-http :80`. Here's a list of all available options. Al
variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`). variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
!!! info !!! info
All config options can also be defined in the `server.yml` file using underscores instead of dashes, e.g. All config options can also be defined in the `server.yml` file using underscores instead of dashes, e.g.
`cache_duration` and `cache-duration` are both supported. This is to support stricter YAML parsers that do `cache_duration` and `cache-duration` are both supported. This is to support stricter YAML parsers that do
not support dashes. not support dashes.
| Config option | Env variable | Format | Default | Description | | Config option | Env variable | Format | Default | Description |
@ -1028,7 +1028,7 @@ variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
| `visitor-subscription-limit` | `NTFY_VISITOR_SUBSCRIPTION_LIMIT` | *number* | 30 | Rate limiting: Number of subscriptions per visitor (IP address) | | `visitor-subscription-limit` | `NTFY_VISITOR_SUBSCRIPTION_LIMIT` | *number* | 30 | Rate limiting: Number of subscriptions per visitor (IP address) |
| `web-root` | `NTFY_WEB_ROOT` | `app`, `home` or `disable` | `app` | Sets web root to landing page (home), web app (app) or disables the web app entirely (disable) | | `web-root` | `NTFY_WEB_ROOT` | `app`, `home` or `disable` | `app` | Sets web root to landing page (home), web app (app) or disables the web app entirely (disable) |
The format for a *duration* is: `<number>(smh)`, e.g. 30s, 20m or 1h. The format for a *duration* is: `<number>(smh)`, e.g. 30s, 20m or 1h.
The format for a *size* is: `<number>(GMK)`, e.g. 1G, 200M or 4000k. The format for a *size* is: `<number>(GMK)`, e.g. 1G, 200M or 4000k.
## Command line options ## Command line options
@ -1045,10 +1045,10 @@ CATEGORY:
DESCRIPTION: DESCRIPTION:
Run the ntfy server and listen for incoming requests Run the ntfy server and listen for incoming requests
The command will load the configuration from /etc/ntfy/server.yml. Config options can The command will load the configuration from /etc/ntfy/server.yml. Config options can
be overridden using the command line options. be overridden using the command line options.
Examples: Examples:
ntfy serve # Starts server in the foreground (on port 80) ntfy serve # Starts server in the foreground (on port 80)
ntfy serve --listen-http :8080 # Starts server with alternate port ntfy serve --listen-http :8080 # Starts server with alternate port
@ -1065,7 +1065,7 @@ OPTIONS:
--cache-duration since, --cache_duration since, -b since buffer messages for this time to allow since requests (default: 12h0m0s) [$NTFY_CACHE_DURATION] --cache-duration since, --cache_duration since, -b since buffer messages for this time to allow since requests (default: 12h0m0s) [$NTFY_CACHE_DURATION]
--cache-file value, --cache_file value, -C value cache file used for message caching [$NTFY_CACHE_FILE] --cache-file value, --cache_file value, -C value cache file used for message caching [$NTFY_CACHE_FILE]
--cache-batch-size value, --cache_batch_size value max size of messages to batch together when writing to message cache (if zero, writes are synchronous) (default: 0) [$NTFY_BATCH_SIZE] --cache-batch-size value, --cache_batch_size value max size of messages to batch together when writing to message cache (if zero, writes are synchronous) (default: 0) [$NTFY_BATCH_SIZE]
--cache-batch-timeout value, --cache_batch_timeout value timeout for batched async writes to the message cache (if zero, writes are synchronous) (default: 0s) [$NTFY_CACHE_BATCH_TIMEOUT] --cache-batch-timeout value, --cache_batch_timeout value timeout for batched async writes to the message cache (if zero, writes are synchronous) (default: 0s) [$NTFY_CACHE_BATCH_TIMEOUT]
--cache-startup-queries value, --cache_startup_queries value queries run when the cache database is initialized [$NTFY_CACHE_STARTUP_QUERIES] --cache-startup-queries value, --cache_startup_queries value queries run when the cache database is initialized [$NTFY_CACHE_STARTUP_QUERIES]
--cert-file value, --cert_file value, -E value certificate file, if listen-https is set [$NTFY_CERT_FILE] --cert-file value, --cert_file value, -E value certificate file, if listen-https is set [$NTFY_CERT_FILE]
--config value, -c value config file (default: /etc/ntfy/server.yml) [$NTFY_CONFIG_FILE] --config value, -c value config file (default: /etc/ntfy/server.yml) [$NTFY_CONFIG_FILE]
@ -1099,4 +1099,3 @@ OPTIONS:
--visitor-subscription-limit value, --visitor_subscription_limit value number of subscriptions per visitor (default: 30) [$NTFY_VISITOR_SUBSCRIPTION_LIMIT] --visitor-subscription-limit value, --visitor_subscription_limit value number of subscriptions per visitor (default: 30) [$NTFY_VISITOR_SUBSCRIPTION_LIMIT]
--web-root value, --web_root value sets web root to landing page (home), web app (app) or disabled (disable) (default: "app") [$NTFY_WEB_ROOT] --web-root value, --web_root value sets web root to landing page (home), web app (app) or disabled (disable) (default: "app") [$NTFY_WEB_ROOT]
``` ```

View file

@ -1,5 +1,5 @@
# Deprecation notices # Deprecation notices
This page is used to list deprecation notices for ntfy. Deprecated commands and options will be This page is used to list deprecation notices for ntfy. Deprecated commands and options will be
**removed after 1-3 months** from the time they were deprecated. How long the feature is deprecated **removed after 1-3 months** from the time they were deprecated. How long the feature is deprecated
before the behavior is changed depends on the severity of the change, and how prominent the feature is. before the behavior is changed depends on the severity of the change, and how prominent the feature is.
@ -34,7 +34,7 @@ and add a notice banner in the Android app instead.
### Android app: Using `since=<timestamp>` instead of `since=<id>` ### Android app: Using `since=<timestamp>` instead of `since=<id>`
> Active since 2022-02-27, behavior changed with v1.14.0 > Active since 2022-02-27, behavior changed with v1.14.0
The Android app started using `since=<id>` instead of `since=<timestamp>`, which means as of Android app v1.14.0, The Android app started using `since=<id>` instead of `since=<timestamp>`, which means as of Android app v1.14.0,
it will not work with servers older than v1.16.0 anymore. This is to simplify handling of deduplication in the Android app. it will not work with servers older than v1.16.0 anymore. This is to simplify handling of deduplication in the Android app.
The `since=<timestamp>` endpoint will continue to work. This is merely a notice that the Android app behavior will change. The `since=<timestamp>` endpoint will continue to work. This is merely a notice that the Android app behavior will change.
@ -57,4 +57,3 @@ just the server.
$ ntfy serve $ ntfy serve
2021/12/17 08:16:01 Listening on :80/http 2021/12/17 08:16:01 Listening on :80/http
``` ```

View file

@ -1,26 +1,26 @@
# Development # Development
Hurray 🥳 🎉, you are interested in writing code for ntfy! **That's awesome.** 😎 Hurray 🥳 🎉, you are interested in writing code for ntfy! **That's awesome.** 😎
I tried my very best to write up detailed instructions, but if at any point in time you run into issues, don't I tried my very best to write up detailed instructions, but if at any point in time you run into issues, don't
hesitate to **contact me on [Discord](https://discord.gg/cT7ECsZj9w) or [Matrix](https://matrix.to/#/#ntfy:matrix.org)**. hesitate to **contact me on [Discord](https://discord.gg/cT7ECsZj9w) or [Matrix](https://matrix.to/#/#ntfy:matrix.org)**.
## ntfy server ## ntfy server
The ntfy server source code is available [on GitHub](https://github.com/binwiederhier/ntfy). The codebase for the The ntfy server source code is available [on GitHub](https://github.com/binwiederhier/ntfy). The codebase for the
server consists of three components: server consists of three components:
* **The main server/client** is written in [Go](https://go.dev/) (so you'll need Go). Its main entrypoint is at * **The main server/client** is written in [Go](https://go.dev/) (so you'll need Go). Its main entrypoint is at
[main.go](https://github.com/binwiederhier/ntfy/blob/main/main.go), and the meat you're likely interested in is [main.go](https://github.com/binwiederhier/ntfy/blob/main/main.go), and the meat you're likely interested in is
in [server.go](https://github.com/binwiederhier/ntfy/blob/main/server/server.go). Notably, the server uses a in [server.go](https://github.com/binwiederhier/ntfy/blob/main/server/server.go). Notably, the server uses a
[SQLite](https://sqlite.org) library called [go-sqlite3](https://github.com/mattn/go-sqlite3), which requires [SQLite](https://sqlite.org) library called [go-sqlite3](https://github.com/mattn/go-sqlite3), which requires
[Cgo](https://go.dev/blog/cgo) and `CGO_ENABLED=1` to be set. Otherwise things will not work (see below). [Cgo](https://go.dev/blog/cgo) and `CGO_ENABLED=1` to be set. Otherwise things will not work (see below).
* **The documentation** is generated by [MkDocs](https://www.mkdocs.org/) and [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/), * **The documentation** is generated by [MkDocs](https://www.mkdocs.org/) and [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/),
which is written in [Python](https://www.python.org/). You'll need Python and MkDocs (via `pip`) only if you want to which is written in [Python](https://www.python.org/). You'll need Python and MkDocs (via `pip`) only if you want to
build the docs. build the docs.
* **The web app** is written in [React](https://reactjs.org/), using [MUI](https://mui.com/). It uses [Create React App](https://create-react-app.dev/) * **The web app** is written in [React](https://reactjs.org/), using [MUI](https://mui.com/). It uses [Create React App](https://create-react-app.dev/)
to build the production build. If you want to modify the web app, you need [nodejs](https://nodejs.org/en/) (for `npm`) to build the production build. If you want to modify the web app, you need [nodejs](https://nodejs.org/en/) (for `npm`)
and install all the 100,000 dependencies (*sigh*). and install all the 100,000 dependencies (*sigh*).
All of these components are built and then **baked into one binary**. All of these components are built and then **baked into one binary**.
### Navigating the code ### Navigating the code
Code: Code:
@ -44,7 +44,7 @@ The `web/` and `docs/` folder are the sources for web app and documentation. Dur
the generated output is copied to `server/site` (web app and landing page) and `server/docs` (documentation). the generated output is copied to `server/site` (web app and landing page) and `server/docs` (documentation).
### Build/test on Gitpod ### Build/test on Gitpod
To get a quick working development environment you can use [Gitpod](https://gitpod.io), an in-browser IDE To get a quick working development environment you can use [Gitpod](https://gitpod.io), an in-browser IDE
that makes it easy to develop ntfy without having to set up a desktop IDE. For any real development, that makes it easy to develop ntfy without having to set up a desktop IDE. For any real development,
I do suggest a proper IDE like [IntelliJ IDEA](https://www.jetbrains.com/idea/). I do suggest a proper IDE like [IntelliJ IDEA](https://www.jetbrains.com/idea/).
@ -57,7 +57,7 @@ I do suggest a proper IDE like [IntelliJ IDEA](https://www.jetbrains.com/idea/).
* [Make](https://www.gnu.org/software/make/) (required for convenience) * [Make](https://www.gnu.org/software/make/) (required for convenience)
* [libsqlite3/libsqlite3-dev](https://www.sqlite.org/) (required for main server, for SQLite cgo-based bindings) * [libsqlite3/libsqlite3-dev](https://www.sqlite.org/) (required for main server, for SQLite cgo-based bindings)
* [GoReleaser](https://goreleaser.com/) (required for a proper main server build) * [GoReleaser](https://goreleaser.com/) (required for a proper main server build)
* [Python](https://www.python.org/) (for `pip`, only to build the docs) * [Python](https://www.python.org/) (for `pip`, only to build the docs)
* [nodejs](https://nodejs.org/en/) (for `npm`, only to build the web app) * [nodejs](https://nodejs.org/en/) (for `npm`, only to build the web app)
### Install dependencies ### Install dependencies
@ -107,16 +107,16 @@ Now check out via git from the [GitHub repository](https://github.com/binwiederh
=== "via SSH" === "via SSH"
``` shell ``` shell
git clone git@github.com:binwiederhier/ntfy.git git clone git@github.com:binwiederhier/ntfy.git
cd ntfy cd ntfy
``` ```
### Build all the things ### Build all the things
Now you can finally build everything. There are tons of `make` targets, so maybe just review what's there first Now you can finally build everything. There are tons of `make` targets, so maybe just review what's there first
by typing `make`: by typing `make`:
``` shell ``` shell
$ make $ make
Typical commands (more see below): Typical commands (more see below):
make build - Build web app, documentation and server/client (sloowwww) make build - Build web app, documentation and server/client (sloowwww)
make cli-linux-amd64 - Build server/client binary (amd64, no web app or docs) make cli-linux-amd64 - Build server/client binary (amd64, no web app or docs)
@ -127,20 +127,20 @@ Typical commands (more see below):
... ...
``` ```
If you want to build the **ntfy binary including web app and docs for all supported architectures** (amd64, armv7, and arm64), If you want to build the **ntfy binary including web app and docs for all supported architectures** (amd64, armv7, and arm64),
you can simply run `make build`: you can simply run `make build`:
``` shell ``` shell
$ make build $ make build
... ...
# This builds web app, docs, and the ntfy binary (for amd64, armv7 and arm64). # This builds web app, docs, and the ntfy binary (for amd64, armv7 and arm64).
# This will be SLOW (5+ minutes on my laptop on the first run). Maybe look at the other make targets? # This will be SLOW (5+ minutes on my laptop on the first run). Maybe look at the other make targets?
``` ```
You'll see all the outputs in the `dist/` folder afterwards: You'll see all the outputs in the `dist/` folder afterwards:
``` bash ``` bash
$ find dist $ find dist
dist dist
dist/metadata.json dist/metadata.json
dist/ntfy_arm64_linux_arm64 dist/ntfy_arm64_linux_arm64
@ -153,7 +153,7 @@ dist/config.yaml
dist/artifacts.json dist/artifacts.json
``` ```
If you also want to build the **Debian/RPM packages and the Docker images for all supported architectures**, you can If you also want to build the **Debian/RPM packages and the Docker images for all supported architectures**, you can
use the `make release-snapshot` target: use the `make release-snapshot` target:
``` shell ``` shell
@ -188,7 +188,7 @@ $ make cli-linux-amd64 install-linux-amd64
$ ntfy serve $ ntfy serve
``` ```
**During development of the main app, you can also just use `go run main.go`**, as long as you run **During development of the main app, you can also just use `go run main.go`**, as long as you run
`make cli-deps-static-sites`at least once and `CGO_ENABLED=1`: `make cli-deps-static-sites`at least once and `CGO_ENABLED=1`:
``` shell ``` shell
@ -209,11 +209,11 @@ This is because we use `go:embed` to embed the documentation and web app, so the
present at `server/docs` and `server/site`. If they are not, you'll see the above error. The `cli-deps-static-sites` present at `server/docs` and `server/site`. If they are not, you'll see the above error. The `cli-deps-static-sites`
target creates dummy files that ensure that you'll be able to build. target creates dummy files that ensure that you'll be able to build.
While not officially supported (or released), you can build and run the server **on macOS** as well. Simply run While not officially supported (or released), you can build and run the server **on macOS** as well. Simply run
`make cli-darwin-server` to build a binary, or `go run main.go serve` (see above) to run it. `make cli-darwin-server` to build a binary, or `go run main.go serve` (see above) to run it.
### Build the web app ### Build the web app
The sources for the web app live in `web/`. As long as you have `npm` installed (see above), building the web app The sources for the web app live in `web/`. As long as you have `npm` installed (see above), building the web app
is really simple. Just type `make web` and you're in business: is really simple. Just type `make web` and you're in business:
``` shell ``` shell
@ -221,11 +221,11 @@ $ make web
... ...
``` ```
This will build the web app using Create React App and then **copy the production build to the `server/site` folder**, so This will build the web app using Create React App and then **copy the production build to the `server/site` folder**, so
that when you `make cli` (or `make cli-linux-amd64`, ...), you will have the web app included in the `ntfy` binary. that when you `make cli` (or `make cli-linux-amd64`, ...), you will have the web app included in the `ntfy` binary.
If you're developing on the web app, it's best to just `cd web` and run `npm start` manually. This will open your browser If you're developing on the web app, it's best to just `cd web` and run `npm start` manually. This will open your browser
at `http://127.0.0.1:3000` with the web app, and as you edit the source files, they will be recompiled and the browser at `http://127.0.0.1:3000` with the web app, and as you edit the source files, they will be recompiled and the browser
will automatically refresh: will automatically refresh:
``` shell ``` shell
@ -234,7 +234,7 @@ $ npm start
``` ```
### Build the docs ### Build the docs
The sources for the docs live in `docs/`. Similarly to the web app, you can simply run `make docs` to build the The sources for the docs live in `docs/`. Similarly to the web app, you can simply run `make docs` to build the
documentation. As long as you have `mkdocs` installed (see above), this should work fine: documentation. As long as you have `mkdocs` installed (see above), this should work fine:
``` shell ``` shell
@ -242,8 +242,8 @@ $ make docs
... ...
``` ```
If you are changing the documentation, you should be running `mkdocs serve` directly. This will build the documentation, If you are changing the documentation, you should be running `mkdocs serve` directly. This will build the documentation,
serve the files at `http://127.0.0.1:8000/`, and rebuild every time you save the source files: serve the files at `http://127.0.0.1:8000/`, and rebuild every time you save the source files:
``` ```
$ mkdocs serve $ mkdocs serve
@ -269,8 +269,8 @@ The Android app has two flavors:
* [build.gradle](https://github.com/binwiederhier/ntfy-android/blob/main/app/build.gradle) - Main build file * [build.gradle](https://github.com/binwiederhier/ntfy-android/blob/main/app/build.gradle) - Main build file
### IDE/Environment ### IDE/Environment
You should download [Android Studio](https://developer.android.com/studio) (or [IntelliJ IDEA](https://www.jetbrains.com/idea/) You should download [Android Studio](https://developer.android.com/studio) (or [IntelliJ IDEA](https://www.jetbrains.com/idea/)
with the relevant Android plugins). Everything else will just be a pain for you. Do yourself a favor. 😀 with the relevant Android plugins). Everything else will just be a pain for you. Do yourself a favor. 😀
### Check out the code ### Check out the code
First check out the repository: First check out the repository:

View file

@ -33,10 +33,10 @@ GitHub have been hopeless. In case it ever becomes available, I want to know imm
## Low disk space alerts ## Low disk space alerts
Here's a simple cronjob that I use to alert me when the disk space on the root disk is running low. It's simple, but Here's a simple cronjob that I use to alert me when the disk space on the root disk is running low. It's simple, but
effective. effective.
``` bash ``` bash
#!/bin/bash #!/bin/bash
mingigs=10 mingigs=10
@ -78,7 +78,7 @@ to notify yourself on SSH login.
## Collect data from multiple machines ## Collect data from multiple machines
The other day I was running tasks on 20 servers, and I wanted to collect the interim results The other day I was running tasks on 20 servers, and I wanted to collect the interim results
as a CSV in one place. Each of the servers was publishing to a topic as the results completed (`publish-result.sh`), as a CSV in one place. Each of the servers was publishing to a topic as the results completed (`publish-result.sh`),
and I had one central collector to grab the results as they came in (`collect-results.sh`). and I had one central collector to grab the results as they came in (`collect-results.sh`).
It looked something like this: It looked something like this:
@ -89,10 +89,10 @@ It looked something like this:
[ -n "$result" ] && echo "$result" >> results.csv [ -n "$result" ] && echo "$result" >> results.csv
done < <(stdbuf -i0 -o0 curl -s ntfy.sh/results/raw) done < <(stdbuf -i0 -o0 curl -s ntfy.sh/results/raw)
``` ```
=== "publish-result.sh" === "publish-result.sh"
```bash ```bash
// This script was run on each of the 20 servers. It was doing heavy processing ... // This script was run on each of the 20 servers. It was doing heavy processing ...
// Publish script results // Publish script results
curl -d "$(hostname),$count,$time" ntfy.sh/results curl -d "$(hostname),$count,$time" ntfy.sh/results
``` ```
@ -136,7 +136,7 @@ You can send a message during a workflow run with curl. Here is an example sendi
``` ```
## Watchtower (shoutrrr) ## Watchtower (shoutrrr)
You can use [shoutrrr](https://github.com/containrrr/shoutrrr) generic webhook support to send You can use [shoutrrr](https://github.com/containrrr/shoutrrr) generic webhook support to send
[Watchtower](https://github.com/containrrr/watchtower/) notifications to your ntfy topic. [Watchtower](https://github.com/containrrr/watchtower/) notifications to your ntfy topic.
Example docker-compose.yml: Example docker-compose.yml:
@ -156,7 +156,7 @@ shoutrrr send -u "generic+https://ntfy.sh/my_watchtower_topic?title=WatchtowerUp
## Sonarr, Radarr, Lidarr, Readarr, Prowlarr, SABnzbd ## Sonarr, Radarr, Lidarr, Readarr, Prowlarr, SABnzbd
It's possible to use custom scripts for all the *arr services, plus SABnzbd. Notifications for downloads, warnings, grabs etc. It's possible to use custom scripts for all the *arr services, plus SABnzbd. Notifications for downloads, warnings, grabs etc.
Some simple bash scripts to achieve this are kindly provided in [nickexyz's repository](https://github.com/nickexyz/ntfy-shellscripts). Some simple bash scripts to achieve this are kindly provided in [nickexyz's repository](https://github.com/nickexyz/ntfy-shellscripts).
## Node-RED ## Node-RED
You can use the HTTP request node to send messages with [Node-RED](https://nodered.org), some examples: You can use the HTTP request node to send messages with [Node-RED](https://nodered.org), some examples:
@ -503,7 +503,7 @@ Select **Alert Contact Type** = Webhook. Then set your desired **Friendly Name**
{ {
"topic":"myTopic", "topic":"myTopic",
"title": "*monitorFriendlyName* *alertTypeFriendlyName*", "title": "*monitorFriendlyName* *alertTypeFriendlyName*",
"message": "*alertDetails*", "message": "*alertDetails*",
"tags": ["green_circle"], "tags": ["green_circle"],
"priority": 3, "priority": 3,
"click": https://uptimerobot.com/dashboard#*monitorID* "click": https://uptimerobot.com/dashboard#*monitorID*
@ -515,7 +515,7 @@ You can create two Alert Contacts each with a different icon and priority, for e
{ {
"topic":"myTopic", "topic":"myTopic",
"title": "*monitorFriendlyName* *alertTypeFriendlyName*", "title": "*monitorFriendlyName* *alertTypeFriendlyName*",
"message": "*alertDetails*", "message": "*alertDetails*",
"tags": ["red_circle"], "tags": ["red_circle"],
"priority": 3, "priority": 3,
"click": https://uptimerobot.com/dashboard#*monitorID* "click": https://uptimerobot.com/dashboard#*monitorID*
@ -529,7 +529,7 @@ You can now add the created Alerts Contact(s) to the monitor(s) and test the not
## Apprise ## Apprise
ntfy is integrated natively into [Apprise](https://github.com/caronc/apprise) (also check out the ntfy is integrated natively into [Apprise](https://github.com/caronc/apprise) (also check out the
[Apprise/ntfy wiki page](https://github.com/caronc/apprise/wiki/Notify_ntfy)). [Apprise/ntfy wiki page](https://github.com/caronc/apprise/wiki/Notify_ntfy)).
You can use it like this: You can use it like this:
@ -548,7 +548,7 @@ apprise -vv -t "Test Message Title" -b "Test Message Body" \
## Rundeck ## Rundeck
Rundeck by default sends only HTML email which is not processed by ntfy SMTP server. Append following configurations to Rundeck by default sends only HTML email which is not processed by ntfy SMTP server. Append following configurations to
[rundeck-config.properties](https://docs.rundeck.com/docs/administration/configuration/config-file-reference.html) : [rundeck-config.properties](https://docs.rundeck.com/docs/administration/configuration/config-file-reference.html) :
``` ```
@ -570,5 +570,3 @@ Example `template.html`:
Add notification on Rundeck (attachment type must be: `Attached as file to email`): Add notification on Rundeck (attachment type must be: `Attached as file to email`):
![Rundeck](static/img/rundeck.png) ![Rundeck](static/img/rundeck.png)

View file

@ -8,15 +8,15 @@ Yes. As long as you don't abuse it, it'll be available and free of charge. While
server without signup and free of charge, I may also offer paid plans in the future. server without signup and free of charge, I may also offer paid plans in the future.
## What are the uptime guarantees? ## What are the uptime guarantees?
Best effort. Best effort.
ntfy currently runs on a single DigitalOcean droplet, without any scale out strategy or redundancies. When the time comes, ntfy currently runs on a single DigitalOcean droplet, without any scale out strategy or redundancies. When the time comes,
I'll add scale out features, but for now it is what it is. I'll add scale out features, but for now it is what it is.
In the first year of its life, and to this day (Dec'22), ntfy had **no outages** that I can remember. Other than short In the first year of its life, and to this day (Dec'22), ntfy had **no outages** that I can remember. Other than short
blips and some HTTP 500 spikes, it has been rock solid. blips and some HTTP 500 spikes, it has been rock solid.
There is a [status page](https://ntfy.statuspage.io/) which is updated based on some automated checks via the amazingly There is a [status page](https://ntfy.statuspage.io/) which is updated based on some automated checks via the amazingly
awesome [healthchecks.io](https://healthchecks.io/) (_no affiliation, just a fan_). awesome [healthchecks.io](https://healthchecks.io/) (_no affiliation, just a fan_).
## What happens if there are multiple subscribers to the same topic? ## What happens if there are multiple subscribers to the same topic?
@ -25,7 +25,7 @@ As per usual with pub-sub, all subscribers receive notifications if they are sub
## Will you know what topics exist, can you spy on me? ## Will you know what topics exist, can you spy on me?
If you don't trust me or your messages are sensitive, run your own server. It's open source. If you don't trust me or your messages are sensitive, run your own server. It's open source.
That said, the logs do contain topic names and IP addresses, but I don't use them for anything other than That said, the logs do contain topic names and IP addresses, but I don't use them for anything other than
troubleshooting and rate limiting. Messages are cached for the duration configured in `server.yml` (12h by default) troubleshooting and rate limiting. Messages are cached for the duration configured in `server.yml` (12h by default)
to facilitate service restarts, message polling and to overcome client network disruptions. to facilitate service restarts, message polling and to overcome client network disruptions.
## Can I self-host it? ## Can I self-host it?
@ -35,16 +35,16 @@ your own server as well. Check out the [install instructions](install.md).
## Is Firebase used? ## Is Firebase used?
In addition to caching messages locally and delivering them to long-polling subscribers, all messages are also In addition to caching messages locally and delivering them to long-polling subscribers, all messages are also
published to Firebase Cloud Messaging (FCM) (if `FirebaseKeyFile` is set, which it is on ntfy.sh). This published to Firebase Cloud Messaging (FCM) (if `FirebaseKeyFile` is set, which it is on ntfy.sh). This
is to facilitate notifications on Android. is to facilitate notifications on Android.
If you do not care for Firebase, I suggest you install the [F-Droid version](https://f-droid.org/en/packages/io.heckel.ntfy/) If you do not care for Firebase, I suggest you install the [F-Droid version](https://f-droid.org/en/packages/io.heckel.ntfy/)
of the app and [self-host your own ntfy server](install.md). of the app and [self-host your own ntfy server](install.md).
## How much battery does the Android app use? ## How much battery does the Android app use?
If you use the ntfy.sh server, and you don't use the [instant delivery](subscribe/phone.md#instant-delivery) feature, If you use the ntfy.sh server, and you don't use the [instant delivery](subscribe/phone.md#instant-delivery) feature,
the Android/iOS app uses no additional battery, since Firebase Cloud Messaging (FCM) is used. If you use your own server, the Android/iOS app uses no additional battery, since Firebase Cloud Messaging (FCM) is used. If you use your own server,
or you use *instant delivery* (Android only), the app has to maintain a constant connection to the server, which consumes or you use *instant delivery* (Android only), the app has to maintain a constant connection to the server, which consumes
about 0-1% of battery in 17h of use (on my phone). There has been a ton of testing and improvement around this. I think it's pretty about 0-1% of battery in 17h of use (on my phone). There has been a ton of testing and improvement around this. I think it's pretty
decent now. decent now.
## What is instant delivery? ## What is instant delivery?
@ -63,10 +63,10 @@ it, or hopefully, somebody else will come along and help out. Please review the
## Can I disable the web app? Can I protect it with a login screen? ## Can I disable the web app? Can I protect it with a login screen?
The web app is a static website without a backend (other than the ntfy API). All data is stored locally in the browser The web app is a static website without a backend (other than the ntfy API). All data is stored locally in the browser
cache and local storage. That means it does not need to be protected with a login screen, and it poses no additional cache and local storage. That means it does not need to be protected with a login screen, and it poses no additional
security risk. So technically, it does not need to be disabled. security risk. So technically, it does not need to be disabled.
However, if you still want to disable it, you can do so with the `web-root: disable` option in the `server.yml` file. However, if you still want to disable it, you can do so with the `web-root: disable` option in the `server.yml` file.
Think of the ntfy web app like an Android/iOS app. It is freely available and accessible to anyone, yet useless without Think of the ntfy web app like an Android/iOS app. It is freely available and accessible to anyone, yet useless without
a proper backend. So as long as you secure your backend with ACLs, exposing the ntfy web app to the Internet is harmless. a proper backend. So as long as you secure your backend with ACLs, exposing the ntfy web app to the Internet is harmless.

View file

@ -9,8 +9,8 @@ or POST requests. I use it to notify myself when scripts fail, or long-running c
To [receive notifications on your phone](subscribe/phone.md), install the app, either via Google Play or F-Droid. To [receive notifications on your phone](subscribe/phone.md), install the app, either via Google Play or F-Droid.
Once installed, open it and subscribe to a topic of your choosing. Topics don't have to explicitly be created, so just Once installed, open it and subscribe to a topic of your choosing. Topics don't have to explicitly be created, so just
pick a name and use it later when you [publish a message](publish.md). Note that **topic names are public, so it's wise pick a name and use it later when you [publish a message](publish.md). Note that **topic names are public, so it's wise
to choose something that cannot be guessed easily.** to choose something that cannot be guessed easily.**
For this guide, we'll just use `mytopic` as our topic name: For this guide, we'll just use `mytopic` as our topic name:
@ -23,7 +23,7 @@ That's it. After you tap "Subscribe", the app is listening for new messages on t
## Step 2: Send a message ## Step 2: Send a message
Now let's [send a message](publish.md) to our topic. It's easy in every language, since we're just using HTTP PUT/POST, Now let's [send a message](publish.md) to our topic. It's easy in every language, since we're just using HTTP PUT/POST,
or with the [ntfy CLI](install.md). The message is in the request body. Here's an example showing how to publish a or with the [ntfy CLI](install.md). The message is in the request body. Here's an example showing how to publish a
simple message using a POST request: simple message using a POST request:
=== "Command line (curl)" === "Command line (curl)"
@ -40,7 +40,7 @@ simple message using a POST request:
``` http ``` http
POST /mytopic HTTP/1.1 POST /mytopic HTTP/1.1
Host: ntfy.sh Host: ntfy.sh
Backup successful 😀 Backup successful 😀
``` ```
@ -91,5 +91,3 @@ Here's another video showing the entire process:
<video controls muted autoplay loop width="650" src="static/img/android-video-overview.mp4"></video> <video controls muted autoplay loop width="650" src="static/img/android-video-overview.mp4"></video>
<figcaption>Sending push notifications to your Android phone</figcaption> <figcaption>Sending push notifications to your Android phone</figcaption>
</figure> </figure>

View file

@ -1,7 +1,7 @@
# Installing ntfy # Installing ntfy
The `ntfy` CLI allows you to [publish messages](publish.md), [subscribe to topics](subscribe/cli.md) as well as to The `ntfy` CLI allows you to [publish messages](publish.md), [subscribe to topics](subscribe/cli.md) as well as to
self-host your own ntfy server. It's all pretty straight forward. Just install the binary, package or Docker image, self-host your own ntfy server. It's all pretty straight forward. Just install the binary, package or Docker image,
configure it and run it. Just like any other software. No fuzz. configure it and run it. Just like any other software. No fuzz.
!!! info !!! info
The following steps are only required if you want to **self-host your own ntfy server or you want to use the ntfy CLI**. The following steps are only required if you want to **self-host your own ntfy server or you want to use the ntfy CLI**.
@ -18,7 +18,7 @@ We support amd64, armv7 and arm64.
To run the ntfy server, then just run `ntfy serve` (or `systemctl start ntfy` when using the deb/rpm). To run the ntfy server, then just run `ntfy serve` (or `systemctl start ntfy` when using the deb/rpm).
To send messages, use `ntfy publish`. To subscribe to topics, use `ntfy subscribe` (see [subscribing via CLI](subscribe/cli.md) To send messages, use `ntfy publish`. To subscribe to topics, use `ntfy subscribe` (see [subscribing via CLI](subscribe/cli.md)
for details). for details).
## Linux binaries ## Linux binaries
Please check out the [releases page](https://github.com/binwiederhier/ntfy/releases) for binaries and Please check out the [releases page](https://github.com/binwiederhier/ntfy/releases) for binaries and
@ -69,7 +69,7 @@ Installation via Debian repository:
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
sudo apt install apt-transport-https sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main' \ sudo sh -c "echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main' \
> /etc/apt/sources.list.d/archive.heckel.io.list" > /etc/apt/sources.list.d/archive.heckel.io.list"
sudo apt update sudo apt update
sudo apt install ntfy sudo apt install ntfy
sudo systemctl enable ntfy sudo systemctl enable ntfy
@ -141,7 +141,7 @@ Manually installing the .deb file:
=== "x86_64/amd64" === "x86_64/amd64"
```bash ```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_linux_amd64.rpm sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_linux_amd64.rpm
sudo systemctl enable ntfy sudo systemctl enable ntfy
sudo systemctl start ntfy sudo systemctl start ntfy
``` ```
@ -155,14 +155,14 @@ Manually installing the .deb file:
=== "armv7/armhf" === "armv7/armhf"
```bash ```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_linux_armv7.rpm sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_linux_armv7.rpm
sudo systemctl enable ntfy sudo systemctl enable ntfy
sudo systemctl start ntfy sudo systemctl start ntfy
``` ```
=== "arm64" === "arm64"
```bash ```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_linux_arm64.rpm sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_linux_arm64.rpm
sudo systemctl enable ntfy sudo systemctl enable ntfy
sudo systemctl start ntfy sudo systemctl start ntfy
``` ```
@ -185,35 +185,35 @@ ntfy is packaged in nixpkgs as `ntfy-sh`. It can be installed by adding the pack
nix-env -iA ntfy-sh nix-env -iA ntfy-sh
``` ```
NixOS also supports [declarative setup of the ntfy server](https://search.nixos.org/options?channel=unstable&show=services.ntfy-sh.enable&from=0&size=50&sort=relevance&type=packages&query=ntfy). NixOS also supports [declarative setup of the ntfy server](https://search.nixos.org/options?channel=unstable&show=services.ntfy-sh.enable&from=0&size=50&sort=relevance&type=packages&query=ntfy).
## macOS ## macOS
The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on macOS as well. The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on macOS as well.
To install, please [download the tarball](https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_macOS_all.tar.gz), To install, please [download the tarball](https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_macOS_all.tar.gz),
extract it and place it somewhere in your `PATH` (e.g. `/usr/local/bin/ntfy`). extract it and place it somewhere in your `PATH` (e.g. `/usr/local/bin/ntfy`).
If run as `root`, ntfy will look for its config at `/etc/ntfy/client.yml`. For all other users, it'll look for it at If run as `root`, ntfy will look for its config at `/etc/ntfy/client.yml`. For all other users, it'll look for it at
`~/Library/Application Support/ntfy/client.yml` (sample included in the tarball). `~/Library/Application Support/ntfy/client.yml` (sample included in the tarball).
```bash ```bash
curl -L https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_macOS_all.tar.gz > ntfy_1.29.1_macOS_all.tar.gz curl -L https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_macOS_all.tar.gz > ntfy_1.29.1_macOS_all.tar.gz
tar zxvf ntfy_1.29.1_macOS_all.tar.gz tar zxvf ntfy_1.29.1_macOS_all.tar.gz
sudo cp -a ntfy_1.29.1_macOS_all/ntfy /usr/local/bin/ntfy sudo cp -a ntfy_1.29.1_macOS_all/ntfy /usr/local/bin/ntfy
mkdir ~/Library/Application\ Support/ntfy mkdir ~/Library/Application\ Support/ntfy
cp ntfy_1.29.1_macOS_all/client/client.yml ~/Library/Application\ Support/ntfy/client.yml cp ntfy_1.29.1_macOS_all/client/client.yml ~/Library/Application\ Support/ntfy/client.yml
ntfy --help ntfy --help
``` ```
!!! info !!! info
There is a [GitHub issue](https://github.com/binwiederhier/ntfy/issues/286) about making ntfy installable via There is a [GitHub issue](https://github.com/binwiederhier/ntfy/issues/286) about making ntfy installable via
[Homebrew](https://brew.sh/). I'll eventually get to that, but I'd also love if somebody else stepped up to do it. [Homebrew](https://brew.sh/). I'll eventually get to that, but I'd also love if somebody else stepped up to do it.
Also, you can build and run the ntfy server on macOS as well, though I don't officially support that. Also, you can build and run the ntfy server on macOS as well, though I don't officially support that.
Check out the [build instructions](develop.md) for details. Check out the [build instructions](develop.md) for details.
## Windows ## Windows
The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on Windows as well. The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on Windows as well.
To install, please [download the latest ZIP](https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_windows_x86_64.zip), To install, please [download the latest ZIP](https://github.com/binwiederhier/ntfy/releases/download/v1.29.1/ntfy_1.29.1_windows_x86_64.zip),
extract it and place the `ntfy.exe` binary somewhere in your `%Path%`. extract it and place the `ntfy.exe` binary somewhere in your `%Path%`.
The default path for the client config file is at `%AppData%\ntfy\client.yml` (not created automatically, sample in the ZIP file). The default path for the client config file is at `%AppData%\ntfy\client.yml` (not created automatically, sample in the ZIP file).
@ -226,15 +226,15 @@ Also available in [Scoop's](https://scoop.sh) Main repository:
[GitHub issue](https://github.com/binwiederhier/ntfy/issues) to let me know. [GitHub issue](https://github.com/binwiederhier/ntfy/issues) to let me know.
## Docker ## Docker
The [ntfy image](https://hub.docker.com/r/binwiederhier/ntfy) is available for amd64, armv6, armv7 and arm64. It should The [ntfy image](https://hub.docker.com/r/binwiederhier/ntfy) is available for amd64, armv6, armv7 and arm64. It should
be pretty straight forward to use. be pretty straight forward to use.
The server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent The server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent
[message cache](config.md#message-cache), you also need to map a volume to `/var/cache/ntfy`. To change other settings, [message cache](config.md#message-cache), you also need to map a volume to `/var/cache/ntfy`. To change other settings,
you should map `/etc/ntfy`, so you can edit `/etc/ntfy/server.yml`. you should map `/etc/ntfy`, so you can edit `/etc/ntfy/server.yml`.
!!! info !!! info
Note that the Docker image **does not contain a `/etc/ntfy/server.yml` file**. If you'd like to use a config file, Note that the Docker image **does not contain a `/etc/ntfy/server.yml` file**. If you'd like to use a config file,
please manually create one outside the image and map it as a volume, e.g. via `-v /etc/ntfy:/etc/ntfy`. You may please manually create one outside the image and map it as a volume, e.g. via `-v /etc/ntfy:/etc/ntfy`. You may
use the [`server.yml` file on GitHub](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml) as a template. use the [`server.yml` file on GitHub](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml) as a template.
@ -438,7 +438,7 @@ Configuration is relatively straightforward. As an example, a minimal configurat
=== "from-file" === "from-file"
```bash ```bash
kubectl create configmap ntfy --from-file=server.yml kubectl create configmap ntfy --from-file=server.yml
``` ```
## Kustomize ## Kustomize
@ -447,16 +447,16 @@ ntfy can be deployed in a Kubernetes cluster with [Kustomize](https://github.com
to customize Kubernetes objects using a `kustomization.yaml` file. to customize Kubernetes objects using a `kustomization.yaml` file.
1. Create new folder - `ntfy` 1. Create new folder - `ntfy`
2. Add all files listed below 2. Add all files listed below
1. `kustomization.yaml` - stores all configmaps and resources used in a deployment 1. `kustomization.yaml` - stores all configmaps and resources used in a deployment
2. `ntfy-deployment.yaml` - define deployment type and its parameters 2. `ntfy-deployment.yaml` - define deployment type and its parameters
3. `ntfy-pvc.yaml` - describes how [persistent volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) will be created 3. `ntfy-pvc.yaml` - describes how [persistent volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) will be created
4. `ntfy-svc.yaml` - expose application to the internal kubernetes network 4. `ntfy-svc.yaml` - expose application to the internal kubernetes network
5. `ntfy-ingress.yaml` - expose service to outside the network using [ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/) 5. `ntfy-ingress.yaml` - expose service to outside the network using [ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/)
6. `server.yaml` - simple server configuration 6. `server.yaml` - simple server configuration
3. Replace **TESTNAMESPACE** within `kustomization.yaml` with designated namespace 3. Replace **TESTNAMESPACE** within `kustomization.yaml` with designated namespace
4. Replace **ntfy.test** within `ntfy-ingress.yaml` with desired DNS name 4. Replace **ntfy.test** within `ntfy-ingress.yaml` with desired DNS name
5. Apply configuration to cluster set in current context: 5. Apply configuration to cluster set in current context:
```bash ```bash
kubectl apply -k /ntfy kubectl apply -k /ntfy
@ -473,9 +473,9 @@ kubectl apply -k /ntfy
- ntfy-ingress.yaml # ingress definition - ntfy-ingress.yaml # ingress definition
configMapGenerator: # will parse config from raw config to configmap,it allows for dynamic reload of application if additional app is deployed ie https://github.com/stakater/Reloader configMapGenerator: # will parse config from raw config to configmap,it allows for dynamic reload of application if additional app is deployed ie https://github.com/stakater/Reloader
- name: server-config - name: server-config
files: files:
- server.yml - server.yml
namespace: TESTNAMESPACE # select namespace for whole application namespace: TESTNAMESPACE # select namespace for whole application
``` ```
=== "ntfy-deployment.yaml" === "ntfy-deployment.yaml"
```yaml ```yaml
@ -497,7 +497,7 @@ kubectl apply -k /ntfy
app: ntfy-pod app: ntfy-pod
spec: spec:
containers: containers:
- name: ntfy - name: ntfy
image: binwiederhier/ntfy:v1.28.0 # set deployed version image: binwiederhier/ntfy:v1.28.0 # set deployed version
args: ["serve"] args: ["serve"]
env: #example of adjustments made in environmental variables env: #example of adjustments made in environmental variables
@ -508,8 +508,8 @@ kubectl apply -k /ntfy
- name: NTFY_LOG_LEVEL # adjust log level - name: NTFY_LOG_LEVEL # adjust log level
value: INFO value: INFO
- name: NTFY_BASE_URL # add base url - name: NTFY_BASE_URL # add base url
value: XXXXXXXXXX value: XXXXXXXXXX
ports: ports:
- containerPort: 80 - containerPort: 80
name: http-ntfy name: http-ntfy
resources: resources:
@ -533,7 +533,7 @@ kubectl apply -k /ntfy
persistentVolumeClaim: # stores /cache/ntfy in defined pv persistentVolumeClaim: # stores /cache/ntfy in defined pv
claimName: ntfy-pvc claimName: ntfy-pvc
``` ```
=== "ntfy-pvc.yaml" === "ntfy-pvc.yaml"
```yaml ```yaml
apiVersion: v1 apiVersion: v1
@ -554,7 +554,7 @@ kubectl apply -k /ntfy
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: ntfy-svc name: ntfy-svc
spec: spec:
type: ClusterIP type: ClusterIP
selector: selector:

View file

@ -6,7 +6,7 @@ I've added a ⭐ to projects or posts that have a significant following, or had
## Public ntfy servers ## Public ntfy servers
Here's a list of public ntfy servers. As of right now, there is only one official server. The others are provided by the Here's a list of public ntfy servers. As of right now, there is only one official server. The others are provided by the
ntfy community. Thanks to everyone running a public server. **You guys rock!** ntfy community. Thanks to everyone running a public server. **You guys rock!**
| URL | Country | | URL | Country |
@ -43,7 +43,7 @@ and uptime of third party servers, so use of each server is **at your own discre
- [FindMyDevice](https://gitlab.com/Nulide/findmydevice/) - Find your Device with an SMS or online with the help of FMDServer - [FindMyDevice](https://gitlab.com/Nulide/findmydevice/) - Find your Device with an SMS or online with the help of FMDServer
- [Tox Push Message App](https://github.com/zoff99/tox_push_msg_app) - Tox Push Message App - [Tox Push Message App](https://github.com/zoff99/tox_push_msg_app) - Tox Push Message App
## Libraries ## Libraries
- [ntfy-php-library](https://github.com/VerifiedJoseph/ntfy-php-library) - PHP library for sending messages using a ntfy server (PHP) - [ntfy-php-library](https://github.com/VerifiedJoseph/ntfy-php-library) - PHP library for sending messages using a ntfy server (PHP)
- [ntfy-notifier](https://github.com/DAcodedBEAT/ntfy-notifier) - Symfony Notifier integration for ntfy (PHP) - [ntfy-notifier](https://github.com/DAcodedBEAT/ntfy-notifier) - Symfony Notifier integration for ntfy (PHP)
@ -65,7 +65,7 @@ and uptime of third party servers, so use of each server is **at your own discre
- [ntfyr](https://github.com/haxwithaxe/ntfyr) - A simple commandline tool to send notifications to ntfy - [ntfyr](https://github.com/haxwithaxe/ntfyr) - A simple commandline tool to send notifications to ntfy
- [ntfy.py](https://github.com/ioqy/ntfy-client-python) - ntfy.py is a simple nfty.sh client for sending notifications - [ntfy.py](https://github.com/ioqy/ntfy-client-python) - ntfy.py is a simple nfty.sh client for sending notifications
## Projects + scripts ## Projects + scripts
- [Grafana-to-ntfy](https://github.com/kittyandrew/grafana-to-ntfy) - Grafana-to-ntfy alerts channel (Rust) - [Grafana-to-ntfy](https://github.com/kittyandrew/grafana-to-ntfy) - Grafana-to-ntfy alerts channel (Rust)
- [ntfy-long-zsh-command](https://github.com/robfox92/ntfy-long-zsh-command) - Notifies you once a long-running command completes (zsh) - [ntfy-long-zsh-command](https://github.com/robfox92/ntfy-long-zsh-command) - Notifies you once a long-running command completes (zsh)
@ -97,16 +97,16 @@ and uptime of third party servers, so use of each server is **at your own discre
- [ntfy-notification-channel](https://github.com/wijourdil/ntfy-notification-channel) - Laravel Notification channel for ntfy (PHP) - [ntfy-notification-channel](https://github.com/wijourdil/ntfy-notification-channel) - Laravel Notification channel for ntfy (PHP)
- [ntfy_on_a_chip](https://github.com/gergepalfi/ntfy_on_a_chip) - ESP8266 and ESP32 client code to communicate with ntfy - [ntfy_on_a_chip](https://github.com/gergepalfi/ntfy_on_a_chip) - ESP8266 and ESP32 client code to communicate with ntfy
- [ntfy-sdk](https://github.com/yukibtc/ntfy-sdk) - ntfy client library to send notifications (Rust) - [ntfy-sdk](https://github.com/yukibtc/ntfy-sdk) - ntfy client library to send notifications (Rust)
- [ntfy_ynh](https://github.com/YunoHost-Apps/ntfy_ynh) - ntfy app for YunoHost - [ntfy_ynh](https://github.com/YunoHost-Apps/ntfy_ynh) - ntfy app for YunoHost
- [drone-ntfy](https://github.com/Clortox/drone-ntfy) - Drone.io plugin for sending ntfy notifications from a pipeline - [drone-ntfy](https://github.com/Clortox/drone-ntfy) - Drone.io plugin for sending ntfy notifications from a pipeline
## Blog + forum posts ## Blog + forum posts
- [ntfy setup instructions](https://docs.benjamin-altpeter.de/network/vms/1001029-ntfy/) - benjamin-altpeter.de - 12/2022 - [ntfy setup instructions](https://docs.benjamin-altpeter.de/network/vms/1001029-ntfy/) - benjamin-altpeter.de - 12/2022
- [Ntfy Self-Hosted Push Notifications](https://lachlanlife.net/posts/2022-12-ntfy/) - lachlanlife.net - 12/2022 - [Ntfy Self-Hosted Push Notifications](https://lachlanlife.net/posts/2022-12-ntfy/) - lachlanlife.net - 12/2022
- [ntfy.sh](https://paramdeo.com/til/ntfy-sh) - paramdeo.com - 11/2022 - [ntfy.sh](https://paramdeo.com/til/ntfy-sh) - paramdeo.com - 11/2022
- [Using ntfy to warn me when my computer is discharging](https://ulysseszh.github.io/programming/2022/11/28/ntfy-warn-discharge.html) - ulysseszh.github.io - 11/2022 - [Using ntfy to warn me when my computer is discharging](https://ulysseszh.github.io/programming/2022/11/28/ntfy-warn-discharge.html) - ulysseszh.github.io - 11/2022
- [ntfy - Push Notification Service](https://dizzytech.de/posts/ntfy/) - dizzytech.de - 11/2022 - [ntfy - Push Notification Service](https://dizzytech.de/posts/ntfy/) - dizzytech.de - 11/2022
- [Console #132](https://console.substack.com/p/console-132) ⭐ - console.substack.com - 11/2022 - [Console #132](https://console.substack.com/p/console-132) ⭐ - console.substack.com - 11/2022
- [MeshCentral - Ntfy Push Notifications ](https://www.youtube.com/watch?v=wyE4rtUd4Bg) - youtube.com - 11/2022 - [MeshCentral - Ntfy Push Notifications ](https://www.youtube.com/watch?v=wyE4rtUd4Bg) - youtube.com - 11/2022
- [Changelog | Tracking layoffs, tech worker demand still high, ntfy, ...](https://changelog.com/news/tracking-layoffs-tech-worker-demand-still-high-ntfy-devenv-markdoc-mike-bifulco-Y1jW) ⭐ - changelog.com - 11/2022 - [Changelog | Tracking layoffs, tech worker demand still high, ntfy, ...](https://changelog.com/news/tracking-layoffs-tech-worker-demand-still-high-ntfy-devenv-markdoc-mike-bifulco-Y1jW) ⭐ - changelog.com - 11/2022
@ -118,11 +118,11 @@ and uptime of third party servers, so use of each server is **at your own discre
- [Ntfy et Jeedom : un plugin](https://lunarok-domotique.com/2022/11/ntfy-et-jeedom/) - lunarok-domotique.com - 11/2022 - [Ntfy et Jeedom : un plugin](https://lunarok-domotique.com/2022/11/ntfy-et-jeedom/) - lunarok-domotique.com - 11/2022
- [Crea tu propio servidor de notificaciones con Ntfy](https://blog.parravidales.es/crea-tu-propio-servidor-de-notificaciones-con-ntfy/) - blog.parravidales.es - 11/2022 - [Crea tu propio servidor de notificaciones con Ntfy](https://blog.parravidales.es/crea-tu-propio-servidor-de-notificaciones-con-ntfy/) - blog.parravidales.es - 11/2022
- [Zero-cost push notifications to your phone or desktop via PUT/POST ](https://lobste.rs/s/41dq13/zero_cost_push_notifications_your_phone) - lobste.rs - 10/2022 - [Zero-cost push notifications to your phone or desktop via PUT/POST ](https://lobste.rs/s/41dq13/zero_cost_push_notifications_your_phone) - lobste.rs - 10/2022
- [A nifty push notification system: ntfy](https://jpmens.net/2022/10/30/a-nifty-push-notification-system-ntfy/) - jpmens.net - 10/2022 - [A nifty push notification system: ntfy](https://jpmens.net/2022/10/30/a-nifty-push-notification-system-ntfy/) - jpmens.net - 10/2022
- [Alarmanlage der dritten Art (YouTube video)](https://www.youtube.com/watch?v=altb5QLHbaU&feature=youtu.be) - youtube.com - 10/2022 - [Alarmanlage der dritten Art (YouTube video)](https://www.youtube.com/watch?v=altb5QLHbaU&feature=youtu.be) - youtube.com - 10/2022
- [Neue Services: Ntfy, TikTok und RustDesk](https://adminforge.de/tools/neue-services-ntfy-tiktok-und-rustdesk/) - adminforge.de - 9/2022 - [Neue Services: Ntfy, TikTok und RustDesk](https://adminforge.de/tools/neue-services-ntfy-tiktok-und-rustdesk/) - adminforge.de - 9/2022
- [Ntfy, le service de notifications quil vous faut](https://www.cachem.fr/ntfy-le-service-de-notifications-quil-vous-faut/) - cachem.fr - 9/2022 - [Ntfy, le service de notifications quil vous faut](https://www.cachem.fr/ntfy-le-service-de-notifications-quil-vous-faut/) - cachem.fr - 9/2022
- [NAS Synology et notifications avec ntfy](https://www.cachem.fr/synology-notifications-ntfy/) - cachem.fr - 9/2022 - [NAS Synology et notifications avec ntfy](https://www.cachem.fr/synology-notifications-ntfy/) - cachem.fr - 9/2022
- [Self hosted Mobile Push Notifications using NTFY | Thejesh GN](https://thejeshgn.com/2022/08/23/self-hosted-mobile-push-notifications-using-ntfy/) - thejeshgn.com - 8/2022 - [Self hosted Mobile Push Notifications using NTFY | Thejesh GN](https://thejeshgn.com/2022/08/23/self-hosted-mobile-push-notifications-using-ntfy/) - thejeshgn.com - 8/2022
- [Fedora Magazine | 4 cool new projects to try in Copr](https://fedoramagazine.org/4-cool-new-projects-to-try-in-copr-for-august-2022/) - fedoramagazine.org - 8/2022 - [Fedora Magazine | 4 cool new projects to try in Copr](https://fedoramagazine.org/4-cool-new-projects-to-try-in-copr-for-august-2022/) - fedoramagazine.org - 8/2022
- [Docker로 오픈소스 푸시알람 프로젝트 ntfy.sh 설치 및 사용하기.(Feat. Uptimekuma)](https://svrforum.com/svr/398979) - svrforum.com - 8/2022 - [Docker로 오픈소스 푸시알람 프로젝트 ntfy.sh 설치 및 사용하기.(Feat. Uptimekuma)](https://svrforum.com/svr/398979) - svrforum.com - 8/2022
@ -131,7 +131,7 @@ and uptime of third party servers, so use of each server is **at your own discre
- [Install guide (with Docker)](https://chowdera.com/2022/150/202205301257379077.html) - chowdera.com - 5/2022 - [Install guide (with Docker)](https://chowdera.com/2022/150/202205301257379077.html) - chowdera.com - 5/2022
- [无需注册的通知服务ntfy](https://blog.csdn.net/wbsu2004/article/details/125040247) - blog.csdn.net - 5/2022 - [无需注册的通知服务ntfy](https://blog.csdn.net/wbsu2004/article/details/125040247) - blog.csdn.net - 5/2022
- [Updated review post (Jan-Lukas Else)](https://jlelse.blog/thoughts/2022/04/ntfy) - jlelse.blog - 4/2022 - [Updated review post (Jan-Lukas Else)](https://jlelse.blog/thoughts/2022/04/ntfy) - jlelse.blog - 4/2022
- [Using ntfy and Tasker together](https://lachlanlife.net/posts/2022-04-tasker-ntfy/) - lachlanlife.net - 4/2022 - [Using ntfy and Tasker together](https://lachlanlife.net/posts/2022-04-tasker-ntfy/) - lachlanlife.net - 4/2022
- [Reddit feature update post](https://www.reddit.com/r/selfhosted/comments/uetlso/ntfy_is_a_tool_to_send_push_notifications_to_your/) ⭐ - reddit.com - 4/2022 - [Reddit feature update post](https://www.reddit.com/r/selfhosted/comments/uetlso/ntfy_is_a_tool_to_send_push_notifications_to_your/) ⭐ - reddit.com - 4/2022
- [無料で簡単に通知の送受信ができつつオープンソースでセルフホストも可能な「ntfy」を使ってみた](https://gigazine.net/news/20220404-ntfy-push-notification/) - gigazine.net - 4/2022 - [無料で簡単に通知の送受信ができつつオープンソースでセルフホストも可能な「ntfy」を使ってみた](https://gigazine.net/news/20220404-ntfy-push-notification/) - gigazine.net - 4/2022
- [Pocketmags ntfy review](https://pocketmags.com/us/linux-format-magazine/march-2022/articles/1104187/ntfy) - pocketmags.com - 3/2022 - [Pocketmags ntfy review](https://pocketmags.com/us/linux-format-magazine/march-2022/articles/1104187/ntfy) - pocketmags.com - 3/2022

View file

@ -15,14 +15,14 @@ Please send experienced iOS developers my way to help me figure this out.
## iOS app not receiving notifications (anymore) ## iOS app not receiving notifications (anymore)
If notifications do not show up at all anymore, there are a few causes for it (that I know of): If notifications do not show up at all anymore, there are a few causes for it (that I know of):
**Firebase+APNS are being weird and buggy**: **Firebase+APNS are being weird and buggy**:
If this is the case, usually it helps to **remove the topic/subscription and re-add it**. That will force Firebase to If this is the case, usually it helps to **remove the topic/subscription and re-add it**. That will force Firebase to
re-subscribe to the Firebase topic. re-subscribe to the Firebase topic.
**Self-hosted only: No `upstream-base-url` set, or `base-url` mismatch**: **Self-hosted only: No `upstream-base-url` set, or `base-url` mismatch**:
To make self-hosted servers work with the iOS To make self-hosted servers work with the iOS
app, I had to do some horrible things (see [iOS instant notifications](config.md#ios-instant-notifications) for details). app, I had to do some horrible things (see [iOS instant notifications](config.md#ios-instant-notifications) for details).
Be sure that in your selfhosted server: Be sure that in your selfhosted server:
* Set `upstream-base-url: "https://ntfy.sh"` (**not your own hostname!**) * Set `upstream-base-url: "https://ntfy.sh"` (**not your own hostname!**)
* Ensure that the URL you set in `base-url` **matches exactly** what you set the Default Server in iOS to * Ensure that the URL you set in `base-url` **matches exactly** what you set the Default Server in iOS to

View file

@ -8,5 +8,5 @@ any outside service. All data is exclusively used to make the service function p
I use is Firebase Cloud Messaging (FCM) service, which is required to provide instant Android notifications (see I use is Firebase Cloud Messaging (FCM) service, which is required to provide instant Android notifications (see
[FAQ](faq.md) for details). To avoid FCM altogether, download the F-Droid version. [FAQ](faq.md) for details). To avoid FCM altogether, download the F-Droid version.
For debugging purposes, the ntfy server may temporarily log request paths, remote IP addresses or even topics For debugging purposes, the ntfy server may temporarily log request paths, remote IP addresses or even topics
or messages, though typically this is turned off. or messages, though typically this is turned off.

View file

@ -1,6 +1,6 @@
# Publishing # Publishing
Publishing messages can be done via HTTP PUT/POST or via the [ntfy CLI](install.md). Topics are created on the fly by Publishing messages can be done via HTTP PUT/POST or via the [ntfy CLI](install.md). Topics are created on the fly by
subscribing or publishing to them. Because there is no sign-up, **the topic is essentially a password**, so pick subscribing or publishing to them. Because there is no sign-up, **the topic is essentially a password**, so pick
something that's not easily guessable. something that's not easily guessable.
Here's an example showing how to publish a simple message using a POST request: Here's an example showing how to publish a simple message using a POST request:
@ -43,7 +43,7 @@ Here's an example showing how to publish a simple message using a POST request:
=== "Python" === "Python"
``` python ``` python
requests.post("https://ntfy.sh/mytopic", requests.post("https://ntfy.sh/mytopic",
data="Backup successful 😀".encode(encoding='utf-8')) data="Backup successful 😀".encode(encoding='utf-8'))
``` ```
@ -65,7 +65,7 @@ If you have the [Android app](subscribe/phone.md) installed on your phone, this
<figcaption>Android notification</figcaption> <figcaption>Android notification</figcaption>
</figure> </figure>
There are more features related to publishing messages: You can set a [notification priority](#message-priority), There are more features related to publishing messages: You can set a [notification priority](#message-priority),
a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an example that uses some of them at together: a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an example that uses some of them at together:
=== "Command line (curl)" === "Command line (curl)"
@ -95,7 +95,7 @@ a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an
Title: Unauthorized access detected Title: Unauthorized access detected
Priority: urgent Priority: urgent
Tags: warning,skull Tags: warning,skull
Remote access to phils-laptop detected. Act right away. Remote access to phils-laptop detected. Act right away.
``` ```
@ -128,10 +128,10 @@ a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an
$headers = @{ Title="Unauthorized access detected" $headers = @{ Title="Unauthorized access detected"
Priority="urgent" Priority="urgent"
Tags="warning,skull" } Tags="warning,skull" }
$body = "Remote access to phils-laptop detected. Act right away." $body = "Remote access to phils-laptop detected. Act right away."
Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body $body -UseBasicParsing Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body $body -UseBasicParsing
``` ```
=== "Python" === "Python"
``` python ``` python
requests.post("https://ntfy.sh/phil_alerts", requests.post("https://ntfy.sh/phil_alerts",
@ -174,8 +174,8 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
-H "Actions: http, Open door, https://api.nest.com/open/yAxkasd, clear=true" \ -H "Actions: http, Open door, https://api.nest.com/open/yAxkasd, clear=true" \
-H "Email: phil@example.com" \ -H "Email: phil@example.com" \
-d "There's someone at the door. 🐶 -d "There's someone at the door. 🐶
Please check if it's a good boy or a hooman. Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell." \ Doggies have been known to ring the doorbell." \
ntfy.sh/mydoorbell ntfy.sh/mydoorbell
``` ```
@ -189,8 +189,8 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
--email="phil@example.com" \ --email="phil@example.com" \
mydoorbell \ mydoorbell \
"There's someone at the door. 🐶 "There's someone at the door. 🐶
Please check if it's a good boy or a hooman. Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell." Doggies have been known to ring the doorbell."
``` ```
@ -202,13 +202,13 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
Attach: https://nest.com/view/yAxkasd.jpg Attach: https://nest.com/view/yAxkasd.jpg
Actions: http, Open door, https://api.nest.com/open/yAxkasd, clear=true Actions: http, Open door, https://api.nest.com/open/yAxkasd, clear=true
Email: phil@example.com Email: phil@example.com
There's someone at the door. 🐶 There's someone at the door. 🐶
Please check if it's a good boy or a hooman. Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell. Doggies have been known to ring the doorbell.
``` ```
=== "JavaScript" === "JavaScript"
``` javascript ``` javascript
fetch('https://ntfy.sh/mydoorbell', { fetch('https://ntfy.sh/mydoorbell', {
@ -220,8 +220,8 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
'Email': 'phil@example.com' 'Email': 'phil@example.com'
}, },
body: `There's someone at the door. 🐶 body: `There's someone at the door. 🐶
Please check if it's a good boy or a hooman. Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell.`, Doggies have been known to ring the doorbell.`,
}) })
``` ```
@ -230,8 +230,8 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
``` go ``` go
req, _ := http.NewRequest("POST", "https://ntfy.sh/mydoorbell", req, _ := http.NewRequest("POST", "https://ntfy.sh/mydoorbell",
strings.NewReader(`There's someone at the door. 🐶 strings.NewReader(`There's someone at the door. 🐶
Please check if it's a good boy or a hooman. Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell.`)) Doggies have been known to ring the doorbell.`))
req.Header.Set("Click", "https://home.nest.com/") req.Header.Set("Click", "https://home.nest.com/")
req.Header.Set("Attach", "https://nest.com/view/yAxkasd.jpg") req.Header.Set("Attach", "https://nest.com/view/yAxkasd.jpg")
@ -249,7 +249,7 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
Email="phil@example.com" } Email="phil@example.com" }
$body = @' $body = @'
There's someone at the door. 🐶 There's someone at the door. 🐶
Please check if it's a good boy or a hooman. Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell. Doggies have been known to ring the doorbell.
'@ '@
@ -283,7 +283,7 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
"Actions": "http, Open door, https://api.nest.com/open/yAxkasd, clear=true\r\n" . "Actions": "http, Open door, https://api.nest.com/open/yAxkasd, clear=true\r\n" .
"Email": "phil@example.com\r\n", "Email": "phil@example.com\r\n",
'content' => 'There\'s someone at the door. 🐶 'content' => 'There\'s someone at the door. 🐶
Please check if it\'s a good boy or a hooman. Please check if it\'s a good boy or a hooman.
Doggies have been known to ring the doorbell.' Doggies have been known to ring the doorbell.'
] ]
@ -298,7 +298,7 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
## Message title ## Message title
_Supported on:_ :material-android: :material-apple: :material-firefox: _Supported on:_ :material-android: :material-apple: :material-firefox:
The notification title is typically set to the topic short URL (e.g. `ntfy.sh/mytopic`). To override the title, The notification title is typically set to the topic short URL (e.g. `ntfy.sh/mytopic`). To override the title,
you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`). you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
=== "Command line (curl)" === "Command line (curl)"
@ -320,7 +320,7 @@ you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
POST /controversial HTTP/1.1 POST /controversial HTTP/1.1
Host: ntfy.sh Host: ntfy.sh
Title: Dogs are better than cats Title: Dogs are better than cats
Oh my ... Oh my ...
``` ```
@ -400,7 +400,7 @@ You can set the priority with the header `X-Priority` (or any of its aliases: `P
=== "ntfy CLI" === "ntfy CLI"
``` ```
ntfy publish \ ntfy publish \
-p 5 \ -p 5 \
phil_alerts An urgent message phil_alerts An urgent message
``` ```
@ -437,7 +437,7 @@ You can set the priority with the header `X-Priority` (or any of its aliases: `P
$body = "An urgent message" $body = "An urgent message"
Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body $body -UseBasicParsing Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body $body -UseBasicParsing
``` ```
=== "Python" === "Python"
``` python ``` python
requests.post("https://ntfy.sh/phil_alerts", requests.post("https://ntfy.sh/phil_alerts",
@ -468,12 +468,12 @@ _Supported on:_ :material-android: :material-apple: :material-firefox:
You can tag messages with emojis and other relevant strings: You can tag messages with emojis and other relevant strings:
* **Emojis**: If a tag matches an [emoji short code](emojis.md), it'll be converted to an emoji and prepended * **Emojis**: If a tag matches an [emoji short code](emojis.md), it'll be converted to an emoji and prepended
to title or message. to title or message.
* **Other tags:** If a tag doesn't match, it will be listed below the notification. * **Other tags:** If a tag doesn't match, it will be listed below the notification.
This feature is useful for things like warnings (⚠️, ️🚨, or 🚩), but also to simply tag messages otherwise (e.g. script This feature is useful for things like warnings (⚠️, ️🚨, or 🚩), but also to simply tag messages otherwise (e.g. script
names, hostnames, etc.). Use [the emoji short code list](emojis.md) to figure out what tags can be converted to emojis. names, hostnames, etc.). Use [the emoji short code list](emojis.md) to figure out what tags can be converted to emojis.
Here's an **excerpt of emojis** I've found very useful in alert messages: Here's an **excerpt of emojis** I've found very useful in alert messages:
<table class="remove-md-box"><tr> <table class="remove-md-box"><tr>
@ -488,7 +488,7 @@ Here's an **excerpt of emojis** I've found very useful in alert messages:
</tbody></table> </tbody></table>
</td> </td>
<td> <td>
<table><thead><tr><th>Tag</th><th>Emoji</th></tr></thead><tbody> <table><thead><tr><th>Tag</th><th>Emoji</th></tr></thead><tbody>
<tr><td><code>-1</code></td><td>👎️</td></tr> <tr><td><code>-1</code></td><td>👎️</td></tr>
<tr><td><code>warning</code></td><td>⚠️</td></tr> <tr><td><code>warning</code></td><td>⚠️</td></tr>
<tr><td><code>rotating_light</code></td><td>️🚨</td></tr> <tr><td><code>rotating_light</code></td><td>️🚨</td></tr>
@ -502,7 +502,7 @@ Here's an **excerpt of emojis** I've found very useful in alert messages:
<tr><td><code>facepalm</code></td><td>🤦</td></tr> <tr><td><code>facepalm</code></td><td>🤦</td></tr>
<tr><td><code>no_entry</code></td><td></td></tr> <tr><td><code>no_entry</code></td><td></td></tr>
<tr><td><code>no_entry_sign</code></td><td>🚫</td></tr> <tr><td><code>no_entry_sign</code></td><td>🚫</td></tr>
<tr><td><code>cd</code></td><td>💿</td></tr> <tr><td><code>cd</code></td><td>💿</td></tr>
<tr><td><code>computer</code></td><td>💻</td></tr> <tr><td><code>computer</code></td><td>💻</td></tr>
<tr><td>...</td><td>...</td></tr> <tr><td>...</td><td>...</td></tr>
</tbody></table> </tbody></table>
@ -531,7 +531,7 @@ them with a comma, e.g. `tag1,tag2,tag3`.
POST /backups HTTP/1.1 POST /backups HTTP/1.1
Host: ntfy.sh Host: ntfy.sh
Tags: warning,mailsrv13,daily-backup Tags: warning,mailsrv13,daily-backup
Backup of mailsrv13 failed Backup of mailsrv13 failed
``` ```
@ -587,22 +587,22 @@ them with a comma, e.g. `tag1,tag2,tag3`.
## Scheduled delivery ## Scheduled delivery
_Supported on:_ :material-android: :material-apple: :material-firefox: _Supported on:_ :material-android: :material-apple: :material-firefox:
You can delay the delivery of messages and let ntfy send them at a later date. This can be used to send yourself You can delay the delivery of messages and let ntfy send them at a later date. This can be used to send yourself
reminders or even to execute commands at a later date (if your subscriber acts on messages). reminders or even to execute commands at a later date (if your subscriber acts on messages).
Usage is pretty straight forward. You can set the delivery time using the `X-Delay` header (or any of its aliases: `Delay`, Usage is pretty straight forward. You can set the delivery time using the `X-Delay` header (or any of its aliases: `Delay`,
`X-At`, `At`, `X-In` or `In`), either by specifying a Unix timestamp (e.g. `1639194738`), a duration (e.g. `30m`, `X-At`, `At`, `X-In` or `In`), either by specifying a Unix timestamp (e.g. `1639194738`), a duration (e.g. `30m`,
`3h`, `2 days`), or a natural language time string (e.g. `10am`, `8:30pm`, `tomorrow, 3pm`, `Tuesday, 7am`, `3h`, `2 days`), or a natural language time string (e.g. `10am`, `8:30pm`, `tomorrow, 3pm`, `Tuesday, 7am`,
[and more](https://github.com/olebedev/when)). [and more](https://github.com/olebedev/when)).
As of today, the minimum delay you can set is **10 seconds** and the maximum delay is **3 days**. This can currently As of today, the minimum delay you can set is **10 seconds** and the maximum delay is **3 days**. This can currently
not be configured otherwise ([let me know](https://github.com/binwiederhier/ntfy/issues) if you'd like to change not be configured otherwise ([let me know](https://github.com/binwiederhier/ntfy/issues) if you'd like to change
these limits). these limits).
For the purposes of [message caching](config.md#message-cache), scheduled messages are kept in the cache until 12 hours For the purposes of [message caching](config.md#message-cache), scheduled messages are kept in the cache until 12 hours
after they were delivered (or whatever the server-side cache duration is set to). For instance, if a message is scheduled after they were delivered (or whatever the server-side cache duration is set to). For instance, if a message is scheduled
to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Also note that naturally, to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Also note that naturally,
[turning off server-side caching](#message-caching) is not possible in combination with this feature. [turning off server-side caching](#message-caching) is not possible in combination with this feature.
=== "Command line (curl)" === "Command line (curl)"
``` ```
@ -650,7 +650,7 @@ to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Al
$body = "Good morning" $body = "Good morning"
Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body $body -UseBasicParsing Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body $body -UseBasicParsing
``` ```
=== "Python" === "Python"
``` python ``` python
requests.post("https://ntfy.sh/hello", requests.post("https://ntfy.sh/hello",
@ -686,19 +686,19 @@ Here are a few examples (assuming today's date is **12/10/2021, 9am, Eastern Tim
</td> </td>
</tr></table> </tr></table>
## Webhooks (publish via GET) ## Webhooks (publish via GET)
_Supported on:_ :material-android: :material-apple: :material-firefox: _Supported on:_ :material-android: :material-apple: :material-firefox:
In addition to using PUT/POST, you can also send to topics via simple HTTP GET requests. This makes it easy to use In addition to using PUT/POST, you can also send to topics via simple HTTP GET requests. This makes it easy to use
a ntfy topic as a [webhook](https://en.wikipedia.org/wiki/Webhook), or if your client has limited HTTP support (e.g. a ntfy topic as a [webhook](https://en.wikipedia.org/wiki/Webhook), or if your client has limited HTTP support (e.g.
like the [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid) Android app). like the [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid) Android app).
To send messages via HTTP GET, simply call the `/publish` endpoint (or its aliases `/send` and `/trigger`). Without To send messages via HTTP GET, simply call the `/publish` endpoint (or its aliases `/send` and `/trigger`). Without
any arguments, this will send the message `triggered` to the topic. However, you can provide all arguments that are any arguments, this will send the message `triggered` to the topic. However, you can provide all arguments that are
also supported as HTTP headers as URL-encoded arguments. Be sure to check the list of all also supported as HTTP headers as URL-encoded arguments. Be sure to check the list of all
[supported parameters and headers](#list-of-all-parameters) for details. [supported parameters and headers](#list-of-all-parameters) for details.
For instance, assuming your topic is `mywebhook`, you can simply call `/mywebhook/trigger` to send a message For instance, assuming your topic is `mywebhook`, you can simply call `/mywebhook/trigger` to send a message
(aka trigger the webhook): (aka trigger the webhook):
=== "Command line (curl)" === "Command line (curl)"
@ -730,7 +730,7 @@ For instance, assuming your topic is `mywebhook`, you can simply call `/mywebhoo
=== "PowerShell" === "PowerShell"
``` powershell ``` powershell
Invoke-RestMethod -Method 'Get' -Uri "ntfy.sh/mywebhook/trigger" Invoke-RestMethod -Method 'Get' -Uri "ntfy.sh/mywebhook/trigger"
``` ```
=== "Python" === "Python"
``` python ``` python
@ -742,8 +742,8 @@ For instance, assuming your topic is `mywebhook`, you can simply call `/mywebhoo
file_get_contents('https://ntfy.sh/mywebhook/trigger'); file_get_contents('https://ntfy.sh/mywebhook/trigger');
``` ```
To add a custom message, simply append the `message=` URL parameter. And of course you can set the To add a custom message, simply append the `message=` URL parameter. And of course you can set the
[message priority](#message-priority), the [message title](#message-title), and [tags](#tags-emojis) as well. [message priority](#message-priority), the [message title](#message-title), and [tags](#tags-emojis) as well.
For a full list of possible parameters, check the list of [supported parameters and headers](#list-of-all-parameters). For a full list of possible parameters, check the list of [supported parameters and headers](#list-of-all-parameters).
Here's an example with a custom message, tags and a priority: Here's an example with a custom message, tags and a priority:
@ -794,8 +794,8 @@ Here's an example with a custom message, tags and a priority:
## Publish as JSON ## Publish as JSON
_Supported on:_ :material-android: :material-apple: :material-firefox: _Supported on:_ :material-android: :material-apple: :material-firefox:
For some integrations with other tools (e.g. [Jellyfin](https://jellyfin.org/), [overseerr](https://overseerr.dev/)), For some integrations with other tools (e.g. [Jellyfin](https://jellyfin.org/), [overseerr](https://overseerr.dev/)),
adding custom headers to HTTP requests may be tricky or impossible, so ntfy also allows publishing the entire message adding custom headers to HTTP requests may be tricky or impossible, so ntfy also allows publishing the entire message
as JSON in the request body. as JSON in the request body.
To publish as JSON, simple PUT/POST the JSON object directly to the ntfy root URL. The message format is described below To publish as JSON, simple PUT/POST the JSON object directly to the ntfy root URL. The message format is described below
@ -803,9 +803,9 @@ the example.
!!! info !!! info
To publish as JSON, you must **PUT/POST to the ntfy root URL**, not to the topic URL. Be sure to check that you're To publish as JSON, you must **PUT/POST to the ntfy root URL**, not to the topic URL. Be sure to check that you're
POST-ing to `https://ntfy.sh/` (correct), and not to `https://ntfy.sh/mytopic` (incorrect). POST-ing to `https://ntfy.sh/` (correct), and not to `https://ntfy.sh/mytopic` (incorrect).
Here's an example using most supported parameters. Check the table below for a complete list. The `topic` parameter Here's an example using most supported parameters. Check the table below for a complete list. The `topic` parameter
is the only required one: is the only required one:
=== "Command line (curl)" === "Command line (curl)"
@ -863,9 +863,9 @@ is the only required one:
=== "Go" === "Go"
``` go ``` go
// You should probably use json.Marshal() instead and make a proper struct, // You should probably use json.Marshal() instead and make a proper struct,
// or even just use req.Header.Set() like in the other examples, but for the // or even just use req.Header.Set() like in the other examples, but for the
// sake of the example, this is easier. // sake of the example, this is easier.
body := `{ body := `{
"topic": "mytopic", "topic": "mytopic",
"message": "Disk space is low at 5.1 GB", "message": "Disk space is low at 5.1 GB",
@ -894,7 +894,7 @@ is the only required one:
tags = @("warning", "cd") tags = @("warning", "cd")
click = "https://homecamera.lan/xasds1h2xsSsa/" click = "https://homecamera.lan/xasds1h2xsSsa/"
actions = @( actions = @(
@{ @{
action = "view" action = "view"
label = "Admin panel" label = "Admin panel"
url = "https://filesrv.lan/admin" url = "https://filesrv.lan/admin"
@ -942,7 +942,7 @@ is the only required one:
])); ]));
``` ```
The JSON message format closely mirrors the format of the message you can consume when you [subscribe via the API](subscribe/api.md) The JSON message format closely mirrors the format of the message you can consume when you [subscribe via the API](subscribe/api.md)
(see [JSON message format](subscribe/api.md#json-message-format) for details), but is not exactly identical. Here's an overview of (see [JSON message format](subscribe/api.md#json-message-format) for details), but is not exactly identical. Here's an overview of
all the supported fields: all the supported fields:
@ -964,9 +964,9 @@ all the supported fields:
_Supported on:_ :material-android: :material-apple: :material-firefox: _Supported on:_ :material-android: :material-apple: :material-firefox:
You can add action buttons to notifications to allow yourself to react to a notification directly. This is incredibly You can add action buttons to notifications to allow yourself to react to a notification directly. This is incredibly
useful and has countless applications. useful and has countless applications.
You can control your home appliances (open/close garage door, change temperature on thermostat, ...), react to common You can control your home appliances (open/close garage door, change temperature on thermostat, ...), react to common
monitoring alerts (clear logs when disk is full, ...), and many other things. The sky is the limit. monitoring alerts (clear logs when disk is full, ...), and many other things. The sky is the limit.
As of today, the following actions are supported: As of today, the following actions are supported:
@ -987,7 +987,7 @@ Here's an example of what that a notification with actions can look like:
You can define **up to three user actions** in your notifications, using either of the following methods: You can define **up to three user actions** in your notifications, using either of the following methods:
* In the [`X-Actions` header](#using-a-header), using a simple comma-separated format * In the [`X-Actions` header](#using-a-header), using a simple comma-separated format
* As a [JSON array](#using-a-json-array) in the `actions` key, when [publishing as JSON](#publish-as-json) * As a [JSON array](#using-a-json-array) in the `actions` key, when [publishing as JSON](#publish-as-json)
#### Using a header #### Using a header
To define actions using the `X-Actions` header (or any of its aliases: `Actions`, `Action`), use the following format: To define actions using the `X-Actions` header (or any of its aliases: `Actions`, `Action`), use the following format:
@ -1002,14 +1002,14 @@ To define actions using the `X-Actions` header (or any of its aliases: `Actions`
<action1>, <label1>, paramN=... [; <action2>, <label2>, ...] <action1>, <label1>, paramN=... [; <action2>, <label2>, ...]
``` ```
Multiple actions are separated by a semicolon (`;`), and key/value pairs are separated by commas (`,`). Values may be Multiple actions are separated by a semicolon (`;`), and key/value pairs are separated by commas (`,`). Values may be
quoted with double quotes (`"`) or single quotes (`'`) if the value itself contains commas or semicolons. quoted with double quotes (`"`) or single quotes (`'`) if the value itself contains commas or semicolons.
The `action=` and `label=` prefix are optional in all actions, and the `url=` prefix is optional in the `view` and The `action=` and `label=` prefix are optional in all actions, and the `url=` prefix is optional in the `view` and
`http` action. The only limitation of this format is that depending on your language/library, UTF-8 characters may not `http` action. The only limitation of this format is that depending on your language/library, UTF-8 characters may not
work. If they don't, use the [JSON array format](#using-a-json-array) instead. work. If they don't, use the [JSON array format](#using-a-json-array) instead.
As an example, here's how you can create the above notification using this format. Refer to the [`view` action](#open-websiteapp) and As an example, here's how you can create the above notification using this format. Refer to the [`view` action](#open-websiteapp) and
[`http` action](#send-http-request) section for details on the specific actions: [`http` action](#send-http-request) section for details on the specific actions:
=== "Command line (curl)" === "Command line (curl)"
@ -1046,8 +1046,8 @@ As an example, here's how you can create the above notification using this forma
fetch('https://ntfy.sh/myhome', { fetch('https://ntfy.sh/myhome', {
method: 'POST', method: 'POST',
body: 'You left the house. Turn down the A/C?', body: 'You left the house. Turn down the A/C?',
headers: { headers: {
'Actions': 'view, Open portal, https://home.nest.com/, clear=true; http, Turn down, https://api.nest.com/, body=\'{"temperature": 65}\'' 'Actions': 'view, Open portal, https://home.nest.com/, clear=true; http, Turn down, https://api.nest.com/, body=\'{"temperature": 65}\''
} }
}) })
``` ```
@ -1086,9 +1086,9 @@ As an example, here's how you can create the above notification using this forma
] ]
])); ]));
``` ```
#### Using a JSON array #### Using a JSON array
Alternatively, the same actions can be defined as **JSON array**, if the notification is defined as part of the JSON body Alternatively, the same actions can be defined as **JSON array**, if the notification is defined as part of the JSON body
(see [publish as JSON](#publish-as-json)): (see [publish as JSON](#publish-as-json)):
=== "Command line (curl)" === "Command line (curl)"
@ -1189,7 +1189,7 @@ Alternatively, the same actions can be defined as **JSON array**, if the notific
``` go ``` go
// You should probably use json.Marshal() instead and make a proper struct, // You should probably use json.Marshal() instead and make a proper struct,
// but for the sake of the example, this is easier. // but for the sake of the example, this is easier.
body := `{ body := `{
"topic": "myhome", "topic": "myhome",
"message": "You left the house. Turn down the A/C?", "message": "You left the house. Turn down the A/C?",
@ -1291,16 +1291,16 @@ Alternatively, the same actions can be defined as **JSON array**, if the notific
])); ]));
``` ```
The required/optional fields for each action depend on the type of the action itself. Please refer to The required/optional fields for each action depend on the type of the action itself. Please refer to
[`view` action](#open-websiteapp), [`broadcasst` action](#send-android-broadcast), and [`http` action](#send-http-request) [`view` action](#open-websiteapp), [`broadcasst` action](#send-android-broadcast), and [`http` action](#send-http-request)
for details. for details.
### Open website/app ### Open website/app
_Supported on:_ :material-android: :material-apple: :material-firefox: _Supported on:_ :material-android: :material-apple: :material-firefox:
The `view` action **opens a website or app when the action button is tapped**, e.g. a browser, a Google Maps location, or The `view` action **opens a website or app when the action button is tapped**, e.g. a browser, a Google Maps location, or
even a deep link into Twitter or a show ntfy topic. How exactly the action is handled depends on how Android and your even a deep link into Twitter or a show ntfy topic. How exactly the action is handled depends on how Android and your
desktop browser treat the links. Normally it'll just open a link in the browser. desktop browser treat the links. Normally it'll just open a link in the browser.
Examples: Examples:
@ -1343,8 +1343,8 @@ Here's an example using the [`X-Actions` header](#using-a-header):
fetch('https://ntfy.sh/myhome', { fetch('https://ntfy.sh/myhome', {
method: 'POST', method: 'POST',
body: 'Somebody retweeted your tweet.', body: 'Somebody retweeted your tweet.',
headers: { headers: {
'Actions': 'view, Open Twitter, https://twitter.com/binwiederhier/status/1467633927951163392' 'Actions': 'view, Open Twitter, https://twitter.com/binwiederhier/status/1467633927951163392'
} }
}) })
``` ```
@ -1456,7 +1456,7 @@ And the same example using [JSON publishing](#publish-as-json):
``` go ``` go
// You should probably use json.Marshal() instead and make a proper struct, // You should probably use json.Marshal() instead and make a proper struct,
// but for the sake of the example, this is easier. // but for the sake of the example, this is easier.
body := `{ body := `{
"topic": "myhome", "topic": "myhome",
"message": "Somebody retweeted your tweet.", "message": "Somebody retweeted your tweet.",
@ -1585,8 +1585,8 @@ Here's an example using the [`X-Actions` header](#using-a-header):
fetch('https://ntfy.sh/wifey', { fetch('https://ntfy.sh/wifey', {
method: 'POST', method: 'POST',
body: 'Your wife requested you send a picture of yourself.', body: 'Your wife requested you send a picture of yourself.',
headers: { headers: {
'Actions': 'broadcast, Take picture, extras.cmd=pic, extras.camera=front' 'Actions': 'broadcast, Take picture, extras.cmd=pic, extras.camera=front'
} }
}) })
``` ```
@ -1710,7 +1710,7 @@ And the same example using [JSON publishing](#publish-as-json):
``` go ``` go
// You should probably use json.Marshal() instead and make a proper struct, // You should probably use json.Marshal() instead and make a proper struct,
// but for the sake of the example, this is easier. // but for the sake of the example, this is easier.
body := `{ body := `{
"topic": "wifey", "topic": "wifey",
"message": "Your wife requested you send a picture of yourself.", "message": "Your wife requested you send a picture of yourself.",
@ -1812,7 +1812,7 @@ The `http` action **sends a HTTP request when the action button is tapped**. You
for whatever systems you have, e.g. opening the garage door, or turning on/off lights. for whatever systems you have, e.g. opening the garage door, or turning on/off lights.
By default, this action sends a **POST request** (not GET!), though this can be changed with the `method` parameter. By default, this action sends a **POST request** (not GET!), though this can be changed with the `method` parameter.
The only required parameter is `url`. Headers can be passed along using the `headers` parameter. The only required parameter is `url`. Headers can be passed along using the `headers` parameter.
Here's an example using the [`X-Actions` header](#using-a-header): Here's an example using the [`X-Actions` header](#using-a-header):
@ -1846,8 +1846,8 @@ Here's an example using the [`X-Actions` header](#using-a-header):
fetch('https://ntfy.sh/myhome', { fetch('https://ntfy.sh/myhome', {
method: 'POST', method: 'POST',
body: 'Garage door has been open for 15 minutes. Close it?', body: 'Garage door has been open for 15 minutes. Close it?',
headers: { headers: {
'Actions': 'http, Close door, https://api.mygarage.lan/, method=PUT, headers.Authorization=Bearer zAzsx1sk.., body={\"action\": \"close\"}' 'Actions': 'http, Close door, https://api.mygarage.lan/, method=PUT, headers.Authorization=Bearer zAzsx1sk.., body={\"action\": \"close\"}'
} }
}) })
``` ```
@ -1979,7 +1979,7 @@ And the same example using [JSON publishing](#publish-as-json):
``` go ``` go
// You should probably use json.Marshal() instead and make a proper struct, // You should probably use json.Marshal() instead and make a proper struct,
// but for the sake of the example, this is easier. // but for the sake of the example, this is easier.
body := `{ body := `{
"topic": "myhome", "topic": "myhome",
"message": "Garage door has been open for 15 minutes. Close it?", "message": "Garage door has been open for 15 minutes. Close it?",
@ -2002,7 +2002,7 @@ And the same example using [JSON publishing](#publish-as-json):
=== "PowerShell" === "PowerShell"
``` powershell ``` powershell
# Powershell requires the 'Depth' argument to equal 3 here to expand 'headers', # Powershell requires the 'Depth' argument to equal 3 here to expand 'headers',
# otherwise it will read System.Collections.Hashtable in the returned JSON # otherwise it will read System.Collections.Hashtable in the returned JSON
$uri = "https://ntfy.sh" $uri = "https://ntfy.sh"
@ -2088,13 +2088,13 @@ The `http` action supports the following fields:
## Click action ## Click action
_Supported on:_ :material-android: :material-apple: :material-firefox: _Supported on:_ :material-android: :material-apple: :material-firefox:
You can define which URL to open when a notification is clicked. This may be useful if your notification is related You can define which URL to open when a notification is clicked. This may be useful if your notification is related
to a Zabbix alert or a transaction that you'd like to provide the deep-link for. Tapping the notification will open to a Zabbix alert or a transaction that you'd like to provide the deep-link for. Tapping the notification will open
the web browser (or the app) and open the website. the web browser (or the app) and open the website.
To define a click action for the notification, pass a URL as the value of the `X-Click` header (or its aliase `Click`). To define a click action for the notification, pass a URL as the value of the `X-Click` header (or its aliase `Click`).
If you pass a website URL (`http://` or `https://`) the web browser will open. If you pass another URI that can be handled If you pass a website URL (`http://` or `https://`) the web browser will open. If you pass another URI that can be handled
by another app, the responsible app may open. by another app, the responsible app may open.
Examples: Examples:
@ -2126,7 +2126,7 @@ Here's an example that will open Reddit when the notification is clicked:
``` http ``` http
POST /reddit_alerts HTTP/1.1 POST /reddit_alerts HTTP/1.1
Host: ntfy.sh Host: ntfy.sh
Click: https://www.reddit.com/message/messages Click: https://www.reddit.com/message/messages
New messages on Reddit New messages on Reddit
``` ```
@ -2181,19 +2181,19 @@ _Supported on:_ :material-android: :material-firefox:
You can **send images and other files to your phone** as attachments to a notification. The attachments are then downloaded You can **send images and other files to your phone** as attachments to a notification. The attachments are then downloaded
onto your phone (depending on size and setting automatically), and can be used from the Downloads folder. onto your phone (depending on size and setting automatically), and can be used from the Downloads folder.
There are two different ways to send attachments: There are two different ways to send attachments:
* sending [a local file](#attach-local-file) via PUT, e.g. from `~/Flowers/flower.jpg` or `ringtone.mp3` * sending [a local file](#attach-local-file) via PUT, e.g. from `~/Flowers/flower.jpg` or `ringtone.mp3`
* or by [passing an external URL](#attach-file-from-a-url) as an attachment, e.g. `https://f-droid.org/F-Droid.apk` * or by [passing an external URL](#attach-file-from-a-url) as an attachment, e.g. `https://f-droid.org/F-Droid.apk`
### Attach local file ### Attach local file
To **send a file from your computer** as an attachment, you can send it as the PUT request body. If a message is greater To **send a file from your computer** as an attachment, you can send it as the PUT request body. If a message is greater
than the maximum message size (4,096 bytes) or consists of non UTF-8 characters, the ntfy server will automatically than the maximum message size (4,096 bytes) or consists of non UTF-8 characters, the ntfy server will automatically
detect the mime type and size, and send the message as an attachment file. To send smaller text-only messages or files detect the mime type and size, and send the message as an attachment file. To send smaller text-only messages or files
as attachments, you must pass a filename by passing the `X-Filename` header or query parameter (or any of its aliases as attachments, you must pass a filename by passing the `X-Filename` header or query parameter (or any of its aliases
`Filename`, `File` or `f`). `Filename`, `File` or `f`).
By default, and how ntfy.sh is configured, the **max attachment size is 15 MB** (with 100 MB total per visitor). By default, and how ntfy.sh is configured, the **max attachment size is 15 MB** (with 100 MB total per visitor).
Attachments **expire after 3 hours**, which typically is plenty of time for the user to download it, or for the Android app Attachments **expire after 3 hours**, which typically is plenty of time for the user to download it, or for the Android app
to auto-download it. Please also check out the [other limits below](#limitations). to auto-download it. Please also check out the [other limits below](#limitations).
@ -2220,7 +2220,7 @@ Here's an example showing how to upload an image:
Host: ntfy.sh Host: ntfy.sh
Filename: flower.jpg Filename: flower.jpg
Content-Type: 52312 Content-Type: 52312
(binary JPEG data) (binary JPEG data)
``` ```
@ -2256,7 +2256,7 @@ Here's an example showing how to upload an image:
'header' => 'header' =>
"Content-Type: application/octet-stream\r\n" . // Does not matter "Content-Type: application/octet-stream\r\n" . // Does not matter
"Filename: flower.jpg", "Filename: flower.jpg",
'content' => file_get_contents('flower.jpg') // Dangerous for large files 'content' => file_get_contents('flower.jpg') // Dangerous for large files
] ]
])); ]));
``` ```
@ -2270,13 +2270,13 @@ Here's what that looks like on Android:
### Attach file from a URL ### Attach file from a URL
Instead of sending a local file to your phone, you can use **an external URL** to specify where the attachment is hosted. Instead of sending a local file to your phone, you can use **an external URL** to specify where the attachment is hosted.
This could be a Dropbox link, a file from social media, or any other publicly available URL. Since the files are This could be a Dropbox link, a file from social media, or any other publicly available URL. Since the files are
externally hosted, the expiration or size limits from above do not apply here. externally hosted, the expiration or size limits from above do not apply here.
To attach an external file, simple pass the `X-Attach` header or query parameter (or any of its aliases `Attach` or `a`) To attach an external file, simple pass the `X-Attach` header or query parameter (or any of its aliases `Attach` or `a`)
to specify the attachment URL. It can be any type of file. to specify the attachment URL. It can be any type of file.
ntfy will automatically try to derive the file name from the URL (e.g `https://example.com/flower.jpg` will yield a ntfy will automatically try to derive the file name from the URL (e.g `https://example.com/flower.jpg` will yield a
filename `flower.jpg`). To override this filename, you may send the `X-Filename` header or query parameter (or any of its filename `flower.jpg`). To override this filename, you may send the `X-Filename` header or query parameter (or any of its
aliases `Filename`, `File` or `f`). aliases `Filename`, `File` or `f`).
@ -2354,7 +2354,7 @@ _Supported on:_ :material-android:
You can include an icon that will appear next to the text of the notification. Simply pass the `X-Icon` header or query You can include an icon that will appear next to the text of the notification. Simply pass the `X-Icon` header or query
parameter (or its alias `Icon`) to specify the URL that the icon is located at. The client will automatically download parameter (or its alias `Icon`) to specify the URL that the icon is located at. The client will automatically download
the icon (unless it is already cached locally, and less than 24 hours old), and show it in the notification. Icons are the icon (unless it is already cached locally, and less than 24 hours old), and show it in the notification. Icons are
cached locally in the client until the notification is deleted. **Only JPEG and PNG images are supported at this time**. cached locally in the client until the notification is deleted. **Only JPEG and PNG images are supported at this time**.
Here's an example showing how to include an icon: Here's an example showing how to include an icon:
@ -2394,7 +2394,7 @@ Here's an example showing how to include an icon:
``` javascript ``` javascript
fetch('https://ntfy.sh/tvshows', { fetch('https://ntfy.sh/tvshows', {
method: 'POST', method: 'POST',
headers: { headers: {
'Icon': 'https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png', 'Icon': 'https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png',
'Title': 'Kodi: Resuming Playback', 'Title': 'Kodi: Resuming Playback',
'Tags': 'arrow_forward' 'Tags': 'arrow_forward'
@ -2458,14 +2458,14 @@ Here's an example of how it will look on Android:
## E-mail notifications ## E-mail notifications
_Supported on:_ :material-android: :material-apple: :material-firefox: _Supported on:_ :material-android: :material-apple: :material-firefox:
You can forward messages to e-mail by specifying an address in the header. This can be useful for messages that You can forward messages to e-mail by specifying an address in the header. This can be useful for messages that
you'd like to persist longer, or to blast-notify yourself on all possible channels. you'd like to persist longer, or to blast-notify yourself on all possible channels.
Usage is easy: Simply pass the `X-Email` header (or any of its aliases: `X-E-mail`, `Email`, `E-mail`, `Mail`, or `e`). Usage is easy: Simply pass the `X-Email` header (or any of its aliases: `X-E-mail`, `Email`, `E-mail`, `Mail`, or `e`).
Only one e-mail address is supported. Only one e-mail address is supported.
Since ntfy does not provide auth (yet), the rate limiting is pretty strict (see [limitations](#limitations)). In the Since ntfy does not provide auth (yet), the rate limiting is pretty strict (see [limitations](#limitations)). In the
default configuration, you get **16 e-mails per visitor** (IP address) and then after that one per hour. On top of default configuration, you get **16 e-mails per visitor** (IP address) and then after that one per hour. On top of
that, your IP address appears in the e-mail body. This is to prevent abuse. that, your IP address appears in the e-mail body. This is to prevent abuse.
=== "Command line (curl)" === "Command line (curl)"
@ -2476,7 +2476,7 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
-H "Priority: high" \ -H "Priority: high" \
-d "Unknown login from 5.31.23.83 to backups.example.com" \ -d "Unknown login from 5.31.23.83 to backups.example.com" \
ntfy.sh/alerts ntfy.sh/alerts
curl -H "Email: phil@example.com" -d "You've Got Mail" curl -H "Email: phil@example.com" -d "You've Got Mail"
curl -d "You've Got Mail" "ntfy.sh/alerts?email=phil@example.com" curl -d "You've Got Mail" "ntfy.sh/alerts?email=phil@example.com"
``` ```
@ -2505,7 +2505,7 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
fetch('https://ntfy.sh/alerts', { fetch('https://ntfy.sh/alerts', {
method: 'POST', method: 'POST',
body: "Unknown login from 5.31.23.83 to backups.example.com", body: "Unknown login from 5.31.23.83 to backups.example.com",
headers: { headers: {
'Email': 'phil@example.com', 'Email': 'phil@example.com',
'Tags': 'warning,skull,backup-host,ssh-login', 'Tags': 'warning,skull,backup-host,ssh-login',
'Priority': 'high' 'Priority': 'high'
@ -2515,7 +2515,7 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
=== "Go" === "Go"
``` go ``` go
req, _ := http.NewRequest("POST", "https://ntfy.sh/alerts", req, _ := http.NewRequest("POST", "https://ntfy.sh/alerts",
strings.NewReader("Unknown login from 5.31.23.83 to backups.example.com")) strings.NewReader("Unknown login from 5.31.23.83 to backups.example.com"))
req.Header.Set("Email", "phil@example.com") req.Header.Set("Email", "phil@example.com")
req.Header.Set("Tags", "warning,skull,backup-host,ssh-login") req.Header.Set("Tags", "warning,skull,backup-host,ssh-login")
@ -2538,7 +2538,7 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
``` python ``` python
requests.post("https://ntfy.sh/alerts", requests.post("https://ntfy.sh/alerts",
data="Unknown login from 5.31.23.83 to backups.example.com", data="Unknown login from 5.31.23.83 to backups.example.com",
headers={ headers={
"Email": "phil@example.com", "Email": "phil@example.com",
"Tags": "warning,skull,backup-host,ssh-login", "Tags": "warning,skull,backup-host,ssh-login",
"Priority": "high" "Priority": "high"
@ -2571,11 +2571,11 @@ Here's what that looks like in Google Mail:
_Supported on:_ :material-android: :material-apple: :material-firefox: _Supported on:_ :material-android: :material-apple: :material-firefox:
You can publish messages to a topic via e-mail, i.e. by sending an email to a specific address. For instance, you can You can publish messages to a topic via e-mail, i.e. by sending an email to a specific address. For instance, you can
publish a message to the topic `sometopic` by sending an e-mail to `ntfy-sometopic@ntfy.sh`. This is useful for e-mail publish a message to the topic `sometopic` by sending an e-mail to `ntfy-sometopic@ntfy.sh`. This is useful for e-mail
based integrations such as for statuspage.io (though these days most services also support webhooks and HTTP calls). based integrations such as for statuspage.io (though these days most services also support webhooks and HTTP calls).
Depending on the [server configuration](config.md#e-mail-publishing), the e-mail address format can have a prefix to Depending on the [server configuration](config.md#e-mail-publishing), the e-mail address format can have a prefix to
prevent spam on topics. For ntfy.sh, the prefix is configured to `ntfy-`, meaning that the general e-mail address prevent spam on topics. For ntfy.sh, the prefix is configured to `ntfy-`, meaning that the general e-mail address
format is: format is:
``` ```
@ -2583,7 +2583,7 @@ ntfy-$topic@ntfy.sh
``` ```
As of today, e-mail publishing only supports adding a [message title](#message-title) (the e-mail subject). Tags, priority, As of today, e-mail publishing only supports adding a [message title](#message-title) (the e-mail subject). Tags, priority,
delay and other features are not supported (yet). Here's an example that will publish a message with the delay and other features are not supported (yet). Here's an example that will publish a message with the
title `You've Got Mail` to topic `sometopic` (see [ntfy.sh/sometopic](https://ntfy.sh/sometopic)): title `You've Got Mail` to topic `sometopic` (see [ntfy.sh/sometopic](https://ntfy.sh/sometopic)):
<figure markdown> <figure markdown>
@ -2596,17 +2596,17 @@ title `You've Got Mail` to topic `sometopic` (see [ntfy.sh/sometopic](https://nt
### Authentication ### Authentication
Depending on whether the server is configured to support [access control](config.md#access-control), some topics Depending on whether the server is configured to support [access control](config.md#access-control), some topics
may be read/write protected so that only users with the correct credentials can subscribe or publish to them. may be read/write protected so that only users with the correct credentials can subscribe or publish to them.
To publish/subscribe to protected topics, you can: To publish/subscribe to protected topics, you can:
* Use [basic auth](#basic-auth), e.g. `Authorization: Basic dGVzdHVzZXI6ZmFrZXBhc3N3b3Jk` * Use [basic auth](#basic-auth), e.g. `Authorization: Basic dGVzdHVzZXI6ZmFrZXBhc3N3b3Jk`
* or use the [`auth` query parameter](#query-param), e.g. `?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw` * or use the [`auth` query parameter](#query-param), e.g. `?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw`
!!! warning !!! warning
Base64 only encodes username and password. It **is not encrypting it**. For your self-hosted server, Base64 only encodes username and password. It **is not encrypting it**. For your self-hosted server,
**be sure to use HTTPS to avoid eavesdropping** and exposing your password. **be sure to use HTTPS to avoid eavesdropping** and exposing your password.
#### Basic auth #### Basic auth
Here's an example using [Basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication), with a user `testuser` Here's an example using [Basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication), with a user `testuser`
and password `fakepassword`: and password `fakepassword`:
=== "Command line (curl)" === "Command line (curl)"
@ -2685,8 +2685,8 @@ and password `fakepassword`:
])); ]));
``` ```
To generate the `Authorization` header, use **standard base64** to encode the colon-separated `<username>:<password>` To generate the `Authorization` header, use **standard base64** to encode the colon-separated `<username>:<password>`
and prepend the word `Basic`, i.e. `Authorization: Basic base64(<username>:<password>)`. Here's some pseudo-code that and prepend the word `Basic`, i.e. `Authorization: Basic base64(<username>:<password>)`. Here's some pseudo-code that
hopefully explains it better: hopefully explains it better:
``` ```
@ -2766,8 +2766,8 @@ Here's an example using the `auth` query parameter:
])); ]));
``` ```
To generate the value of the `auth` parameter, encode the value of the `Authorization` header (see anove) using To generate the value of the `auth` parameter, encode the value of the `Authorization` header (see anove) using
**raw base64 encoding** (like base64, but strip any trailing `=`). Here's some pseudo-code that hopefully **raw base64 encoding** (like base64, but strip any trailing `=`). Here's some pseudo-code that hopefully
explains it better: explains it better:
``` ```
@ -2777,7 +2777,7 @@ authHeader = "Basic " + base64(username + ":" + password) // -> Basic dGVzdHVzZX
authParam = base64_raw(authHeader) // -> QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw (no trailing =) authParam = base64_raw(authHeader) // -> QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw (no trailing =)
// If your language does not have a function to encode raw base64, simply use normal base64 // If your language does not have a function to encode raw base64, simply use normal base64
// and REMOVE TRAILING "=" characters. // and REMOVE TRAILING "=" characters.
``` ```
The following command will generate the appropriate value for you on *nix systems: The following command will generate the appropriate value for you on *nix systems:
@ -2788,17 +2788,17 @@ echo -n "Basic `echo -n 'testuser:fakepassword' | base64`" | base64 | tr -d '='
### Message caching ### Message caching
!!! info !!! info
If `Cache: no` is used, messages will only be delivered to connected subscribers, and won't be re-delivered if a If `Cache: no` is used, messages will only be delivered to connected subscribers, and won't be re-delivered if a
client re-connects. If a subscriber has (temporary) network issues or is reconnecting momentarily, client re-connects. If a subscriber has (temporary) network issues or is reconnecting momentarily,
**messages might be missed**. **messages might be missed**.
By default, the ntfy server caches messages on disk for 12 hours (see [message caching](config.md#message-cache)), so By default, the ntfy server caches messages on disk for 12 hours (see [message caching](config.md#message-cache)), so
all messages you publish are stored server-side for a little while. The reason for this is to overcome temporary all messages you publish are stored server-side for a little while. The reason for this is to overcome temporary
client-side network disruptions, but arguably this feature also may raise privacy concerns. client-side network disruptions, but arguably this feature also may raise privacy concerns.
To avoid messages being cached server-side entirely, you can set `X-Cache` header (or its alias: `Cache`) to `no`. To avoid messages being cached server-side entirely, you can set `X-Cache` header (or its alias: `Cache`) to `no`.
This will make sure that your message is not cached on the server, even if server-side caching is enabled. Messages This will make sure that your message is not cached on the server, even if server-side caching is enabled. Messages
are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fetch-cached-messages) and are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fetch-cached-messages) and
[`poll=1`](subscribe/api.md#poll-for-messages) won't return the message anymore. [`poll=1`](subscribe/api.md#poll-for-messages) won't return the message anymore.
=== "Command line (curl)" === "Command line (curl)"
@ -2869,12 +2869,12 @@ are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fe
### Disable Firebase ### Disable Firebase
!!! info !!! info
If `Firebase: no` is used and [instant delivery](subscribe/phone.md#instant-delivery) isn't enabled in the Android If `Firebase: no` is used and [instant delivery](subscribe/phone.md#instant-delivery) isn't enabled in the Android
app (Google Play variant only), **message delivery will be significantly delayed (up to 15 minutes)**. To overcome app (Google Play variant only), **message delivery will be significantly delayed (up to 15 minutes)**. To overcome
this delay, simply enable instant delivery. this delay, simply enable instant delivery.
The ntfy server can be configured to use [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) The ntfy server can be configured to use [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging)
(see [Firebase config](config.md#firebase-fcm)) for message delivery on Android (to minimize the app's battery footprint). (see [Firebase config](config.md#firebase-fcm)) for message delivery on Android (to minimize the app's battery footprint).
The ntfy.sh server is configured this way, meaning that all messages published to ntfy.sh are also published to corresponding The ntfy.sh server is configured this way, meaning that all messages published to ntfy.sh are also published to corresponding
FCM topics. FCM topics.
@ -2949,7 +2949,7 @@ to `no`. This will instruct the server not to forward messages to Firebase.
### UnifiedPush ### UnifiedPush
!!! info !!! info
This setting is not relevant to users, only to app developers and people interested in [UnifiedPush](https://unifiedpush.org). This setting is not relevant to users, only to app developers and people interested in [UnifiedPush](https://unifiedpush.org).
[UnifiedPush](https://unifiedpush.org) is a standard for receiving push notifications without using the Google-owned [UnifiedPush](https://unifiedpush.org) is a standard for receiving push notifications without using the Google-owned
[Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) service. It puts push notifications [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) service. It puts push notifications
@ -2957,16 +2957,16 @@ in the control of the user. ntfy can act as a **UnifiedPush distributor**, forwa
When publishing messages to a topic, apps using ntfy as a UnifiedPush distributor can set the `X-UnifiedPush` header or query When publishing messages to a topic, apps using ntfy as a UnifiedPush distributor can set the `X-UnifiedPush` header or query
parameter (or any of its aliases `unifiedpush` or `up`) to `1` to [disable Firebase](#disable-firebase). As of today, this parameter (or any of its aliases `unifiedpush` or `up`) to `1` to [disable Firebase](#disable-firebase). As of today, this
option is mostly equivalent to `Firebase: no`, but was introduced to allow future flexibility. The flag additionally option is mostly equivalent to `Firebase: no`, but was introduced to allow future flexibility. The flag additionally
enables auto-detection of the message encoding. If the message is binary, it'll be encoded as base64. enables auto-detection of the message encoding. If the message is binary, it'll be encoded as base64.
### Matrix Gateway ### Matrix Gateway
The ntfy server implements a [Matrix Push Gateway](https://spec.matrix.org/v1.2/push-gateway-api/) (in combination with The ntfy server implements a [Matrix Push Gateway](https://spec.matrix.org/v1.2/push-gateway-api/) (in combination with
[UnifiedPush](https://unifiedpush.org) as the [Provider Push Protocol](https://unifiedpush.org/developers/gateway/)). This makes it easier to integrate [UnifiedPush](https://unifiedpush.org) as the [Provider Push Protocol](https://unifiedpush.org/developers/gateway/)). This makes it easier to integrate
with self-hosted [Matrix](https://matrix.org/) servers (such as [synapse](https://github.com/matrix-org/synapse)), since with self-hosted [Matrix](https://matrix.org/) servers (such as [synapse](https://github.com/matrix-org/synapse)), since
you don't have to set up a separate push proxy (such as [common-proxies](https://github.com/UnifiedPush/common-proxies)). you don't have to set up a separate push proxy (such as [common-proxies](https://github.com/UnifiedPush/common-proxies)).
In short, ntfy accepts Matrix messages on the `/_matrix/push/v1/notify` endpoint (see [Push Gateway API](https://spec.matrix.org/v1.2/push-gateway-api/)), In short, ntfy accepts Matrix messages on the `/_matrix/push/v1/notify` endpoint (see [Push Gateway API](https://spec.matrix.org/v1.2/push-gateway-api/)),
and forwards them to the ntfy topic defined in the `pushkey` of the message. The message will then be forwarded to the and forwards them to the ntfy topic defined in the `pushkey` of the message. The message will then be forwarded to the
ntfy Android app, and passed on to the Matrix client there. ntfy Android app, and passed on to the Matrix client there.
@ -2989,7 +2989,7 @@ that you can use to try out what [authentication and access control](#authentica
| [mytopic-wo](https://ntfy.sh/mytopic-wo) | `testuser` (password: `testuser`) | Write-only for `testuser`, no access for anyone else | Test topic | | [mytopic-wo](https://ntfy.sh/mytopic-wo) | `testuser` (password: `testuser`) | Write-only for `testuser`, no access for anyone else | Test topic |
## Limitations ## Limitations
There are a few limitations to the API to prevent abuse and to keep the server healthy. Almost all of these settings There are a few limitations to the API to prevent abuse and to keep the server healthy. Almost all of these settings
are configurable via the server side [rate limiting settings](config.md#rate-limiting). Most of these limits you won't run into, are configurable via the server side [rate limiting settings](config.md#rate-limiting). Most of these limits you won't run into,
but just in case, let's list them all: but just in case, let's list them all:

View file

@ -7,7 +7,7 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release
**Features:** **Features:**
* Web: Generate random topic name button ([#453](https://github.com/binwiederhier/ntfy/issues/453), thanks to [@yardenshoham](https://github.com/yardenshoham)) * Web: Generate random topic name button ([#453](https://github.com/binwiederhier/ntfy/issues/453), thanks to [@yardenshoham](https://github.com/yardenshoham))
* Add [Gitpod config](https://github.com/binwiederhier/ntfy/blob/main/.gitpod.yml) ([#540](https://github.com/binwiederhier/ntfy/pull/540), thanks to [@yardenshoham](https://github.com/yardenshoham)) * Add [Gitpod config](https://github.com/binwiederhier/ntfy/blob/main/.gitpod.yml) ([#540](https://github.com/binwiederhier/ntfy/pull/540), thanks to [@yardenshoham](https://github.com/yardenshoham))
**Bug fixes + maintenance:** **Bug fixes + maintenance:**
@ -67,7 +67,7 @@ requests.
**Documentation:** **Documentation:**
* GitHub Actions example ([#492](https://github.com/binwiederhier/ntfy/pull/492), thanks to [@ksurl](https://github.com/ksurl)) * GitHub Actions example ([#492](https://github.com/binwiederhier/ntfy/pull/492), thanks to [@ksurl](https://github.com/ksurl))
* UnifiedPush ACL clarification ([#497](https://github.com/binwiederhier/ntfy/issues/497), thanks to [@bt90](https://github.com/bt90)) * UnifiedPush ACL clarification ([#497](https://github.com/binwiederhier/ntfy/issues/497), thanks to [@bt90](https://github.com/bt90))
* Install instructions for Kustomize ([#463](https://github.com/binwiederhier/ntfy/pull/463), thanks to [@l-maciej](https://github.com/l-maciej)) * Install instructions for Kustomize ([#463](https://github.com/binwiederhier/ntfy/pull/463), thanks to [@l-maciej](https://github.com/l-maciej))
**Other things:** **Other things:**
@ -78,11 +78,11 @@ requests.
## ntfy server v1.29.0 ## ntfy server v1.29.0
Released November 12, 2022 Released November 12, 2022
This release adds the ability to add rate limit exemptions for IP ranges instead of just specific IP addresses. It also fixes This release adds the ability to add rate limit exemptions for IP ranges instead of just specific IP addresses. It also fixes
a few bugs in the web app and the CLI and adds lots of new examples and install instructions. a few bugs in the web app and the CLI and adds lots of new examples and install instructions.
Thanks to [some love on HN](https://news.ycombinator.com/item?id=33517944), we got so many new ntfy users trying out ntfy Thanks to [some love on HN](https://news.ycombinator.com/item?id=33517944), we got so many new ntfy users trying out ntfy
and joining the [chat rooms](https://github.com/binwiederhier/ntfy#chat--forum). **Welcome to the ntfy community to all of you!** and joining the [chat rooms](https://github.com/binwiederhier/ntfy#chat--forum). **Welcome to the ntfy community to all of you!**
We also got a ton of new **[sponsors and donations](https://github.com/sponsors/binwiederhier)** 💸, which is amazing. I'd like to thank We also got a ton of new **[sponsors and donations](https://github.com/sponsors/binwiederhier)** 💸, which is amazing. I'd like to thank
all of you for believing in the project, and for helping me pay the server cost. The HN spike increased the AWS cost quite a bit. all of you for believing in the project, and for helping me pay the server cost. The HN spike increased the AWS cost quite a bit.
@ -120,13 +120,13 @@ all of you for believing in the project, and for helping me pay the server cost.
**Sponsorships:**: **Sponsorships:**:
Thank you to the amazing folks who decided to [sponsor ntfy](https://github.com/sponsors/binwiederhier). Thank you for Thank you to the amazing folks who decided to [sponsor ntfy](https://github.com/sponsors/binwiederhier). Thank you for
helping carry the cost of the public server and developer licenses, and more importantly: Thank you for believing in ntfy! helping carry the cost of the public server and developer licenses, and more importantly: Thank you for believing in ntfy!
You guys rock! You guys rock!
A list of all the sponsors can be found in the [README](https://github.com/binwiederhier/ntfy/blob/main/README.md). A list of all the sponsors can be found in the [README](https://github.com/binwiederhier/ntfy/blob/main/README.md).
## ntfy Android app v1.14.0 ## ntfy Android app v1.14.0
Released September 27, 2022 Released September 27, 2022
This release adds the ability to set a custom icon to each notification, as well as a display name to subscriptions. We This release adds the ability to set a custom icon to each notification, as well as a display name to subscriptions. We
@ -164,7 +164,7 @@ This release primarily adds icon support for the Android app, and adds a display
Aside from that, we fixed a few random bugs, most importantly the `Priority` header bug that allows the use behind Aside from that, we fixed a few random bugs, most importantly the `Priority` header bug that allows the use behind
Cloudflare. We also added a ton of documentation. Most prominently, an [integrations + projects page](https://ntfy.sh/docs/integrations/). Cloudflare. We also added a ton of documentation. Most prominently, an [integrations + projects page](https://ntfy.sh/docs/integrations/).
As of now, I also have started accepting **[donations and sponsorships](https://github.com/sponsors/binwiederhier)** 💸. As of now, I also have started accepting **[donations and sponsorships](https://github.com/sponsors/binwiederhier)** 💸.
I would be very humbled if you consider donating. I would be very humbled if you consider donating.
**Features:** **Features:**
@ -200,8 +200,8 @@ I would be very humbled if you consider donating.
Released June 23, 2022 Released June 23, 2022
This release brings two new CLI options to wait for a command to finish, or for a PID to exit. It also adds more detail This release brings two new CLI options to wait for a command to finish, or for a PID to exit. It also adds more detail
to trace debug output. Aside from other bugs, it fixes a performance issue that occurred in large installations every to trace debug output. Aside from other bugs, it fixes a performance issue that occurred in large installations every
minute or so, due to competing stats gathering (personal installations will likely be unaffected by this). minute or so, due to competing stats gathering (personal installations will likely be unaffected by this).
**Features:** **Features:**
@ -226,7 +226,7 @@ minute or so, due to competing stats gathering (personal installations will like
Released June 16, 2022 Released June 16, 2022
This release adds a Matrix Push Gateway directly into ntfy, to make self-hosting a Matrix server easier. The Windows This release adds a Matrix Push Gateway directly into ntfy, to make self-hosting a Matrix server easier. The Windows
CLI is now available via Scoop, and ntfy is now natively supported in Uptime Kuma. CLI is now available via Scoop, and ntfy is now natively supported in Uptime Kuma.
**Features:** **Features:**
@ -265,8 +265,8 @@ set your server as the default server for new topics.
## ntfy server v1.25.2 ## ntfy server v1.25.2
Released June 2, 2022 Released June 2, 2022
This release adds the ability to set a log level to facilitate easier debugging of live systems. It also solves a This release adds the ability to set a log level to facilitate easier debugging of live systems. It also solves a
production problem with a few over-users that resulted in Firebase quota problems (only applying to the over-users). production problem with a few over-users that resulted in Firebase quota problems (only applying to the over-users).
We now block visitors from using Firebase if they trigger a quota exceeded response. We now block visitors from using Firebase if they trigger a quota exceeded response.
On top of that, we updated the Firebase SDK and are now building the release in GitHub Actions. We've also got two On top of that, we updated the Firebase SDK and are now building the release in GitHub Actions. We've also got two
@ -279,7 +279,7 @@ more translations: Chinese/Simplified and Dutch.
**Bugs**: **Bugs**:
* Respect Firebase "quota exceeded" response for topics, block Firebase publishing for user for 10min ([#289](https://github.com/binwiederhier/ntfy/issues/289)) * Respect Firebase "quota exceeded" response for topics, block Firebase publishing for user for 10min ([#289](https://github.com/binwiederhier/ntfy/issues/289))
* Fix documentation header blue header due to mkdocs-material theme update (no ticket) * Fix documentation header blue header due to mkdocs-material theme update (no ticket)
**Maintenance:** **Maintenance:**
@ -367,7 +367,7 @@ The app is now available in the [App Store](https://apps.apple.com/us/app/ntfy/i
## ntfy server v1.23.0 ## ntfy server v1.23.0
Released May 21, 2022 Released May 21, 2022
This release ships a CLI for Windows and macOS, as well as the ability to disable the web app entirely. On top of that, This release ships a CLI for Windows and macOS, as well as the ability to disable the web app entirely. On top of that,
it adds support for APNs, the iOS messaging service. This is needed for the (soon to be released) iOS app. it adds support for APNs, the iOS messaging service. This is needed for the (soon to be released) iOS app.
**Features:** **Features:**
@ -391,7 +391,7 @@ it adds support for APNs, the iOS messaging service. This is needed for the (soo
* Portuguese/Brazil (thanks to [@tiagotriques](https://hosted.weblate.org/user/tiagotriques/) and [@pireshenrique22](https://hosted.weblate.org/user/pireshenrique22/)) * Portuguese/Brazil (thanks to [@tiagotriques](https://hosted.weblate.org/user/tiagotriques/) and [@pireshenrique22](https://hosted.weblate.org/user/pireshenrique22/))
Thank you to the many translators, who helped translate the new strings so quickly. I am humbled and amazed by your help. Thank you to the many translators, who helped translate the new strings so quickly. I am humbled and amazed by your help.
## ntfy Android app v1.13.0 ## ntfy Android app v1.13.0
Released May 11, 2022 Released May 11, 2022
@ -465,10 +465,10 @@ Released Apr 25, 2022
The main feature in this Android release is [Action Buttons](https://ntfy.sh/docs/publish/#action-buttons), a feature The main feature in this Android release is [Action Buttons](https://ntfy.sh/docs/publish/#action-buttons), a feature
that allows users to add actions to the notifications. Actions can be to view a website or app, send a broadcast, or that allows users to add actions to the notifications. Actions can be to view a website or app, send a broadcast, or
send a HTTP request. send a HTTP request.
We also added support for [ntfy:// deep links](https://ntfy.sh/docs/subscribe/phone/#ntfy-links), added three more We also added support for [ntfy:// deep links](https://ntfy.sh/docs/subscribe/phone/#ntfy-links), added three more
languages and fixed a ton of bugs. languages and fixed a ton of bugs.
**Features:** **Features:**
@ -509,9 +509,9 @@ Thanks to [@s-h-a-r-d](https://github.com/s-h-a-r-d) (aka @Shard), [@cmeis](http
## ntfy server v1.21.2 ## ntfy server v1.21.2
Released Apr 24, 2022 Released Apr 24, 2022
In this release, the web app got translation support and was translated into 9 languages already 🇧🇬 🇩🇪 🇺🇸 🌎. In this release, the web app got translation support and was translated into 9 languages already 🇧🇬 🇩🇪 🇺🇸 🌎.
It also re-adds support for ARMv6, and adds server-side support for Action Buttons. [Action Buttons](https://ntfy.sh/docs/publish/#action-buttons) It also re-adds support for ARMv6, and adds server-side support for Action Buttons. [Action Buttons](https://ntfy.sh/docs/publish/#action-buttons)
is a feature that will be released in the Android app soon. It allows users to add actions to the notifications. is a feature that will be released in the Android app soon. It allows users to add actions to the notifications.
Limited support is available in the web app. Limited support is available in the web app.
**Features:** **Features:**
@ -543,7 +543,7 @@ Limited support is available in the web app.
**Integrations:** **Integrations:**
[Apprise](https://github.com/caronc/apprise) support was fully released in [v0.9.8.2](https://github.com/caronc/apprise/releases/tag/v0.9.8.2) [Apprise](https://github.com/caronc/apprise) support was fully released in [v0.9.8.2](https://github.com/caronc/apprise/releases/tag/v0.9.8.2)
of Apprise. Thanks to [@particledecay](https://github.com/particledecay) and [@caronc](https://github.com/caronc) for their fantastic work. of Apprise. Thanks to [@particledecay](https://github.com/particledecay) and [@caronc](https://github.com/caronc) for their fantastic work.
You can try it yourself like this (detailed usage in the [Apprise wiki](https://github.com/caronc/apprise/wiki/Notify_ntfy)): You can try it yourself like this (detailed usage in the [Apprise wiki](https://github.com/caronc/apprise/wiki/Notify_ntfy)):
``` ```
@ -593,7 +593,7 @@ Released Apr 6, 2022
**Features:**: **Features:**:
* Added message bar and publish dialog ([#196](https://github.com/binwiederhier/ntfy/issues/196)) * Added message bar and publish dialog ([#196](https://github.com/binwiederhier/ntfy/issues/196))
**Bug fixes:** **Bug fixes:**
@ -624,7 +624,7 @@ Released Mar 30, 2022
* Improved [e-mail publishing](config.md#e-mail-publishing) documentation * Improved [e-mail publishing](config.md#e-mail-publishing) documentation
## ntfy server v1.18.1 ## ntfy server v1.18.1
Released Mar 21, 2022 Released Mar 21, 2022
_This release ships no features or bug fixes. It's merely a documentation update._ _This release ships no features or bug fixes. It's merely a documentation update._
**Documentation:** **Documentation:**
@ -653,8 +653,8 @@ Released Mar 16, 2022
**Features:** **Features:**
* [Publish messages as JSON](https://ntfy.sh/docs/publish/#publish-as-json) ([#133](https://github.com/binwiederhier/ntfy/issues/133), * [Publish messages as JSON](https://ntfy.sh/docs/publish/#publish-as-json) ([#133](https://github.com/binwiederhier/ntfy/issues/133),
thanks [@cmeis](https://github.com/cmeis) for reporting, thanks to [@Joeharrison94](https://github.com/Joeharrison94) and thanks [@cmeis](https://github.com/cmeis) for reporting, thanks to [@Joeharrison94](https://github.com/Joeharrison94) and
[@Fallenbagel](https://github.com/Fallenbagel) for testing) [@Fallenbagel](https://github.com/Fallenbagel) for testing)
**Bug fixes:** **Bug fixes:**
@ -682,7 +682,7 @@ Released Mar 11, 2022
* Replace [web app](https://ntfy.sh/app) with a React/MUI-based web app from the 21st century (#111) * Replace [web app](https://ntfy.sh/app) with a React/MUI-based web app from the 21st century (#111)
* Web UI broken with auth (#132, thanks for reporting @arminus) * Web UI broken with auth (#132, thanks for reporting @arminus)
* Send static web resources as `Content-Encoding: gzip`, i.e. docs and web app (no ticket) * Send static web resources as `Content-Encoding: gzip`, i.e. docs and web app (no ticket)
* Add support for auth via `?auth=...` query param, used by WebSocket in web app (no ticket) * Add support for auth via `?auth=...` query param, used by WebSocket in web app (no ticket)
## ntfy server v1.16.0 ## ntfy server v1.16.0
Released Feb 27, 2022 Released Feb 27, 2022
@ -699,7 +699,7 @@ Released Feb 27, 2022
**Technical notes:** **Technical notes:**
* As of this release, message IDs will be 12 characters long (as opposed to 10 characters). This is to be able to * As of this release, message IDs will be 12 characters long (as opposed to 10 characters). This is to be able to
distinguish them from Unix timestamps for #151. distinguish them from Unix timestamps for #151.
## ntfy Android app v1.9.1 ## ntfy Android app v1.9.1
@ -746,7 +746,7 @@ Released Feb 6, 2022
**Features:** **Features:**
* Support [auth / access control](https://ntfy.sh/docs/config/#access-control) (#19, thanks to @cmeis, @drsprite/@poblabs, * Support [auth / access control](https://ntfy.sh/docs/config/#access-control) (#19, thanks to @cmeis, @drsprite/@poblabs,
@gedw99, @karmanyaahm, @Mek101, @gc-ss, @julianfoad, @nmoseman, Jakob, PeterCxy, Techlosopher) @gedw99, @karmanyaahm, @Mek101, @gc-ss, @julianfoad, @nmoseman, Jakob, PeterCxy, Techlosopher)
* Export/upload log now allows censored/uncensored logs (no ticket) * Export/upload log now allows censored/uncensored logs (no ticket)
* Removed wake lock (except for notification dispatching, no ticket) * Removed wake lock (except for notification dispatching, no ticket)

View file

@ -1,130 +1,133 @@
:root > * { :root > * {
--md-primary-fg-color: #338574; --md-primary-fg-color: #338574;
--md-primary-fg-color--light: #338574; --md-primary-fg-color--light: #338574;
--md-primary-fg-color--dark: #338574; --md-primary-fg-color--dark: #338574;
} }
.md-header__button.md-logo :is(img, svg) { .md-header__button.md-logo :is(img, svg) {
width: unset !important; width: unset !important;
} }
.md-header__topic:first-child { .md-header__topic:first-child {
font-weight: 400; font-weight: 400;
} }
.md-typeset h4 { .md-typeset h4 {
font-weight: 500 !important; font-weight: 500 !important;
margin: 0 !important; margin: 0 !important;
font-size: 1.1em !important; font-size: 1.1em !important;
} }
.admonition { .admonition {
font-size: .74rem !important; font-size: 0.74rem !important;
} }
article { article {
padding-bottom: 50px; padding-bottom: 50px;
} }
figure img, figure video { figure img,
border-radius: 7px; figure video {
border-radius: 7px;
} }
body[data-md-color-scheme="default"] figure img, body[data-md-color-scheme="default"] figure video { body[data-md-color-scheme="default"] figure img,
filter: drop-shadow(3px 3px 3px #ccc); body[data-md-color-scheme="default"] figure video {
filter: drop-shadow(3px 3px 3px #ccc);
} }
body[data-md-color-scheme="slate"] figure img, body[data-md-color-scheme="slate"] figure video { body[data-md-color-scheme="slate"] figure img,
filter: drop-shadow(3px 3px 3px #1a1313); body[data-md-color-scheme="slate"] figure video {
filter: drop-shadow(3px 3px 3px #1a1313);
} }
figure video { figure video {
width: 100%; width: 100%;
max-height: 450px; max-height: 450px;
} }
.remove-md-box { .remove-md-box {
background: none; background: none;
border: none; border: none;
margin: 0 auto; margin: 0 auto;
} }
.remove-md-box td { .remove-md-box td {
padding: 0 10px padding: 0 10px;
} }
/* Lightbox; thanks to https://yossiabramov.com/blog/vanilla-js-lightbox */ /* Lightbox; thanks to https://yossiabramov.com/blog/vanilla-js-lightbox */
.screenshots { .screenshots {
text-align: center; text-align: center;
} }
.screenshots img { .screenshots img {
max-height: 230px; max-height: 230px;
max-width: 300px; max-width: 300px;
margin: 3px; margin: 3px;
border-radius: 5px; border-radius: 5px;
filter: drop-shadow(2px 2px 2px #ddd); filter: drop-shadow(2px 2px 2px #ddd);
} }
.screenshots .nowrap { .screenshots .nowrap {
white-space: nowrap; white-space: nowrap;
} }
.lightbox { .lightbox {
opacity: 0; opacity: 0;
visibility: hidden; visibility: hidden;
position: fixed; position: fixed;
left:0; left: 0;
right: 0; right: 0;
top: 0; top: 0;
bottom: 0; bottom: 0;
z-index: -1; z-index: -1;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
transition: all 0.15s ease-in; transition: all 0.15s ease-in;
} }
.lightbox.show { .lightbox.show {
background-color: rgba(0,0,0, 0.75); background-color: rgba(0, 0, 0, 0.75);
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
z-index: 1000; z-index: 1000;
} }
.lightbox img { .lightbox img {
max-width: 90%; max-width: 90%;
max-height: 90%; max-height: 90%;
filter: drop-shadow(5px 5px 10px #222); filter: drop-shadow(5px 5px 10px #222);
border-radius: 5px; border-radius: 5px;
} }
.lightbox .close-lightbox { .lightbox .close-lightbox {
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
top: 30px; top: 30px;
right: 30px; right: 30px;
width: 20px; width: 20px;
height: 20px; height: 20px;
} }
.lightbox .close-lightbox::after, .lightbox .close-lightbox::after,
.lightbox .close-lightbox::before { .lightbox .close-lightbox::before {
content: ''; content: "";
width: 3px; width: 3px;
height: 20px; height: 20px;
background-color: #ddd; background-color: #ddd;
position: absolute; position: absolute;
border-radius: 5px; border-radius: 5px;
transform: rotate(45deg); transform: rotate(45deg);
} }
.lightbox .close-lightbox::before { .lightbox .close-lightbox::before {
transform: rotate(-45deg); transform: rotate(-45deg);
} }
.lightbox .close-lightbox:hover::after, .lightbox .close-lightbox:hover::after,
.lightbox .close-lightbox:hover::before { .lightbox .close-lightbox:hover::before {
background-color: #fff; background-color: #fff;
} }

View file

@ -1,99 +1,109 @@
// Link tabs, as per https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/#linked-tabs // Link tabs, as per https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/#linked-tabs
const savedCodeTab = localStorage.getItem('savedTab') const savedCodeTab = localStorage.getItem("savedTab");
const codeTabs = document.querySelectorAll(".tabbed-set > input") const codeTabs = document.querySelectorAll(".tabbed-set > input");
for (const tab of codeTabs) { for (const tab of codeTabs) {
tab.addEventListener("click", () => { tab.addEventListener("click", () => {
const current = document.querySelector(`label[for=${tab.id}]`) const current = document.querySelector(`label[for=${tab.id}]`);
const pos = current.getBoundingClientRect().top const pos = current.getBoundingClientRect().top;
const labelContent = current.innerHTML const labelContent = current.innerHTML;
const labels = document.querySelectorAll('.tabbed-set > label, .tabbed-alternate > .tabbed-labels > label') const labels = document.querySelectorAll(
for (const label of labels) { ".tabbed-set > label, .tabbed-alternate > .tabbed-labels > label",
if (label.innerHTML === labelContent) { );
document.querySelector(`input[id=${label.getAttribute('for')}]`).checked = true for (const label of labels) {
} if (label.innerHTML === labelContent) {
} document.querySelector(
`input[id=${label.getAttribute("for")}]`,
// Preserve scroll position ).checked = true;
const delta = (current.getBoundingClientRect().top) - pos }
window.scrollBy(0, delta)
// Save
localStorage.setItem('savedTab', labelContent)
})
// Select saved tab
const current = document.querySelector(`label[for=${tab.id}]`)
const labelContent = current.innerHTML
if (savedCodeTab === labelContent) {
tab.checked = true
} }
// Preserve scroll position
const delta = current.getBoundingClientRect().top - pos;
window.scrollBy(0, delta);
// Save
localStorage.setItem("savedTab", labelContent);
});
// Select saved tab
const current = document.querySelector(`label[for=${tab.id}]`);
const labelContent = current.innerHTML;
if (savedCodeTab === labelContent) {
tab.checked = true;
}
} }
// Lightbox for screenshot // Lightbox for screenshot
const lightbox = document.createElement('div'); const lightbox = document.createElement("div");
lightbox.classList.add('lightbox'); lightbox.classList.add("lightbox");
document.body.appendChild(lightbox); document.body.appendChild(lightbox);
const showScreenshotOverlay = (e, el, group, index) => { const showScreenshotOverlay = (e, el, group, index) => {
lightbox.classList.add('show'); lightbox.classList.add("show");
document.addEventListener('keydown', nextScreenshotKeyboardListener); document.addEventListener("keydown", nextScreenshotKeyboardListener);
return showScreenshot(e, group, index); return showScreenshot(e, group, index);
}; };
const showScreenshot = (e, group, index) => { const showScreenshot = (e, group, index) => {
const actualIndex = resolveScreenshotIndex(group, index); const actualIndex = resolveScreenshotIndex(group, index);
lightbox.innerHTML = '<div class="close-lightbox"></div>' + screenshots[group][actualIndex].innerHTML; lightbox.innerHTML =
lightbox.querySelector('img').onclick = (e) => { return showScreenshot(e, group, actualIndex+1); }; '<div class="close-lightbox"></div>' +
currentScreenshotGroup = group; screenshots[group][actualIndex].innerHTML;
currentScreenshotIndex = actualIndex; lightbox.querySelector("img").onclick = (e) => {
e.stopPropagation(); return showScreenshot(e, group, actualIndex + 1);
return false; };
currentScreenshotGroup = group;
currentScreenshotIndex = actualIndex;
e.stopPropagation();
return false;
}; };
const nextScreenshot = (e) => { const nextScreenshot = (e) => {
return showScreenshot(e, currentScreenshotGroup, currentScreenshotIndex+1); return showScreenshot(e, currentScreenshotGroup, currentScreenshotIndex + 1);
}; };
const previousScreenshot = (e) => { const previousScreenshot = (e) => {
return showScreenshot(e, currentScreenshotGroup, currentScreenshotIndex-1); return showScreenshot(e, currentScreenshotGroup, currentScreenshotIndex - 1);
}; };
const resolveScreenshotIndex = (group, index) => { const resolveScreenshotIndex = (group, index) => {
if (index < 0) { if (index < 0) {
return screenshots[group].length - 1; return screenshots[group].length - 1;
} else if (index > screenshots[group].length - 1) { } else if (index > screenshots[group].length - 1) {
return 0; return 0;
} }
return index; return index;
}; };
const hideScreenshotOverlay = (e) => { const hideScreenshotOverlay = (e) => {
lightbox.classList.remove('show'); lightbox.classList.remove("show");
document.removeEventListener('keydown', nextScreenshotKeyboardListener); document.removeEventListener("keydown", nextScreenshotKeyboardListener);
}; };
const nextScreenshotKeyboardListener = (e) => { const nextScreenshotKeyboardListener = (e) => {
switch (e.keyCode) { switch (e.keyCode) {
case 37: case 37:
previousScreenshot(e); previousScreenshot(e);
break; break;
case 39: case 39:
nextScreenshot(e); nextScreenshot(e);
break; break;
} }
}; };
let currentScreenshotGroup = ''; let currentScreenshotGroup = "";
let currentScreenshotIndex = 0; let currentScreenshotIndex = 0;
let screenshots = {}; let screenshots = {};
Array.from(document.getElementsByClassName('screenshots')).forEach((sg) => { Array.from(document.getElementsByClassName("screenshots")).forEach((sg) => {
const group = sg.id; const group = sg.id;
screenshots[group] = [...sg.querySelectorAll('a')]; screenshots[group] = [...sg.querySelectorAll("a")];
screenshots[group].forEach((el, index) => { screenshots[group].forEach((el, index) => {
el.onclick = (e) => { return showScreenshotOverlay(e, el, group, index); }; el.onclick = (e) => {
}); return showScreenshotOverlay(e, el, group, index);
};
});
}); });
lightbox.onclick = hideScreenshotOverlay; lightbox.onclick = hideScreenshotOverlay;

View file

@ -1,14 +1,14 @@
# Subscribe via API # Subscribe via API
You can create and subscribe to a topic in the [web UI](web.md), via the [phone app](phone.md), via the [ntfy CLI](cli.md), You can create and subscribe to a topic in the [web UI](web.md), via the [phone app](phone.md), via the [ntfy CLI](cli.md),
or in your own app or script by subscribing the API. This page describes how to subscribe via API. You may also want to or in your own app or script by subscribing the API. This page describes how to subscribe via API. You may also want to
check out the page that describes how to [publish messages](../publish.md). check out the page that describes how to [publish messages](../publish.md).
You can consume the subscription API as either a **[simple HTTP stream (JSON, SSE or raw)](#http-stream)**, or You can consume the subscription API as either a **[simple HTTP stream (JSON, SSE or raw)](#http-stream)**, or
**[via WebSockets](#websockets)**. Both are incredibly simple to use. **[via WebSockets](#websockets)**. Both are incredibly simple to use.
## HTTP stream ## HTTP stream
The HTTP stream-based API relies on a simple GET request with a streaming HTTP response, i.e **you open a GET request and The HTTP stream-based API relies on a simple GET request with a streaming HTTP response, i.e **you open a GET request and
the connection stays open forever**, sending messages back as they come in. There are three different API endpoints, which the connection stays open forever**, sending messages back as they come in. There are three different API endpoints, which
only differ in the response format: only differ in the response format:
* [JSON stream](#subscribe-as-json-stream): `<topic>/json` returns a JSON stream, with one JSON message object per line * [JSON stream](#subscribe-as-json-stream): `<topic>/json` returns a JSON stream, with one JSON message object per line
@ -17,8 +17,8 @@ only differ in the response format:
* [Raw stream](#subscribe-as-raw-stream): `<topic>/raw` returns messages as raw text, with one line per message * [Raw stream](#subscribe-as-raw-stream): `<topic>/raw` returns messages as raw text, with one line per message
### Subscribe as JSON stream ### Subscribe as JSON stream
Here are a few examples of how to consume the JSON endpoint (`<topic>/json`). For almost all languages, **this is the Here are a few examples of how to consume the JSON endpoint (`<topic>/json`). For almost all languages, **this is the
recommended way to subscribe to a topic**. The notable exception is JavaScript, for which the recommended way to subscribe to a topic**. The notable exception is JavaScript, for which the
[SSE/EventSource stream](#subscribe-as-sse-stream) is much easier to work with. [SSE/EventSource stream](#subscribe-as-sse-stream) is much easier to work with.
=== "Command line (curl)" === "Command line (curl)"
@ -45,7 +45,7 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
HTTP/1.1 200 OK HTTP/1.1 200 OK
Content-Type: application/x-ndjson; charset=utf-8 Content-Type: application/x-ndjson; charset=utf-8
Transfer-Encoding: chunked Transfer-Encoding: chunked
{"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"} {"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"}
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Disk full"} {"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Disk full"}
{"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"} {"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"}
@ -86,7 +86,7 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
### Subscribe as SSE stream ### Subscribe as SSE stream
Using [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) in JavaScript, you can consume Using [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) in JavaScript, you can consume
notifications via a [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events) stream. It's incredibly notifications via a [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events) stream. It's incredibly
easy to use. Here's what it looks like. You may also want to check out the [full example on GitHub](https://github.com/binwiederhier/ntfy/tree/main/examples/web-example-eventsource). easy to use. Here's what it looks like. You may also want to check out the [full example on GitHub](https://github.com/binwiederhier/ntfy/tree/main/examples/web-example-eventsource).
=== "Command line (curl)" === "Command line (curl)"
@ -94,9 +94,9 @@ easy to use. Here's what it looks like. You may also want to check out the [full
$ curl -s ntfy.sh/mytopic/sse $ curl -s ntfy.sh/mytopic/sse
event: open event: open
data: {"id":"weSj9RtNkj","time":1635528898,"event":"open","topic":"mytopic"} data: {"id":"weSj9RtNkj","time":1635528898,"event":"open","topic":"mytopic"}
data: {"id":"p0M5y6gcCY","time":1635528909,"event":"message","topic":"mytopic","message":"Hi!"} data: {"id":"p0M5y6gcCY","time":1635528909,"event":"message","topic":"mytopic","message":"Hi!"}
event: keepalive event: keepalive
data: {"id":"VNxNIg5fpt","time":1635528928,"event":"keepalive","topic":"test"} data: {"id":"VNxNIg5fpt","time":1635528928,"event":"keepalive","topic":"test"}
... ...
@ -113,9 +113,9 @@ easy to use. Here's what it looks like. You may also want to check out the [full
event: open event: open
data: {"id":"weSj9RtNkj","time":1635528898,"event":"open","topic":"mytopic"} data: {"id":"weSj9RtNkj","time":1635528898,"event":"open","topic":"mytopic"}
data: {"id":"p0M5y6gcCY","time":1635528909,"event":"message","topic":"mytopic","message":"Hi!"} data: {"id":"p0M5y6gcCY","time":1635528909,"event":"message","topic":"mytopic","message":"Hi!"}
event: keepalive event: keepalive
data: {"id":"VNxNIg5fpt","time":1635528928,"event":"keepalive","topic":"test"} data: {"id":"VNxNIg5fpt","time":1635528928,"event":"keepalive","topic":"test"}
... ...
@ -131,14 +131,14 @@ easy to use. Here's what it looks like. You may also want to check out the [full
### Subscribe as raw stream ### Subscribe as raw stream
The `/raw` endpoint will output one line per message, and **will only include the message body**. It's useful for extremely The `/raw` endpoint will output one line per message, and **will only include the message body**. It's useful for extremely
simple scripts, and doesn't include all the data. Additional fields such as [priority](../publish.md#message-priority), simple scripts, and doesn't include all the data. Additional fields such as [priority](../publish.md#message-priority),
[tags](../publish.md#tags--emojis--) or [message title](../publish.md#message-title) are not included in this output [tags](../publish.md#tags--emojis--) or [message title](../publish.md#message-title) are not included in this output
format. Keepalive messages are sent as empty lines. format. Keepalive messages are sent as empty lines.
=== "Command line (curl)" === "Command line (curl)"
``` ```
$ curl -s ntfy.sh/disk-alerts/raw $ curl -s ntfy.sh/disk-alerts/raw
Disk full Disk full
... ...
``` ```
@ -170,7 +170,7 @@ format. Keepalive messages are sent as empty lines.
``` ```
=== "Python" === "Python"
``` python ``` python
resp = requests.get("https://ntfy.sh/disk-alerts/raw", stream=True) resp = requests.get("https://ntfy.sh/disk-alerts/raw", stream=True)
for line in resp.iter_lines(): for line in resp.iter_lines():
if line: if line:
@ -189,13 +189,13 @@ format. Keepalive messages are sent as empty lines.
``` ```
## WebSockets ## WebSockets
You may also subscribe to topics via [WebSockets](https://en.wikipedia.org/wiki/WebSocket), which is also widely You may also subscribe to topics via [WebSockets](https://en.wikipedia.org/wiki/WebSocket), which is also widely
supported in many languages. Most notably, WebSockets are natively supported in JavaScript. On the command line, supported in many languages. Most notably, WebSockets are natively supported in JavaScript. On the command line,
I recommend [websocat](https://github.com/vi/websocat), a fantastic tool similar to `socat` or `curl`, but specifically I recommend [websocat](https://github.com/vi/websocat), a fantastic tool similar to `socat` or `curl`, but specifically
for WebSockets. for WebSockets.
The WebSockets endpoint is available at `<topic>/ws` and returns messages as JSON objects similar to the The WebSockets endpoint is available at `<topic>/ws` and returns messages as JSON objects similar to the
[JSON stream endpoint](#subscribe-as-json-stream). [JSON stream endpoint](#subscribe-as-json-stream).
=== "Command line (websocat)" === "Command line (websocat)"
``` ```
@ -246,7 +246,7 @@ curl -s "ntfy.sh/mytopic/json?poll=1"
### Fetch cached messages ### Fetch cached messages
Messages may be cached for a couple of hours (see [message caching](../config.md#message-cache)) to account for network Messages may be cached for a couple of hours (see [message caching](../config.md#message-cache)) to account for network
interruptions of subscribers. If the server has configured message caching, you can read back what you missed by using interruptions of subscribers. If the server has configured message caching, you can read back what you missed by using
the `since=` query parameter. It takes a duration (e.g. `10m` or `30s`), a Unix timestamp (e.g. `1635528757`), the `since=` query parameter. It takes a duration (e.g. `10m` or `30s`), a Unix timestamp (e.g. `1635528757`),
a message ID (e.g. `nFS3knfcQ1xe`), or `all` (all cached messages). a message ID (e.g. `nFS3knfcQ1xe`), or `all` (all cached messages).
@ -257,9 +257,9 @@ curl -s "ntfy.sh/mytopic/json?since=nFS3knfcQ1xe"
``` ```
### Fetch scheduled messages ### Fetch scheduled messages
Messages that are [scheduled to be delivered](../publish.md#scheduled-delivery) at a later date are not typically Messages that are [scheduled to be delivered](../publish.md#scheduled-delivery) at a later date are not typically
returned when subscribing via the API, which makes sense, because after all, the messages have technically not been returned when subscribing via the API, which makes sense, because after all, the messages have technically not been
delivered yet. To also return scheduled messages from the API, you can use the `scheduled=1` (alias: `sched=1`) delivered yet. To also return scheduled messages from the API, you can use the `scheduled=1` (alias: `sched=1`)
parameter (makes most sense with the `poll=1` parameter): parameter (makes most sense with the `poll=1` parameter):
``` ```
@ -268,8 +268,8 @@ curl -s "ntfy.sh/mytopic/json?poll=1&sched=1"
### Filter messages ### Filter messages
You can filter which messages are returned based on the well-known message fields `id`, `message`, `title`, `priority` and You can filter which messages are returned based on the well-known message fields `id`, `message`, `title`, `priority` and
`tags`. Here's an example that only returns messages of high or urgent priority that contains the both tags `tags`. Here's an example that only returns messages of high or urgent priority that contains the both tags
"zfs-error" and "error". Note that the `priority` filter is a logical OR and the `tags` filter is a logical AND. "zfs-error" and "error". Note that the `priority` filter is a logical OR and the `tags` filter is a logical AND.
``` ```
$ curl "ntfy.sh/alerts/json?priority=high&tags=zfs-error" $ curl "ntfy.sh/alerts/json?priority=high&tags=zfs-error"
@ -289,7 +289,7 @@ Available filters (all case-insensitive):
| `tags` | `X-Tags`, `tag`, `ta` | `ntfy.sh/mytopic?/jsontags=error,alert` | Only return messages that match *all listed tags* (comma-separated) | | `tags` | `X-Tags`, `tag`, `ta` | `ntfy.sh/mytopic?/jsontags=error,alert` | Only return messages that match *all listed tags* (comma-separated) |
### Subscribe to multiple topics ### Subscribe to multiple topics
It's possible to subscribe to multiple topics in one HTTP call by providing a comma-separated list of topics It's possible to subscribe to multiple topics in one HTTP call by providing a comma-separated list of topics
in the URL. This allows you to reduce the number of connections you have to maintain: in the URL. This allows you to reduce the number of connections you have to maintain:
``` ```
@ -318,7 +318,7 @@ format of the message. It's very straight forward:
| Field | Required | Type | Example | Description | | Field | Required | Type | Example | Description |
|--------------|----------|---------------------------------------------------|-------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------| |--------------|----------|---------------------------------------------------|-------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
| `id` | ✔️ | *string* | `hwQ2YpKdmg` | Randomly chosen message identifier | | `id` | ✔️ | *string* | `hwQ2YpKdmg` | Randomly chosen message identifier |
| `time` | ✔️ | *number* | `1635528741` | Message date time, as Unix time stamp | | `time` | ✔️ | *number* | `1635528741` | Message date time, as Unix time stamp |
| `event` | ✔️ | `open`, `keepalive`, `message`, or `poll_request` | `message` | Message type, typically you'd be only interested in `message` | | `event` | ✔️ | `open`, `keepalive`, `message`, or `poll_request` | `message` | Message type, typically you'd be only interested in `message` |
| `topic` | ✔️ | *string* | `topic1,topic2` | Comma-separated list of topics the message is associated with; only one for all `message` events, but may be a list in `open` events | | `topic` | ✔️ | *string* | `topic1,topic2` | Comma-separated list of topics the message is associated with; only one for all `message` events, but may be a list in `open` events |
| `message` | - | *string* | `Some message` | Message body; always present in `message` events | | `message` | - | *string* | `Some message` | Message body; always present in `message` events |
@ -334,7 +334,7 @@ format of the message. It's very straight forward:
| Field | Required | Type | Example | Description | | Field | Required | Type | Example | Description |
|-----------|----------|-------------|--------------------------------|-----------------------------------------------------------------------------------------------------------| |-----------|----------|-------------|--------------------------------|-----------------------------------------------------------------------------------------------------------|
| `name` | ✔️ | *string* | `attachment.jpg` | Name of the attachment, can be overridden with `X-Filename`, see [attachments](../publish.md#attachments) | | `name` | ✔️ | *string* | `attachment.jpg` | Name of the attachment, can be overridden with `X-Filename`, see [attachments](../publish.md#attachments) |
| `url` | ✔️ | *URL* | `https://example.com/file.jpg` | URL of the attachment | | `url` | ✔️ | *URL* | `https://example.com/file.jpg` | URL of the attachment |
| `type` | - | *mime type* | `image/jpeg` | Mime type of the attachment, only defined if attachment was uploaded to ntfy server | | `type` | - | *mime type* | `image/jpeg` | Mime type of the attachment, only defined if attachment was uploaded to ntfy server |
| `size` | - | *number* | `33848` | Size of the attachment in bytes, only defined if attachment was uploaded to ntfy server | | `size` | - | *number* | `33848` | Size of the attachment in bytes, only defined if attachment was uploaded to ntfy server |
| `expires` | - | *number* | `1635528741` | Attachment expiry date as Unix time stamp, only defined if attachment was uploaded to ntfy server | | `expires` | - | *number* | `1635528741` | Attachment expiry date as Unix time stamp, only defined if attachment was uploaded to ntfy server |
@ -396,7 +396,7 @@ Here's an example for each message type:
"event": "keepalive", "event": "keepalive",
"topic": "phil_alerts" "topic": "phil_alerts"
} }
``` ```
=== "Poll request message" === "Poll request message"
``` json ``` json

View file

@ -4,14 +4,14 @@ to topics via the ntfy CLI. The CLI is included in the same `ntfy` binary that c
!!! info !!! info
The **ntfy CLI is not required to send or receive messages**. You can instead [send messages with curl](../publish.md), The **ntfy CLI is not required to send or receive messages**. You can instead [send messages with curl](../publish.md),
and even use it to [subscribe to topics](api.md). It may be a little more convenient to use the ntfy CLI than writing and even use it to [subscribe to topics](api.md). It may be a little more convenient to use the ntfy CLI than writing
your own script. It all depends on the use case. 😀 your own script. It all depends on the use case. 😀
## Install + configure ## Install + configure
To install the ntfy CLI, simply **follow the steps outlined on the [install page](../install.md)**. The ntfy server and To install the ntfy CLI, simply **follow the steps outlined on the [install page](../install.md)**. The ntfy server and
client are the same binary, so it's all very convenient. After installing, you can (optionally) configure the client client are the same binary, so it's all very convenient. After installing, you can (optionally) configure the client
by creating `~/.config/ntfy/client.yml` (for the non-root user), or `/etc/ntfy/client.yml` (for the root user). You by creating `~/.config/ntfy/client.yml` (for the non-root user), or `/etc/ntfy/client.yml` (for the root user). You
can find a [skeleton config](https://github.com/binwiederhier/ntfy/blob/main/client/client.yml) on GitHub. can find a [skeleton config](https://github.com/binwiederhier/ntfy/blob/main/client/client.yml) on GitHub.
If you just want to use [ntfy.sh](https://ntfy.sh), you don't have to change anything. If you **self-host your own server**, If you just want to use [ntfy.sh](https://ntfy.sh), you don't have to change anything. If you **self-host your own server**,
you may want to edit the `default-host` option: you may want to edit the `default-host` option:
@ -24,7 +24,7 @@ default-host: https://ntfy.myhost.com
``` ```
## Publish messages ## Publish messages
You can send messages with the ntfy CLI using the `ntfy publish` command (or any of its aliases `pub`, `send` or You can send messages with the ntfy CLI using the `ntfy publish` command (or any of its aliases `pub`, `send` or
`trigger`). There are a lot of examples on the page about [publishing messages](../publish.md), but here are a few `trigger`). There are a lot of examples on the page about [publishing messages](../publish.md), but here are a few
quick ones: quick ones:
@ -32,7 +32,7 @@ quick ones:
``` ```
ntfy publish mytopic This is a message ntfy publish mytopic This is a message
ntfy publish mytopic "This is a message" ntfy publish mytopic "This is a message"
ntfy pub mytopic "This is a message" ntfy pub mytopic "This is a message"
``` ```
=== "Send with title, priority, and tags" === "Send with title, priority, and tags"
@ -78,7 +78,7 @@ $ ntfy pub --file README.md mytopic | jq .
``` ```
### Wait for PID/command ### Wait for PID/command
If you have a long-running command and want to **publish a notification when the command completes**, If you have a long-running command and want to **publish a notification when the command completes**,
you may wrap it with `ntfy publish --wait-cmd` (aliases: `--cmd`, `--done`). Or, if you forgot to wrap it, and the you may wrap it with `ntfy publish --wait-cmd` (aliases: `--cmd`, `--done`). Or, if you forgot to wrap it, and the
command is already running, you can wait for the process to complete with `ntfy publish --wait-pid` (alias: `--pid`). command is already running, you can wait for the process to complete with `ntfy publish --wait-pid` (alias: `--pid`).
@ -123,15 +123,15 @@ Or, if you already started the long-running process and want to wait for it usin
## Subscribe to topics ## Subscribe to topics
You can subscribe to topics using `ntfy subscribe`. Depending on how it is called, this command You can subscribe to topics using `ntfy subscribe`. Depending on how it is called, this command
will either print or execute a command for every arriving message. There are a few different ways will either print or execute a command for every arriving message. There are a few different ways
in which the command can be run: in which the command can be run:
### Stream messages as JSON ### Stream messages as JSON
``` ```
ntfy subscribe TOPIC ntfy subscribe TOPIC
``` ```
If you run the command like this, it prints the JSON representation of every incoming message. This is useful If you run the command like this, it prints the JSON representation of every incoming message. This is useful
when you have a command that wants to stream-read incoming JSON messages. Unless `--poll` is passed, this command when you have a command that wants to stream-read incoming JSON messages. Unless `--poll` is passed, this command
stays open forever. stays open forever.
``` ```
@ -152,7 +152,7 @@ ntfy subscribe TOPIC COMMAND
``` ```
If you run it like this, a COMMAND is executed for every incoming messages. Scroll down to see a list of available If you run it like this, a COMMAND is executed for every incoming messages. Scroll down to see a list of available
environment variables. Here are a few examples: environment variables. Here are a few examples:
``` ```
ntfy sub mytopic 'notify-send "$m"' ntfy sub mytopic 'notify-send "$m"'
ntfy sub topic1 /my/script.sh ntfy sub topic1 /my/script.sh
@ -164,7 +164,7 @@ ntfy sub topic1 'echo "Message $m was received. Its title was $t and it had prio
<figcaption>Execute command on incoming messages</figcaption> <figcaption>Execute command on incoming messages</figcaption>
</figure> </figure>
The message fields are passed to the command as environment variables and can be used in scripts. Note that since The message fields are passed to the command as environment variables and can be used in scripts. Note that since
these are environment variables, you typically don't have to worry about quoting too much, as long as you enclose them these are environment variables, you typically don't have to worry about quoting too much, as long as you enclose them
in double-quotes, you should be fine: in double-quotes, you should be fine:
@ -178,7 +178,7 @@ in double-quotes, you should be fine:
| `$NTFY_PRIORITY` | `$priority`, `$prio`, `$p` | Message priority (1=min, 5=max) | | `$NTFY_PRIORITY` | `$priority`, `$prio`, `$p` | Message priority (1=min, 5=max) |
| `$NTFY_TAGS` | `$tags`, `$tag`, `$ta` | Message tags (comma separated list) | | `$NTFY_TAGS` | `$tags`, `$tag`, `$ta` | Message tags (comma separated list) |
| `$NTFY_RAW` | `$raw` | Raw JSON message | | `$NTFY_RAW` | `$raw` | Raw JSON message |
### Subscribe to multiple topics ### Subscribe to multiple topics
``` ```
ntfy subscribe --from-config ntfy subscribe --from-config
@ -242,8 +242,8 @@ Here's an example config file that subscribes to three different topics, executi
In this example, when `ntfy subscribe --from-config` is executed: In this example, when `ntfy subscribe --from-config` is executed:
* Messages to `echo-this` simply echos to standard out * Messages to `echo-this` simply echos to standard out
* Messages to `alerts` display as desktop notification for high priority messages using [notify-send](https://manpages.ubuntu.com/manpages/focal/man1/notify-send.1.html) (Linux), * Messages to `alerts` display as desktop notification for high priority messages using [notify-send](https://manpages.ubuntu.com/manpages/focal/man1/notify-send.1.html) (Linux),
[notifu](https://www.paralint.com/projects/notifu/) (Windows) or `osascript` (macOS) [notifu](https://www.paralint.com/projects/notifu/) (Windows) or `osascript` (macOS)
* Messages to `calc` open the calculator 😀 (*because, why not*) * Messages to `calc` open the calculator 😀 (*because, why not*)
* Messages to `print-temp` execute an inline script and print the CPU temperature (Linux version only) * Messages to `print-temp` execute an inline script and print the CPU temperature (Linux version only)
@ -271,8 +271,8 @@ if you install the deb/rpm package. To configure it, simply edit `/etc/ntfy/clie
The `ntfy-client.service` runs as user `ntfy`, meaning that typical Linux permission restrictions apply. See below The `ntfy-client.service` runs as user `ntfy`, meaning that typical Linux permission restrictions apply. See below
for how to fix this. for how to fix this.
If the service runs on your personal desktop machine, you may want to override the service user/group (`User=` and `Group=`), and If the service runs on your personal desktop machine, you may want to override the service user/group (`User=` and `Group=`), and
adjust the `DISPLAY` and `DBUS_SESSION_BUS_ADDRESS` environment variables. This will allow you to run commands in your X session adjust the `DISPLAY` and `DBUS_SESSION_BUS_ADDRESS` environment variables. This will allow you to run commands in your X session
as the primary machine user. as the primary machine user.
You can either manually override these systemd service entries with `sudo systemctl edit ntfy-client`, and add this You can either manually override these systemd service entries with `sudo systemctl edit ntfy-client`, and add this
@ -306,7 +306,7 @@ Depending on whether the server is configured to support [access control](../con
may be read/write protected so that only users with the correct credentials can subscribe or publish to them. may be read/write protected so that only users with the correct credentials can subscribe or publish to them.
To publish/subscribe to protected topics, you can use [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication) To publish/subscribe to protected topics, you can use [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication)
with a valid username/password. For your self-hosted server, **be sure to use HTTPS to avoid eavesdropping** and exposing with a valid username/password. For your self-hosted server, **be sure to use HTTPS to avoid eavesdropping** and exposing
your password. your password.
You can either add your username and password to the configuration file: You can either add your username and password to the configuration file:
=== "~/.config/ntfy/client.yml" === "~/.config/ntfy/client.yml"

View file

@ -1,14 +1,14 @@
# Subscribe from your phone # Subscribe from your phone
You can use the ntfy [Android App](https://play.google.com/store/apps/details?id=io.heckel.ntfy) or [iOS app](https://apps.apple.com/us/app/ntfy/id1625396347) You can use the ntfy [Android App](https://play.google.com/store/apps/details?id=io.heckel.ntfy) or [iOS app](https://apps.apple.com/us/app/ntfy/id1625396347)
to receive notifications directly on your phone. Just like the server, this app is also open source, and the code is available to receive notifications directly on your phone. Just like the server, this app is also open source, and the code is available
on GitHub ([Android](https://github.com/binwiederhier/ntfy-android), [iOS](https://github.com/binwiederhier/ntfy-ios)). Feel free to on GitHub ([Android](https://github.com/binwiederhier/ntfy-android), [iOS](https://github.com/binwiederhier/ntfy-ios)). Feel free to
contribute, or [build your own](../develop.md). contribute, or [build your own](../develop.md).
<a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img src="../../static/img/badge-googleplay.png"></a> <a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img src="../../static/img/badge-googleplay.png"></a>
<a href="https://f-droid.org/en/packages/io.heckel.ntfy/"><img src="../../static/img/badge-fdroid.png"></a> <a href="https://f-droid.org/en/packages/io.heckel.ntfy/"><img src="../../static/img/badge-fdroid.png"></a>
<a href="https://apps.apple.com/us/app/ntfy/id1625396347"><img src="../../static/img/badge-appstore.png"></a> <a href="https://apps.apple.com/us/app/ntfy/id1625396347"><img src="../../static/img/badge-appstore.png"></a>
You can get the Android app from both [Google Play](https://play.google.com/store/apps/details?id=io.heckel.ntfy) and You can get the Android app from both [Google Play](https://play.google.com/store/apps/details?id=io.heckel.ntfy) and
from [F-Droid](https://f-droid.org/en/packages/io.heckel.ntfy/). Both are largely identical, with the one exception that from [F-Droid](https://f-droid.org/en/packages/io.heckel.ntfy/). Both are largely identical, with the one exception that
the F-Droid flavor does not use Firebase. The iOS app can be downloaded from the [App Store](https://apps.apple.com/us/app/ntfy/id1625396347). the F-Droid flavor does not use Firebase. The iOS app can be downloaded from the [App Store](https://apps.apple.com/us/app/ntfy/id1625396347).
@ -65,8 +65,8 @@ setting, and other settings such as popover or notification dot:
## Instant delivery ## Instant delivery
_Supported on:_ :material-android: _Supported on:_ :material-android:
Instant delivery allows you to receive messages on your phone instantly, **even when your phone is in doze mode**, i.e. Instant delivery allows you to receive messages on your phone instantly, **even when your phone is in doze mode**, i.e.
when the screen turns off, and you leave it on the desk for a while. This is achieved with a foreground service, which when the screen turns off, and you leave it on the desk for a while. This is achieved with a foreground service, which
you'll see as a permanent notification that looks like this: you'll see as a permanent notification that looks like this:
<figure markdown> <figure markdown>
@ -75,7 +75,7 @@ you'll see as a permanent notification that looks like this:
</figure> </figure>
Android does not allow you to dismiss this notification, unless you turn off the notification channel in the settings. Android does not allow you to dismiss this notification, unless you turn off the notification channel in the settings.
To do so, long-press on the foreground notification (screenshot above) and navigate to the settings. Then toggle the To do so, long-press on the foreground notification (screenshot above) and navigate to the settings. Then toggle the
"Subscription Service" off: "Subscription Service" off:
<figure markdown> <figure markdown>
@ -83,12 +83,12 @@ To do so, long-press on the foreground notification (screenshot above) and navig
<figcaption>Turning off the persistent instant delivery notification</figcaption> <figcaption>Turning off the persistent instant delivery notification</figcaption>
</figure> </figure>
**Limitations without instant delivery**: Without instant delivery, **messages may arrive with a significant delay** **Limitations without instant delivery**: Without instant delivery, **messages may arrive with a significant delay**
(sometimes many minutes, or even hours later). If you've ever picked up your phone and (sometimes many minutes, or even hours later). If you've ever picked up your phone and
suddenly had 10 messages that were sent long before you know what I'm talking about. suddenly had 10 messages that were sent long before you know what I'm talking about.
The reason for this is [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging). FCM is the The reason for this is [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging). FCM is the
*only* Google approved way to send push messages to Android devices, and it's what pretty much all apps use to deliver push *only* Google approved way to send push messages to Android devices, and it's what pretty much all apps use to deliver push
notifications. Firebase is overall pretty bad at delivering messages in time, but on Android, most apps are stuck with it. notifications. Firebase is overall pretty bad at delivering messages in time, but on Android, most apps are stuck with it.
The ntfy Android app uses Firebase only for the main host `ntfy.sh`, and only in the Google Play flavor of the app. The ntfy Android app uses Firebase only for the main host `ntfy.sh`, and only in the Google Play flavor of the app.
@ -113,10 +113,10 @@ _Supported on:_ :material-android:
The ntfy Android app supports deep linking directly to topics. This is useful when integrating with [automation apps](#automation-apps) The ntfy Android app supports deep linking directly to topics. This is useful when integrating with [automation apps](#automation-apps)
such as [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid) or [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm), such as [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid) or [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm),
or to simply directly link to a topic from a mobile website. or to simply directly link to a topic from a mobile website.
!!! info !!! info
Android deep linking of http/https links is very brittle and limited, which is why something like `https://<host>/<topic>/subscribe` is Android deep linking of http/https links is very brittle and limited, which is why something like `https://<host>/<topic>/subscribe` is
**not possible**, and instead `ntfy://` links have to be used. More details in [issue #20](https://github.com/binwiederhier/ntfy/issues/20). **not possible**, and instead `ntfy://` links have to be used. More details in [issue #20](https://github.com/binwiederhier/ntfy/issues/20).
**Supported link formats:** **Supported link formats:**
@ -132,10 +132,10 @@ or to simply directly link to a topic from a mobile website.
_Supported on:_ :material-android: _Supported on:_ :material-android:
[UnifiedPush](https://unifiedpush.org) is a standard for receiving push notifications without using the Google-owned [UnifiedPush](https://unifiedpush.org) is a standard for receiving push notifications without using the Google-owned
[Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) service. It puts push notifications [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) service. It puts push notifications
in the control of the user. ntfy can act as a **UnifiedPush distributor**, forwarding messages to apps that support it. in the control of the user. ntfy can act as a **UnifiedPush distributor**, forwarding messages to apps that support it.
To use ntfy as a distributor, simply select it in one of the [supported apps](https://unifiedpush.org/users/apps/). To use ntfy as a distributor, simply select it in one of the [supported apps](https://unifiedpush.org/users/apps/).
That's it. It's a one-step installation 😀. If desired, you can select your own [selfhosted ntfy server](../install.md) That's it. It's a one-step installation 😀. If desired, you can select your own [selfhosted ntfy server](../install.md)
to handle messages. Here's an example with [FluffyChat](https://fluffychat.im/): to handle messages. Here's an example with [FluffyChat](https://fluffychat.im/):
@ -156,7 +156,7 @@ or [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.
To react on incoming notifications, you have to register to intents with the `io.heckel.ntfy.MESSAGE_RECEIVED` action (see To react on incoming notifications, you have to register to intents with the `io.heckel.ntfy.MESSAGE_RECEIVED` action (see
[code for details](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt)). [code for details](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt)).
Here's an example using [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid) Here's an example using [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid)
and [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm), but any app that can catch and [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm), but any app that can catch
broadcasts is supported: broadcasts is supported:
<div id="integration-screenshots-receive" class="screenshots"> <div id="integration-screenshots-receive" class="screenshots">
@ -170,7 +170,7 @@ broadcasts is supported:
</div> </div>
For MacroDroid, be sure to type in the package name `io.heckel.ntfy`, otherwise intents may be silently swallowed. For MacroDroid, be sure to type in the package name `io.heckel.ntfy`, otherwise intents may be silently swallowed.
If you're using topics to drive automation, you'll likely want to mute the topic in the ntfy app. This will prevent If you're using topics to drive automation, you'll likely want to mute the topic in the ntfy app. This will prevent
notification popups: notification popups:
<figure markdown> <figure markdown>
@ -204,10 +204,10 @@ Here's a list of extras you can access. Most likely, you'll want to filter for `
#### Send messages using intents #### Send messages using intents
To send messages from other apps (such as [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid) To send messages from other apps (such as [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid)
and [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm)), you can and [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm)), you can
broadcast an intent with the `io.heckel.ntfy.SEND_MESSAGE` action. The ntfy Android app will forward the intent as a HTTP broadcast an intent with the `io.heckel.ntfy.SEND_MESSAGE` action. The ntfy Android app will forward the intent as a HTTP
POST request to [publish a message](../publish.md). This is primarily useful for apps that do not support HTTP POST/PUT POST request to [publish a message](../publish.md). This is primarily useful for apps that do not support HTTP POST/PUT
(like MacroDroid). In Tasker, you can simply use the "HTTP Request" action, which is a little easier and also works if (like MacroDroid). In Tasker, you can simply use the "HTTP Request" action, which is a little easier and also works if
ntfy is not installed. ntfy is not installed.
Here's what that looks like: Here's what that looks like:

View file

@ -1,12 +1,12 @@
# Subscribe from the Web UI # Subscribe from the Web UI
You can use the Web UI to subscribe to topics as well. If you do, and you keep the website open, **notifications will You can use the Web UI to subscribe to topics as well. If you do, and you keep the website open, **notifications will
pop up as desktop notifications**. Simply type in the topic name and click the *Subscribe* button. The browser will pop up as desktop notifications**. Simply type in the topic name and click the *Subscribe* button. The browser will
keep a connection open and listen for incoming notifications. keep a connection open and listen for incoming notifications.
To learn how to send messages, check out the [publishing page](../publish.md). To learn how to send messages, check out the [publishing page](../publish.md).
<div id="web-screenshots" class="screenshots"> <div id="web-screenshots" class="screenshots">
<a href="../../static/img/web-detail.png"><img src="../../static/img/web-detail.png"/></a> <a href="../../static/img/web-detail.png"><img src="../../static/img/web-detail.png"/></a>
<a href="../../static/img/web-notification.png"><img src="../../static/img/web-notification.png"/></a> <a href="../../static/img/web-notification.png"><img src="../../static/img/web-notification.png"/></a>
<a href="../../static/img/web-subscribe.png"><img src="../../static/img/web-subscribe.png"/></a> <a href="../../static/img/web-subscribe.png"><img src="../../static/img/web-subscribe.png"/></a>
</div> </div>

View file

@ -1,56 +1,64 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<title>ntfy.sh: EventSource Example</title> <title>ntfy.sh: EventSource Example</title>
<meta name="robots" content="noindex, nofollow" /> <meta name="robots" content="noindex, nofollow" />
<style> <style>
body { font-size: 1.2em; line-height: 130%; } body {
#events { font-family: monospace; } font-size: 1.2em;
line-height: 130%;
}
#events {
font-family: monospace;
}
</style> </style>
</head> </head>
<body> <body>
<h1>ntfy.sh: EventSource Example</h1> <h1>ntfy.sh: EventSource Example</h1>
<p> <p>
This is an example showing how to use <a href="https://ntfy.sh">ntfy.sh</a> with This is an example showing how to use
<a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource">EventSource</a>.<br/> <a href="https://ntfy.sh">ntfy.sh</a> with
This example doesn't need a server. You can just save the HTML page and run it from anywhere. <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource"
</p> >EventSource</a
<button id="publishButton">Send test notification</button> >.<br />
<p><b>Log:</b></p> This example doesn't need a server. You can just save the HTML page and
<div id="events"></div> run it from anywhere.
</p>
<button id="publishButton">Send test notification</button>
<p><b>Log:</b></p>
<div id="events"></div>
<script type="text/javascript"> <script type="text/javascript">
const publishURL = `https://ntfy.sh/example`; const publishURL = `https://ntfy.sh/example`;
const subscribeURL = `https://ntfy.sh/example/sse`; const subscribeURL = `https://ntfy.sh/example/sse`;
const events = document.getElementById('events'); const events = document.getElementById("events");
const eventSource = new EventSource(subscribeURL); const eventSource = new EventSource(subscribeURL);
// Publish button // Publish button
document.getElementById("publishButton").onclick = () => { document.getElementById("publishButton").onclick = () => {
fetch(publishURL, { fetch(publishURL, {
method: 'POST', // works with PUT as well, though that sends an OPTIONS request too! method: "POST", // works with PUT as well, though that sends an OPTIONS request too!
body: `It is ${new Date().toString()}. This is a test.` body: `It is ${new Date().toString()}. This is a test.`,
}) });
}; };
// Incoming events // Incoming events
eventSource.onopen = () => { eventSource.onopen = () => {
let event = document.createElement('div'); let event = document.createElement("div");
event.innerHTML = `EventSource connected to ${subscribeURL}`; event.innerHTML = `EventSource connected to ${subscribeURL}`;
events.appendChild(event); events.appendChild(event);
}; };
eventSource.onerror = (e) => { eventSource.onerror = (e) => {
let event = document.createElement('div'); let event = document.createElement("div");
event.innerHTML = `EventSource error: Failed to connect to ${subscribeURL}`; event.innerHTML = `EventSource error: Failed to connect to ${subscribeURL}`;
events.appendChild(event); events.appendChild(event);
}; };
eventSource.onmessage = (e) => { eventSource.onmessage = (e) => {
let event = document.createElement('div'); let event = document.createElement("div");
event.innerHTML = e.data; event.innerHTML = e.data;
events.appendChild(event); events.appendChild(event);
}; };
</script> </script>
</body>
</body>
</html> </html>

View file

@ -2,10 +2,11 @@ package main
import ( import (
"fmt" "fmt"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/cmd"
"os" "os"
"runtime" "runtime"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/cmd"
) )
var ( var (

View file

@ -15,12 +15,12 @@ theme:
include_search_page: false include_search_page: false
search_index_only: true search_index_only: true
palette: palette:
- media: "(prefers-color-scheme: light)" # Light mode - media: "(prefers-color-scheme: light)" # Light mode
scheme: default scheme: default
toggle: toggle:
icon: material/lightbulb-outline icon: material/lightbulb-outline
name: Switch to dark mode name: Switch to dark mode
- media: "(prefers-color-scheme: dark)" # Dark mode - media: "(prefers-color-scheme: dark)" # Dark mode
scheme: slate scheme: slate
accent: indigo accent: indigo
toggle: toggle:
@ -71,26 +71,24 @@ plugins:
minify_html: true minify_html: true
nav: nav:
- "Getting started": index.md - "Getting started": index.md
- "Publishing": - "Publishing":
- "Sending messages": publish.md - "Sending messages": publish.md
- "Subscribing": - "Subscribing":
- "From your phone": subscribe/phone.md - "From your phone": subscribe/phone.md
- "From the Web UI": subscribe/web.md - "From the Web UI": subscribe/web.md
- "From the CLI": subscribe/cli.md - "From the CLI": subscribe/cli.md
- "Using the API": subscribe/api.md - "Using the API": subscribe/api.md
- "Self-hosting": - "Self-hosting":
- "Installation": install.md - "Installation": install.md
- "Configuration": config.md - "Configuration": config.md
- "Other things": - "Other things":
- "FAQs": faq.md - "FAQs": faq.md
- "Examples": examples.md - "Examples": examples.md
- "Integrations + projects": integrations.md - "Integrations + projects": integrations.md
- "Release notes": releases.md - "Release notes": releases.md
- "Emojis 🥳 🎉": emojis.md - "Emojis 🥳 🎉": emojis.md
- "Known issues": known-issues.md - "Known issues": known-issues.md
- "Deprecation notices": deprecations.md - "Deprecation notices": deprecations.md
- "Development": develop.md - "Development": develop.md
- "Privacy policy": privacy.md - "Privacy policy": privacy.md

File diff suppressed because it is too large Load diff

View file

@ -7,4 +7,3 @@ if [ "$1" = "purge" ] || [ "$1" = "0" ]; then
rm -f /etc/ntfy/server.yml /etc/ntfy/client.yml rm -f /etc/ntfy/server.yml /etc/ntfy/client.yml
rmdir /etc/ntfy || true rmdir /etc/ntfy || true
fi fi

View file

@ -4,10 +4,11 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"heckel.io/ntfy/util"
"regexp" "regexp"
"strings" "strings"
"unicode/utf8" "unicode/utf8"
"heckel.io/ntfy/util"
) )
const ( const (

View file

@ -1,8 +1,9 @@
package server package server
import ( import (
"github.com/stretchr/testify/require"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestParseActions(t *testing.T) { func TestParseActions(t *testing.T) {

View file

@ -1,9 +1,10 @@
package server_test package server_test
import ( import (
"testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"heckel.io/ntfy/server" "heckel.io/ntfy/server"
"testing"
) )
func TestConfig_New(t *testing.T) { func TestConfig_New(t *testing.T) {

View file

@ -3,13 +3,14 @@ package server
import ( import (
"errors" "errors"
"fmt" "fmt"
"heckel.io/ntfy/util"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"sync" "sync"
"time" "time"
"heckel.io/ntfy/util"
) )
var ( var (

View file

@ -3,12 +3,13 @@ package server
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/stretchr/testify/require"
"heckel.io/ntfy/util"
"os" "os"
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require"
"heckel.io/ntfy/util"
) )
var ( var (

File diff suppressed because one or more lines are too long

View file

@ -32,7 +32,7 @@ const (
priority INT NOT NULL, priority INT NOT NULL,
tags TEXT NOT NULL, tags TEXT NOT NULL,
click TEXT NOT NULL, click TEXT NOT NULL,
icon TEXT NOT NULL, icon TEXT NOT NULL,
actions TEXT NOT NULL, actions TEXT NOT NULL,
attachment_name TEXT NOT NULL, attachment_name TEXT NOT NULL,
attachment_type TEXT NOT NULL, attachment_type TEXT NOT NULL,
@ -56,31 +56,31 @@ const (
selectRowIDFromMessageID = `SELECT id FROM messages WHERE mid = ?` // Do not include topic, see #336 and TestServer_PollSinceID_MultipleTopics selectRowIDFromMessageID = `SELECT id FROM messages WHERE mid = ?` // Do not include topic, see #336 and TestServer_PollSinceID_MultipleTopics
selectMessagesSinceTimeQuery = ` selectMessagesSinceTimeQuery = `
SELECT mid, time, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding SELECT mid, time, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding
FROM messages FROM messages
WHERE topic = ? AND time >= ? AND published = 1 WHERE topic = ? AND time >= ? AND published = 1
ORDER BY time, id ORDER BY time, id
` `
selectMessagesSinceTimeIncludeScheduledQuery = ` selectMessagesSinceTimeIncludeScheduledQuery = `
SELECT mid, time, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding SELECT mid, time, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding
FROM messages FROM messages
WHERE topic = ? AND time >= ? WHERE topic = ? AND time >= ?
ORDER BY time, id ORDER BY time, id
` `
selectMessagesSinceIDQuery = ` selectMessagesSinceIDQuery = `
SELECT mid, time, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding SELECT mid, time, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding
FROM messages FROM messages
WHERE topic = ? AND id > ? AND published = 1 WHERE topic = ? AND id > ? AND published = 1
ORDER BY time, id ORDER BY time, id
` `
selectMessagesSinceIDIncludeScheduledQuery = ` selectMessagesSinceIDIncludeScheduledQuery = `
SELECT mid, time, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding SELECT mid, time, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding
FROM messages FROM messages
WHERE topic = ? AND (id > ? OR published = 0) WHERE topic = ? AND (id > ? OR published = 0)
ORDER BY time, id ORDER BY time, id
` `
selectMessagesDueQuery = ` selectMessagesDueQuery = `
SELECT mid, time, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding SELECT mid, time, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding
FROM messages FROM messages
WHERE time <= ? AND published = 0 WHERE time <= ? AND published = 0
ORDER BY time, id ORDER BY time, id
` `
@ -159,12 +159,12 @@ const (
); );
CREATE INDEX IF NOT EXISTS idx_mid ON messages_new (mid); CREATE INDEX IF NOT EXISTS idx_mid ON messages_new (mid);
CREATE INDEX IF NOT EXISTS idx_topic ON messages_new (topic); CREATE INDEX IF NOT EXISTS idx_topic ON messages_new (topic);
INSERT INSERT
INTO messages_new ( INTO messages_new (
mid, time, topic, message, title, priority, tags, click, attachment_name, attachment_type, mid, time, topic, message, title, priority, tags, click, attachment_name, attachment_type,
attachment_size, attachment_expires, attachment_url, attachment_owner, encoding, published) attachment_size, attachment_expires, attachment_url, attachment_owner, encoding, published)
SELECT SELECT
id, time, topic, message, title, priority, tags, click, attachment_name, attachment_type, id, time, topic, message, title, priority, tags, click, attachment_name, attachment_type,
attachment_size, attachment_expires, attachment_url, attachment_owner, encoding, published attachment_size, attachment_expires, attachment_url, attachment_owner, encoding, published
FROM messages; FROM messages;
DROP TABLE messages; DROP TABLE messages;
@ -189,7 +189,7 @@ const (
// 8 -> 9 // 8 -> 9
migrate8To9AlterMessagesTableQuery = ` migrate8To9AlterMessagesTableQuery = `
CREATE INDEX IF NOT EXISTS idx_time ON messages (time); CREATE INDEX IF NOT EXISTS idx_time ON messages (time);
` `
) )

View file

@ -412,7 +412,7 @@ func TestSqliteCache_Migration_From1(t *testing.T) {
CREATE TABLE IF NOT EXISTS schemaVersion ( CREATE TABLE IF NOT EXISTS schemaVersion (
id INT PRIMARY KEY, id INT PRIMARY KEY,
version INT NOT NULL version INT NOT NULL
); );
INSERT INTO schemaVersion (id, version) VALUES (1, 1); INSERT INTO schemaVersion (id, version) VALUES (1, 1);
`) `)
require.Nil(t, err) require.Nil(t, err)
@ -447,8 +447,8 @@ func TestSqliteCache_Migration_From1(t *testing.T) {
func TestSqliteCache_StartupQueries_WAL(t *testing.T) { func TestSqliteCache_StartupQueries_WAL(t *testing.T) {
filename := newSqliteTestCacheFile(t) filename := newSqliteTestCacheFile(t)
startupQueries := `pragma journal_mode = WAL; startupQueries := `pragma journal_mode = WAL;
pragma synchronous = normal; pragma synchronous = normal;
pragma temp_store = memory;` pragma temp_store = memory;`
db, err := newSqliteCache(filename, startupQueries, 0, 0, false) db, err := newSqliteCache(filename, startupQueries, 0, 0, false)
require.Nil(t, err) require.Nil(t, err)

View file

@ -4,14 +4,15 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"strings"
firebase "firebase.google.com/go/v4" firebase "firebase.google.com/go/v4"
"firebase.google.com/go/v4/messaging" "firebase.google.com/go/v4/messaging"
"fmt"
"google.golang.org/api/option" "google.golang.org/api/option"
"heckel.io/ntfy/auth" "heckel.io/ntfy/auth"
"heckel.io/ntfy/log" "heckel.io/ntfy/log"
"heckel.io/ntfy/util" "heckel.io/ntfy/util"
"strings"
) )
const ( const (

View file

@ -4,11 +4,12 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
"io" "io"
"net/http" "net/http"
"strings" "strings"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
) )
// Matrix Push Gateway / UnifiedPush / ntfy integration: // Matrix Push Gateway / UnifiedPush / ntfy integration:

View file

@ -172,7 +172,7 @@ func TestServer_StaticSites(t *testing.T) {
rr = request(t, s, "GET", "/static/css/home.css", "", nil) rr = request(t, s, "GET", "/static/css/home.css", "", nil)
require.Equal(t, 200, rr.Code) require.Equal(t, 200, rr.Code)
require.Contains(t, rr.Body.String(), `html, body {`) require.Contains(t, rr.Body.String(), "html,\nbody {")
rr = request(t, s, "GET", "/docs", "", nil) rr = request(t, s, "GET", "/docs", "", nil)
require.Equal(t, 301, rr.Code) require.Equal(t, 301, rr.Code)

View file

@ -4,14 +4,15 @@ import (
_ "embed" // required by go:embed _ "embed" // required by go:embed
"encoding/json" "encoding/json"
"fmt" "fmt"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
"mime" "mime"
"net" "net"
"net/smtp" "net/smtp"
"strings" "strings"
"sync" "sync"
"time" "time"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
) )
type mailer interface { type mailer interface {

View file

@ -1,8 +1,9 @@
package server package server
import ( import (
"github.com/stretchr/testify/require"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestFormatMail_Basic(t *testing.T) { func TestFormatMail_Basic(t *testing.T) {

View file

@ -4,8 +4,6 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"github.com/emersion/go-smtp"
"heckel.io/ntfy/log"
"io" "io"
"mime" "mime"
"mime/multipart" "mime/multipart"
@ -15,6 +13,9 @@ import (
"net/mail" "net/mail"
"strings" "strings"
"sync" "sync"
"github.com/emersion/go-smtp"
"heckel.io/ntfy/log"
) )
var ( var (

View file

@ -1,12 +1,13 @@
package server package server
import ( import (
"github.com/emersion/go-smtp"
"github.com/stretchr/testify/require"
"net" "net"
"net/http" "net/http"
"strings" "strings"
"testing" "testing"
"github.com/emersion/go-smtp"
"github.com/stretchr/testify/require"
) )
func TestSmtpBackend_Multipart(t *testing.T) { func TestSmtpBackend_Multipart(t *testing.T) {

View file

@ -1,9 +1,10 @@
package server package server
import ( import (
"heckel.io/ntfy/log"
"math/rand" "math/rand"
"sync" "sync"
"heckel.io/ntfy/log"
) )
// topic represents a channel to which subscribers can subscribe, and publishers // topic represents a channel to which subscribers can subscribe, and publishers

View file

@ -2,11 +2,12 @@ package server
import ( import (
"fmt" "fmt"
"github.com/emersion/go-smtp"
"heckel.io/ntfy/util"
"net/http" "net/http"
"strings" "strings"
"unicode/utf8" "unicode/utf8"
"github.com/emersion/go-smtp"
"heckel.io/ntfy/util"
) )
func readBoolParam(r *http.Request, defaultValue bool, names ...string) bool { func readBoolParam(r *http.Request, defaultValue bool, names ...string) bool {

View file

@ -3,11 +3,12 @@ package server
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/stretchr/testify/require"
"math/rand" "math/rand"
"net/http" "net/http"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestReadBoolParam(t *testing.T) { func TestReadBoolParam(t *testing.T) {

View file

@ -2,12 +2,13 @@ package test
import ( import (
"fmt" "fmt"
"heckel.io/ntfy/server"
"math/rand" "math/rand"
"net/http" "net/http"
"path/filepath" "path/filepath"
"testing" "testing"
"time" "time"
"heckel.io/ntfy/server"
) )
func init() { func init() {

View file

@ -2,13 +2,14 @@ package main
import ( import (
"context" "context"
firebase "firebase.google.com/go/v4"
"firebase.google.com/go/v4/messaging"
"flag" "flag"
"fmt" "fmt"
"google.golang.org/api/option"
"os" "os"
"strings" "strings"
firebase "firebase.google.com/go/v4"
"firebase.google.com/go/v4/messaging"
"google.golang.org/api/option"
) )
func main() { func main() {

View file

@ -1,12 +1,13 @@
package util_test package util_test
import ( import (
"github.com/stretchr/testify/require"
"heckel.io/ntfy/util"
"math/rand" "math/rand"
"sync" "sync"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require"
"heckel.io/ntfy/util"
) )
func TestBatchingQueue_InfTimeout(t *testing.T) { func TestBatchingQueue_InfTimeout(t *testing.T) {

View file

@ -2,9 +2,10 @@ package util
import ( import (
"crypto/rand" "crypto/rand"
"github.com/stretchr/testify/require"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestSniffWriter_WriteHTML(t *testing.T) { func TestSniffWriter_WriteHTML(t *testing.T) {

View file

@ -2,11 +2,12 @@ package util
import ( import (
"embed" "embed"
"github.com/stretchr/testify/require"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require"
) )
var ( var (

View file

@ -2,11 +2,12 @@ package util
import ( import (
"compress/gzip" "compress/gzip"
"github.com/stretchr/testify/require"
"io" "io"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestGzipHandler(t *testing.T) { func TestGzipHandler(t *testing.T) {

View file

@ -2,10 +2,11 @@ package util
import ( import (
"errors" "errors"
"golang.org/x/time/rate"
"io" "io"
"sync" "sync"
"time" "time"
"golang.org/x/time/rate"
) )
// ErrLimitReached is the error returned by the Limiter and LimitWriter when the predefined limit has been reached // ErrLimitReached is the error returned by the Limiter and LimitWriter when the predefined limit has been reached

View file

@ -2,9 +2,10 @@ package util
import ( import (
"bytes" "bytes"
"github.com/stretchr/testify/require"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require"
) )
func TestFixedLimiter_Add(t *testing.T) { func TestFixedLimiter_Add(t *testing.T) {

View file

@ -1,10 +1,11 @@
package util package util
import ( import (
"github.com/stretchr/testify/require"
"io" "io"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestPeak_LimitReached(t *testing.T) { func TestPeak_LimitReached(t *testing.T) {

View file

@ -2,11 +2,12 @@ package util
import ( import (
"errors" "errors"
"github.com/olebedev/when"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/olebedev/when"
) )
var ( var (

View file

@ -1,9 +1,10 @@
package util package util
import ( import (
"github.com/stretchr/testify/require"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require"
) )
var ( var (

View file

@ -4,6 +4,6 @@
// The actual config is dynamically generated server-side. // The actual config is dynamically generated server-side.
var config = { var config = {
appRoot: "/", appRoot: "/",
disallowedTopics: ["docs", "static", "file", "app", "settings"] disallowedTopics: ["docs", "static", "file", "app", "settings"],
}; };

View file

@ -1,182 +1,266 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<title>ntfy.sh | Send push notifications to your phone via PUT/POST</title> <title>ntfy.sh | Send push notifications to your phone via PUT/POST</title>
<link rel="stylesheet" href="static/css/home.css" type="text/css"> <link rel="stylesheet" href="static/css/home.css" type="text/css" />
<!-- Mobile view --> <!-- Mobile view -->
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"> <meta
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> name="viewport"
<meta name="HandheldFriendly" content="true"> content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="HandheldFriendly" content="true" />
<!-- Mobile browsers, background color --> <!-- Mobile browsers, background color -->
<meta name="theme-color" content="#317f6f"> <meta name="theme-color" content="#317f6f" />
<meta name="msapplication-navbutton-color" content="#317f6f"> <meta name="msapplication-navbutton-color" content="#317f6f" />
<meta name="apple-mobile-web-app-status-bar-style" content="#317f6f"> <meta name="apple-mobile-web-app-status-bar-style" content="#317f6f" />
<!-- Favicon, see favicon.io --> <!-- Favicon, see favicon.io -->
<link rel="icon" type="image/png" href="static/img/favicon.png"> <link rel="icon" type="image/png" href="static/img/favicon.png" />
<!-- Previews in Google, Slack, WhatsApp, etc. --> <!-- Previews in Google, Slack, WhatsApp, etc. -->
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" /> <meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="ntfy.sh" /> <meta property="og:site_name" content="ntfy.sh" />
<meta property="og:title" content="ntfy.sh | Push notifications to your phone or desktop via PUT/POST" /> <meta
<meta property="og:description" content="ntfy is a simple HTTP-based pub-sub notification service. It allows you to send desktop notifications via scripts from any computer, entirely without signup or cost. Made with ❤ by Philipp C. Heckel, Apache License 2.0, source at https://heckel.io/ntfy." /> property="og:title"
content="ntfy.sh | Push notifications to your phone or desktop via PUT/POST"
/>
<meta
property="og:description"
content="ntfy is a simple HTTP-based pub-sub notification service. It allows you to send desktop notifications via scripts from any computer, entirely without signup or cost. Made with ❤ by Philipp C. Heckel, Apache License 2.0, source at https://heckel.io/ntfy."
/>
<meta property="og:image" content="/static/img/ntfy.png" /> <meta property="og:image" content="/static/img/ntfy.png" />
<meta property="og:url" content="https://ntfy.sh" /> <meta property="og:url" content="https://ntfy.sh" />
<!-- Fonts --> <!-- Fonts -->
<link rel="stylesheet" href="static/css/fonts.css" type="text/css"> <link rel="stylesheet" href="static/css/fonts.css" type="text/css" />
</head> </head>
<body> <body>
<nav id="header">
<nav id="header"> <div id="headerBox">
<div id="headerBox"> <img id="logo" src="static/img/ntfy.png" alt="logo" />
<img id="logo" src="static/img/ntfy.png" alt="logo"/>
<div id="name">ntfy</div> <div id="name">ntfy</div>
<ol> <ol>
<li><a href="app">Web app</a></li> <li><a href="app">Web app</a></li>
<li><a href="docs/subscribe/phone/">Android/iOS</a></li> <li><a href="docs/subscribe/phone/">Android/iOS</a></li>
<li><a href="docs/">Docs</a></li> <li><a href="docs/">Docs</a></li>
<li><a href="docs/publish/">API</a></li> <li><a href="docs/publish/">API</a></li>
<li><a href="https://github.com/binwiederhier/ntfy">GitHub</a></li> <li><a href="https://github.com/binwiederhier/ntfy">GitHub</a></li>
</ol> </ol>
</div> </div>
</nav> </nav>
<div id="main"> <div id="main">
<h1>Send push notifications to your phone or desktop via PUT/POST</h1> <h1>Send push notifications to your phone or desktop via PUT/POST</h1>
<p> <p>
<b>ntfy</b> (pronounce: <i>notify</i>) is a simple HTTP-based <a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">pub-sub</a> notification service. <b>ntfy</b> (pronounce: <i>notify</i>) is a simple HTTP-based
It allows you to send notifications to your phone or desktop via scripts from any computer, <a
entirely <b>without signup, cost or setup</b>. It's also <a href="https://github.com/binwiederhier/ntfy">open source</a> if you want to run your own. href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern"
</p> >pub-sub</a
<div id="screenshots"> >
<a href="static/img/screenshot-curl.png"><img src="static/img/screenshot-curl.png"/></a> notification service. It allows you to send notifications to your phone
<a href="static/img/screenshot-web-detail.png"><img src="static/img/screenshot-web-detail.png"/></a> or desktop via scripts from any computer, entirely
<b>without signup, cost or setup</b>. It's also
<a href="https://github.com/binwiederhier/ntfy">open source</a> if you
want to run your own.
</p>
<div id="screenshots">
<a href="static/img/screenshot-curl.png"
><img src="static/img/screenshot-curl.png"
/></a>
<a href="static/img/screenshot-web-detail.png"
><img src="static/img/screenshot-web-detail.png"
/></a>
<span class="nowrap"> <span class="nowrap">
<a href="static/img/screenshot-phone-main.jpg"><img src="static/img/screenshot-phone-main.jpg"/></a> <a href="static/img/screenshot-phone-main.jpg"
<a href="static/img/screenshot-phone-detail.jpg"><img src="static/img/screenshot-phone-detail.jpg"/></a> ><img src="static/img/screenshot-phone-main.jpg"
<a href="static/img/screenshot-phone-notification.jpg"><img src="static/img/screenshot-phone-notification.jpg"/></a> /></a>
<a href="static/img/screenshot-phone-detail.jpg"
><img src="static/img/screenshot-phone-detail.jpg"
/></a>
<a href="static/img/screenshot-phone-notification.jpg"
><img src="static/img/screenshot-phone-notification.jpg"
/></a>
</span> </span>
</div> </div>
<h2 id="publish" class="anchor">Publishing messages</h2> <h2 id="publish" class="anchor">Publishing messages</h2>
<p> <p>
<a href="docs/publish/">Publishing messages</a> can be done via PUT or POST. Topics are created on the fly by subscribing or publishing to them. <a href="docs/publish/">Publishing messages</a> can be done via PUT or
Because there is no sign-up, <b>the topic is essentially a password</b>, so pick something that's not easily guessable. POST. Topics are created on the fly by subscribing or publishing to
</p> them. Because there is no sign-up,
<p class="smallMarginBottom"> <b>the topic is essentially a password</b>, so pick something that's not
Here's an example showing how to publish a message using a POST request (via <tt>curl -d</tt>): easily guessable.
</p> </p>
<code> <p class="smallMarginBottom">
curl -d "Backup successful 😀" <span class="ntfyUrl">ntfy.sh</span>/mytopic Here's an example showing how to publish a message using a POST request
</code> (via <tt>curl -d</tt>):
<p class="smallMarginBottom"> </p>
There are <a href="docs/publish/">more features</a> related to publishing messages: You can set a <code>
<a href="docs/publish/#message-priority">notification priority</a>, a <a href="docs/publish/#message-title">title</a>, curl -d "Backup successful 😀"
and <a href="docs/publish/#tags-emojis">tag messages</a>. <span class="ntfyUrl">ntfy.sh</span>/mytopic
Here's an example using some of them together: </code>
</p> <p class="smallMarginBottom">
<code> There are <a href="docs/publish/">more features</a> related to
curl \<br/> publishing messages: You can set a
&nbsp;&nbsp;-H "Title: Unauthorized access detected" \<br/> <a href="docs/publish/#message-priority">notification priority</a>, a
&nbsp;&nbsp;-H "Priority: urgent" \<br/> <a href="docs/publish/#message-title">title</a>, and
&nbsp;&nbsp;-H "Tags: warning,skull" \<br/> <a href="docs/publish/#tags-emojis">tag messages</a>. Here's an example
&nbsp;&nbsp;-d "Remote access to $(hostname) detected. Act right away." \<br/> using some of them together:
</p>
<code>
curl \<br />
&nbsp;&nbsp;-H "Title: Unauthorized access detected" \<br />
&nbsp;&nbsp;-H "Priority: urgent" \<br />
&nbsp;&nbsp;-H "Tags: warning,skull" \<br />
&nbsp;&nbsp;-d "Remote access to $(hostname) detected. Act right away."
\<br />
&nbsp;&nbsp;<span class="ntfyUrl">ntfy.sh</span>/mytopic &nbsp;&nbsp;<span class="ntfyUrl">ntfy.sh</span>/mytopic
</code> </code>
<p> <p>
Here's what that looks like in the <a href="docs/subscribe/phone/">Android app</a>: Here's what that looks like in the
</p> <a href="docs/subscribe/phone/">Android app</a>:
<figure> </p>
<img src="static/img/screenshot-phone-popover.png" style="max-height: 200px"/> <figure>
<img
src="static/img/screenshot-phone-popover.png"
style="max-height: 200px"
/>
<figcaption>Urgent notification with pop-over</figcaption> <figcaption>Urgent notification with pop-over</figcaption>
</figure> </figure>
<h2 id="subscribe" class="anchor">Subscribe to a topic</h2> <h2 id="subscribe" class="anchor">Subscribe to a topic</h2>
<p> <p>
You can create and subscribe to a topic either <a href="docs/subscribe/phone/">using your phone</a>, You can create and subscribe to a topic either
in <a href="docs/subscribe/web/">this web UI</a>, or in your own app by <a href="docs/subscribe/api/">subscribing via the API</a>. <a href="docs/subscribe/phone/">using your phone</a>, in
</p> <a href="docs/subscribe/web/">this web UI</a>, or in your own app by
<a href="docs/subscribe/api/">subscribing via the API</a>.
</p>
<h3 id="subscribe-phone" class="anchor">Subscribe from your phone</h3> <h3 id="subscribe-phone" class="anchor">Subscribe from your phone</h3>
<p> <p>
Simply get the app and start <a href="docs/publish/">publishing messages</a>. To learn more about the app, Simply get the app and start
<a href="docs/subscribe/phone/">check out the documentation</a>. <a href="docs/publish/">publishing messages</a>. To learn more about the
</p> app, <a href="docs/subscribe/phone/">check out the documentation</a>.
<p> </p>
<a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img src="static/img/badge-googleplay.png"></a> <p>
<a href="https://f-droid.org/en/packages/io.heckel.ntfy/"><img src="static/img/badge-fdroid.png"></a> <a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"
<a href="https://apps.apple.com/us/app/ntfy/id1625396347"><img src="static/img/badge-appstore.png"></a> ><img src="static/img/badge-googleplay.png"
</p> /></a>
<p> <a href="https://f-droid.org/en/packages/io.heckel.ntfy/"
Here's a video showing the app in action: ><img src="static/img/badge-fdroid.png"
</p> /></a>
<figure> <a href="https://apps.apple.com/us/app/ntfy/id1625396347"
<video controls muted autoplay loop src="static/img/android-video-overview.mp4" style="max-width: 650px"></video> ><img src="static/img/badge-appstore.png"
<figcaption>Sending push notifications to your Android phone</figcaption> /></a>
</figure> </p>
<p>Here's a video showing the app in action:</p>
<figure>
<video
controls
muted
autoplay
loop
src="static/img/android-video-overview.mp4"
style="max-width: 650px"
></video>
<figcaption>
Sending push notifications to your Android phone
</figcaption>
</figure>
<h3 id="subscribe-web" class="anchor">Subscribe via web app</h3> <h3 id="subscribe-web" class="anchor">Subscribe via web app</h3>
<p> <p>
Subscribe to topics in the <a href="app">web app</a> and receive messages as <b>desktop notification</b>. Subscribe to topics in the <a href="app">web app</a> and receive
It is available at <b><a href="app"><span class="ntfyUrl">ntfy.sh</span>/app</a></b>. messages as <b>desktop notification</b>. It is available at
</p> <b
<figure> ><a href="app"><span class="ntfyUrl">ntfy.sh</span>/app</a></b
<a href="app"><img src="static/img/screenshot-web-detail.png" width="100%"/></a> >.
<figcaption>ntfy web app, available at <a href="app"><span class="ntfyUrl">ntfy.sh</span>/app</a></figcaption> </p>
</figure> <figure>
<a href="app"
><img src="static/img/screenshot-web-detail.png" width="100%"
/></a>
<figcaption>
ntfy web app, available at
<a href="app"><span class="ntfyUrl">ntfy.sh</span>/app</a>
</figcaption>
</figure>
<h3 id="subscribe-api" class="anchor">Subscribe using the API</h3> <h3 id="subscribe-api" class="anchor">Subscribe using the API</h3>
<p> <p>
There's a super simple API that you can use to integrate your own app. You can consume There's a super simple API that you can use to integrate your own app.
a <a href="docs/subscribe/api/#subscribe-as-json-stream">JSON stream</a>, You can consume a
an <a href="docs/subscribe/api/#subscribe-as-sse-stream">SSE/EventSource stream</a>, <a href="docs/subscribe/api/#subscribe-as-json-stream">JSON stream</a>,
a <a href="docs/subscribe/api/#subscribe-as-raw-stream">plain text stream</a>, an
or <a href="docs/subscribe/api/#websockets">via WebSockets</a>. <a href="docs/subscribe/api/#subscribe-as-sse-stream"
</p> >SSE/EventSource stream</a
<p class="smallMarginBottom"> >, a
Here's an example for JSON. The <b>connection stays open</b>, so you can retrieve messages as they come in: <a href="docs/subscribe/api/#subscribe-as-raw-stream"
</p> >plain text stream</a
<code> >, or <a href="docs/subscribe/api/#websockets">via WebSockets</a>.
$ curl -s <span class="ntfyUrl">ntfy.sh</span>/mytopic/json<br/> </p>
{"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"}<br/> <p class="smallMarginBottom">
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Hi!"}<br/> Here's an example for JSON. The <b>connection stays open</b>, so you can
{"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"}<br/> retrieve messages as they come in:
</p>
<code>
$ curl -s <span class="ntfyUrl">ntfy.sh</span>/mytopic/json<br />
{"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"}<br />
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Hi!"}<br />
{"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"}<br />
... ...
</code> </code>
<p> <p>Here's a short video demonstrating it in action:</p>
Here's a short video demonstrating it in action: <figure>
</p> <video
<figure> controls
<video controls muted autoplay loop src="static/img/android-video-subscribe-api.mp4" style="max-width: 650px"></video> muted
<figcaption>Subscribing to the JSON stream with <tt>curl</tt></figcaption> autoplay
</figure> loop
src="static/img/android-video-subscribe-api.mp4"
style="max-width: 650px"
></video>
<figcaption>
Subscribing to the JSON stream with <tt>curl</tt>
</figcaption>
</figure>
<h3 id="docs" class="anchor">Check out the docs!</h3> <h3 id="docs" class="anchor">Check out the docs!</h3>
<p> <p>
ntfy has so many more features and you can learn about all of them <a href="docs/">in the documentation</a> ntfy has so many more features and you can learn about all of them
(I tried my very best to make it the best docs ever 😉, not sure if I succeeded, hehe). <a href="docs/">in the documentation</a>
</p> (I tried my very best to make it the best docs ever 😉, not sure if I
<figure> succeeded, hehe).
<a href="docs/"><img width="100%" src="static/img/screenshot-docs.png"/></a> </p>
<figure>
<a href="docs/"
><img width="100%" src="static/img/screenshot-docs.png"
/></a>
<figcaption>Check out the documentation</figcaption> <figcaption>Check out the documentation</figcaption>
</figure> </figure>
<h3 id="free-software" class="anchor">100% open source &amp; forever free</h3> <h3 id="free-software" class="anchor">
<p> 100% open source &amp; forever free
I love free software, and I'm doing this because it's fun. I have no bad intentions, and I will </h3>
never monetize or sell your information. This service will always stay <p>
<a href="https://github.com/binwiederhier/ntfy">free and open</a>. I love free software, and I'm doing this because it's fun. I have no bad
You can read more in the <a href="docs/faq/">FAQs</a> and in the <a href="docs/privacy/">privacy policy</a>. intentions, and I will never monetize or sell your information. This
</p> service will always stay
<a href="https://github.com/binwiederhier/ntfy">free and open</a>. You
can read more in the <a href="docs/faq/">FAQs</a> and in the
<a href="docs/privacy/">privacy policy</a>.
</p>
<center id="ironicCenterTagDontFreakOut"><i>Made with ❤️ by <a href="https://heckel.io">Philipp C. Heckel</a></i></center> <center id="ironicCenterTagDontFreakOut">
</div> <i>Made with ❤️ by <a href="https://heckel.io">Philipp C. Heckel</a></i>
<div id="lightbox" class="lightbox"></div> </center>
<script src="static/js/home.js"></script> </div>
</body> <div id="lightbox" class="lightbox"></div>
<script src="static/js/home.js"></script>
</body>
</html> </html>

View file

@ -1,43 +1,59 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<title>ntfy web</title> <title>ntfy web</title>
<!-- Mobile view --> <!-- Mobile view -->
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"> <meta
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> name="viewport"
<meta name="HandheldFriendly" content="true"> content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="HandheldFriendly" content="true" />
<!-- Mobile browsers, background color --> <!-- Mobile browsers, background color -->
<meta name="theme-color" content="#317f6f"> <meta name="theme-color" content="#317f6f" />
<meta name="msapplication-navbutton-color" content="#317f6f"> <meta name="msapplication-navbutton-color" content="#317f6f" />
<meta name="apple-mobile-web-app-status-bar-style" content="#317f6f"> <meta name="apple-mobile-web-app-status-bar-style" content="#317f6f" />
<!-- Favicon, see favicon.io --> <!-- Favicon, see favicon.io -->
<link rel="icon" type="image/png" href="%PUBLIC_URL%/static/img/favicon.png"> <link
rel="icon"
type="image/png"
href="%PUBLIC_URL%/static/img/favicon.png"
/>
<!-- Previews in Google, Slack, WhatsApp, etc. --> <!-- Previews in Google, Slack, WhatsApp, etc. -->
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" /> <meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="ntfy web" /> <meta property="og:site_name" content="ntfy web" />
<meta property="og:title" content="ntfy web" /> <meta property="og:title" content="ntfy web" />
<meta property="og:description" content="ntfy lets you send push notifications via scripts from any computer or phone, entirely without signup or cost. Made with ❤ by Philipp C. Heckel, Apache License 2.0, source at https://heckel.io/ntfy." /> <meta
<meta property="og:image" content="%PUBLIC_URL%/static/img/ntfy.png" /> property="og:description"
<meta property="og:url" content="https://ntfy.sh" /> content="ntfy lets you send push notifications via scripts from any computer or phone, entirely without signup or cost. Made with ❤ by Philipp C. Heckel, Apache License 2.0, source at https://heckel.io/ntfy."
/>
<meta property="og:image" content="%PUBLIC_URL%/static/img/ntfy.png" />
<meta property="og:url" content="https://ntfy.sh" />
<!-- Never index --> <!-- Never index -->
<meta name="robots" content="noindex, nofollow" /> <meta name="robots" content="noindex, nofollow" />
<!-- Fonts --> <!-- Fonts -->
<link rel="stylesheet" href="%PUBLIC_URL%/static/css/fonts.css" type="text/css"> <link
</head> rel="stylesheet"
<body> href="%PUBLIC_URL%/static/css/fonts.css"
<noscript> type="text/css"
ntfy web requires JavaScript, but you can also use the <a href="https://ntfy.sh/docs/subscribe/cli/">CLI</a> />
or <a href="https://ntfy.sh/docs/subscribe/phone/">Android/iOS app</a> to subscribe. </head>
</noscript> <body>
<div id="root"></div> <noscript>
<script src="%PUBLIC_URL%/config.js"></script> ntfy web requires JavaScript, but you can also use the
</body> <a href="https://ntfy.sh/docs/subscribe/cli/">CLI</a> or
<a href="https://ntfy.sh/docs/subscribe/phone/">Android/iOS app</a> to
subscribe.
</noscript>
<div id="root"></div>
<script src="%PUBLIC_URL%/config.js"></script>
</body>
</html> </html>

View file

@ -2,40 +2,40 @@
/* roboto-300 - latin */ /* roboto-300 - latin */
@font-face { @font-face {
font-family: 'Roboto'; font-family: "Roboto";
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: local(''), src: local(""), url("../fonts/roboto-v29-latin-300.woff2") format("woff2"),
url('../fonts/roboto-v29-latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../fonts/roboto-v29-latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ url("../fonts/roboto-v29-latin-300.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
} }
/* roboto-regular - latin */ /* roboto-regular - latin */
@font-face { @font-face {
font-family: 'Roboto'; font-family: "Roboto";
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: local(''), src: local(""), url("../fonts/roboto-v29-latin-regular.woff2") format("woff2"),
url('../fonts/roboto-v29-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../fonts/roboto-v29-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ url("../fonts/roboto-v29-latin-regular.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
} }
/* roboto-500 - latin */ /* roboto-500 - latin */
@font-face { @font-face {
font-family: 'Roboto'; font-family: "Roboto";
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
src: local(''), src: local(""), url("../fonts/roboto-v29-latin-500.woff2") format("woff2"),
url('../fonts/roboto-v29-latin-500.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../fonts/roboto-v29-latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ url("../fonts/roboto-v29-latin-500.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
} }
/* roboto-700 - latin */ /* roboto-700 - latin */
@font-face { @font-face {
font-family: 'Roboto'; font-family: "Roboto";
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: local(''), src: local(""), url("../fonts/roboto-v29-latin-700.woff2") format("woff2"),
url('../fonts/roboto-v29-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../fonts/roboto-v29-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ url("../fonts/roboto-v29-latin-700.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
} }

View file

@ -1,280 +1,283 @@
/* general styling */ /* general styling */
html, body { html,
font-family: 'Roboto', sans-serif; body {
font-weight: 400; font-family: "Roboto", sans-serif;
font-size: 1.1em; font-weight: 400;
color: #444; font-size: 1.1em;
margin: 0; color: #444;
padding: 0; margin: 0;
padding: 0;
} }
html { html {
/* prevent scrollbar from repositioning website: /* prevent scrollbar from repositioning website:
* https://www.w3docs.com/snippets/css/how-to-prevent-scrollbar-from-repositioning-web-page.html */ * https://www.w3docs.com/snippets/css/how-to-prevent-scrollbar-from-repositioning-web-page.html */
overflow-y: scroll; overflow-y: scroll;
} }
a, a:visited { a,
color: #338574; a:visited {
color: #338574;
} }
a:hover { a:hover {
text-decoration: none; text-decoration: none;
color: #317f6f; color: #317f6f;
} }
h1 { h1 {
margin-top: 35px; margin-top: 35px;
margin-bottom: 30px; margin-bottom: 30px;
font-size: 2.5em; font-size: 2.5em;
word-wrap: break-word; /* For very long topics */ word-wrap: break-word; /* For very long topics */
padding-right: 40px; /* For the X on the detail page */ padding-right: 40px; /* For the X on the detail page */
font-weight: 300; font-weight: 300;
color: #666; color: #666;
} }
h2 { h2 {
margin-top: 30px; margin-top: 30px;
margin-bottom: 5px; margin-bottom: 5px;
font-size: 1.8em; font-size: 1.8em;
font-weight: 300; font-weight: 300;
color: #333; color: #333;
} }
h3 { h3 {
margin-top: 25px; margin-top: 25px;
margin-bottom: 5px; margin-bottom: 5px;
font-size: 1.3em; font-size: 1.3em;
font-weight: 300; font-weight: 300;
color: #333; color: #333;
} }
p { p {
margin-top: 10px; margin-top: 10px;
margin-bottom: 20px; margin-bottom: 20px;
line-height: 160%; line-height: 160%;
font-weight: 400; font-weight: 400;
} }
p.smallMarginBottom { p.smallMarginBottom {
margin-bottom: 10px; margin-bottom: 10px;
} }
b { b {
font-weight: 500; font-weight: 500;
} }
tt { tt {
background: #eee; background: #eee;
padding: 2px 7px; padding: 2px 7px;
border-radius: 3px; border-radius: 3px;
} }
code { code {
display: block; display: block;
background: #eee; background: #eee;
font-family: monospace; font-family: monospace;
padding: 20px; padding: 20px;
border-radius: 3px; border-radius: 3px;
margin-top: 10px; margin-top: 10px;
margin-bottom: 20px; margin-bottom: 20px;
overflow-x: auto; overflow-x: auto;
white-space: nowrap; white-space: nowrap;
} }
/* Main page */ /* Main page */
#main { #main {
max-width: 900px; max-width: 900px;
margin: 0 auto 50px auto; margin: 0 auto 50px auto;
padding: 0 10px; padding: 0 10px;
} }
#error { #error {
color: darkred; color: darkred;
font-style: italic; font-style: italic;
} }
#ironicCenterTagDontFreakOut { #ironicCenterTagDontFreakOut {
color: #666; color: #666;
} }
/* Anchors */ /* Anchors */
.anchor .anchorLink { .anchor .anchorLink {
color: #ccc; color: #ccc;
text-decoration: none; text-decoration: none;
padding: 0 5px; padding: 0 5px;
visibility: hidden; visibility: hidden;
} }
.anchor:hover .anchorLink { .anchor:hover .anchorLink {
visibility: visible; visibility: visible;
} }
.anchor .anchorLink:hover { .anchor .anchorLink:hover {
color: #338574; color: #338574;
visibility: visible; visibility: visible;
} }
/* Figures */ /* Figures */
figure { figure {
text-align: center; text-align: center;
} }
figure img, figure video { figure img,
filter: drop-shadow(3px 3px 3px #ccc); figure video {
border-radius: 7px; filter: drop-shadow(3px 3px 3px #ccc);
max-width: 100%; border-radius: 7px;
max-width: 100%;
} }
figure video { figure video {
width: 100%; width: 100%;
max-height: 450px; max-height: 450px;
} }
figcaption { figcaption {
text-align: center; text-align: center;
font-style: italic; font-style: italic;
padding-top: 10px; padding-top: 10px;
} }
/* Screenshots */ /* Screenshots */
#screenshots { #screenshots {
text-align: center; text-align: center;
} }
#screenshots img { #screenshots img {
height: 190px; height: 190px;
margin: 3px; margin: 3px;
border-radius: 5px; border-radius: 5px;
filter: drop-shadow(2px 2px 2px #ddd); filter: drop-shadow(2px 2px 2px #ddd);
} }
#screenshots .nowrap { #screenshots .nowrap {
white-space: nowrap; white-space: nowrap;
} }
/* Lightbox; thanks to https://yossiabramov.com/blog/vanilla-js-lightbox */ /* Lightbox; thanks to https://yossiabramov.com/blog/vanilla-js-lightbox */
.lightbox { .lightbox {
opacity: 0; opacity: 0;
visibility: hidden; visibility: hidden;
position: fixed; position: fixed;
left:0; left: 0;
right: 0; right: 0;
top: 0; top: 0;
bottom: 0; bottom: 0;
z-index: -1; z-index: -1;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
transition: all 0.15s ease-in; transition: all 0.15s ease-in;
} }
.lightbox.show { .lightbox.show {
background-color: rgba(0,0,0, 0.75); background-color: rgba(0, 0, 0, 0.75);
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
z-index: 1000; z-index: 1000;
} }
.lightbox img { .lightbox img {
max-width: 90%; max-width: 90%;
max-height: 90%; max-height: 90%;
filter: drop-shadow(5px 5px 10px #222); filter: drop-shadow(5px 5px 10px #222);
border-radius: 5px; border-radius: 5px;
} }
.lightbox .close-lightbox { .lightbox .close-lightbox {
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
top: 30px; top: 30px;
right: 30px; right: 30px;
width: 20px; width: 20px;
height: 20px; height: 20px;
} }
.lightbox .close-lightbox::after, .lightbox .close-lightbox::after,
.lightbox .close-lightbox::before { .lightbox .close-lightbox::before {
content: ''; content: "";
width: 3px; width: 3px;
height: 20px; height: 20px;
background-color: #ddd; background-color: #ddd;
position: absolute; position: absolute;
border-radius: 5px; border-radius: 5px;
transform: rotate(45deg); transform: rotate(45deg);
} }
.lightbox .close-lightbox::before { .lightbox .close-lightbox::before {
transform: rotate(-45deg); transform: rotate(-45deg);
} }
.lightbox .close-lightbox:hover::after, .lightbox .close-lightbox:hover::after,
.lightbox .close-lightbox:hover::before { .lightbox .close-lightbox:hover::before {
background-color: #fff; background-color: #fff;
} }
/* Header */ /* Header */
#header { #header {
background: #338574; background: #338574;
height: 130px; height: 130px;
} }
#header #headerBox { #header #headerBox {
max-width: 900px; max-width: 900px;
margin: 0 auto; margin: 0 auto;
padding: 0 10px; padding: 0 10px;
} }
#header #logo { #header #logo {
margin-top: 23px; margin-top: 23px;
float: left; float: left;
} }
#header #name { #header #name {
float: left; float: left;
color: white; color: white;
font-size: 2.6em; font-size: 2.6em;
font-weight: 300; font-weight: 300;
margin: 35px 0 0 20px; margin: 35px 0 0 20px;
} }
#header ol { #header ol {
list-style-type: none; list-style-type: none;
float: right; float: right;
margin-top: 80px; margin-top: 80px;
} }
#header ol li { #header ol li {
display: inline-block; display: inline-block;
margin: 0 10px; margin: 0 10px;
font-weight: 400; font-weight: 400;
} }
#header ol li a, nav ol li a:visited { #header ol li a,
color: white; nav ol li a:visited {
text-decoration: none; color: white;
text-decoration: none;
} }
#header ol li a:hover { #header ol li a:hover {
text-decoration: underline; text-decoration: underline;
} }
li { li {
padding: 4px 0; padding: 4px 0;
margin: 4px 0; margin: 4px 0;
font-size: 0.9em; font-size: 0.9em;
} }
/* Hide top menu SMALL SCREEN */ /* Hide top menu SMALL SCREEN */
@media only screen and (max-width: 780px) { @media only screen and (max-width: 780px) {
#header ol { #header ol {
display: none; display: none;
} }
} }

View file

@ -1,84 +1,88 @@
/* All the things */ /* All the things */
let currentUrl = window.location.hostname; let currentUrl = window.location.hostname;
if (window.location.port) { if (window.location.port) {
currentUrl += ':' + window.location.port currentUrl += ":" + window.location.port;
} }
/* Screenshots */ /* Screenshots */
const lightbox = document.getElementById("lightbox"); const lightbox = document.getElementById("lightbox");
const showScreenshotOverlay = (e, el, index) => { const showScreenshotOverlay = (e, el, index) => {
lightbox.classList.add('show'); lightbox.classList.add("show");
document.addEventListener('keydown', nextScreenshotKeyboardListener); document.addEventListener("keydown", nextScreenshotKeyboardListener);
return showScreenshot(e, index); return showScreenshot(e, index);
}; };
const showScreenshot = (e, index) => { const showScreenshot = (e, index) => {
const actualIndex = resolveScreenshotIndex(index); const actualIndex = resolveScreenshotIndex(index);
lightbox.innerHTML = '<div class="close-lightbox"></div>' + screenshots[actualIndex].innerHTML; lightbox.innerHTML =
lightbox.querySelector('img').onclick = (e) => { return showScreenshot(e,actualIndex+1); }; '<div class="close-lightbox"></div>' + screenshots[actualIndex].innerHTML;
currentScreenshotIndex = actualIndex; lightbox.querySelector("img").onclick = (e) => {
e.stopPropagation(); return showScreenshot(e, actualIndex + 1);
return false; };
currentScreenshotIndex = actualIndex;
e.stopPropagation();
return false;
}; };
const nextScreenshot = (e) => { const nextScreenshot = (e) => {
return showScreenshot(e, currentScreenshotIndex+1); return showScreenshot(e, currentScreenshotIndex + 1);
}; };
const previousScreenshot = (e) => { const previousScreenshot = (e) => {
return showScreenshot(e, currentScreenshotIndex-1); return showScreenshot(e, currentScreenshotIndex - 1);
}; };
const resolveScreenshotIndex = (index) => { const resolveScreenshotIndex = (index) => {
if (index < 0) { if (index < 0) {
return screenshots.length - 1; return screenshots.length - 1;
} else if (index > screenshots.length - 1) { } else if (index > screenshots.length - 1) {
return 0; return 0;
} }
return index; return index;
}; };
const hideScreenshotOverlay = (e) => { const hideScreenshotOverlay = (e) => {
lightbox.classList.remove('show'); lightbox.classList.remove("show");
document.removeEventListener('keydown', nextScreenshotKeyboardListener); document.removeEventListener("keydown", nextScreenshotKeyboardListener);
}; };
const nextScreenshotKeyboardListener = (e) => { const nextScreenshotKeyboardListener = (e) => {
switch (e.keyCode) { switch (e.keyCode) {
case 37: case 37:
previousScreenshot(e); previousScreenshot(e);
break; break;
case 39: case 39:
nextScreenshot(e); nextScreenshot(e);
break; break;
} }
}; };
let currentScreenshotIndex = 0; let currentScreenshotIndex = 0;
const screenshots = [...document.querySelectorAll("#screenshots a")]; const screenshots = [...document.querySelectorAll("#screenshots a")];
screenshots.forEach((el, index) => { screenshots.forEach((el, index) => {
el.onclick = (e) => { return showScreenshotOverlay(e, el, index); }; el.onclick = (e) => {
return showScreenshotOverlay(e, el, index);
};
}); });
lightbox.onclick = hideScreenshotOverlay; lightbox.onclick = hideScreenshotOverlay;
// Add anchor links // Add anchor links
document.querySelectorAll('.anchor').forEach((el) => { document.querySelectorAll(".anchor").forEach((el) => {
if (el.hasAttribute('id')) { if (el.hasAttribute("id")) {
const id = el.getAttribute('id'); const id = el.getAttribute("id");
const anchor = document.createElement('a'); const anchor = document.createElement("a");
anchor.innerHTML = `<a href="#${id}" class="anchorLink">#</a>`; anchor.innerHTML = `<a href="#${id}" class="anchorLink">#</a>`;
el.appendChild(anchor); el.appendChild(anchor);
} }
}); });
// Change ntfy.sh url and protocol to match self-hosted one // Change ntfy.sh url and protocol to match self-hosted one
document.querySelectorAll('.ntfyUrl').forEach((el) => { document.querySelectorAll(".ntfyUrl").forEach((el) => {
el.innerHTML = currentUrl; el.innerHTML = currentUrl;
}); });
document.querySelectorAll('.ntfyProtocol').forEach((el) => { document.querySelectorAll(".ntfyProtocol").forEach((el) => {
el.innerHTML = window.location.protocol + "//"; el.innerHTML = window.location.protocol + "//";
}); });

View file

@ -1,191 +1,191 @@
{ {
"action_bar_clear_notifications": "Премахване на известия", "action_bar_clear_notifications": "Премахване на известия",
"alert_grant_description": "Разрешете на мрежовия четец да показва известия.", "alert_grant_description": "Разрешете на мрежовия четец да показва известия.",
"notifications_attachment_copy_url_title": "Копиране на адреса на прикачения файл", "notifications_attachment_copy_url_title": "Копиране на адреса на прикачения файл",
"notifications_example": "Пример", "notifications_example": "Пример",
"notifications_no_subscriptions_title": "Липсват абонаменти", "notifications_no_subscriptions_title": "Липсват абонаменти",
"nav_topics_title": "Абонаменти", "nav_topics_title": "Абонаменти",
"action_bar_send_test_notification": "Пробно известие", "action_bar_send_test_notification": "Пробно известие",
"action_bar_unsubscribe": "Отписване", "action_bar_unsubscribe": "Отписване",
"nav_button_all_notifications": "Всички известия", "nav_button_all_notifications": "Всички известия",
"action_bar_settings": "Настройки", "action_bar_settings": "Настройки",
"publish_dialog_title_topic": "Публикуване в темата {{topic}}", "publish_dialog_title_topic": "Публикуване в темата {{topic}}",
"publish_dialog_title_no_topic": "Изпращане", "publish_dialog_title_no_topic": "Изпращане",
"publish_dialog_progress_uploading": "Изпращане…", "publish_dialog_progress_uploading": "Изпращане…",
"publish_dialog_progress_uploading_detail": "Изпращане {{loaded}}/{{total}} ({{percent}}%)…", "publish_dialog_progress_uploading_detail": "Изпращане {{loaded}}/{{total}} ({{percent}}%)…",
"publish_dialog_message_published": "Известието е публикувано", "publish_dialog_message_published": "Известието е публикувано",
"publish_dialog_attachment_limits_file_and_quota_reached": "надвишава ограничението от {{fileSizeLimit}} за размер на файл и квотата, остават {{remainingBytes}}", "publish_dialog_attachment_limits_file_and_quota_reached": "надвишава ограничението от {{fileSizeLimit}} за размер на файл и квотата, остават {{remainingBytes}}",
"publish_dialog_message_label": "Съобщение", "publish_dialog_message_label": "Съобщение",
"publish_dialog_message_placeholder": "Въведете съобщение", "publish_dialog_message_placeholder": "Въведете съобщение",
"publish_dialog_other_features": "Други възможности:", "publish_dialog_other_features": "Други възможности:",
"publish_dialog_chip_click_label": "Адрес", "publish_dialog_chip_click_label": "Адрес",
"publish_dialog_chip_email_label": "Препращане към ел. поща", "publish_dialog_chip_email_label": "Препращане към ел. поща",
"publish_dialog_chip_attach_url_label": "Прикачване на файл от адрес", "publish_dialog_chip_attach_url_label": "Прикачване на файл от адрес",
"publish_dialog_chip_attach_file_label": "Прикачване местен файл", "publish_dialog_chip_attach_file_label": "Прикачване местен файл",
"publish_dialog_chip_delay_label": "Забавяне на изпращането", "publish_dialog_chip_delay_label": "Забавяне на изпращането",
"publish_dialog_chip_topic_label": "Промяна на темата", "publish_dialog_chip_topic_label": "Промяна на темата",
"publish_dialog_button_cancel_sending": "Отменяне на изпращането", "publish_dialog_button_cancel_sending": "Отменяне на изпращането",
"publish_dialog_button_cancel": "Отказ", "publish_dialog_button_cancel": "Отказ",
"subscribe_dialog_error_user_anonymous": "анонимен", "subscribe_dialog_error_user_anonymous": "анонимен",
"prefs_notifications_title": "Известия", "prefs_notifications_title": "Известия",
"prefs_notifications_sound_title": "Звук при получаване", "prefs_notifications_sound_title": "Звук при получаване",
"prefs_notifications_sound_no_sound": "Без звук", "prefs_notifications_sound_no_sound": "Без звук",
"prefs_notifications_min_priority_title": "Най-нисък приоритет", "prefs_notifications_min_priority_title": "Най-нисък приоритет",
"prefs_notifications_min_priority_any": "Всички", "prefs_notifications_min_priority_any": "Всички",
"prefs_notifications_min_priority_low_and_higher": "Нисък приоритет и по-висок", "prefs_notifications_min_priority_low_and_higher": "Нисък приоритет и по-висок",
"prefs_notifications_min_priority_default_and_higher": "Подразбиран приоритет и по-висок", "prefs_notifications_min_priority_default_and_higher": "Подразбиран приоритет и по-висок",
"prefs_notifications_min_priority_high_and_higher": "Висок приоритет и по-висок", "prefs_notifications_min_priority_high_and_higher": "Висок приоритет и по-висок",
"prefs_notifications_min_priority_max_only": "Само най-висок приоритет", "prefs_notifications_min_priority_max_only": "Само най-висок приоритет",
"prefs_notifications_delete_after_never": "Никога", "prefs_notifications_delete_after_never": "Никога",
"prefs_users_add_button": "Добавяне", "prefs_users_add_button": "Добавяне",
"prefs_users_dialog_password_label": "Парола", "prefs_users_dialog_password_label": "Парола",
"alert_not_supported_description": "Мрежовият четец не поддържа известия.", "alert_not_supported_description": "Мрежовият четец не поддържа известия.",
"message_bar_type_message": "Въведете съобщение", "message_bar_type_message": "Въведете съобщение",
"message_bar_error_publishing": "Грешка при изпращане на известието", "message_bar_error_publishing": "Грешка при изпращане на известието",
"notifications_copied_to_clipboard": "Копирано в междинната памет", "notifications_copied_to_clipboard": "Копирано в междинната памет",
"notifications_attachment_link_expired": "препратката за изтегляне е с изтекла давност", "notifications_attachment_link_expired": "препратката за изтегляне е с изтекла давност",
"nav_button_settings": "Настройки", "nav_button_settings": "Настройки",
"nav_button_documentation": "Ръководство", "nav_button_documentation": "Ръководство",
"nav_button_subscribe": "Абониране за тема", "nav_button_subscribe": "Абониране за тема",
"alert_grant_title": "Известията са изключени", "alert_grant_title": "Известията са изключени",
"alert_grant_button": "Разрешаване", "alert_grant_button": "Разрешаване",
"notifications_tags": "Етикети", "notifications_tags": "Етикети",
"nav_button_publish_message": "Изпращане", "nav_button_publish_message": "Изпращане",
"alert_not_supported_title": "Не се поддържат известия", "alert_not_supported_title": "Не се поддържат известия",
"notifications_attachment_open_title": "Към {{url}}", "notifications_attachment_open_title": "Към {{url}}",
"notifications_attachment_copy_url_button": "Копиране на адреса", "notifications_attachment_copy_url_button": "Копиране на адреса",
"notifications_attachment_open_button": "Отваряне на прикачения файл", "notifications_attachment_open_button": "Отваряне на прикачения файл",
"notifications_attachment_link_expires": "препратката изтича на {{date}}", "notifications_attachment_link_expires": "препратката изтича на {{date}}",
"notifications_actions_open_url_title": "Към {{url}}", "notifications_actions_open_url_title": "Към {{url}}",
"notifications_click_copy_url_button": "Копиране на препратка", "notifications_click_copy_url_button": "Копиране на препратка",
"notifications_click_open_button": "Отваряне", "notifications_click_open_button": "Отваряне",
"notifications_click_copy_url_title": "Копиране на препратката в междинната памет", "notifications_click_copy_url_title": "Копиране на препратката в междинната памет",
"notifications_none_for_topic_title": "Липсват известия в темата", "notifications_none_for_topic_title": "Липсват известия в темата",
"notifications_none_for_any_title": "Липсват известия", "notifications_none_for_any_title": "Липсват известия",
"notifications_none_for_topic_description": "За да изпратите известия в тази тема направете заявка чрез методите PUT или POST към адреса й.", "notifications_none_for_topic_description": "За да изпратите известия в тази тема направете заявка чрез методите PUT или POST към адреса й.",
"notifications_none_for_any_description": "За да изпратите известия в тема направете заявка чрез методите PUT или POST към адреса ѝ. Ето пример с една от вашите теми.", "notifications_none_for_any_description": "За да изпратите известия в тема направете заявка чрез методите PUT или POST към адреса ѝ. Ето пример с една от вашите теми.",
"notifications_no_subscriptions_description": "Щракнете върху „{{linktext}}“, за да създадете тема или да се абонирате. След това като направите заявка чрез методите PUT или POST ще ги получите тук.", "notifications_no_subscriptions_description": "Щракнете върху „{{linktext}}“, за да създадете тема или да се абонирате. След това като направите заявка чрез методите PUT или POST ще ги получите тук.",
"notifications_more_details": "За допълнителна информация посетете <websiteLink>страницата</websiteLink> или <docsLink>документацията</docsLink>.", "notifications_more_details": "За допълнителна информация посетете <websiteLink>страницата</websiteLink> или <docsLink>документацията</docsLink>.",
"publish_dialog_priority_min": "Най-нисък приоритет", "publish_dialog_priority_min": "Най-нисък приоритет",
"publish_dialog_attachment_limits_file_reached": "надвишава ограничението от {{fileSizeLimit}} за размер на файл", "publish_dialog_attachment_limits_file_reached": "надвишава ограничението от {{fileSizeLimit}} за размер на файл",
"publish_dialog_base_url_label": "Адрес на услугата", "publish_dialog_base_url_label": "Адрес на услугата",
"publish_dialog_base_url_placeholder": "Адрес на услугата, напр. https://example.com", "publish_dialog_base_url_placeholder": "Адрес на услугата, напр. https://example.com",
"publish_dialog_topic_placeholder": "Име на темата, напр. phils_alerts", "publish_dialog_topic_placeholder": "Име на темата, напр. phils_alerts",
"publish_dialog_priority_low": "Нисък приоритет", "publish_dialog_priority_low": "Нисък приоритет",
"publish_dialog_attachment_limits_quota_reached": "надвишава квотата, остават {{remainingBytes}}", "publish_dialog_attachment_limits_quota_reached": "надвишава квотата, остават {{remainingBytes}}",
"publish_dialog_priority_high": "Висок приоритет", "publish_dialog_priority_high": "Висок приоритет",
"publish_dialog_priority_default": "Подразбиран приоритет", "publish_dialog_priority_default": "Подразбиран приоритет",
"publish_dialog_title_placeholder": "Заглавие на известието, напр. Предупреждение за диска", "publish_dialog_title_placeholder": "Заглавие на известието, напр. Предупреждение за диска",
"publish_dialog_tags_label": "Етикети", "publish_dialog_tags_label": "Етикети",
"publish_dialog_email_label": "Адрес на електронна поща", "publish_dialog_email_label": "Адрес на електронна поща",
"publish_dialog_priority_max": "Най-висок приоритет", "publish_dialog_priority_max": "Най-висок приоритет",
"publish_dialog_tags_placeholder": "Разделени със запетая етикети, напр. warning, srv1-backup", "publish_dialog_tags_placeholder": "Разделени със запетая етикети, напр. warning, srv1-backup",
"publish_dialog_click_label": "Адрес", "publish_dialog_click_label": "Адрес",
"publish_dialog_topic_label": "Име на темата", "publish_dialog_topic_label": "Име на темата",
"publish_dialog_title_label": "Заглавие", "publish_dialog_title_label": "Заглавие",
"publish_dialog_priority_label": "Приоритет", "publish_dialog_priority_label": "Приоритет",
"publish_dialog_click_placeholder": "Адрес, който се отваря при щракване върху известието", "publish_dialog_click_placeholder": "Адрес, който се отваря при щракване върху известието",
"publish_dialog_email_placeholder": "Поща, на която да се препрати известието, напр. phil@example.com", "publish_dialog_email_placeholder": "Поща, на която да се препрати известието, напр. phil@example.com",
"publish_dialog_attach_label": "Адрес на прикачения файл", "publish_dialog_attach_label": "Адрес на прикачения файл",
"publish_dialog_filename_placeholder": "Име на прикачения файл", "publish_dialog_filename_placeholder": "Име на прикачения файл",
"publish_dialog_attach_placeholder": "Прикачете файл от адрес, напр. https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "Прикачете файл от адрес, напр. https://f-droid.org/F-Droid.apk",
"prefs_notifications_delete_after_three_hours": "След три часа", "prefs_notifications_delete_after_three_hours": "След три часа",
"publish_dialog_filename_label": "Име на файла", "publish_dialog_filename_label": "Име на файла",
"publish_dialog_delay_label": "Забавяне", "publish_dialog_delay_label": "Забавяне",
"publish_dialog_details_examples_description": "За примери и подробно описание на всички възможности при изпращане, вижте <docsLink>документацията</docsLink>.", "publish_dialog_details_examples_description": "За примери и подробно описание на всички възможности при изпращане, вижте <docsLink>документацията</docsLink>.",
"publish_dialog_button_send": "Изпращане", "publish_dialog_button_send": "Изпращане",
"publish_dialog_checkbox_publish_another": "Изпращане на повече", "publish_dialog_checkbox_publish_another": "Изпращане на повече",
"publish_dialog_attached_file_title": "Прикачен файл:", "publish_dialog_attached_file_title": "Прикачен файл:",
"publish_dialog_attached_file_filename_placeholder": "Име на прикачения файл", "publish_dialog_attached_file_filename_placeholder": "Име на прикачения файл",
"publish_dialog_drop_file_here": "Пуснете файла тук", "publish_dialog_drop_file_here": "Пуснете файла тук",
"subscribe_dialog_subscribe_description": "Възможно е темите да не са защитени с парола, затова изберете име, което е трудно за отгатване. След като се абонирате, можете да изпращате известия чрез методите PUT или POST.", "subscribe_dialog_subscribe_description": "Възможно е темите да не са защитени с парола, затова изберете име, което е трудно за отгатване. След като се абонирате, можете да изпращате известия чрез методите PUT или POST.",
"emoji_picker_search_placeholder": "Търсете емоция", "emoji_picker_search_placeholder": "Търсете емоция",
"subscribe_dialog_subscribe_title": "Абониране за тема", "subscribe_dialog_subscribe_title": "Абониране за тема",
"subscribe_dialog_subscribe_topic_placeholder": "Име на темата, напр. phils_alerts", "subscribe_dialog_subscribe_topic_placeholder": "Име на темата, напр. phils_alerts",
"subscribe_dialog_subscribe_use_another_label": "Използване на друг сървър", "subscribe_dialog_subscribe_use_another_label": "Използване на друг сървър",
"subscribe_dialog_login_username_label": "Потребител, напр. phil", "subscribe_dialog_login_username_label": "Потребител, напр. phil",
"subscribe_dialog_login_button_back": "Назад", "subscribe_dialog_login_button_back": "Назад",
"subscribe_dialog_subscribe_button_cancel": "Отказ", "subscribe_dialog_subscribe_button_cancel": "Отказ",
"subscribe_dialog_login_description": "Темата е защитена. За да се абонирате въведете потребител и парола.", "subscribe_dialog_login_description": "Темата е защитена. За да се абонирате въведете потребител и парола.",
"subscribe_dialog_subscribe_button_subscribe": "Абониране", "subscribe_dialog_subscribe_button_subscribe": "Абониране",
"subscribe_dialog_login_title": "Изисква се вход", "subscribe_dialog_login_title": "Изисква се вход",
"prefs_notifications_delete_after_title": "Автоматично премахване", "prefs_notifications_delete_after_title": "Автоматично премахване",
"prefs_notifications_delete_after_one_day": "След един ден", "prefs_notifications_delete_after_one_day": "След един ден",
"prefs_users_table_user_header": "Потребител", "prefs_users_table_user_header": "Потребител",
"prefs_users_dialog_title_edit": "Промяна на потребител", "prefs_users_dialog_title_edit": "Промяна на потребител",
"prefs_users_dialog_base_url_label": "Адрес на услугата, e.g. https://ntfy.sh", "prefs_users_dialog_base_url_label": "Адрес на услугата, e.g. https://ntfy.sh",
"prefs_users_dialog_button_cancel": "Отказ", "prefs_users_dialog_button_cancel": "Отказ",
"prefs_users_dialog_button_save": "Запазване", "prefs_users_dialog_button_save": "Запазване",
"prefs_appearance_language_title": "Език", "prefs_appearance_language_title": "Език",
"subscribe_dialog_login_password_label": "Парола", "subscribe_dialog_login_password_label": "Парола",
"subscribe_dialog_login_button_login": "Вход", "subscribe_dialog_login_button_login": "Вход",
"subscribe_dialog_error_user_not_authorized": "Потребителят {{username}} няма достъп", "subscribe_dialog_error_user_not_authorized": "Потребителят {{username}} няма достъп",
"prefs_appearance_title": "Външен вид", "prefs_appearance_title": "Външен вид",
"publish_dialog_delay_placeholder": "Забавяне на изпращането, {{unixTimestamp}}, {{relativeTime}} или „{{naturalLanguage}}“ (на английски)", "publish_dialog_delay_placeholder": "Забавяне на изпращането, {{unixTimestamp}}, {{relativeTime}} или „{{naturalLanguage}}“ (на английски)",
"prefs_notifications_delete_after_one_week": "След една седмица", "prefs_notifications_delete_after_one_week": "След една седмица",
"prefs_users_title": "Управление на потребители", "prefs_users_title": "Управление на потребители",
"prefs_users_table_base_url_header": "Адрес на услугата", "prefs_users_table_base_url_header": "Адрес на услугата",
"prefs_users_dialog_title_add": "Добавяне на потребител", "prefs_users_dialog_title_add": "Добавяне на потребител",
"prefs_notifications_delete_after_one_month": "След един месец", "prefs_notifications_delete_after_one_month": "След един месец",
"prefs_users_dialog_username_label": "Потребител, напр. phil", "prefs_users_dialog_username_label": "Потребител, напр. phil",
"prefs_users_dialog_button_add": "Добавяне", "prefs_users_dialog_button_add": "Добавяне",
"error_boundary_title": "О, не, ntfy се срина", "error_boundary_title": "О, не, ntfy се срина",
"error_boundary_description": "Това очевидно не трябва да се случва. Много съжаляваме!<br/>Ако имате минута, <githubLink>докладвайте в GitHub</githubLink> или ни уведомете в <discordLink>Discord</discordLink> или <matrixLink>Matrix</matrixLink>.", "error_boundary_description": "Това очевидно не трябва да се случва. Много съжаляваме!<br/>Ако имате минута, <githubLink>докладвайте в GitHub</githubLink> или ни уведомете в <discordLink>Discord</discordLink> или <matrixLink>Matrix</matrixLink>.",
"error_boundary_stack_trace": "Следа от стека", "error_boundary_stack_trace": "Следа от стека",
"error_boundary_gathering_info": "Събиране на допълнителна информация…", "error_boundary_gathering_info": "Събиране на допълнителна информация…",
"notifications_loading": "Зареждане на известия…", "notifications_loading": "Зареждане на известия…",
"error_boundary_button_copy_stack_trace": "Копиране на следата от стека", "error_boundary_button_copy_stack_trace": "Копиране на следата от стека",
"prefs_users_description": "Добавяйте и премахвайте потребители за защитените теми. Имайте предвид, че потребителското име и паролата се съхраняват в местната памет на мрежовия четец.", "prefs_users_description": "Добавяйте и премахвайте потребители за защитените теми. Имайте предвид, че потребителското име и паролата се съхраняват в местната памет на мрежовия четец.",
"prefs_notifications_sound_description_none": "Известията не са съпроводени със звук", "prefs_notifications_sound_description_none": "Известията не са съпроводени със звук",
"prefs_notifications_sound_description_some": "При пристигане известията са съпроводени от звука „{{sound}}“", "prefs_notifications_sound_description_some": "При пристигане известията са съпроводени от звука „{{sound}}“",
"prefs_notifications_delete_after_never_description": "Известията никога не се премахват автоматично", "prefs_notifications_delete_after_never_description": "Известията никога не се премахват автоматично",
"prefs_notifications_delete_after_three_hours_description": "Известията се премахват автоматично след три часа", "prefs_notifications_delete_after_three_hours_description": "Известията се премахват автоматично след три часа",
"priority_min": "най-нисък", "priority_min": "най-нисък",
"priority_low": "нисък", "priority_low": "нисък",
"priority_high": "висок", "priority_high": "висок",
"priority_max": "най-висок", "priority_max": "най-висок",
"priority_default": "подразбиран", "priority_default": "подразбиран",
"prefs_notifications_delete_after_one_week_description": "Известията се премахват автоматично след една седмица", "prefs_notifications_delete_after_one_week_description": "Известията се премахват автоматично след една седмица",
"prefs_notifications_delete_after_one_day_description": "Известията се премахват автоматично след един ден", "prefs_notifications_delete_after_one_day_description": "Известията се премахват автоматично след един ден",
"prefs_notifications_min_priority_description_max": "Показват се известията с приоритет 5 (най-висок)", "prefs_notifications_min_priority_description_max": "Показват се известията с приоритет 5 (най-висок)",
"prefs_notifications_delete_after_one_month_description": "Известията се премахват автоматично след един месец", "prefs_notifications_delete_after_one_month_description": "Известията се премахват автоматично след един месец",
"prefs_notifications_min_priority_description_any": "Показват се всички известия, независимо от приоритета", "prefs_notifications_min_priority_description_any": "Показват се всички известия, независимо от приоритета",
"prefs_notifications_min_priority_description_x_or_higher": "Показват се известията с приоритет {{number}} ({{name}}) или по-висок", "prefs_notifications_min_priority_description_x_or_higher": "Показват се известията с приоритет {{number}} ({{name}}) или по-висок",
"notifications_actions_http_request_title": "Изпращане на HTTP {{method}} до {{url}}", "notifications_actions_http_request_title": "Изпращане на HTTP {{method}} до {{url}}",
"notifications_actions_not_supported": "Действието не се поддържа от приложението за интернет", "notifications_actions_not_supported": "Действието не се поддържа от приложението за интернет",
"action_bar_show_menu": "Показване на менюто", "action_bar_show_menu": "Показване на менюто",
"action_bar_logo_alt": "Логотип на ntfy", "action_bar_logo_alt": "Логотип на ntfy",
"action_bar_toggle_mute": "Заглушаване или пускне на известията", "action_bar_toggle_mute": "Заглушаване или пускне на известията",
"action_bar_toggle_action_menu": "Отваряне или затваряне на менюто с действията", "action_bar_toggle_action_menu": "Отваряне или затваряне на менюто с действията",
"nav_button_muted": "Известията са заглушени", "nav_button_muted": "Известията са заглушени",
"notifications_list": "Списък с известия", "notifications_list": "Списък с известия",
"notifications_list_item": "Известие", "notifications_list_item": "Известие",
"notifications_delete": "Премахване", "notifications_delete": "Премахване",
"notifications_mark_read": "Отбелязване като прочетено", "notifications_mark_read": "Отбелязване като прочетено",
"nav_button_connecting": "свързване", "nav_button_connecting": "свързване",
"message_bar_show_dialog": "Показване на диалога за публикуване", "message_bar_show_dialog": "Показване на диалога за публикуване",
"message_bar_publish": "Публикуване на съобщение", "message_bar_publish": "Публикуване на съобщение",
"notifications_priority_x": "Приоритет {{priority}}", "notifications_priority_x": "Приоритет {{priority}}",
"notifications_new_indicator": "Ново известие", "notifications_new_indicator": "Ново известие",
"notifications_attachment_image": "Прикачено изображение", "notifications_attachment_image": "Прикачено изображение",
"notifications_attachment_file_image": "файл на изображение", "notifications_attachment_file_image": "файл на изображение",
"notifications_attachment_file_video": "видео", "notifications_attachment_file_video": "видео",
"notifications_attachment_file_audio": "аудио", "notifications_attachment_file_audio": "аудио",
"notifications_attachment_file_app": "инсталационен файл на приложение за Android", "notifications_attachment_file_app": "инсталационен файл на приложение за Android",
"notifications_attachment_file_document": "друг документ", "notifications_attachment_file_document": "друг документ",
"publish_dialog_emoji_picker_show": "Избор на емоция", "publish_dialog_emoji_picker_show": "Избор на емоция",
"publish_dialog_topic_reset": "Нулиране на тема", "publish_dialog_topic_reset": "Нулиране на тема",
"publish_dialog_click_reset": "Премахване на адрес", "publish_dialog_click_reset": "Премахване на адрес",
"publish_dialog_email_reset": "Премахване на препращането към ел. поща", "publish_dialog_email_reset": "Премахване на препращането към ел. поща",
"publish_dialog_delay_reset": "Премахва забавянето на изпращането", "publish_dialog_delay_reset": "Премахва забавянето на изпращането",
"publish_dialog_attached_file_remove": "Премахване на прикачения файл", "publish_dialog_attached_file_remove": "Премахване на прикачения файл",
"emoji_picker_search_clear": "Изчистване на търсенето", "emoji_picker_search_clear": "Изчистване на търсенето",
"subscribe_dialog_subscribe_base_url_label": "Адрес на услугата", "subscribe_dialog_subscribe_base_url_label": "Адрес на услугата",
"prefs_notifications_sound_play": "Възпроизвеждане на избрания звук", "prefs_notifications_sound_play": "Възпроизвеждане на избрания звук",
"publish_dialog_attach_reset": "Премахване на адреса на файла за прикачане", "publish_dialog_attach_reset": "Премахване на адреса на файла за прикачане",
"prefs_users_delete_button": "Премахване", "prefs_users_delete_button": "Премахване",
"prefs_users_table": "Таблица с потребители", "prefs_users_table": "Таблица с потребители",
"prefs_users_edit_button": "Промяна на потребител", "prefs_users_edit_button": "Промяна на потребител",
"error_boundary_unsupported_indexeddb_title": "Поверително разглеждане не се поддържа", "error_boundary_unsupported_indexeddb_title": "Поверително разглеждане не се поддържа",
"error_boundary_unsupported_indexeddb_description": "За да работи интернет-приложението ntfy се нуждае от IndexedDB, а мрежовият четец не поддържа IndexedDB в режим на поверително разглеждане.<br/><br/>Въпреки това, няма смисъл да използвате интернет-приложението ntfy в режим на поверително разглеждане, тъй като всичко се пази в хранилището на четеца. Можете да прочетете повече по <githubLink>проблема в GitHub</githubLink> или да се свържете с нас в <discordLink>Discord</discordLink> или <matrixLink>Matrix</matrixLink>." "error_boundary_unsupported_indexeddb_description": "За да работи интернет-приложението ntfy се нуждае от IndexedDB, а мрежовият четец не поддържа IndexedDB в режим на поверително разглеждане.<br/><br/>Въпреки това, няма смисъл да използвате интернет-приложението ntfy в режим на поверително разглеждане, тъй като всичко се пази в хранилището на четеца. Можете да прочетете повече по <githubLink>проблема в GitHub</githubLink> или да се свържете с нас в <discordLink>Discord</discordLink> или <matrixLink>Matrix</matrixLink>."
} }

View file

@ -1,191 +1,191 @@
{ {
"action_bar_settings": "Nastavení", "action_bar_settings": "Nastavení",
"action_bar_send_test_notification": "Odeslání testovacího oznámení", "action_bar_send_test_notification": "Odeslání testovacího oznámení",
"action_bar_clear_notifications": "Vymazat všechna oznámení", "action_bar_clear_notifications": "Vymazat všechna oznámení",
"action_bar_unsubscribe": "Odhlásit odběr", "action_bar_unsubscribe": "Odhlásit odběr",
"message_bar_type_message": "Zde napište zprávu", "message_bar_type_message": "Zde napište zprávu",
"message_bar_error_publishing": "Chyba při odesílání oznámení", "message_bar_error_publishing": "Chyba při odesílání oznámení",
"nav_topics_title": "Odebíraná témata", "nav_topics_title": "Odebíraná témata",
"nav_button_all_notifications": "Všechna oznámení", "nav_button_all_notifications": "Všechna oznámení",
"nav_button_settings": "Nastavení", "nav_button_settings": "Nastavení",
"nav_button_documentation": "Dokumentace", "nav_button_documentation": "Dokumentace",
"nav_button_publish_message": "Odeslat oznámení", "nav_button_publish_message": "Odeslat oznámení",
"nav_button_subscribe": "Přihlásit se k odběru tématu", "nav_button_subscribe": "Přihlásit se k odběru tématu",
"alert_grant_title": "Oznámení jsou zakázána", "alert_grant_title": "Oznámení jsou zakázána",
"alert_grant_description": "Udělte prohlížeči oprávnění k zobrazování oznámení na ploše.", "alert_grant_description": "Udělte prohlížeči oprávnění k zobrazování oznámení na ploše.",
"alert_grant_button": "Udělit nyní", "alert_grant_button": "Udělit nyní",
"alert_not_supported_title": "Oznámení nejsou podporována", "alert_not_supported_title": "Oznámení nejsou podporována",
"alert_not_supported_description": "Oznámení nejsou ve vašem prohlížeči podporována.", "alert_not_supported_description": "Oznámení nejsou ve vašem prohlížeči podporována.",
"notifications_copied_to_clipboard": "Zkopírováno do schránky", "notifications_copied_to_clipboard": "Zkopírováno do schránky",
"notifications_tags": "Značky", "notifications_tags": "Značky",
"notifications_attachment_copy_url_title": "Kopírovat URL přílohy do schránky", "notifications_attachment_copy_url_title": "Kopírovat URL přílohy do schránky",
"notifications_attachment_copy_url_button": "Kopírovat URL", "notifications_attachment_copy_url_button": "Kopírovat URL",
"notifications_attachment_open_title": "Přejít na {{url}}", "notifications_attachment_open_title": "Přejít na {{url}}",
"notifications_attachment_open_button": "Otevřít přílohu", "notifications_attachment_open_button": "Otevřít přílohu",
"notifications_attachment_link_expires": "platnost odkazu končí {{date}}", "notifications_attachment_link_expires": "platnost odkazu končí {{date}}",
"notifications_attachment_link_expired": "platnost odkazu ke stažení vypršela", "notifications_attachment_link_expired": "platnost odkazu ke stažení vypršela",
"notifications_click_copy_url_title": "Kopírovat URL odkazu do schránky", "notifications_click_copy_url_title": "Kopírovat URL odkazu do schránky",
"notifications_click_copy_url_button": "Kopírovat odkaz", "notifications_click_copy_url_button": "Kopírovat odkaz",
"notifications_click_open_button": "Otevřít odkaz", "notifications_click_open_button": "Otevřít odkaz",
"notifications_none_for_topic_title": "K tomuto tématu jste zatím neobdrželi žádné oznámení.", "notifications_none_for_topic_title": "K tomuto tématu jste zatím neobdrželi žádné oznámení.",
"notifications_none_for_topic_description": "Pro odeslání oznámení k tomuto tématu, odešlete PUT nebo POST požadavek na URL tématu.", "notifications_none_for_topic_description": "Pro odeslání oznámení k tomuto tématu, odešlete PUT nebo POST požadavek na URL tématu.",
"notifications_example": "Příklad", "notifications_example": "Příklad",
"publish_dialog_base_url_placeholder": "URL služby, např. https://example.com", "publish_dialog_base_url_placeholder": "URL služby, např. https://example.com",
"publish_dialog_topic_label": "Název tématu", "publish_dialog_topic_label": "Název tématu",
"publish_dialog_topic_placeholder": "Název tématu, např. phil_alerts", "publish_dialog_topic_placeholder": "Název tématu, např. phil_alerts",
"publish_dialog_priority_default": "Výchozí priorita", "publish_dialog_priority_default": "Výchozí priorita",
"publish_dialog_priority_high": "Vysoká priorita", "publish_dialog_priority_high": "Vysoká priorita",
"publish_dialog_priority_max": "Nevyšší priorita", "publish_dialog_priority_max": "Nevyšší priorita",
"publish_dialog_base_url_label": "URL služby", "publish_dialog_base_url_label": "URL služby",
"prefs_users_dialog_password_label": "Heslo", "prefs_users_dialog_password_label": "Heslo",
"prefs_users_dialog_title_add": "Přidat uživatele", "prefs_users_dialog_title_add": "Přidat uživatele",
"prefs_users_dialog_title_edit": "Upravit uživatele", "prefs_users_dialog_title_edit": "Upravit uživatele",
"prefs_users_dialog_base_url_label": "URL služby, např. https://ntfy.sh", "prefs_users_dialog_base_url_label": "URL služby, např. https://ntfy.sh",
"prefs_users_dialog_username_label": "Uživatelské jméno, např. phil", "prefs_users_dialog_username_label": "Uživatelské jméno, např. phil",
"notifications_actions_open_url_title": "Přejít na {{url}}", "notifications_actions_open_url_title": "Přejít na {{url}}",
"notifications_none_for_any_title": "Neobdrželi jste žádná oznámení.", "notifications_none_for_any_title": "Neobdrželi jste žádná oznámení.",
"notifications_none_for_any_description": "Pro odeslání oznámení k tématu stačí na URL tématu odeslat PUT nebo POST požadavek. Zde je příklad s použitím jednoho z vašich témat.", "notifications_none_for_any_description": "Pro odeslání oznámení k tématu stačí na URL tématu odeslat PUT nebo POST požadavek. Zde je příklad s použitím jednoho z vašich témat.",
"notifications_no_subscriptions_description": "Kliknutím na \"{{linktext}}\" vytvoříte téma nebo se k němu přihlásíte. Poté můžete odesílat zprávy prostřednictvím PUT nebo POST požadavků a zde budete dostávat oznámení.", "notifications_no_subscriptions_description": "Kliknutím na \"{{linktext}}\" vytvoříte téma nebo se k němu přihlásíte. Poté můžete odesílat zprávy prostřednictvím PUT nebo POST požadavků a zde budete dostávat oznámení.",
"notifications_more_details": "Další informace naleznete na <websiteLink>webových stránkách</websiteLink> nebo v <docsLink>dokumentaci</docsLink>.", "notifications_more_details": "Další informace naleznete na <websiteLink>webových stránkách</websiteLink> nebo v <docsLink>dokumentaci</docsLink>.",
"publish_dialog_title_topic": "Odeslat do {{téma}}", "publish_dialog_title_topic": "Odeslat do {{téma}}",
"publish_dialog_title_no_topic": "Odeslat oznámení", "publish_dialog_title_no_topic": "Odeslat oznámení",
"publish_dialog_progress_uploading": "Nahrávání …", "publish_dialog_progress_uploading": "Nahrávání …",
"publish_dialog_message_published": "Oznámení odesláno", "publish_dialog_message_published": "Oznámení odesláno",
"publish_dialog_attachment_limits_file_and_quota_reached": "překračuje {{fileSizeLimit}} limit souboru a kvótu, {{remainingBytes}} zbývá", "publish_dialog_attachment_limits_file_and_quota_reached": "překračuje {{fileSizeLimit}} limit souboru a kvótu, {{remainingBytes}} zbývá",
"publish_dialog_attachment_limits_quota_reached": "překračuje kvótu, {{remainingBytes}} zbývá", "publish_dialog_attachment_limits_quota_reached": "překračuje kvótu, {{remainingBytes}} zbývá",
"publish_dialog_priority_min": "Nejnižší priorita", "publish_dialog_priority_min": "Nejnižší priorita",
"publish_dialog_title_label": "Název", "publish_dialog_title_label": "Název",
"publish_dialog_title_placeholder": "Název oznámení, např. Upozornění na volné místo na disku", "publish_dialog_title_placeholder": "Název oznámení, např. Upozornění na volné místo na disku",
"publish_dialog_message_placeholder": "Zde napište zprávu", "publish_dialog_message_placeholder": "Zde napište zprávu",
"publish_dialog_tags_label": "Značky", "publish_dialog_tags_label": "Značky",
"publish_dialog_priority_label": "Priorita", "publish_dialog_priority_label": "Priorita",
"publish_dialog_click_label": "Klikněte na URL", "publish_dialog_click_label": "Klikněte na URL",
"publish_dialog_click_placeholder": "Adresa URL, která se otevře po kliknutí na oznámení", "publish_dialog_click_placeholder": "Adresa URL, která se otevře po kliknutí na oznámení",
"publish_dialog_email_label": "E-mail", "publish_dialog_email_label": "E-mail",
"publish_dialog_email_placeholder": "Adresa pro odeslání oznámení, např. phil@example.com", "publish_dialog_email_placeholder": "Adresa pro odeslání oznámení, např. phil@example.com",
"publish_dialog_attach_label": "URL přílohy", "publish_dialog_attach_label": "URL přílohy",
"publish_dialog_filename_label": "Název souboru", "publish_dialog_filename_label": "Název souboru",
"publish_dialog_filename_placeholder": "Název souboru přílohy", "publish_dialog_filename_placeholder": "Název souboru přílohy",
"publish_dialog_delay_label": "Zpoždění", "publish_dialog_delay_label": "Zpoždění",
"publish_dialog_delay_placeholder": "Zpožděné doručení, např. {{unixTimestamp}}, {{relativeTime}} nebo \"{{naturalLanguage}}\". (pouze v angličtině)", "publish_dialog_delay_placeholder": "Zpožděné doručení, např. {{unixTimestamp}}, {{relativeTime}} nebo \"{{naturalLanguage}}\". (pouze v angličtině)",
"publish_dialog_chip_click_label": "Klikněte na URL", "publish_dialog_chip_click_label": "Klikněte na URL",
"publish_dialog_chip_email_label": "Přeposlat na e-mail", "publish_dialog_chip_email_label": "Přeposlat na e-mail",
"publish_dialog_chip_delay_label": "Zpožděné doručení", "publish_dialog_chip_delay_label": "Zpožděné doručení",
"publish_dialog_chip_topic_label": "Změnit téma", "publish_dialog_chip_topic_label": "Změnit téma",
"publish_dialog_details_examples_description": "Příklady a podrobný popis všech funkcí odesílání naleznete v <docsLink>dokumentaci</docsLink>.", "publish_dialog_details_examples_description": "Příklady a podrobný popis všech funkcí odesílání naleznete v <docsLink>dokumentaci</docsLink>.",
"publish_dialog_chip_attach_url_label": "Připojit soubor pomocí URL", "publish_dialog_chip_attach_url_label": "Připojit soubor pomocí URL",
"publish_dialog_chip_attach_file_label": "Připojit místní soubor", "publish_dialog_chip_attach_file_label": "Připojit místní soubor",
"publish_dialog_button_send": "Odeslat", "publish_dialog_button_send": "Odeslat",
"publish_dialog_checkbox_publish_another": "Odeslat další", "publish_dialog_checkbox_publish_another": "Odeslat další",
"publish_dialog_attached_file_title": "Přiložený soubor:", "publish_dialog_attached_file_title": "Přiložený soubor:",
"publish_dialog_attached_file_filename_placeholder": "Název souboru přílohy", "publish_dialog_attached_file_filename_placeholder": "Název souboru přílohy",
"publish_dialog_drop_file_here": "Přetáhněte soubor sem", "publish_dialog_drop_file_here": "Přetáhněte soubor sem",
"emoji_picker_search_placeholder": "Hledat emodži", "emoji_picker_search_placeholder": "Hledat emodži",
"subscribe_dialog_subscribe_title": "Přihlásit odběr tématu", "subscribe_dialog_subscribe_title": "Přihlásit odběr tématu",
"subscribe_dialog_subscribe_description": "Témata nemusí být chráněna heslem, proto zvolte název, který není snadné uhodnout. Jakmile se přihlásíte k odběru, můžete odesílat oznámení pomocí PUT/POST požadavků.", "subscribe_dialog_subscribe_description": "Témata nemusí být chráněna heslem, proto zvolte název, který není snadné uhodnout. Jakmile se přihlásíte k odběru, můžete odesílat oznámení pomocí PUT/POST požadavků.",
"subscribe_dialog_subscribe_topic_placeholder": "Název tématu, např. phil_alerts", "subscribe_dialog_subscribe_topic_placeholder": "Název tématu, např. phil_alerts",
"subscribe_dialog_subscribe_use_another_label": "Použít jiný server", "subscribe_dialog_subscribe_use_another_label": "Použít jiný server",
"subscribe_dialog_login_title": "Vyžadováno přihlášení", "subscribe_dialog_login_title": "Vyžadováno přihlášení",
"subscribe_dialog_login_description": "Toto téma je chráněno heslem. Pro přihlášení k odběru zadejte prosím uživatelské jméno a heslo.", "subscribe_dialog_login_description": "Toto téma je chráněno heslem. Pro přihlášení k odběru zadejte prosím uživatelské jméno a heslo.",
"subscribe_dialog_subscribe_button_cancel": "Zrušit", "subscribe_dialog_subscribe_button_cancel": "Zrušit",
"subscribe_dialog_subscribe_button_subscribe": "Přihlásit odběr", "subscribe_dialog_subscribe_button_subscribe": "Přihlásit odběr",
"subscribe_dialog_login_username_label": "Uživatelské jméno, např. phil", "subscribe_dialog_login_username_label": "Uživatelské jméno, např. phil",
"subscribe_dialog_login_password_label": "Heslo", "subscribe_dialog_login_password_label": "Heslo",
"subscribe_dialog_login_button_back": "Zpět", "subscribe_dialog_login_button_back": "Zpět",
"subscribe_dialog_login_button_login": "Přihlásit se", "subscribe_dialog_login_button_login": "Přihlásit se",
"subscribe_dialog_error_user_not_authorized": "Uživatel {{username}} není autorizován", "subscribe_dialog_error_user_not_authorized": "Uživatel {{username}} není autorizován",
"subscribe_dialog_error_user_anonymous": "anonymně", "subscribe_dialog_error_user_anonymous": "anonymně",
"prefs_notifications_title": "Oznámení", "prefs_notifications_title": "Oznámení",
"prefs_notifications_sound_description_some": "Oznámení přehrají při doručení zvuk {{sound}}", "prefs_notifications_sound_description_some": "Oznámení přehrají při doručení zvuk {{sound}}",
"prefs_notifications_min_priority_description_x_or_higher": "Zobrazit oznámení, pokud je priorita {{number}} ({{name}}) nebo vyšší", "prefs_notifications_min_priority_description_x_or_higher": "Zobrazit oznámení, pokud je priorita {{number}} ({{name}}) nebo vyšší",
"prefs_notifications_min_priority_description_max": "Zobrazit oznámení, pokud je priorita 5 (nejvyšší)", "prefs_notifications_min_priority_description_max": "Zobrazit oznámení, pokud je priorita 5 (nejvyšší)",
"prefs_notifications_min_priority_any": "Jakákoli priorita", "prefs_notifications_min_priority_any": "Jakákoli priorita",
"prefs_notifications_min_priority_low_and_higher": "Nízká priorita a vyšší", "prefs_notifications_min_priority_low_and_higher": "Nízká priorita a vyšší",
"prefs_notifications_min_priority_default_and_higher": "Výchozí priorita a vyšší", "prefs_notifications_min_priority_default_and_higher": "Výchozí priorita a vyšší",
"prefs_notifications_min_priority_high_and_higher": "Vysoká priorita a vyšší", "prefs_notifications_min_priority_high_and_higher": "Vysoká priorita a vyšší",
"prefs_notifications_delete_after_three_hours": "Po třech hodinách", "prefs_notifications_delete_after_three_hours": "Po třech hodinách",
"prefs_notifications_delete_after_one_day": "Po jednom dni", "prefs_notifications_delete_after_one_day": "Po jednom dni",
"prefs_notifications_delete_after_one_week": "Po jednom týdnu", "prefs_notifications_delete_after_one_week": "Po jednom týdnu",
"prefs_notifications_delete_after_one_month": "Po jednom měsíci", "prefs_notifications_delete_after_one_month": "Po jednom měsíci",
"prefs_notifications_delete_after_never_description": "Oznámení nejsou nikdy automaticky mazána", "prefs_notifications_delete_after_never_description": "Oznámení nejsou nikdy automaticky mazána",
"prefs_notifications_delete_after_three_hours_description": "Oznámení se automaticky odstraní po třech hodinách", "prefs_notifications_delete_after_three_hours_description": "Oznámení se automaticky odstraní po třech hodinách",
"prefs_notifications_delete_after_one_day_description": "Oznámení se automaticky odstraní po jednom dni", "prefs_notifications_delete_after_one_day_description": "Oznámení se automaticky odstraní po jednom dni",
"prefs_notifications_delete_after_one_week_description": "Oznámení se automaticky odstraní po jednom týdnu", "prefs_notifications_delete_after_one_week_description": "Oznámení se automaticky odstraní po jednom týdnu",
"prefs_notifications_delete_after_one_month_description": "Oznámení se automaticky odstraní po jednom měsíci", "prefs_notifications_delete_after_one_month_description": "Oznámení se automaticky odstraní po jednom měsíci",
"prefs_users_title": "Správa uživatelů", "prefs_users_title": "Správa uživatelů",
"prefs_users_add_button": "Přidat uživatele", "prefs_users_add_button": "Přidat uživatele",
"prefs_users_table_user_header": "Uživatel", "prefs_users_table_user_header": "Uživatel",
"prefs_users_table_base_url_header": "URL služby", "prefs_users_table_base_url_header": "URL služby",
"prefs_users_dialog_button_cancel": "Zrušit", "prefs_users_dialog_button_cancel": "Zrušit",
"prefs_users_dialog_button_add": "Přidat", "prefs_users_dialog_button_add": "Přidat",
"prefs_users_dialog_button_save": "Uložit", "prefs_users_dialog_button_save": "Uložit",
"priority_min": "nejnižší", "priority_min": "nejnižší",
"priority_low": "nízká", "priority_low": "nízká",
"priority_default": "výchozí", "priority_default": "výchozí",
"priority_high": "vysoká", "priority_high": "vysoká",
"priority_max": "nejvyšší", "priority_max": "nejvyšší",
"error_boundary_title": "Ale ne, ntfy havaroval", "error_boundary_title": "Ale ne, ntfy havaroval",
"error_boundary_description": "K tomu by samozřejmě nemělo docházet. Velmi se za to omlouváme.<br/>Pokud máte chvilku, nahlaste to prosím <githubLink>na GitHubu</githubLink> nebo nám dejte vědět prostřednictvím <discordLink>Discordu</discordLink> nebo <matrixLink>Matrixu</matrixLink>.", "error_boundary_description": "K tomu by samozřejmě nemělo docházet. Velmi se za to omlouváme.<br/>Pokud máte chvilku, nahlaste to prosím <githubLink>na GitHubu</githubLink> nebo nám dejte vědět prostřednictvím <discordLink>Discordu</discordLink> nebo <matrixLink>Matrixu</matrixLink>.",
"error_boundary_button_copy_stack_trace": "Kopírovat výpis zásobníku", "error_boundary_button_copy_stack_trace": "Kopírovat výpis zásobníku",
"error_boundary_stack_trace": "Výpis zásobníku", "error_boundary_stack_trace": "Výpis zásobníku",
"publish_dialog_tags_placeholder": "Seznam značek oddělených čárkou, např. warning, srv1-backup", "publish_dialog_tags_placeholder": "Seznam značek oddělených čárkou, např. warning, srv1-backup",
"notifications_actions_not_supported": "Akce není podporována ve webové aplikaci", "notifications_actions_not_supported": "Akce není podporována ve webové aplikaci",
"notifications_actions_http_request_title": "Odeslat HTTP {{metoda}} na {{url}}", "notifications_actions_http_request_title": "Odeslat HTTP {{metoda}} na {{url}}",
"notifications_no_subscriptions_title": "Vypadá to, že ještě nemáte žádné odběry.", "notifications_no_subscriptions_title": "Vypadá to, že ještě nemáte žádné odběry.",
"prefs_notifications_min_priority_description_any": "Zobrazit všechna oznámení bez ohledu na prioritu", "prefs_notifications_min_priority_description_any": "Zobrazit všechna oznámení bez ohledu na prioritu",
"publish_dialog_priority_low": "Nízká priorita", "publish_dialog_priority_low": "Nízká priorita",
"publish_dialog_message_label": "Zpráva", "publish_dialog_message_label": "Zpráva",
"publish_dialog_button_cancel": "Zrušit", "publish_dialog_button_cancel": "Zrušit",
"notifications_loading": "Načítání oznámení …", "notifications_loading": "Načítání oznámení …",
"publish_dialog_progress_uploading_detail": "Nahrávání {{loaded}}/{{total}} ({{percent}}%) …", "publish_dialog_progress_uploading_detail": "Nahrávání {{loaded}}/{{total}} ({{percent}}%) …",
"publish_dialog_attachment_limits_file_reached": "překračuje {{fileSizeLimit}} limit souboru", "publish_dialog_attachment_limits_file_reached": "překračuje {{fileSizeLimit}} limit souboru",
"publish_dialog_attach_placeholder": "Připojit soubor pomocí URL, např. https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "Připojit soubor pomocí URL, např. https://f-droid.org/F-Droid.apk",
"publish_dialog_button_cancel_sending": "Zrušit odesílání", "publish_dialog_button_cancel_sending": "Zrušit odesílání",
"publish_dialog_other_features": "Další funkce:", "publish_dialog_other_features": "Další funkce:",
"prefs_notifications_sound_title": "Zvuk oznámení", "prefs_notifications_sound_title": "Zvuk oznámení",
"prefs_notifications_min_priority_max_only": "Pouze nejvyšší priorita", "prefs_notifications_min_priority_max_only": "Pouze nejvyšší priorita",
"prefs_notifications_min_priority_title": "Nejnižší priorita", "prefs_notifications_min_priority_title": "Nejnižší priorita",
"prefs_notifications_delete_after_title": "Odstranit oznámení", "prefs_notifications_delete_after_title": "Odstranit oznámení",
"prefs_notifications_delete_after_never": "Nikdy", "prefs_notifications_delete_after_never": "Nikdy",
"prefs_notifications_sound_no_sound": "Žádný zvuk", "prefs_notifications_sound_no_sound": "Žádný zvuk",
"prefs_notifications_sound_description_none": "Oznámení nepřehrají při doručení žádný zvuk", "prefs_notifications_sound_description_none": "Oznámení nepřehrají při doručení žádný zvuk",
"prefs_users_description": "Zde můžete přidávat/odebírat uživatele pro chráněná témata. Upozorňujeme, že uživatelské jméno a heslo jsou uloženy v místním úložišti prohlížeče.", "prefs_users_description": "Zde můžete přidávat/odebírat uživatele pro chráněná témata. Upozorňujeme, že uživatelské jméno a heslo jsou uloženy v místním úložišti prohlížeče.",
"error_boundary_gathering_info": "Získejte více informací …", "error_boundary_gathering_info": "Získejte více informací …",
"prefs_appearance_language_title": "Jazyk", "prefs_appearance_language_title": "Jazyk",
"prefs_appearance_title": "Vzhled", "prefs_appearance_title": "Vzhled",
"action_bar_show_menu": "Zobrazit nabídku", "action_bar_show_menu": "Zobrazit nabídku",
"action_bar_logo_alt": "logo ntfy", "action_bar_logo_alt": "logo ntfy",
"action_bar_toggle_mute": "Ztlumení/zrušení ztlumení oznámení", "action_bar_toggle_mute": "Ztlumení/zrušení ztlumení oznámení",
"action_bar_toggle_action_menu": "Otevřít/zavřít nabídku akcí", "action_bar_toggle_action_menu": "Otevřít/zavřít nabídku akcí",
"message_bar_show_dialog": "Zobrazit okno pro odesílání oznámení", "message_bar_show_dialog": "Zobrazit okno pro odesílání oznámení",
"message_bar_publish": "Odeslat zprávu", "message_bar_publish": "Odeslat zprávu",
"nav_button_muted": "Oznámení ztlumena", "nav_button_muted": "Oznámení ztlumena",
"nav_button_connecting": "připojování", "nav_button_connecting": "připojování",
"notifications_list": "Seznam oznámení", "notifications_list": "Seznam oznámení",
"notifications_list_item": "Oznámení", "notifications_list_item": "Oznámení",
"notifications_mark_read": "Označit jako přečtené", "notifications_mark_read": "Označit jako přečtené",
"notifications_delete": "Smazat", "notifications_delete": "Smazat",
"notifications_new_indicator": "Nové oznámení", "notifications_new_indicator": "Nové oznámení",
"notifications_attachment_image": "Obrázek přílohy", "notifications_attachment_image": "Obrázek přílohy",
"notifications_attachment_file_image": "soubor s obrázkem", "notifications_attachment_file_image": "soubor s obrázkem",
"notifications_attachment_file_video": "video soubor", "notifications_attachment_file_video": "video soubor",
"notifications_attachment_file_audio": "zvukový soubor", "notifications_attachment_file_audio": "zvukový soubor",
"notifications_attachment_file_app": "Soubor s aplikací pro Android", "notifications_attachment_file_app": "Soubor s aplikací pro Android",
"publish_dialog_emoji_picker_show": "Vybrat emoji", "publish_dialog_emoji_picker_show": "Vybrat emoji",
"publish_dialog_topic_reset": "Obnovení tématu", "publish_dialog_topic_reset": "Obnovení tématu",
"publish_dialog_click_reset": "Odebrat URL kliknutím", "publish_dialog_click_reset": "Odebrat URL kliknutím",
"publish_dialog_email_reset": "Odebrat přeposlání e-mailu", "publish_dialog_email_reset": "Odebrat přeposlání e-mailu",
"publish_dialog_attach_reset": "Odebrat URL přílohy", "publish_dialog_attach_reset": "Odebrat URL přílohy",
"publish_dialog_attached_file_remove": "Odebrat přiložený soubor", "publish_dialog_attached_file_remove": "Odebrat přiložený soubor",
"emoji_picker_search_clear": "Vyčistit vyhledávání", "emoji_picker_search_clear": "Vyčistit vyhledávání",
"prefs_users_edit_button": "Upravit uživatele", "prefs_users_edit_button": "Upravit uživatele",
"prefs_users_delete_button": "Odstranit uživatele", "prefs_users_delete_button": "Odstranit uživatele",
"error_boundary_unsupported_indexeddb_title": "Soukromé prohlížení není podporováno", "error_boundary_unsupported_indexeddb_title": "Soukromé prohlížení není podporováno",
"error_boundary_unsupported_indexeddb_description": "Webová aplikace ntfy potřebuje ke svému fungování databázi IndexedDB a váš prohlížeč v režimu soukromého prohlížení databázi IndexedDB nepodporuje.<br/><br/>To je sice nepříjemné, ale používat webovou aplikaci ntfy v režimu soukromého prohlížení stejně nemá smysl, protože vše je uloženo v úložišti prohlížeče. Více se o tom můžete dočíst <githubLink>v tomto tématu na GitHubu</githubLink>, nebo se na nás obrátit pomocí služeb <discordLink>Discord</discordLink> nebo <matrixLink>Matrix</matrixLink>.", "error_boundary_unsupported_indexeddb_description": "Webová aplikace ntfy potřebuje ke svému fungování databázi IndexedDB a váš prohlížeč v režimu soukromého prohlížení databázi IndexedDB nepodporuje.<br/><br/>To je sice nepříjemné, ale používat webovou aplikaci ntfy v režimu soukromého prohlížení stejně nemá smysl, protože vše je uloženo v úložišti prohlížeče. Více se o tom můžete dočíst <githubLink>v tomto tématu na GitHubu</githubLink>, nebo se na nás obrátit pomocí služeb <discordLink>Discord</discordLink> nebo <matrixLink>Matrix</matrixLink>.",
"notifications_priority_x": "Priorita {{priority}}", "notifications_priority_x": "Priorita {{priority}}",
"subscribe_dialog_subscribe_base_url_label": "URL služby", "subscribe_dialog_subscribe_base_url_label": "URL služby",
"prefs_notifications_sound_play": "Přehrát vybraný zvuk", "prefs_notifications_sound_play": "Přehrát vybraný zvuk",
"prefs_users_table": "Tabulka uživatelů", "prefs_users_table": "Tabulka uživatelů",
"notifications_attachment_file_document": "jiný dokument", "notifications_attachment_file_document": "jiný dokument",
"publish_dialog_delay_reset": "Odebrat odložené doručení" "publish_dialog_delay_reset": "Odebrat odložené doručení"
} }

View file

@ -1,191 +1,191 @@
{ {
"nav_topics_title": "Abonnierte Themen", "nav_topics_title": "Abonnierte Themen",
"nav_button_all_notifications": "Alle Benachrichtigungen", "nav_button_all_notifications": "Alle Benachrichtigungen",
"nav_button_settings": "Einstellungen", "nav_button_settings": "Einstellungen",
"nav_button_documentation": "Dokumentation", "nav_button_documentation": "Dokumentation",
"nav_button_publish_message": "Benachrichtigung senden", "nav_button_publish_message": "Benachrichtigung senden",
"nav_button_subscribe": "Thema abonnieren", "nav_button_subscribe": "Thema abonnieren",
"alert_grant_title": "Benachrichtigungen sind deaktiviert", "alert_grant_title": "Benachrichtigungen sind deaktiviert",
"publish_dialog_base_url_label": "Service-URL", "publish_dialog_base_url_label": "Service-URL",
"publish_dialog_details_examples_description": "Beispiele und ausführliche Informationen zu allen Optionen findest Du in der <docsLink>Dokumentation</docsLink>.", "publish_dialog_details_examples_description": "Beispiele und ausführliche Informationen zu allen Optionen findest Du in der <docsLink>Dokumentation</docsLink>.",
"publish_dialog_attached_file_filename_placeholder": "Dateiname des Anhangs", "publish_dialog_attached_file_filename_placeholder": "Dateiname des Anhangs",
"subscribe_dialog_login_description": "Dieses Thema benötigt eine Anmeldung. Bitte gib Benutzernamen und Kennwort ein.", "subscribe_dialog_login_description": "Dieses Thema benötigt eine Anmeldung. Bitte gib Benutzernamen und Kennwort ein.",
"prefs_notifications_title": "Benachrichtigungen", "prefs_notifications_title": "Benachrichtigungen",
"prefs_notifications_sound_title": "Benachrichtigungston", "prefs_notifications_sound_title": "Benachrichtigungston",
"prefs_notifications_min_priority_max_only": "Nur höchste Priorität", "prefs_notifications_min_priority_max_only": "Nur höchste Priorität",
"prefs_notifications_delete_after_never": "Nie", "prefs_notifications_delete_after_never": "Nie",
"prefs_users_dialog_password_label": "Kennwort", "prefs_users_dialog_password_label": "Kennwort",
"prefs_users_dialog_button_cancel": "Abbrechen", "prefs_users_dialog_button_cancel": "Abbrechen",
"prefs_users_dialog_button_add": "Hinzufügen", "prefs_users_dialog_button_add": "Hinzufügen",
"prefs_users_dialog_button_save": "Speichern", "prefs_users_dialog_button_save": "Speichern",
"prefs_appearance_language_title": "Sprache", "prefs_appearance_language_title": "Sprache",
"notifications_none_for_any_description": "Um Benachrichtigungen an ein Thema zu senden, schicke einen PUT/POST-Request an die Themen-URL. Hier ist ein Beispiel mit einem Deiner Themen.", "notifications_none_for_any_description": "Um Benachrichtigungen an ein Thema zu senden, schicke einen PUT/POST-Request an die Themen-URL. Hier ist ein Beispiel mit einem Deiner Themen.",
"publish_dialog_message_placeholder": "Gib hier eine Nachricht ein", "publish_dialog_message_placeholder": "Gib hier eine Nachricht ein",
"notifications_attachment_link_expires": "Link läuft ab am/um {{date}}", "notifications_attachment_link_expires": "Link läuft ab am/um {{date}}",
"notifications_click_copy_url_title": "Link-URL in Zwischenablage kopieren", "notifications_click_copy_url_title": "Link-URL in Zwischenablage kopieren",
"publish_dialog_priority_low": "Niedrige Priorität", "publish_dialog_priority_low": "Niedrige Priorität",
"publish_dialog_message_label": "Nachricht", "publish_dialog_message_label": "Nachricht",
"action_bar_unsubscribe": "Von Thema abmelden", "action_bar_unsubscribe": "Von Thema abmelden",
"notifications_copied_to_clipboard": "In Zwischenablage kopiert", "notifications_copied_to_clipboard": "In Zwischenablage kopiert",
"notifications_loading": "Benachrichtigungen werden geladen …", "notifications_loading": "Benachrichtigungen werden geladen …",
"notifications_attachment_open_title": "Gehe zu {{url}}", "notifications_attachment_open_title": "Gehe zu {{url}}",
"notifications_none_for_any_title": "Du hast keine Benachrichtigungen empfangen.", "notifications_none_for_any_title": "Du hast keine Benachrichtigungen empfangen.",
"action_bar_send_test_notification": "Test-Benachrichtigung senden", "action_bar_send_test_notification": "Test-Benachrichtigung senden",
"alert_grant_description": "Dem Browser erlauben, Desktop-Benachrichtigungen anzuzeigen.", "alert_grant_description": "Dem Browser erlauben, Desktop-Benachrichtigungen anzuzeigen.",
"notifications_tags": "Tags", "notifications_tags": "Tags",
"message_bar_type_message": "Gib hier eine Nachricht ein", "message_bar_type_message": "Gib hier eine Nachricht ein",
"message_bar_error_publishing": "Fehler beim Senden der Benachrichtigung", "message_bar_error_publishing": "Fehler beim Senden der Benachrichtigung",
"alert_not_supported_title": "Benachrichtigungen werden nicht unterstützt", "alert_not_supported_title": "Benachrichtigungen werden nicht unterstützt",
"alert_not_supported_description": "Benachrichtigungen werden von Deinem Browser nicht unterstützt.", "alert_not_supported_description": "Benachrichtigungen werden von Deinem Browser nicht unterstützt.",
"action_bar_settings": "Einstellungen", "action_bar_settings": "Einstellungen",
"action_bar_clear_notifications": "Alle Benachrichtigungen löschen", "action_bar_clear_notifications": "Alle Benachrichtigungen löschen",
"alert_grant_button": "Jetzt erlauben", "alert_grant_button": "Jetzt erlauben",
"notifications_none_for_topic_title": "Du hast für dieses Thema noch keine Benachrichtigungen empfangen.", "notifications_none_for_topic_title": "Du hast für dieses Thema noch keine Benachrichtigungen empfangen.",
"notifications_click_open_button": "Link öffnen", "notifications_click_open_button": "Link öffnen",
"notifications_more_details": "Ausführlichere Informationen findest Du auf der <websiteLink>Website</websiteLink> und in der <docsLink>Dokumentation</docsLink>.", "notifications_more_details": "Ausführlichere Informationen findest Du auf der <websiteLink>Website</websiteLink> und in der <docsLink>Dokumentation</docsLink>.",
"notifications_attachment_copy_url_title": "URL des Anhangs in Zwischenablage kopieren", "notifications_attachment_copy_url_title": "URL des Anhangs in Zwischenablage kopieren",
"notifications_attachment_copy_url_button": "URL kopieren", "notifications_attachment_copy_url_button": "URL kopieren",
"notifications_attachment_open_button": "Anhang öffnen", "notifications_attachment_open_button": "Anhang öffnen",
"notifications_attachment_link_expired": "Download-Link ist abgelaufen", "notifications_attachment_link_expired": "Download-Link ist abgelaufen",
"notifications_click_copy_url_button": "Link kopieren", "notifications_click_copy_url_button": "Link kopieren",
"notifications_actions_open_url_title": "Gehe zu {{url}}", "notifications_actions_open_url_title": "Gehe zu {{url}}",
"publish_dialog_other_features": "Andere Optionen:", "publish_dialog_other_features": "Andere Optionen:",
"notifications_none_for_topic_description": "Um Benachrichtigungen an dieses Thema zu senden, PUTe/POSTe an die Themen-URL.", "notifications_none_for_topic_description": "Um Benachrichtigungen an dieses Thema zu senden, PUTe/POSTe an die Themen-URL.",
"notifications_no_subscriptions_title": "Anscheinend hast Du noch keine Themen abonniert.", "notifications_no_subscriptions_title": "Anscheinend hast Du noch keine Themen abonniert.",
"notifications_no_subscriptions_description": "Klicke den „{{linktext}}“-Link um ein Thema zu erstellen oder zu abonnieren. Danach kannst Du Nachrichten per PUT oder POST senden und erhältst hier die Benachrichtigungen.", "notifications_no_subscriptions_description": "Klicke den „{{linktext}}“-Link um ein Thema zu erstellen oder zu abonnieren. Danach kannst Du Nachrichten per PUT oder POST senden und erhältst hier die Benachrichtigungen.",
"notifications_example": "Beispiel", "notifications_example": "Beispiel",
"publish_dialog_progress_uploading": "Wird hochgeladen …", "publish_dialog_progress_uploading": "Wird hochgeladen …",
"publish_dialog_title_topic": "Senden an {{topic}}", "publish_dialog_title_topic": "Senden an {{topic}}",
"publish_dialog_title_no_topic": "Benachrichtigung senden", "publish_dialog_title_no_topic": "Benachrichtigung senden",
"publish_dialog_message_published": "Benachrichtigung gesendet", "publish_dialog_message_published": "Benachrichtigung gesendet",
"publish_dialog_attachment_limits_file_and_quota_reached": "überschreitet das Dateigrößen-Limit {{fileSizeLimit}} und die Quota, {{remainingBytes}} übrig", "publish_dialog_attachment_limits_file_and_quota_reached": "überschreitet das Dateigrößen-Limit {{fileSizeLimit}} und die Quota, {{remainingBytes}} übrig",
"publish_dialog_progress_uploading_detail": "Hochladen {{loaded}}/{{total}} ({{percent}} %) …", "publish_dialog_progress_uploading_detail": "Hochladen {{loaded}}/{{total}} ({{percent}} %) …",
"publish_dialog_priority_max": "Max. Priorität", "publish_dialog_priority_max": "Max. Priorität",
"publish_dialog_topic_placeholder": "Thema, z.B. phil_alerts", "publish_dialog_topic_placeholder": "Thema, z.B. phil_alerts",
"publish_dialog_attachment_limits_file_reached": "überschreitet das Dateigrößen-Limit {{filesizeLimit}}", "publish_dialog_attachment_limits_file_reached": "überschreitet das Dateigrößen-Limit {{filesizeLimit}}",
"publish_dialog_topic_label": "Thema", "publish_dialog_topic_label": "Thema",
"publish_dialog_priority_default": "Standard-Priorität", "publish_dialog_priority_default": "Standard-Priorität",
"publish_dialog_base_url_placeholder": "Service-URL, z.B. https://example.com", "publish_dialog_base_url_placeholder": "Service-URL, z.B. https://example.com",
"publish_dialog_attachment_limits_quota_reached": "überschreitet die Quota, {{remainingBytes}} übrig", "publish_dialog_attachment_limits_quota_reached": "überschreitet die Quota, {{remainingBytes}} übrig",
"publish_dialog_priority_min": "Min. Priorität", "publish_dialog_priority_min": "Min. Priorität",
"publish_dialog_priority_high": "Hohe Priorität", "publish_dialog_priority_high": "Hohe Priorität",
"publish_dialog_title_label": "Titel", "publish_dialog_title_label": "Titel",
"publish_dialog_tags_placeholder": "Komma-getrennte Liste von Tags, z.B. Warnung, srv1-Backup", "publish_dialog_tags_placeholder": "Komma-getrennte Liste von Tags, z.B. Warnung, srv1-Backup",
"publish_dialog_priority_label": "Priorität", "publish_dialog_priority_label": "Priorität",
"publish_dialog_filename_label": "Dateiname", "publish_dialog_filename_label": "Dateiname",
"publish_dialog_title_placeholder": "Benachrichtigungs-Titel, z.B. CPU-Last-Warnung", "publish_dialog_title_placeholder": "Benachrichtigungs-Titel, z.B. CPU-Last-Warnung",
"publish_dialog_tags_label": "Tags", "publish_dialog_tags_label": "Tags",
"publish_dialog_click_label": "Klick-URL", "publish_dialog_click_label": "Klick-URL",
"publish_dialog_click_placeholder": "URL die geöffnet werden soll, wenn die Benachrichtigung angeklickt wird", "publish_dialog_click_placeholder": "URL die geöffnet werden soll, wenn die Benachrichtigung angeklickt wird",
"publish_dialog_email_label": "E-Mail", "publish_dialog_email_label": "E-Mail",
"publish_dialog_attach_label": "URL des Anhangs", "publish_dialog_attach_label": "URL des Anhangs",
"publish_dialog_attach_placeholder": "Datei von URL anhängen, z.B. https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "Datei von URL anhängen, z.B. https://f-droid.org/F-Droid.apk",
"publish_dialog_filename_placeholder": "Dateiname des Anhangs", "publish_dialog_filename_placeholder": "Dateiname des Anhangs",
"publish_dialog_delay_label": "Verzögerung", "publish_dialog_delay_label": "Verzögerung",
"publish_dialog_email_placeholder": "E-Mail-Adresse, an die die Benachrichtigung gesendet werden soll, z.B. phil@example.com", "publish_dialog_email_placeholder": "E-Mail-Adresse, an die die Benachrichtigung gesendet werden soll, z.B. phil@example.com",
"publish_dialog_chip_click_label": "Klick-URL", "publish_dialog_chip_click_label": "Klick-URL",
"publish_dialog_button_cancel_sending": "Senden abbrechen", "publish_dialog_button_cancel_sending": "Senden abbrechen",
"publish_dialog_drop_file_here": "Datei hierher ziehen", "publish_dialog_drop_file_here": "Datei hierher ziehen",
"publish_dialog_chip_email_label": "An E-Mail weiterleiten", "publish_dialog_chip_email_label": "An E-Mail weiterleiten",
"publish_dialog_button_cancel": "Abbrechen", "publish_dialog_button_cancel": "Abbrechen",
"publish_dialog_chip_attach_file_label": "Lokale Datei anhängen", "publish_dialog_chip_attach_file_label": "Lokale Datei anhängen",
"prefs_notifications_min_priority_title": "Minimale Priorität", "prefs_notifications_min_priority_title": "Minimale Priorität",
"prefs_users_add_button": "Benutzer hinzufügen", "prefs_users_add_button": "Benutzer hinzufügen",
"publish_dialog_delay_placeholder": "Auslieferung verzögern, z.B. {{unixTimestamp}}, {{relativeTime}}, oder \"{{naturalLanguage}}\" (nur Englisch)", "publish_dialog_delay_placeholder": "Auslieferung verzögern, z.B. {{unixTimestamp}}, {{relativeTime}}, oder \"{{naturalLanguage}}\" (nur Englisch)",
"prefs_appearance_title": "Darstellung", "prefs_appearance_title": "Darstellung",
"subscribe_dialog_login_password_label": "Kennwort", "subscribe_dialog_login_password_label": "Kennwort",
"subscribe_dialog_login_button_back": "Zurück", "subscribe_dialog_login_button_back": "Zurück",
"publish_dialog_chip_attach_url_label": "Datei von URL anhängen", "publish_dialog_chip_attach_url_label": "Datei von URL anhängen",
"publish_dialog_chip_delay_label": "Auslieferung verzögern", "publish_dialog_chip_delay_label": "Auslieferung verzögern",
"publish_dialog_chip_topic_label": "Thema ändern", "publish_dialog_chip_topic_label": "Thema ändern",
"subscribe_dialog_subscribe_title": "Thema abonnieren", "subscribe_dialog_subscribe_title": "Thema abonnieren",
"subscribe_dialog_login_username_label": "Benutzername, z.B. phil", "subscribe_dialog_login_username_label": "Benutzername, z.B. phil",
"subscribe_dialog_login_button_login": "Anmelden", "subscribe_dialog_login_button_login": "Anmelden",
"prefs_notifications_sound_no_sound": "Kein Ton", "prefs_notifications_sound_no_sound": "Kein Ton",
"prefs_notifications_min_priority_default_and_higher": "Standard-Priorität und höher", "prefs_notifications_min_priority_default_and_higher": "Standard-Priorität und höher",
"subscribe_dialog_subscribe_topic_placeholder": "Thema, z.B. phil_alerts", "subscribe_dialog_subscribe_topic_placeholder": "Thema, z.B. phil_alerts",
"publish_dialog_button_send": "Senden", "publish_dialog_button_send": "Senden",
"publish_dialog_checkbox_publish_another": "Weitere Nachricht senden", "publish_dialog_checkbox_publish_another": "Weitere Nachricht senden",
"publish_dialog_attached_file_title": "Dateianhang:", "publish_dialog_attached_file_title": "Dateianhang:",
"emoji_picker_search_placeholder": "Emoji suchen", "emoji_picker_search_placeholder": "Emoji suchen",
"subscribe_dialog_subscribe_description": "Themen sind evtl. nicht kennwort-geschützt, also wähle einen schwer zu erratenden Namen. Nach dem Abonnieren kannst Du Benachrichtigungen per POST/PUT senden.", "subscribe_dialog_subscribe_description": "Themen sind evtl. nicht kennwort-geschützt, also wähle einen schwer zu erratenden Namen. Nach dem Abonnieren kannst Du Benachrichtigungen per POST/PUT senden.",
"subscribe_dialog_subscribe_use_another_label": "Anderen Server verwenden", "subscribe_dialog_subscribe_use_another_label": "Anderen Server verwenden",
"subscribe_dialog_subscribe_button_cancel": "Abbrechen", "subscribe_dialog_subscribe_button_cancel": "Abbrechen",
"subscribe_dialog_subscribe_button_subscribe": "Abonnieren", "subscribe_dialog_subscribe_button_subscribe": "Abonnieren",
"subscribe_dialog_login_title": "Anmeldung erforderlich", "subscribe_dialog_login_title": "Anmeldung erforderlich",
"subscribe_dialog_error_user_anonymous": "anonym", "subscribe_dialog_error_user_anonymous": "anonym",
"subscribe_dialog_error_user_not_authorized": "Benutzer {{username}} hat keine Berechtigung", "subscribe_dialog_error_user_not_authorized": "Benutzer {{username}} hat keine Berechtigung",
"prefs_notifications_min_priority_any": "Alle Prioritäten", "prefs_notifications_min_priority_any": "Alle Prioritäten",
"prefs_notifications_min_priority_low_and_higher": "Niedrige Priorität und höher", "prefs_notifications_min_priority_low_and_higher": "Niedrige Priorität und höher",
"prefs_notifications_min_priority_high_and_higher": "Hohe Priorität und höher", "prefs_notifications_min_priority_high_and_higher": "Hohe Priorität und höher",
"prefs_notifications_delete_after_title": "Benachrichtigungen löschen", "prefs_notifications_delete_after_title": "Benachrichtigungen löschen",
"prefs_notifications_delete_after_three_hours": "Nach drei Stunden", "prefs_notifications_delete_after_three_hours": "Nach drei Stunden",
"prefs_users_dialog_title_edit": "Benutzer bearbeiten", "prefs_users_dialog_title_edit": "Benutzer bearbeiten",
"prefs_notifications_delete_after_one_day": "Nach einem Tag", "prefs_notifications_delete_after_one_day": "Nach einem Tag",
"prefs_notifications_delete_after_one_week": "Nach einer Woche", "prefs_notifications_delete_after_one_week": "Nach einer Woche",
"prefs_notifications_delete_after_one_month": "Nach einem Monat", "prefs_notifications_delete_after_one_month": "Nach einem Monat",
"prefs_users_title": "Benutzer verwalten", "prefs_users_title": "Benutzer verwalten",
"prefs_users_table_user_header": "Benutzer", "prefs_users_table_user_header": "Benutzer",
"prefs_users_table_base_url_header": "Service-URL", "prefs_users_table_base_url_header": "Service-URL",
"prefs_users_dialog_base_url_label": "Service-URL, z.B. https://ntfy.sh", "prefs_users_dialog_base_url_label": "Service-URL, z.B. https://ntfy.sh",
"prefs_users_dialog_username_label": "Benutzername, z.B. phil", "prefs_users_dialog_username_label": "Benutzername, z.B. phil",
"prefs_users_description": "Benutzer für kennwort-geschützte Themen hinzufügen/löschen. Achtung: Benutzername und Kennwort werden im lokalen Browser-Speicher abgelegt.", "prefs_users_description": "Benutzer für kennwort-geschützte Themen hinzufügen/löschen. Achtung: Benutzername und Kennwort werden im lokalen Browser-Speicher abgelegt.",
"prefs_users_dialog_title_add": "Benutzer hinzufügen", "prefs_users_dialog_title_add": "Benutzer hinzufügen",
"error_boundary_title": "Oh nein, ntfy ist abgestürzt", "error_boundary_title": "Oh nein, ntfy ist abgestürzt",
"error_boundary_description": "Das sollte offensichtlich nicht passieren. Sorry.<br/>Wenn möglich, <githubLink>melde den Fehler auf GitHub</githubLink> oder schreibe uns auf <discordLink>Discord</discordLink> oder <matrixLink>Matrix</matrixLink>.", "error_boundary_description": "Das sollte offensichtlich nicht passieren. Sorry.<br/>Wenn möglich, <githubLink>melde den Fehler auf GitHub</githubLink> oder schreibe uns auf <discordLink>Discord</discordLink> oder <matrixLink>Matrix</matrixLink>.",
"error_boundary_stack_trace": "Stacktrace", "error_boundary_stack_trace": "Stacktrace",
"error_boundary_gathering_info": "Weitere Informationen sammeln …", "error_boundary_gathering_info": "Weitere Informationen sammeln …",
"error_boundary_button_copy_stack_trace": "Stacktrace kopieren", "error_boundary_button_copy_stack_trace": "Stacktrace kopieren",
"prefs_notifications_delete_after_never_description": "Benachrichtigungen werden nie automatisch gelöscht", "prefs_notifications_delete_after_never_description": "Benachrichtigungen werden nie automatisch gelöscht",
"prefs_notifications_delete_after_one_month_description": "Benachrichtigungen werden nach einem Monat automatisch gelöscht", "prefs_notifications_delete_after_one_month_description": "Benachrichtigungen werden nach einem Monat automatisch gelöscht",
"prefs_notifications_min_priority_description_any": "Alle Benachrichtigungen (aller Prioritäten) anzeigen", "prefs_notifications_min_priority_description_any": "Alle Benachrichtigungen (aller Prioritäten) anzeigen",
"prefs_notifications_min_priority_description_max": "Zeige Benachrichtigungen wenn ihre Priorität5 (max) ist", "prefs_notifications_min_priority_description_max": "Zeige Benachrichtigungen wenn ihre Priorität5 (max) ist",
"priority_low": "niedrig", "priority_low": "niedrig",
"priority_default": "Standard", "priority_default": "Standard",
"priority_high": "hoch", "priority_high": "hoch",
"priority_max": "max", "priority_max": "max",
"prefs_notifications_sound_description_none": "Kein Ton beim Empfang einer Benachrichtigung", "prefs_notifications_sound_description_none": "Kein Ton beim Empfang einer Benachrichtigung",
"prefs_notifications_sound_description_some": "Sound {{sound}} beim Eintreffen einer Benachrichtigung abspielen", "prefs_notifications_sound_description_some": "Sound {{sound}} beim Eintreffen einer Benachrichtigung abspielen",
"prefs_notifications_min_priority_description_x_or_higher": "Zeige Benachrichtigungen wenn ihre Priorität {{number}} ({{name}}) oder höher ist", "prefs_notifications_min_priority_description_x_or_higher": "Zeige Benachrichtigungen wenn ihre Priorität {{number}} ({{name}}) oder höher ist",
"prefs_notifications_delete_after_three_hours_description": "Benachrichtigungen werden nach drei Stunden automatisch gelöscht", "prefs_notifications_delete_after_three_hours_description": "Benachrichtigungen werden nach drei Stunden automatisch gelöscht",
"prefs_notifications_delete_after_one_day_description": "Benachrichtigungen werden nach einem Tag automatisch gelöscht", "prefs_notifications_delete_after_one_day_description": "Benachrichtigungen werden nach einem Tag automatisch gelöscht",
"prefs_notifications_delete_after_one_week_description": "Benachrichtigungen werden nach einer Woche automatisch gelöscht", "prefs_notifications_delete_after_one_week_description": "Benachrichtigungen werden nach einer Woche automatisch gelöscht",
"priority_min": "min", "priority_min": "min",
"notifications_actions_not_supported": "Diese Aktion wird in der Web-App nicht unterstützt", "notifications_actions_not_supported": "Diese Aktion wird in der Web-App nicht unterstützt",
"notifications_actions_http_request_title": "Sende HTTP {{method}} an {{url}}", "notifications_actions_http_request_title": "Sende HTTP {{method}} an {{url}}",
"action_bar_show_menu": "Menü anzeigen", "action_bar_show_menu": "Menü anzeigen",
"action_bar_toggle_mute": "Stummschaltung der Benachrichtigungen an/aus", "action_bar_toggle_mute": "Stummschaltung der Benachrichtigungen an/aus",
"message_bar_show_dialog": "Dialog zur Veröffentlichung anzeigen", "message_bar_show_dialog": "Dialog zur Veröffentlichung anzeigen",
"message_bar_publish": "Benachrichtigung veröffentlichen", "message_bar_publish": "Benachrichtigung veröffentlichen",
"nav_button_connecting": "verbinde", "nav_button_connecting": "verbinde",
"notifications_list": "Benachrichtigungsliste", "notifications_list": "Benachrichtigungsliste",
"notifications_mark_read": "Als gelesen markieren", "notifications_mark_read": "Als gelesen markieren",
"notifications_delete": "Löschen", "notifications_delete": "Löschen",
"notifications_priority_x": "Priorität {{priority}}", "notifications_priority_x": "Priorität {{priority}}",
"notifications_attachment_file_image": "Bilddatei", "notifications_attachment_file_image": "Bilddatei",
"notifications_attachment_image": "Bild des Anhangs", "notifications_attachment_image": "Bild des Anhangs",
"notifications_attachment_file_video": "Videodatei", "notifications_attachment_file_video": "Videodatei",
"notifications_attachment_file_audio": "Audiodatei", "notifications_attachment_file_audio": "Audiodatei",
"notifications_attachment_file_app": "Android App-Datei", "notifications_attachment_file_app": "Android App-Datei",
"notifications_attachment_file_document": "anderes Dokument", "notifications_attachment_file_document": "anderes Dokument",
"publish_dialog_attached_file_remove": "Angehängte Datei entfernen", "publish_dialog_attached_file_remove": "Angehängte Datei entfernen",
"emoji_picker_search_clear": "Suche leeren", "emoji_picker_search_clear": "Suche leeren",
"subscribe_dialog_subscribe_base_url_label": "Service URL", "subscribe_dialog_subscribe_base_url_label": "Service URL",
"prefs_notifications_sound_play": "Gewählten Sound abspielen", "prefs_notifications_sound_play": "Gewählten Sound abspielen",
"prefs_users_table": "Benutzertabelle", "prefs_users_table": "Benutzertabelle",
"prefs_users_edit_button": "Benutzer bearbeiten", "prefs_users_edit_button": "Benutzer bearbeiten",
"prefs_users_delete_button": "Benutzer löschen", "prefs_users_delete_button": "Benutzer löschen",
"error_boundary_unsupported_indexeddb_title": "Private Browser-Tabs werden nicht unterstützt", "error_boundary_unsupported_indexeddb_title": "Private Browser-Tabs werden nicht unterstützt",
"publish_dialog_delay_reset": "Verzögerte Zustellung entfernen", "publish_dialog_delay_reset": "Verzögerte Zustellung entfernen",
"error_boundary_unsupported_indexeddb_description": "Die ntfy Web-App benötigt eine IndexedDB für eine korrekte Funktion, und Dein Browser unterstützt in privaten Tabs keinen IndexedDB.<br/><br/>Das ist zwar ärgerlich, eine Nutzung von ntfy in einem privaten Tab macht aber auch wenig Sinn da alle Daten im Browser gespeichert werden. Weitere Informationen gibt es <githubLink>in diesem GitHub-Issue</githubLink>, oder im Chat bei <discordLink>Discord</discordLink> oder <matrixLink>Matrix</matrixLink>.", "error_boundary_unsupported_indexeddb_description": "Die ntfy Web-App benötigt eine IndexedDB für eine korrekte Funktion, und Dein Browser unterstützt in privaten Tabs keinen IndexedDB.<br/><br/>Das ist zwar ärgerlich, eine Nutzung von ntfy in einem privaten Tab macht aber auch wenig Sinn da alle Daten im Browser gespeichert werden. Weitere Informationen gibt es <githubLink>in diesem GitHub-Issue</githubLink>, oder im Chat bei <discordLink>Discord</discordLink> oder <matrixLink>Matrix</matrixLink>.",
"action_bar_toggle_action_menu": "Aktionsmenü öffnen/schließen", "action_bar_toggle_action_menu": "Aktionsmenü öffnen/schließen",
"notifications_new_indicator": "Neue Benachrichtigung", "notifications_new_indicator": "Neue Benachrichtigung",
"publish_dialog_email_reset": "Email-Weiterleitung entfernen", "publish_dialog_email_reset": "Email-Weiterleitung entfernen",
"action_bar_logo_alt": "ntfy Logo", "action_bar_logo_alt": "ntfy Logo",
"nav_button_muted": "Benachrichtigungen stummgeschaltet", "nav_button_muted": "Benachrichtigungen stummgeschaltet",
"notifications_list_item": "Benachrichtigung", "notifications_list_item": "Benachrichtigung",
"publish_dialog_emoji_picker_show": "Emoji wählen", "publish_dialog_emoji_picker_show": "Emoji wählen",
"publish_dialog_topic_reset": "Thema zurücksetzen", "publish_dialog_topic_reset": "Thema zurücksetzen",
"publish_dialog_attach_reset": "angehängte URL entfernen", "publish_dialog_attach_reset": "angehängte URL entfernen",
"publish_dialog_click_reset": "Klick-URL entfernen" "publish_dialog_click_reset": "Klick-URL entfernen"
} }

View file

@ -1,191 +1,191 @@
{ {
"action_bar_settings": "Configuración", "action_bar_settings": "Configuración",
"action_bar_send_test_notification": "Enviar notificación de prueba", "action_bar_send_test_notification": "Enviar notificación de prueba",
"action_bar_clear_notifications": "Borrar todas las notificaciones", "action_bar_clear_notifications": "Borrar todas las notificaciones",
"nav_topics_title": "Tópicos suscritos", "nav_topics_title": "Tópicos suscritos",
"alert_grant_button": "Conceder ahora", "alert_grant_button": "Conceder ahora",
"action_bar_unsubscribe": "Cancelar la suscripción", "action_bar_unsubscribe": "Cancelar la suscripción",
"message_bar_type_message": "Escriba un mensaje aquí", "message_bar_type_message": "Escriba un mensaje aquí",
"message_bar_error_publishing": "Error al publicar la notificación", "message_bar_error_publishing": "Error al publicar la notificación",
"alert_grant_title": "Las notificaciones están deshabilitadas", "alert_grant_title": "Las notificaciones están deshabilitadas",
"alert_grant_description": "Concede a tu navegador permiso para mostrar notificaciones en el escritorio.", "alert_grant_description": "Concede a tu navegador permiso para mostrar notificaciones en el escritorio.",
"nav_button_all_notifications": "Todas las notificaciones", "nav_button_all_notifications": "Todas las notificaciones",
"nav_button_settings": "Ajustes", "nav_button_settings": "Ajustes",
"nav_button_subscribe": "Suscribirse al tópico", "nav_button_subscribe": "Suscribirse al tópico",
"nav_button_documentation": "Documentación", "nav_button_documentation": "Documentación",
"nav_button_publish_message": "Publicar notificación", "nav_button_publish_message": "Publicar notificación",
"notifications_copied_to_clipboard": "Copiado al portapapeles", "notifications_copied_to_clipboard": "Copiado al portapapeles",
"alert_not_supported_title": "Notificaciones no soportadas", "alert_not_supported_title": "Notificaciones no soportadas",
"alert_not_supported_description": "Las notificaciones no están soportadas por tu navegador.", "alert_not_supported_description": "Las notificaciones no están soportadas por tu navegador.",
"notifications_tags": "Etiquetas", "notifications_tags": "Etiquetas",
"notifications_attachment_copy_url_title": "Copiar la URL del archivo adjunto en el portapapeles", "notifications_attachment_copy_url_title": "Copiar la URL del archivo adjunto en el portapapeles",
"notifications_attachment_copy_url_button": "Copiar URL", "notifications_attachment_copy_url_button": "Copiar URL",
"notifications_attachment_open_title": "Ir a {{url}}", "notifications_attachment_open_title": "Ir a {{url}}",
"notifications_attachment_open_button": "Abrir archivo adjunto", "notifications_attachment_open_button": "Abrir archivo adjunto",
"notifications_attachment_link_expires": "el enlace expira el día {{fecha}}", "notifications_attachment_link_expires": "el enlace expira el día {{fecha}}",
"notifications_attachment_link_expired": "el enlace de descarga ha expirado", "notifications_attachment_link_expired": "el enlace de descarga ha expirado",
"notifications_click_copy_url_title": "Copiar la URL del enlace en el portapapeles", "notifications_click_copy_url_title": "Copiar la URL del enlace en el portapapeles",
"notifications_click_copy_url_button": "Copiar enlace", "notifications_click_copy_url_button": "Copiar enlace",
"notifications_actions_open_url_title": "Ir a {{url}}", "notifications_actions_open_url_title": "Ir a {{url}}",
"notifications_click_open_button": "Abrir enlace", "notifications_click_open_button": "Abrir enlace",
"notifications_none_for_topic_title": "Aún no has recibido ninguna notificación en este tópico.", "notifications_none_for_topic_title": "Aún no has recibido ninguna notificación en este tópico.",
"notifications_none_for_topic_description": "Para enviar notificaciones a este tópico, simplemente realice un PUT o POST a la URL del tópico.", "notifications_none_for_topic_description": "Para enviar notificaciones a este tópico, simplemente realice un PUT o POST a la URL del tópico.",
"notifications_none_for_any_title": "No ha recibido ninguna notificación.", "notifications_none_for_any_title": "No ha recibido ninguna notificación.",
"notifications_no_subscriptions_title": "Parece que aún no tiene ninguna suscripción.", "notifications_no_subscriptions_title": "Parece que aún no tiene ninguna suscripción.",
"notifications_no_subscriptions_description": "Haga clic en el enlace \"{{linktext}}\" para crear o suscribirse a un tópico. Después, puede enviar mensajes a través de un PUT o POST y recibirá notificaciones aquí.", "notifications_no_subscriptions_description": "Haga clic en el enlace \"{{linktext}}\" para crear o suscribirse a un tópico. Después, puede enviar mensajes a través de un PUT o POST y recibirá notificaciones aquí.",
"notifications_more_details": "Para más información, consulta la <websiteLink>página web</websiteLink> o la <docsLink>documentación</docsLink>.", "notifications_more_details": "Para más información, consulta la <websiteLink>página web</websiteLink> o la <docsLink>documentación</docsLink>.",
"notifications_loading": "Cargando notificaciones …", "notifications_loading": "Cargando notificaciones …",
"publish_dialog_title_topic": "Publicar en {{topic}}", "publish_dialog_title_topic": "Publicar en {{topic}}",
"publish_dialog_title_no_topic": "Publicar notificación", "publish_dialog_title_no_topic": "Publicar notificación",
"publish_dialog_progress_uploading": "Cargando …", "publish_dialog_progress_uploading": "Cargando …",
"publish_dialog_progress_uploading_detail": "Cargando {{loaded}}/{{total}} ({{percent}}%) …", "publish_dialog_progress_uploading_detail": "Cargando {{loaded}}/{{total}} ({{percent}}%) …",
"publish_dialog_message_published": "Notificación publicada", "publish_dialog_message_published": "Notificación publicada",
"publish_dialog_attachment_limits_file_and_quota_reached": "supera el límite y la cuota de archivos de {{fileSizeLimit}}, restan {{remainingBytes}}", "publish_dialog_attachment_limits_file_and_quota_reached": "supera el límite y la cuota de archivos de {{fileSizeLimit}}, restan {{remainingBytes}}",
"publish_dialog_attachment_limits_file_reached": "supera el límite de archivos de {{fileSizeLimit}}", "publish_dialog_attachment_limits_file_reached": "supera el límite de archivos de {{fileSizeLimit}}",
"publish_dialog_attachment_limits_quota_reached": "supera la cuota, restan {{remainingBytes}}", "publish_dialog_attachment_limits_quota_reached": "supera la cuota, restan {{remainingBytes}}",
"publish_dialog_priority_min": "Prioridad mínima", "publish_dialog_priority_min": "Prioridad mínima",
"publish_dialog_priority_default": "Prioridad predeterminada", "publish_dialog_priority_default": "Prioridad predeterminada",
"publish_dialog_priority_max": "Prioridad máxima", "publish_dialog_priority_max": "Prioridad máxima",
"publish_dialog_base_url_label": "URL del servicio", "publish_dialog_base_url_label": "URL del servicio",
"publish_dialog_base_url_placeholder": "URL del servicio, por ejemplo, https://example.com", "publish_dialog_base_url_placeholder": "URL del servicio, por ejemplo, https://example.com",
"publish_dialog_topic_label": "Nombre del tópico", "publish_dialog_topic_label": "Nombre del tópico",
"publish_dialog_topic_placeholder": "Nombre del tópico, ej. phil_alerts", "publish_dialog_topic_placeholder": "Nombre del tópico, ej. phil_alerts",
"publish_dialog_title_label": "Título", "publish_dialog_title_label": "Título",
"publish_dialog_message_label": "Mensaje", "publish_dialog_message_label": "Mensaje",
"publish_dialog_tags_placeholder": "Lista de etiquetas separadas por comas, por ejemplo: warning, srv1-backup", "publish_dialog_tags_placeholder": "Lista de etiquetas separadas por comas, por ejemplo: warning, srv1-backup",
"publish_dialog_click_label": "Click URL", "publish_dialog_click_label": "Click URL",
"publish_dialog_click_placeholder": "URL que se abre cuando se hace click en la notificación", "publish_dialog_click_placeholder": "URL que se abre cuando se hace click en la notificación",
"publish_dialog_email_label": "Email", "publish_dialog_email_label": "Email",
"publish_dialog_email_placeholder": "Dirección a la que se reenviará la notificación, por ejemplo, phil@example.com", "publish_dialog_email_placeholder": "Dirección a la que se reenviará la notificación, por ejemplo, phil@example.com",
"publish_dialog_attach_label": "URL del archivo adjunto", "publish_dialog_attach_label": "URL del archivo adjunto",
"publish_dialog_filename_label": "Nombre del archivo", "publish_dialog_filename_label": "Nombre del archivo",
"publish_dialog_delay_placeholder": "Retraso en la entrega, por ejemplo, {{unixTimestamp}}, {{relativeTime}}, o \"{{naturalLanguage}}\" (sólo en inglés)", "publish_dialog_delay_placeholder": "Retraso en la entrega, por ejemplo, {{unixTimestamp}}, {{relativeTime}}, o \"{{naturalLanguage}}\" (sólo en inglés)",
"publish_dialog_other_features": "Otras características:", "publish_dialog_other_features": "Otras características:",
"publish_dialog_chip_click_label": "Click URL", "publish_dialog_chip_click_label": "Click URL",
"publish_dialog_chip_email_label": "Reenviar al email", "publish_dialog_chip_email_label": "Reenviar al email",
"publish_dialog_chip_attach_url_label": "Adjuntar un archivo por URL", "publish_dialog_chip_attach_url_label": "Adjuntar un archivo por URL",
"publish_dialog_chip_attach_file_label": "Adjuntar archivo local", "publish_dialog_chip_attach_file_label": "Adjuntar archivo local",
"publish_dialog_chip_topic_label": "Cambiar de tópico", "publish_dialog_chip_topic_label": "Cambiar de tópico",
"publish_dialog_button_cancel_sending": "Cancelar el envío", "publish_dialog_button_cancel_sending": "Cancelar el envío",
"publish_dialog_button_cancel": "Cancelar", "publish_dialog_button_cancel": "Cancelar",
"publish_dialog_checkbox_publish_another": "Publicar otro", "publish_dialog_checkbox_publish_another": "Publicar otro",
"publish_dialog_attached_file_title": "Archivo adjunto:", "publish_dialog_attached_file_title": "Archivo adjunto:",
"publish_dialog_attached_file_filename_placeholder": "Nombre del archivo adjunto", "publish_dialog_attached_file_filename_placeholder": "Nombre del archivo adjunto",
"publish_dialog_drop_file_here": "Suelta el archivo aquí", "publish_dialog_drop_file_here": "Suelta el archivo aquí",
"emoji_picker_search_placeholder": "Buscar emojis", "emoji_picker_search_placeholder": "Buscar emojis",
"subscribe_dialog_subscribe_title": "Suscribirse al tópico", "subscribe_dialog_subscribe_title": "Suscribirse al tópico",
"subscribe_dialog_subscribe_description": "Los tópicos pueden no estar protegidos por contraseña, así que elija un nombre que no sea fácil de adivinar. Una vez suscrito, puede hacer PUT/POST de notificaciones.", "subscribe_dialog_subscribe_description": "Los tópicos pueden no estar protegidos por contraseña, así que elija un nombre que no sea fácil de adivinar. Una vez suscrito, puede hacer PUT/POST de notificaciones.",
"subscribe_dialog_subscribe_topic_placeholder": "Nombre del tópico, ej. phil_alerts", "subscribe_dialog_subscribe_topic_placeholder": "Nombre del tópico, ej. phil_alerts",
"subscribe_dialog_subscribe_use_another_label": "Usar otro servidor", "subscribe_dialog_subscribe_use_another_label": "Usar otro servidor",
"subscribe_dialog_login_title": "Es necesario iniciar sesión", "subscribe_dialog_login_title": "Es necesario iniciar sesión",
"subscribe_dialog_login_description": "Este tópico está protegido por contraseña. Por favor, introduzca su nombre de usuario y contraseña para suscribirse.", "subscribe_dialog_login_description": "Este tópico está protegido por contraseña. Por favor, introduzca su nombre de usuario y contraseña para suscribirse.",
"subscribe_dialog_login_username_label": "Nombre de usuario, ej. phil", "subscribe_dialog_login_username_label": "Nombre de usuario, ej. phil",
"subscribe_dialog_login_password_label": "Contraseña", "subscribe_dialog_login_password_label": "Contraseña",
"subscribe_dialog_login_button_back": "Volver", "subscribe_dialog_login_button_back": "Volver",
"subscribe_dialog_login_button_login": "Iniciar sesión", "subscribe_dialog_login_button_login": "Iniciar sesión",
"subscribe_dialog_error_user_not_authorized": "Usuario {{username}} no autorizado", "subscribe_dialog_error_user_not_authorized": "Usuario {{username}} no autorizado",
"subscribe_dialog_error_user_anonymous": "anónimo", "subscribe_dialog_error_user_anonymous": "anónimo",
"prefs_notifications_title": "Notificaciones", "prefs_notifications_title": "Notificaciones",
"prefs_notifications_sound_title": "Sonido de notificación", "prefs_notifications_sound_title": "Sonido de notificación",
"prefs_notifications_min_priority_any": "Cualquier prioridad", "prefs_notifications_min_priority_any": "Cualquier prioridad",
"prefs_notifications_min_priority_low_and_higher": "Prioridad baja y superior", "prefs_notifications_min_priority_low_and_higher": "Prioridad baja y superior",
"prefs_notifications_min_priority_max_only": "Solo prioridad máxima", "prefs_notifications_min_priority_max_only": "Solo prioridad máxima",
"prefs_notifications_delete_after_title": "Eliminar notificaciones", "prefs_notifications_delete_after_title": "Eliminar notificaciones",
"prefs_notifications_delete_after_never": "Nunca", "prefs_notifications_delete_after_never": "Nunca",
"prefs_notifications_delete_after_three_hours": "Después de tres horas", "prefs_notifications_delete_after_three_hours": "Después de tres horas",
"prefs_notifications_delete_after_one_day": "Después de un día", "prefs_notifications_delete_after_one_day": "Después de un día",
"prefs_notifications_delete_after_one_week": "Después de una semana", "prefs_notifications_delete_after_one_week": "Después de una semana",
"prefs_notifications_delete_after_one_month": "Después de un mes", "prefs_notifications_delete_after_one_month": "Después de un mes",
"prefs_users_title": "Administrar usuarios", "prefs_users_title": "Administrar usuarios",
"prefs_users_description": "Añada/elimine usuarios para sus tópicos protegidos aquí. Tenga en cuenta que el nombre de usuario y la contraseña se guardan en el almacenamiento local del navegador.", "prefs_users_description": "Añada/elimine usuarios para sus tópicos protegidos aquí. Tenga en cuenta que el nombre de usuario y la contraseña se guardan en el almacenamiento local del navegador.",
"prefs_users_add_button": "Añadir usuario", "prefs_users_add_button": "Añadir usuario",
"prefs_users_dialog_title_edit": "Editar usuario", "prefs_users_dialog_title_edit": "Editar usuario",
"prefs_users_dialog_base_url_label": "URL del servicio, ej. https://ntfy.sh", "prefs_users_dialog_base_url_label": "URL del servicio, ej. https://ntfy.sh",
"prefs_users_dialog_button_add": "Añadir", "prefs_users_dialog_button_add": "Añadir",
"prefs_users_dialog_button_save": "Guardar", "prefs_users_dialog_button_save": "Guardar",
"prefs_appearance_title": "Apariencia", "prefs_appearance_title": "Apariencia",
"prefs_appearance_language_title": "Idioma", "prefs_appearance_language_title": "Idioma",
"error_boundary_title": "Oh no, ntfy tuvo un error", "error_boundary_title": "Oh no, ntfy tuvo un error",
"error_boundary_button_copy_stack_trace": "Copiar el stack trace", "error_boundary_button_copy_stack_trace": "Copiar el stack trace",
"error_boundary_stack_trace": "Stack trace", "error_boundary_stack_trace": "Stack trace",
"error_boundary_gathering_info": "Reunir más información …", "error_boundary_gathering_info": "Reunir más información …",
"notifications_example": "Ejemplo", "notifications_example": "Ejemplo",
"prefs_notifications_min_priority_title": "Prioridad mínima", "prefs_notifications_min_priority_title": "Prioridad mínima",
"notifications_none_for_any_description": "Para enviar notificaciones a un tópico, simplemente realice un PUT o POST a la URL del tópico. Aquí hay un ejemplo usando uno de sus tópicos.", "notifications_none_for_any_description": "Para enviar notificaciones a un tópico, simplemente realice un PUT o POST a la URL del tópico. Aquí hay un ejemplo usando uno de sus tópicos.",
"subscribe_dialog_subscribe_button_cancel": "Cancelar", "subscribe_dialog_subscribe_button_cancel": "Cancelar",
"subscribe_dialog_subscribe_button_subscribe": "Suscribir", "subscribe_dialog_subscribe_button_subscribe": "Suscribir",
"publish_dialog_message_placeholder": "Escriba un mensaje aquí", "publish_dialog_message_placeholder": "Escriba un mensaje aquí",
"publish_dialog_tags_label": "Etiquetas", "publish_dialog_tags_label": "Etiquetas",
"publish_dialog_priority_label": "Prioridad", "publish_dialog_priority_label": "Prioridad",
"publish_dialog_priority_low": "Prioridad baja", "publish_dialog_priority_low": "Prioridad baja",
"publish_dialog_priority_high": "Prioridad alta", "publish_dialog_priority_high": "Prioridad alta",
"publish_dialog_delay_label": "Retraso", "publish_dialog_delay_label": "Retraso",
"publish_dialog_title_placeholder": "Título de la notificación, por ejemplo, Alerta de espacio en disco", "publish_dialog_title_placeholder": "Título de la notificación, por ejemplo, Alerta de espacio en disco",
"publish_dialog_details_examples_description": "Para ver ejemplos y una descripción detallada de todas las funciones de envío, consulte la <docsLink>documentación</docsLink>.", "publish_dialog_details_examples_description": "Para ver ejemplos y una descripción detallada de todas las funciones de envío, consulte la <docsLink>documentación</docsLink>.",
"publish_dialog_attach_placeholder": "Adjuntar un archivo por URL, por ejemplo, https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "Adjuntar un archivo por URL, por ejemplo, https://f-droid.org/F-Droid.apk",
"publish_dialog_filename_placeholder": "Nombre del archivo adjunto", "publish_dialog_filename_placeholder": "Nombre del archivo adjunto",
"publish_dialog_chip_delay_label": "Retraso en la entrega", "publish_dialog_chip_delay_label": "Retraso en la entrega",
"prefs_notifications_min_priority_default_and_higher": "Prioridad predeterminada y superior", "prefs_notifications_min_priority_default_and_higher": "Prioridad predeterminada y superior",
"prefs_notifications_min_priority_high_and_higher": "Prioridad alta y superior", "prefs_notifications_min_priority_high_and_higher": "Prioridad alta y superior",
"prefs_users_table_user_header": "Usuario", "prefs_users_table_user_header": "Usuario",
"prefs_users_table_base_url_header": "URL del servicio", "prefs_users_table_base_url_header": "URL del servicio",
"publish_dialog_button_send": "Enviar", "publish_dialog_button_send": "Enviar",
"prefs_notifications_sound_no_sound": "Sin sonido", "prefs_notifications_sound_no_sound": "Sin sonido",
"prefs_users_dialog_password_label": "Contraseña", "prefs_users_dialog_password_label": "Contraseña",
"error_boundary_description": "Obviamente, esto no debería ocurrir. Lo sentimos mucho.<br/>Si tienes un minuto, por favor <githubLink>informa de esto en GitHub</githubLink>, o avísanos vía <discordLink>Discord</discordLink> o <matrixLink>Matrix</matrixLink>.", "error_boundary_description": "Obviamente, esto no debería ocurrir. Lo sentimos mucho.<br/>Si tienes un minuto, por favor <githubLink>informa de esto en GitHub</githubLink>, o avísanos vía <discordLink>Discord</discordLink> o <matrixLink>Matrix</matrixLink>.",
"prefs_users_dialog_title_add": "Añadir usuario", "prefs_users_dialog_title_add": "Añadir usuario",
"prefs_users_dialog_button_cancel": "Cancelar", "prefs_users_dialog_button_cancel": "Cancelar",
"prefs_users_dialog_username_label": "Nombre de usuario, ej. phil", "prefs_users_dialog_username_label": "Nombre de usuario, ej. phil",
"priority_max": "máx", "priority_max": "máx",
"priority_high": "alta", "priority_high": "alta",
"prefs_notifications_delete_after_one_month_description": "Las notificaciones se eliminan automáticamente después de un mes", "prefs_notifications_delete_after_one_month_description": "Las notificaciones se eliminan automáticamente después de un mes",
"priority_min": "mín", "priority_min": "mín",
"prefs_notifications_delete_after_three_hours_description": "Las notificaciones se eliminan automáticamente después de tres horas", "prefs_notifications_delete_after_three_hours_description": "Las notificaciones se eliminan automáticamente después de tres horas",
"prefs_notifications_sound_description_none": "Las notificaciones no reproducen ningún sonido cuando llegan", "prefs_notifications_sound_description_none": "Las notificaciones no reproducen ningún sonido cuando llegan",
"prefs_notifications_min_priority_description_x_or_higher": "Mostrar notificaciones si la prioridad es {{number}} ({{name}}) o superior", "prefs_notifications_min_priority_description_x_or_higher": "Mostrar notificaciones si la prioridad es {{number}} ({{name}}) o superior",
"prefs_notifications_min_priority_description_max": "Mostrar notificaciones si la prioridad es 5 (máxima)", "prefs_notifications_min_priority_description_max": "Mostrar notificaciones si la prioridad es 5 (máxima)",
"prefs_notifications_sound_description_some": "Las notificaciones reproducen el sonido {{sound}} cuando llegan", "prefs_notifications_sound_description_some": "Las notificaciones reproducen el sonido {{sound}} cuando llegan",
"prefs_notifications_min_priority_description_any": "Mostrando todas las notificaciones, independientemente de su prioridad", "prefs_notifications_min_priority_description_any": "Mostrando todas las notificaciones, independientemente de su prioridad",
"prefs_notifications_delete_after_never_description": "Las notificaciones nunca se borran automáticamente", "prefs_notifications_delete_after_never_description": "Las notificaciones nunca se borran automáticamente",
"priority_default": "predeterminada", "priority_default": "predeterminada",
"prefs_notifications_delete_after_one_day_description": "Las notificaciones se eliminan automáticamente después de un día", "prefs_notifications_delete_after_one_day_description": "Las notificaciones se eliminan automáticamente después de un día",
"prefs_notifications_delete_after_one_week_description": "Las notificaciones se eliminan automáticamente después de una semana", "prefs_notifications_delete_after_one_week_description": "Las notificaciones se eliminan automáticamente después de una semana",
"priority_low": "baja", "priority_low": "baja",
"notifications_actions_not_supported": "Acción no soportada en la aplicación web", "notifications_actions_not_supported": "Acción no soportada en la aplicación web",
"notifications_actions_http_request_title": "Enviar HTTP {{method}} a {{url}}", "notifications_actions_http_request_title": "Enviar HTTP {{method}} a {{url}}",
"error_boundary_unsupported_indexeddb_description": "La aplicación web ntfy necesita IndexedDB para funcionar y su navegador no soporta IndexedDB en modo de navegación privada. <br/> <br/> Si bien esto es desafortunado, tampoco tiene mucho sentido usar la aplicación web ntfy en modo de navegación privada de todos modos, porque todo está almacenado en el almacenamiento del navegador. Puede leer más sobre esto <githubLink>en este issue de GitHub</githubLink>, o hablar con nosotros en <discordLink>Discord</discordLink> o <matrixLink>Matrix</matrixLink>.", "error_boundary_unsupported_indexeddb_description": "La aplicación web ntfy necesita IndexedDB para funcionar y su navegador no soporta IndexedDB en modo de navegación privada. <br/> <br/> Si bien esto es desafortunado, tampoco tiene mucho sentido usar la aplicación web ntfy en modo de navegación privada de todos modos, porque todo está almacenado en el almacenamiento del navegador. Puede leer más sobre esto <githubLink>en este issue de GitHub</githubLink>, o hablar con nosotros en <discordLink>Discord</discordLink> o <matrixLink>Matrix</matrixLink>.",
"action_bar_show_menu": "Mostrar menú", "action_bar_show_menu": "Mostrar menú",
"action_bar_logo_alt": "logo de ntfy", "action_bar_logo_alt": "logo de ntfy",
"action_bar_toggle_action_menu": "Abrir/cerrar el menú de acción", "action_bar_toggle_action_menu": "Abrir/cerrar el menú de acción",
"message_bar_show_dialog": "Mostrar diálogo de publicación", "message_bar_show_dialog": "Mostrar diálogo de publicación",
"message_bar_publish": "Publicar mensaje", "message_bar_publish": "Publicar mensaje",
"nav_button_muted": "Notificaciones silenciadas", "nav_button_muted": "Notificaciones silenciadas",
"nav_button_connecting": "conectando", "nav_button_connecting": "conectando",
"notifications_list": "Lista de notificaciones", "notifications_list": "Lista de notificaciones",
"notifications_list_item": "Notificación", "notifications_list_item": "Notificación",
"notifications_mark_read": "Marcar como leído", "notifications_mark_read": "Marcar como leído",
"notifications_delete": "Eliminar", "notifications_delete": "Eliminar",
"notifications_priority_x": "Prioridad {{priority}}", "notifications_priority_x": "Prioridad {{priority}}",
"notifications_new_indicator": "Nueva notificación", "notifications_new_indicator": "Nueva notificación",
"notifications_attachment_image": "Imagen adjunta", "notifications_attachment_image": "Imagen adjunta",
"notifications_attachment_file_image": "archivo de imagen", "notifications_attachment_file_image": "archivo de imagen",
"notifications_attachment_file_video": "archivo de video", "notifications_attachment_file_video": "archivo de video",
"notifications_attachment_file_audio": "archivo de audio", "notifications_attachment_file_audio": "archivo de audio",
"notifications_attachment_file_app": "Archivo de aplicación de Android", "notifications_attachment_file_app": "Archivo de aplicación de Android",
"notifications_attachment_file_document": "otro documento", "notifications_attachment_file_document": "otro documento",
"action_bar_toggle_mute": "Silenciar/reactivar notificaciones", "action_bar_toggle_mute": "Silenciar/reactivar notificaciones",
"publish_dialog_emoji_picker_show": "Elige un emoji", "publish_dialog_emoji_picker_show": "Elige un emoji",
"publish_dialog_topic_reset": "Restablecer tópico", "publish_dialog_topic_reset": "Restablecer tópico",
"publish_dialog_click_reset": "Eliminar URL de clic", "publish_dialog_click_reset": "Eliminar URL de clic",
"publish_dialog_email_reset": "Eliminar el reenvío de correo electrónico", "publish_dialog_email_reset": "Eliminar el reenvío de correo electrónico",
"publish_dialog_attach_reset": "Eliminar la URL del archivo adjunto", "publish_dialog_attach_reset": "Eliminar la URL del archivo adjunto",
"publish_dialog_delay_reset": "Eliminar entrega retrasada", "publish_dialog_delay_reset": "Eliminar entrega retrasada",
"publish_dialog_attached_file_remove": "Eliminar el archivo adjunto", "publish_dialog_attached_file_remove": "Eliminar el archivo adjunto",
"emoji_picker_search_clear": "Limpiar búsqueda", "emoji_picker_search_clear": "Limpiar búsqueda",
"subscribe_dialog_subscribe_base_url_label": "URL del servicio", "subscribe_dialog_subscribe_base_url_label": "URL del servicio",
"prefs_notifications_sound_play": "Reproducir el sonido seleccionado", "prefs_notifications_sound_play": "Reproducir el sonido seleccionado",
"prefs_users_table": "Tabla de usuarios", "prefs_users_table": "Tabla de usuarios",
"prefs_users_edit_button": "Editar usuario", "prefs_users_edit_button": "Editar usuario",
"prefs_users_delete_button": "Eliminar usuario", "prefs_users_delete_button": "Eliminar usuario",
"error_boundary_unsupported_indexeddb_title": "Navegación privada no soportada" "error_boundary_unsupported_indexeddb_title": "Navegación privada no soportada"
} }

View file

@ -1,191 +1,191 @@
{ {
"nav_topics_title": "Sujets souscrits", "nav_topics_title": "Sujets souscrits",
"action_bar_settings": "Paramètres", "action_bar_settings": "Paramètres",
"action_bar_send_test_notification": "Envoyer une notification de test", "action_bar_send_test_notification": "Envoyer une notification de test",
"action_bar_clear_notifications": "Effacer toutes les notifications", "action_bar_clear_notifications": "Effacer toutes les notifications",
"action_bar_unsubscribe": "Se désabonner", "action_bar_unsubscribe": "Se désabonner",
"message_bar_type_message": "Tapez un message ici", "message_bar_type_message": "Tapez un message ici",
"notifications_attachment_open_button": "Ouvrir la pièce jointe", "notifications_attachment_open_button": "Ouvrir la pièce jointe",
"notifications_attachment_link_expires": "le lien expire {{date}}", "notifications_attachment_link_expires": "le lien expire {{date}}",
"message_bar_error_publishing": "Notification d'erreur de publication", "message_bar_error_publishing": "Notification d'erreur de publication",
"nav_button_all_notifications": "Toutes les notifications", "nav_button_all_notifications": "Toutes les notifications",
"nav_button_settings": "Paramètres", "nav_button_settings": "Paramètres",
"nav_button_documentation": "Documentation", "nav_button_documentation": "Documentation",
"alert_not_supported_description": "Les notifications ne sont pas prises en charge par votre navigateur.", "alert_not_supported_description": "Les notifications ne sont pas prises en charge par votre navigateur.",
"notifications_attachment_copy_url_title": "Copier l'URL de la pièce jointe dans le presse-papiers", "notifications_attachment_copy_url_title": "Copier l'URL de la pièce jointe dans le presse-papiers",
"notifications_attachment_open_title": "Aller à {{url}}", "notifications_attachment_open_title": "Aller à {{url}}",
"notifications_attachment_link_expired": "lien de téléchargement expiré", "notifications_attachment_link_expired": "lien de téléchargement expiré",
"nav_button_publish_message": "Publier la notification", "nav_button_publish_message": "Publier la notification",
"notifications_copied_to_clipboard": "Copié dans le presse-papiers", "notifications_copied_to_clipboard": "Copié dans le presse-papiers",
"alert_not_supported_title": "Notifications non prises en charge", "alert_not_supported_title": "Notifications non prises en charge",
"notifications_tags": "Étiquettes", "notifications_tags": "Étiquettes",
"notifications_attachment_copy_url_button": "Copier l'URL", "notifications_attachment_copy_url_button": "Copier l'URL",
"notifications_click_copy_url_title": "Copier l'URL du lien dans le presse-papiers", "notifications_click_copy_url_title": "Copier l'URL du lien dans le presse-papiers",
"notifications_click_copy_url_button": "Copier le lien", "notifications_click_copy_url_button": "Copier le lien",
"notifications_click_open_button": "Ouvrir le lien", "notifications_click_open_button": "Ouvrir le lien",
"notifications_none_for_topic_title": "Vous n'avez pas encore reçu de notifications pour ce sujet.", "notifications_none_for_topic_title": "Vous n'avez pas encore reçu de notifications pour ce sujet.",
"notifications_actions_open_url_title": "Aller à {{url}}", "notifications_actions_open_url_title": "Aller à {{url}}",
"notifications_example": "Exemple", "notifications_example": "Exemple",
"notifications_loading": "Chargement des notifications…", "notifications_loading": "Chargement des notifications…",
"publish_dialog_progress_uploading": "Téléversement…", "publish_dialog_progress_uploading": "Téléversement…",
"publish_dialog_priority_min": "Priorité minimum", "publish_dialog_priority_min": "Priorité minimum",
"publish_dialog_priority_low": "Basse priorité", "publish_dialog_priority_low": "Basse priorité",
"publish_dialog_priority_default": "Priorité par défaut", "publish_dialog_priority_default": "Priorité par défaut",
"publish_dialog_base_url_label": "URL du service", "publish_dialog_base_url_label": "URL du service",
"publish_dialog_base_url_placeholder": "URL du service, par ex. https://exemple.com", "publish_dialog_base_url_placeholder": "URL du service, par ex. https://exemple.com",
"publish_dialog_title_label": "Titre", "publish_dialog_title_label": "Titre",
"publish_dialog_message_label": "Message", "publish_dialog_message_label": "Message",
"publish_dialog_topic_label": "Nom du sujet", "publish_dialog_topic_label": "Nom du sujet",
"publish_dialog_message_placeholder": "Tapez un message ici", "publish_dialog_message_placeholder": "Tapez un message ici",
"publish_dialog_tags_label": "Étiquettes", "publish_dialog_tags_label": "Étiquettes",
"publish_dialog_email_label": "Courriel", "publish_dialog_email_label": "Courriel",
"publish_dialog_email_placeholder": "Adresse à laquelle transmettre la notification, par exemple phil@exemple.com", "publish_dialog_email_placeholder": "Adresse à laquelle transmettre la notification, par exemple phil@exemple.com",
"publish_dialog_chip_email_label": "Transférer vers le courriel", "publish_dialog_chip_email_label": "Transférer vers le courriel",
"notifications_no_subscriptions_title": "Il semble que vous nayez pas encore dabonnements.", "notifications_no_subscriptions_title": "Il semble que vous nayez pas encore dabonnements.",
"publish_dialog_progress_uploading_detail": "Téléversement {{loaded}}/{{total}} ({{percent}} %) …", "publish_dialog_progress_uploading_detail": "Téléversement {{loaded}}/{{total}} ({{percent}} %) …",
"publish_dialog_message_published": "Notification publiée", "publish_dialog_message_published": "Notification publiée",
"publish_dialog_attachment_limits_file_and_quota_reached": "dépasse la limite et le quota du fichier {{fileSizeLimit}}, {{remainingBytes}} restant", "publish_dialog_attachment_limits_file_and_quota_reached": "dépasse la limite et le quota du fichier {{fileSizeLimit}}, {{remainingBytes}} restant",
"publish_dialog_priority_high": "Haute priorité", "publish_dialog_priority_high": "Haute priorité",
"publish_dialog_priority_max": "Priorité maximum", "publish_dialog_priority_max": "Priorité maximum",
"publish_dialog_attachment_limits_file_reached": "Dépasse la limite du fichier {{fileSizeLimit}}", "publish_dialog_attachment_limits_file_reached": "Dépasse la limite du fichier {{fileSizeLimit}}",
"nav_button_subscribe": "S'abonner au sujet", "nav_button_subscribe": "S'abonner au sujet",
"notifications_no_subscriptions_description": "Cliquez sur le lien « {{linktext}} » pour créer ou vous abonner à un sujet. Après cela, vous pouvez envoyer des messages via PUT ou POST et vous recevrez des notifications ici.", "notifications_no_subscriptions_description": "Cliquez sur le lien « {{linktext}} » pour créer ou vous abonner à un sujet. Après cela, vous pouvez envoyer des messages via PUT ou POST et vous recevrez des notifications ici.",
"alert_grant_title": "Les notifications sont désactivées", "alert_grant_title": "Les notifications sont désactivées",
"alert_grant_description": "Autorisez votre navigateur à afficher les notifications du bureau.", "alert_grant_description": "Autorisez votre navigateur à afficher les notifications du bureau.",
"alert_grant_button": "Accorder maintenant", "alert_grant_button": "Accorder maintenant",
"notifications_none_for_any_title": "Vous n'avez reçu aucune notification.", "notifications_none_for_any_title": "Vous n'avez reçu aucune notification.",
"publish_dialog_title_topic": "Publier vers {{topic}}", "publish_dialog_title_topic": "Publier vers {{topic}}",
"publish_dialog_title_no_topic": "Publier la notification", "publish_dialog_title_no_topic": "Publier la notification",
"notifications_more_details": "Pour plus d'information, visitez <websiteLink>le site web</websiteLink> ou <docsLink>la documentation</docsLink>.", "notifications_more_details": "Pour plus d'information, visitez <websiteLink>le site web</websiteLink> ou <docsLink>la documentation</docsLink>.",
"publish_dialog_title_placeholder": "Titre de la notification, par ex. Alerte d'espace disque", "publish_dialog_title_placeholder": "Titre de la notification, par ex. Alerte d'espace disque",
"publish_dialog_topic_placeholder": "Nom du sujet, par ex. phil_alerts", "publish_dialog_topic_placeholder": "Nom du sujet, par ex. phil_alerts",
"publish_dialog_delay_placeholder": "Délai de réception, par ex. {{unixTimestamp}}, {{relativeTime}}, ou « {{naturalLanguage}} » (en anglais seulement)", "publish_dialog_delay_placeholder": "Délai de réception, par ex. {{unixTimestamp}}, {{relativeTime}}, ou « {{naturalLanguage}} » (en anglais seulement)",
"publish_dialog_other_features": "Autres fonctionnalités :", "publish_dialog_other_features": "Autres fonctionnalités :",
"notifications_actions_not_supported": "Cette action n'est pas supportée dans l'application web", "notifications_actions_not_supported": "Cette action n'est pas supportée dans l'application web",
"notifications_actions_http_request_title": "Envoyer une requête HTTP {{method}} à {{url}}", "notifications_actions_http_request_title": "Envoyer une requête HTTP {{method}} à {{url}}",
"publish_dialog_attachment_limits_quota_reached": "quota dépassé, {{remainingBytes}} restants", "publish_dialog_attachment_limits_quota_reached": "quota dépassé, {{remainingBytes}} restants",
"publish_dialog_tags_placeholder": "Liste séparée par des virgules d'étiquettes, par ex. avertissement,backup-srv1", "publish_dialog_tags_placeholder": "Liste séparée par des virgules d'étiquettes, par ex. avertissement,backup-srv1",
"publish_dialog_priority_label": "Priorité", "publish_dialog_priority_label": "Priorité",
"publish_dialog_click_label": "URL du clic", "publish_dialog_click_label": "URL du clic",
"publish_dialog_click_placeholder": "URL ouverte lors d'un clic sur la notification", "publish_dialog_click_placeholder": "URL ouverte lors d'un clic sur la notification",
"publish_dialog_attach_label": "URL de la pièce jointe", "publish_dialog_attach_label": "URL de la pièce jointe",
"publish_dialog_attach_placeholder": "Attachez un fichier par une URL, par ex. https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "Attachez un fichier par une URL, par ex. https://f-droid.org/F-Droid.apk",
"publish_dialog_filename_label": "Nom du fichier", "publish_dialog_filename_label": "Nom du fichier",
"notifications_none_for_topic_description": "Pour envoyer des notifications à ce sujet, faites simplement une requête PUT ou POST à l'URL du sujet.", "notifications_none_for_topic_description": "Pour envoyer des notifications à ce sujet, faites simplement une requête PUT ou POST à l'URL du sujet.",
"notifications_none_for_any_description": "Pour envoyer des notifications à un sujet, faites simplement une requête PUT ou POST à l'URL du sujet. Voici un exemple utilisant un de vos sujets.", "notifications_none_for_any_description": "Pour envoyer des notifications à un sujet, faites simplement une requête PUT ou POST à l'URL du sujet. Voici un exemple utilisant un de vos sujets.",
"publish_dialog_filename_placeholder": "Nom du fichier joint", "publish_dialog_filename_placeholder": "Nom du fichier joint",
"publish_dialog_delay_label": "Délai", "publish_dialog_delay_label": "Délai",
"publish_dialog_chip_click_label": "Cliquez sur l'URL", "publish_dialog_chip_click_label": "Cliquez sur l'URL",
"subscribe_dialog_subscribe_title": "S'abonner au sujet", "subscribe_dialog_subscribe_title": "S'abonner au sujet",
"subscribe_dialog_login_title": "Connexion nécessaire", "subscribe_dialog_login_title": "Connexion nécessaire",
"prefs_notifications_min_priority_low_and_higher": "Priorité basse et au-dessus", "prefs_notifications_min_priority_low_and_higher": "Priorité basse et au-dessus",
"prefs_users_dialog_button_cancel": "Annuler", "prefs_users_dialog_button_cancel": "Annuler",
"error_boundary_button_copy_stack_trace": "Copier la stack strace", "error_boundary_button_copy_stack_trace": "Copier la stack strace",
"publish_dialog_attached_file_title": "Fichier joint :", "publish_dialog_attached_file_title": "Fichier joint :",
"publish_dialog_checkbox_publish_another": "Publier un autre", "publish_dialog_checkbox_publish_another": "Publier un autre",
"publish_dialog_attached_file_filename_placeholder": "Nom du fichier joint", "publish_dialog_attached_file_filename_placeholder": "Nom du fichier joint",
"subscribe_dialog_subscribe_use_another_label": "Utiliser un autre serveur", "subscribe_dialog_subscribe_use_another_label": "Utiliser un autre serveur",
"subscribe_dialog_subscribe_button_cancel": "Annuler", "subscribe_dialog_subscribe_button_cancel": "Annuler",
"prefs_notifications_sound_description_none": "Les notifications ne font aucun son quand elles arrivent", "prefs_notifications_sound_description_none": "Les notifications ne font aucun son quand elles arrivent",
"prefs_notifications_sound_description_some": "Les notifications jouent le son {{sound}} quand elles arrivent", "prefs_notifications_sound_description_some": "Les notifications jouent le son {{sound}} quand elles arrivent",
"prefs_notifications_min_priority_description_x_or_higher": "Montrer les notifications si leur priorité est {{number}} ({{name}}) ou plus", "prefs_notifications_min_priority_description_x_or_higher": "Montrer les notifications si leur priorité est {{number}} ({{name}}) ou plus",
"publish_dialog_button_cancel": "Annuler", "publish_dialog_button_cancel": "Annuler",
"publish_dialog_button_send": "Envoyer", "publish_dialog_button_send": "Envoyer",
"publish_dialog_drop_file_here": "Déposez un fichier ici", "publish_dialog_drop_file_here": "Déposez un fichier ici",
"emoji_picker_search_placeholder": "Chercher un émoji", "emoji_picker_search_placeholder": "Chercher un émoji",
"subscribe_dialog_subscribe_description": "Le sujet n'est peut-être pas protégé par un mot de passe, choisissez un nom de sujet difficile à deviner. Une fois abonné, vous pouvez PUT/POST des notifications.", "subscribe_dialog_subscribe_description": "Le sujet n'est peut-être pas protégé par un mot de passe, choisissez un nom de sujet difficile à deviner. Une fois abonné, vous pouvez PUT/POST des notifications.",
"subscribe_dialog_subscribe_topic_placeholder": "Nom de sujet, par ex. alertes_de_phil", "subscribe_dialog_subscribe_topic_placeholder": "Nom de sujet, par ex. alertes_de_phil",
"subscribe_dialog_subscribe_button_subscribe": "S'abonner", "subscribe_dialog_subscribe_button_subscribe": "S'abonner",
"subscribe_dialog_login_description": "Ce sujet est protégé par un mot de passe. Veuillez entrer le nom d'utilisateur et le mot de passe pour vous abonner.", "subscribe_dialog_login_description": "Ce sujet est protégé par un mot de passe. Veuillez entrer le nom d'utilisateur et le mot de passe pour vous abonner.",
"subscribe_dialog_login_username_label": "Nom d'utilisateur, par ex. phil", "subscribe_dialog_login_username_label": "Nom d'utilisateur, par ex. phil",
"subscribe_dialog_login_button_login": "Connexion", "subscribe_dialog_login_button_login": "Connexion",
"prefs_notifications_sound_title": "Son de notification", "prefs_notifications_sound_title": "Son de notification",
"prefs_notifications_delete_after_never": "Jamais", "prefs_notifications_delete_after_never": "Jamais",
"prefs_users_table_base_url_header": "URL de service", "prefs_users_table_base_url_header": "URL de service",
"subscribe_dialog_login_password_label": "Mot de passe", "subscribe_dialog_login_password_label": "Mot de passe",
"prefs_notifications_title": "Notifications", "prefs_notifications_title": "Notifications",
"prefs_notifications_delete_after_title": "Supprimer les notifications", "prefs_notifications_delete_after_title": "Supprimer les notifications",
"prefs_users_add_button": "Ajouter un utilisateur", "prefs_users_add_button": "Ajouter un utilisateur",
"subscribe_dialog_login_button_back": "Retour", "subscribe_dialog_login_button_back": "Retour",
"subscribe_dialog_error_user_anonymous": "anonyme", "subscribe_dialog_error_user_anonymous": "anonyme",
"prefs_notifications_sound_no_sound": "Aucun son", "prefs_notifications_sound_no_sound": "Aucun son",
"prefs_notifications_min_priority_title": "Priorité minimum", "prefs_notifications_min_priority_title": "Priorité minimum",
"prefs_notifications_min_priority_description_any": "Montrer toutes les notifications, quelque soit leur priorité", "prefs_notifications_min_priority_description_any": "Montrer toutes les notifications, quelque soit leur priorité",
"prefs_notifications_min_priority_description_max": "Montrer les notifications si la priorité est 5 (max)", "prefs_notifications_min_priority_description_max": "Montrer les notifications si la priorité est 5 (max)",
"prefs_notifications_min_priority_default_and_higher": "Priorité par défaut et au-dessus", "prefs_notifications_min_priority_default_and_higher": "Priorité par défaut et au-dessus",
"prefs_notifications_min_priority_max_only": "Seulement la priorité maximale", "prefs_notifications_min_priority_max_only": "Seulement la priorité maximale",
"prefs_notifications_delete_after_three_hours": "Après trois heures", "prefs_notifications_delete_after_three_hours": "Après trois heures",
"prefs_notifications_delete_after_one_day": "Après un jour", "prefs_notifications_delete_after_one_day": "Après un jour",
"subscribe_dialog_error_user_not_authorized": "L'utilisateur {{username}} n'est pas autorisé", "subscribe_dialog_error_user_not_authorized": "L'utilisateur {{username}} n'est pas autorisé",
"prefs_notifications_min_priority_any": "N'importe quelle priorité", "prefs_notifications_min_priority_any": "N'importe quelle priorité",
"prefs_notifications_min_priority_high_and_higher": "Priorité haute et au-dessus", "prefs_notifications_min_priority_high_and_higher": "Priorité haute et au-dessus",
"prefs_users_dialog_base_url_label": "URL du service, par ex. https://ntfy.sh", "prefs_users_dialog_base_url_label": "URL du service, par ex. https://ntfy.sh",
"prefs_notifications_delete_after_one_week_description": "Les notifications sont supprimées automatiquement après une semaine", "prefs_notifications_delete_after_one_week_description": "Les notifications sont supprimées automatiquement après une semaine",
"prefs_users_dialog_username_label": "Nom d'utilisateur, par ex. phil", "prefs_users_dialog_username_label": "Nom d'utilisateur, par ex. phil",
"prefs_users_dialog_password_label": "Mot de passe", "prefs_users_dialog_password_label": "Mot de passe",
"prefs_notifications_delete_after_one_month_description": "Les notifications sont supprimées automatiquement après un mois", "prefs_notifications_delete_after_one_month_description": "Les notifications sont supprimées automatiquement après un mois",
"prefs_users_title": "Gérer les utilisateurs", "prefs_users_title": "Gérer les utilisateurs",
"prefs_users_description": "Ajoutez/supprimez des utilisateurs pour vos sujets protégés ici. Notez que cet utilisateur et ce mot de passe sont stockés dans le stockage local du navigateur.", "prefs_users_description": "Ajoutez/supprimez des utilisateurs pour vos sujets protégés ici. Notez que cet utilisateur et ce mot de passe sont stockés dans le stockage local du navigateur.",
"prefs_users_table_user_header": "Utilisateur", "prefs_users_table_user_header": "Utilisateur",
"prefs_users_dialog_title_edit": "Éditer l'utilisateur", "prefs_users_dialog_title_edit": "Éditer l'utilisateur",
"prefs_users_dialog_button_add": "Ajouter", "prefs_users_dialog_button_add": "Ajouter",
"error_boundary_description": "Ceci ne devrait évidemment pas arriver. Désolé pour ça.<br/>Si vous avez une minute, merci de <githubLink>signaler ceci sur GitHub</githubLink>, ou faites-le nous savoir par <discordLink>Discord</discordLink> ou <matrixLink>Matric</matrixLink>.", "error_boundary_description": "Ceci ne devrait évidemment pas arriver. Désolé pour ça.<br/>Si vous avez une minute, merci de <githubLink>signaler ceci sur GitHub</githubLink>, ou faites-le nous savoir par <discordLink>Discord</discordLink> ou <matrixLink>Matric</matrixLink>.",
"prefs_users_dialog_title_add": "Ajouter un utilisateur", "prefs_users_dialog_title_add": "Ajouter un utilisateur",
"error_boundary_stack_trace": "Trace de pile d'appels", "error_boundary_stack_trace": "Trace de pile d'appels",
"error_boundary_gathering_info": "Récupérer plus d'information…", "error_boundary_gathering_info": "Récupérer plus d'information…",
"prefs_notifications_delete_after_one_week": "Après une semaine", "prefs_notifications_delete_after_one_week": "Après une semaine",
"prefs_notifications_delete_after_one_month": "Après un mois", "prefs_notifications_delete_after_one_month": "Après un mois",
"prefs_notifications_delete_after_never_description": "Les notifications ne sont jamais supprimées automatiquement", "prefs_notifications_delete_after_never_description": "Les notifications ne sont jamais supprimées automatiquement",
"prefs_notifications_delete_after_three_hours_description": "Les notifications sont supprimées automatiquement après trois heures", "prefs_notifications_delete_after_three_hours_description": "Les notifications sont supprimées automatiquement après trois heures",
"prefs_notifications_delete_after_one_day_description": "Les notifications sont supprimées automatiquement après un jour", "prefs_notifications_delete_after_one_day_description": "Les notifications sont supprimées automatiquement après un jour",
"prefs_appearance_title": "Apparence", "prefs_appearance_title": "Apparence",
"prefs_appearance_language_title": "Langue", "prefs_appearance_language_title": "Langue",
"priority_min": "min", "priority_min": "min",
"priority_low": "basse", "priority_low": "basse",
"priority_default": "défault", "priority_default": "défault",
"priority_high": "haute", "priority_high": "haute",
"priority_max": "max", "priority_max": "max",
"error_boundary_title": "Oh non, ntfy a planté", "error_boundary_title": "Oh non, ntfy a planté",
"publish_dialog_chip_attach_url_label": "Joindre un fichier par URL", "publish_dialog_chip_attach_url_label": "Joindre un fichier par URL",
"publish_dialog_chip_attach_file_label": "Joindre un fichier local", "publish_dialog_chip_attach_file_label": "Joindre un fichier local",
"publish_dialog_chip_delay_label": "Délayer l'envoi", "publish_dialog_chip_delay_label": "Délayer l'envoi",
"publish_dialog_chip_topic_label": "Changer de sujet", "publish_dialog_chip_topic_label": "Changer de sujet",
"publish_dialog_details_examples_description": "Pour des exemples et une description détaillée des fonctionnalités d'envoi, voir la <docsLink>documentation</docsLink>.", "publish_dialog_details_examples_description": "Pour des exemples et une description détaillée des fonctionnalités d'envoi, voir la <docsLink>documentation</docsLink>.",
"publish_dialog_button_cancel_sending": "Annuler l'envoi", "publish_dialog_button_cancel_sending": "Annuler l'envoi",
"prefs_users_dialog_button_save": "Enregistrer", "prefs_users_dialog_button_save": "Enregistrer",
"notifications_new_indicator": "Nouvelle notification", "notifications_new_indicator": "Nouvelle notification",
"publish_dialog_delay_reset": "Retirer le délai de réception", "publish_dialog_delay_reset": "Retirer le délai de réception",
"notifications_list_item": "Notification", "notifications_list_item": "Notification",
"notifications_priority_x": "Priorité {{priority}}", "notifications_priority_x": "Priorité {{priority}}",
"notifications_mark_read": "Marquer comme lu", "notifications_mark_read": "Marquer comme lu",
"notifications_attachment_image": "Image jointe", "notifications_attachment_image": "Image jointe",
"notifications_delete": "Supprimer", "notifications_delete": "Supprimer",
"notifications_attachment_file_video": "fichier vidéo", "notifications_attachment_file_video": "fichier vidéo",
"notifications_attachment_file_audio": "fichier audio", "notifications_attachment_file_audio": "fichier audio",
"prefs_users_table": "Liste des utilisateurs", "prefs_users_table": "Liste des utilisateurs",
"notifications_attachment_file_image": "fichier image", "notifications_attachment_file_image": "fichier image",
"notifications_attachment_file_app": "fichier d'application Android", "notifications_attachment_file_app": "fichier d'application Android",
"notifications_attachment_file_document": "autre document", "notifications_attachment_file_document": "autre document",
"prefs_notifications_sound_play": "Jouer le son sélectionné", "prefs_notifications_sound_play": "Jouer le son sélectionné",
"error_boundary_unsupported_indexeddb_description": "L'application web ntfy a besoin d'IndexedDB pour fonctionner, mais votre navigateur ne supporte pas IndexedDB en navigation privée.<br/><br/>Bien que cela soit regrettable, il serait peu utile d'utiliser l'application web ntfy en navigation privée, car tout est stocké par votre navigateur. Vous pouvez vous renseigner plus amplement à ce propos <githubLink>dans ce ticket GitHub</githubLink>, ou en parler avec nous sur <discordLink>Discord</discordLink> ou <matrixLink>Matrix</matrixLink>.", "error_boundary_unsupported_indexeddb_description": "L'application web ntfy a besoin d'IndexedDB pour fonctionner, mais votre navigateur ne supporte pas IndexedDB en navigation privée.<br/><br/>Bien que cela soit regrettable, il serait peu utile d'utiliser l'application web ntfy en navigation privée, car tout est stocké par votre navigateur. Vous pouvez vous renseigner plus amplement à ce propos <githubLink>dans ce ticket GitHub</githubLink>, ou en parler avec nous sur <discordLink>Discord</discordLink> ou <matrixLink>Matrix</matrixLink>.",
"action_bar_show_menu": "Montrer le menu", "action_bar_show_menu": "Montrer le menu",
"action_bar_toggle_mute": "Mettre en sourdine/réactiver les notifications", "action_bar_toggle_mute": "Mettre en sourdine/réactiver les notifications",
"action_bar_toggle_action_menu": "Ouvrir/fermer le menu d'actions", "action_bar_toggle_action_menu": "Ouvrir/fermer le menu d'actions",
"publish_dialog_emoji_picker_show": "Choisir un emoji", "publish_dialog_emoji_picker_show": "Choisir un emoji",
"publish_dialog_topic_reset": "Réinitialiser le sujet", "publish_dialog_topic_reset": "Réinitialiser le sujet",
"message_bar_publish": "Publier le message", "message_bar_publish": "Publier le message",
"nav_button_muted": "Notifications en sourdine", "nav_button_muted": "Notifications en sourdine",
"nav_button_connecting": "connexion en cours", "nav_button_connecting": "connexion en cours",
"notifications_list": "Liste des notifications", "notifications_list": "Liste des notifications",
"message_bar_show_dialog": "Montrer le formulaire de publication", "message_bar_show_dialog": "Montrer le formulaire de publication",
"action_bar_logo_alt": "Logo de ntfy", "action_bar_logo_alt": "Logo de ntfy",
"publish_dialog_click_reset": "Retirer l'URL du clic", "publish_dialog_click_reset": "Retirer l'URL du clic",
"publish_dialog_email_reset": "Retirer le transfert par courriel", "publish_dialog_email_reset": "Retirer le transfert par courriel",
"publish_dialog_attach_reset": "Retirer l'URL de la pièce jointe", "publish_dialog_attach_reset": "Retirer l'URL de la pièce jointe",
"emoji_picker_search_clear": "Effacer la recherche", "emoji_picker_search_clear": "Effacer la recherche",
"subscribe_dialog_subscribe_base_url_label": "URL du service", "subscribe_dialog_subscribe_base_url_label": "URL du service",
"prefs_users_edit_button": "Éditer l'utilisateur", "prefs_users_edit_button": "Éditer l'utilisateur",
"prefs_users_delete_button": "Supprimer l'utilisateur", "prefs_users_delete_button": "Supprimer l'utilisateur",
"error_boundary_unsupported_indexeddb_title": "Navigation privée non prise en charge", "error_boundary_unsupported_indexeddb_title": "Navigation privée non prise en charge",
"publish_dialog_attached_file_remove": "Retirer le fichier joint" "publish_dialog_attached_file_remove": "Retirer le fichier joint"
} }

View file

@ -1,191 +1,191 @@
{ {
"action_bar_send_test_notification": "Teszt értesítés küldése", "action_bar_send_test_notification": "Teszt értesítés küldése",
"action_bar_clear_notifications": "Összes értesítés törlése", "action_bar_clear_notifications": "Összes értesítés törlése",
"alert_not_supported_description": "A böngésző nem támogatja az értesítések fogadását.", "alert_not_supported_description": "A böngésző nem támogatja az értesítések fogadását.",
"action_bar_settings": "Beállítások", "action_bar_settings": "Beállítások",
"action_bar_unsubscribe": "Leiratkozás", "action_bar_unsubscribe": "Leiratkozás",
"message_bar_type_message": "Írd ide az üzenetet", "message_bar_type_message": "Írd ide az üzenetet",
"message_bar_error_publishing": "Hiba történt az értesítés elküldése közben", "message_bar_error_publishing": "Hiba történt az értesítés elküldése közben",
"nav_button_all_notifications": "Összes értesítés", "nav_button_all_notifications": "Összes értesítés",
"nav_topics_title": "Feliratkozott témák", "nav_topics_title": "Feliratkozott témák",
"alert_grant_title": "Az értesítések le vannak tiltva", "alert_grant_title": "Az értesítések le vannak tiltva",
"alert_grant_description": "Engedélyezd a böngészőnek, hogy asztali értesítéseket jeleníttessen meg.", "alert_grant_description": "Engedélyezd a böngészőnek, hogy asztali értesítéseket jeleníttessen meg.",
"nav_button_settings": "Beállítások", "nav_button_settings": "Beállítások",
"nav_button_documentation": "Dokumentáció", "nav_button_documentation": "Dokumentáció",
"nav_button_publish_message": "Értesítés küldése", "nav_button_publish_message": "Értesítés küldése",
"alert_grant_button": "Engedélyezés", "alert_grant_button": "Engedélyezés",
"alert_not_supported_title": "Nem támogatott funkció", "alert_not_supported_title": "Nem támogatott funkció",
"notifications_copied_to_clipboard": "Másolva a vágólapra", "notifications_copied_to_clipboard": "Másolva a vágólapra",
"notifications_tags": "Címkék", "notifications_tags": "Címkék",
"notifications_attachment_copy_url_title": "Másolja vágólapra a csatolmány URL-ét", "notifications_attachment_copy_url_title": "Másolja vágólapra a csatolmány URL-ét",
"notifications_attachment_copy_url_button": "URL másolása", "notifications_attachment_copy_url_button": "URL másolása",
"notifications_attachment_open_title": "Menjen a(z) {{url}} címre", "notifications_attachment_open_title": "Menjen a(z) {{url}} címre",
"notifications_attachment_open_button": "Csatolmány megnyitása", "notifications_attachment_open_button": "Csatolmány megnyitása",
"notifications_attachment_link_expired": "A letöltési hivatkozás lejárt", "notifications_attachment_link_expired": "A letöltési hivatkozás lejárt",
"notifications_attachment_link_expires": "A hivatkozás {{date}}-kor jár le", "notifications_attachment_link_expires": "A hivatkozás {{date}}-kor jár le",
"nav_button_subscribe": "Feliratkozás témára", "nav_button_subscribe": "Feliratkozás témára",
"notifications_click_copy_url_title": "Másolja vágólapra a hivatkozás URL-ét", "notifications_click_copy_url_title": "Másolja vágólapra a hivatkozás URL-ét",
"notifications_actions_open_url_title": "Menjen a(z) {{url}} címre", "notifications_actions_open_url_title": "Menjen a(z) {{url}} címre",
"notifications_actions_not_supported": "A művelet nem támogatott a webes alkalmazásban", "notifications_actions_not_supported": "A művelet nem támogatott a webes alkalmazásban",
"notifications_actions_http_request_title": "Küldjön HTTP {{method}} kérést a(z) {{url}} címre", "notifications_actions_http_request_title": "Küldjön HTTP {{method}} kérést a(z) {{url}} címre",
"notifications_none_for_topic_title": "Még nem érkezett értesítés erre a témára.", "notifications_none_for_topic_title": "Még nem érkezett értesítés erre a témára.",
"notifications_none_for_any_title": "Még nem érkezett egy értesítés sem.", "notifications_none_for_any_title": "Még nem érkezett egy értesítés sem.",
"notifications_none_for_any_description": "Értesítés beküldéséhez csak küldj egy PUT, vagy POST kérést a téma URL-ére. Itt egy példa az egyik témádhoz.", "notifications_none_for_any_description": "Értesítés beküldéséhez csak küldj egy PUT, vagy POST kérést a téma URL-ére. Itt egy példa az egyik témádhoz.",
"notifications_no_subscriptions_title": "Úgy tűnik, még nem iratkoztál fel egy témára sem.", "notifications_no_subscriptions_title": "Úgy tűnik, még nem iratkoztál fel egy témára sem.",
"publish_dialog_message_published": "Értesítés elküldve", "publish_dialog_message_published": "Értesítés elküldve",
"notifications_example": "Példa", "notifications_example": "Példa",
"notifications_no_subscriptions_description": "Kattints a \"{{linktext}}\" linkre egy téma létrehozásához, vagy rá feliratkozáshoz. Ezután PUT, vagy POST kéréssel fogsz tudni értesítéseket küldeni rá, amik utána meg fognak itt jelenni.", "notifications_no_subscriptions_description": "Kattints a \"{{linktext}}\" linkre egy téma létrehozásához, vagy rá feliratkozáshoz. Ezután PUT, vagy POST kéréssel fogsz tudni értesítéseket küldeni rá, amik utána meg fognak itt jelenni.",
"publish_dialog_priority_low": "Alacsony prioritás", "publish_dialog_priority_low": "Alacsony prioritás",
"publish_dialog_priority_default": "Közepes prioritás", "publish_dialog_priority_default": "Közepes prioritás",
"publish_dialog_priority_high": "Magas prioritás", "publish_dialog_priority_high": "Magas prioritás",
"notifications_more_details": "További információkért keresd fel a <websiteLink>weboldalunkat</websiteLink> vagy olvasd el a <docsLink>dokumentációt</docsLink>.", "notifications_more_details": "További információkért keresd fel a <websiteLink>weboldalunkat</websiteLink> vagy olvasd el a <docsLink>dokumentációt</docsLink>.",
"publish_dialog_title_no_topic": "Értesítés küldése", "publish_dialog_title_no_topic": "Értesítés küldése",
"publish_dialog_attachment_limits_file_and_quota_reached": "túllépi a fájlméret korlátot ({{fileSizeLimit}}) és a kvótát is ({{remainingBytes}} maradt)", "publish_dialog_attachment_limits_file_and_quota_reached": "túllépi a fájlméret korlátot ({{fileSizeLimit}}) és a kvótát is ({{remainingBytes}} maradt)",
"publish_dialog_attachment_limits_quota_reached": "túllépi a kvótát, {{remainingBytes}} maradt", "publish_dialog_attachment_limits_quota_reached": "túllépi a kvótát, {{remainingBytes}} maradt",
"publish_dialog_priority_min": "Legkisebb prioritás", "publish_dialog_priority_min": "Legkisebb prioritás",
"publish_dialog_base_url_label": "A szolgáltatás URL-e", "publish_dialog_base_url_label": "A szolgáltatás URL-e",
"publish_dialog_base_url_placeholder": "A szolgáltatás URL-e, pl: https://example.com", "publish_dialog_base_url_placeholder": "A szolgáltatás URL-e, pl: https://example.com",
"publish_dialog_topic_label": "Téma neve", "publish_dialog_topic_label": "Téma neve",
"publish_dialog_priority_max": "Legmagasabb prioritás", "publish_dialog_priority_max": "Legmagasabb prioritás",
"publish_dialog_topic_placeholder": "Téma neve, pl: jozsi_riasztasai", "publish_dialog_topic_placeholder": "Téma neve, pl: jozsi_riasztasai",
"publish_dialog_title_label": "Cím", "publish_dialog_title_label": "Cím",
"publish_dialog_title_placeholder": "Értesítés címe, pl: Fogy a szabad hely", "publish_dialog_title_placeholder": "Értesítés címe, pl: Fogy a szabad hely",
"publish_dialog_message_label": "Üzenet", "publish_dialog_message_label": "Üzenet",
"publish_dialog_message_placeholder": "Írj ide egy üzenetet", "publish_dialog_message_placeholder": "Írj ide egy üzenetet",
"publish_dialog_tags_label": "Címkék", "publish_dialog_tags_label": "Címkék",
"publish_dialog_tags_placeholder": "Címkék vesszővel elválasztva, pl: fontos,srv1-backup", "publish_dialog_tags_placeholder": "Címkék vesszővel elválasztva, pl: fontos,srv1-backup",
"publish_dialog_priority_label": "Prioritás", "publish_dialog_priority_label": "Prioritás",
"publish_dialog_click_label": "URL", "publish_dialog_click_label": "URL",
"publish_dialog_click_placeholder": "Webcím, ami megnyílik, ha az értesítésre kattintanak", "publish_dialog_click_placeholder": "Webcím, ami megnyílik, ha az értesítésre kattintanak",
"publish_dialog_email_label": "Email", "publish_dialog_email_label": "Email",
"publish_dialog_email_placeholder": "Email cím, amire továbbítjuk az értesítést, pl: jozsi@example.com", "publish_dialog_email_placeholder": "Email cím, amire továbbítjuk az értesítést, pl: jozsi@example.com",
"publish_dialog_attach_label": "Csatolmány URL-e", "publish_dialog_attach_label": "Csatolmány URL-e",
"publish_dialog_filename_label": "Fájlnév", "publish_dialog_filename_label": "Fájlnév",
"publish_dialog_filename_placeholder": "Csatolmány fájlneve", "publish_dialog_filename_placeholder": "Csatolmány fájlneve",
"publish_dialog_delay_label": "Késleltetés", "publish_dialog_delay_label": "Késleltetés",
"publish_dialog_delay_placeholder": "Késleltetett küldés, pl: {{unixTimestamp}}, {{relativeTime}}, vagy \"{{naturalLanguage}}\" (Csak angolul)", "publish_dialog_delay_placeholder": "Késleltetett küldés, pl: {{unixTimestamp}}, {{relativeTime}}, vagy \"{{naturalLanguage}}\" (Csak angolul)",
"publish_dialog_other_features": "Egyéb lehetőségek:", "publish_dialog_other_features": "Egyéb lehetőségek:",
"publish_dialog_chip_click_label": "Kattintási URL", "publish_dialog_chip_click_label": "Kattintási URL",
"publish_dialog_chip_attach_file_label": "Helyi fájl csatolása", "publish_dialog_chip_attach_file_label": "Helyi fájl csatolása",
"publish_dialog_chip_delay_label": "Késleltetett kézbesítés", "publish_dialog_chip_delay_label": "Késleltetett kézbesítés",
"publish_dialog_chip_topic_label": "Téma megváltoztatása", "publish_dialog_chip_topic_label": "Téma megváltoztatása",
"publish_dialog_button_cancel_sending": "Küldés megállítása", "publish_dialog_button_cancel_sending": "Küldés megállítása",
"publish_dialog_button_cancel": "Mégsem", "publish_dialog_button_cancel": "Mégsem",
"publish_dialog_checkbox_publish_another": "Küldök még egyet", "publish_dialog_checkbox_publish_another": "Küldök még egyet",
"publish_dialog_attached_file_title": "Csatolt fájl:", "publish_dialog_attached_file_title": "Csatolt fájl:",
"publish_dialog_attached_file_filename_placeholder": "Csatolmány fájlneve", "publish_dialog_attached_file_filename_placeholder": "Csatolmány fájlneve",
"publish_dialog_drop_file_here": "Ejtsd ide a fájlt", "publish_dialog_drop_file_here": "Ejtsd ide a fájlt",
"emoji_picker_search_placeholder": "Emoji keresése", "emoji_picker_search_placeholder": "Emoji keresése",
"publish_dialog_details_examples_description": "Példákért és az összes küldési képesség részletes leírásához olvasd el a <docsLink>dokumentációt</docsLink>.", "publish_dialog_details_examples_description": "Példákért és az összes küldési képesség részletes leírásához olvasd el a <docsLink>dokumentációt</docsLink>.",
"subscribe_dialog_subscribe_use_another_label": "Használjon másik szervert", "subscribe_dialog_subscribe_use_another_label": "Használjon másik szervert",
"subscribe_dialog_subscribe_button_subscribe": "Feliratkozás", "subscribe_dialog_subscribe_button_subscribe": "Feliratkozás",
"subscribe_dialog_login_title": "Be kell jelentkezni", "subscribe_dialog_login_title": "Be kell jelentkezni",
"subscribe_dialog_subscribe_description": "A témák nem mindig vannak jelszóval védve, ezért olyan nevet válassz, ami nehezen található ki. Miután feliratkoztál, küldhetsz értesítéseket.", "subscribe_dialog_subscribe_description": "A témák nem mindig vannak jelszóval védve, ezért olyan nevet válassz, ami nehezen található ki. Miután feliratkoztál, küldhetsz értesítéseket.",
"subscribe_dialog_login_description": "Ez a téma jelszóval védett. Jelentkezz be a feliratkozáshoz.", "subscribe_dialog_login_description": "Ez a téma jelszóval védett. Jelentkezz be a feliratkozáshoz.",
"subscribe_dialog_login_username_label": "Felhasználónév, pl: jozsi", "subscribe_dialog_login_username_label": "Felhasználónév, pl: jozsi",
"subscribe_dialog_login_password_label": "Jelszó", "subscribe_dialog_login_password_label": "Jelszó",
"subscribe_dialog_login_button_back": "Vissza", "subscribe_dialog_login_button_back": "Vissza",
"subscribe_dialog_login_button_login": "Belépés", "subscribe_dialog_login_button_login": "Belépés",
"subscribe_dialog_error_user_anonymous": "névtelen", "subscribe_dialog_error_user_anonymous": "névtelen",
"subscribe_dialog_error_user_not_authorized": "A(z) {{username}} felhasználónak nincs hozzáférése", "subscribe_dialog_error_user_not_authorized": "A(z) {{username}} felhasználónak nincs hozzáférése",
"prefs_notifications_min_priority_description_any": "Minden értesítést mutat, prioritástól függetlenül", "prefs_notifications_min_priority_description_any": "Minden értesítést mutat, prioritástól függetlenül",
"prefs_notifications_min_priority_description_max": "Csak az 5-ös (legmagasabb) prioritású értesítések jelennek meg", "prefs_notifications_min_priority_description_max": "Csak az 5-ös (legmagasabb) prioritású értesítések jelennek meg",
"prefs_notifications_min_priority_any": "Bármilyen prioritás", "prefs_notifications_min_priority_any": "Bármilyen prioritás",
"prefs_notifications_min_priority_low_and_higher": "Alacsony prioritás, vagy magasabb", "prefs_notifications_min_priority_low_and_higher": "Alacsony prioritás, vagy magasabb",
"prefs_notifications_min_priority_high_and_higher": "Magas, vagy legmagasabb prioritás", "prefs_notifications_min_priority_high_and_higher": "Magas, vagy legmagasabb prioritás",
"prefs_notifications_min_priority_max_only": "Csak a legmagasabb prioritás", "prefs_notifications_min_priority_max_only": "Csak a legmagasabb prioritás",
"prefs_notifications_sound_title": "Értesítés hangja", "prefs_notifications_sound_title": "Értesítés hangja",
"prefs_notifications_sound_description_none": "Az értesítések nem fognak hangot adni, amikor megérkeznek", "prefs_notifications_sound_description_none": "Az értesítések nem fognak hangot adni, amikor megérkeznek",
"prefs_notifications_sound_no_sound": "Hang nélkül", "prefs_notifications_sound_no_sound": "Hang nélkül",
"prefs_notifications_delete_after_one_week": "1 hét után", "prefs_notifications_delete_after_one_week": "1 hét után",
"prefs_notifications_delete_after_one_month": "1 hónap után", "prefs_notifications_delete_after_one_month": "1 hónap után",
"prefs_notifications_delete_after_never_description": "Az értesítések soha nem lesznek automatikusan törölve", "prefs_notifications_delete_after_never_description": "Az értesítések soha nem lesznek automatikusan törölve",
"prefs_notifications_delete_after_three_hours_description": "A 3 óránál régebbi értesítések automatikus törlése", "prefs_notifications_delete_after_three_hours_description": "A 3 óránál régebbi értesítések automatikus törlése",
"prefs_notifications_delete_after_one_day_description": "Az egy napnál régebbi értesítések automatikus törlése", "prefs_notifications_delete_after_one_day_description": "Az egy napnál régebbi értesítések automatikus törlése",
"prefs_users_description": "Itt tudsz hozzáadni/eltávolítani felhasználókat a védett témákról. Fontos, hogy a felhasználónevet és a jelszót a böngésző helyi tárolójába fogjuk menteni.", "prefs_users_description": "Itt tudsz hozzáadni/eltávolítani felhasználókat a védett témákról. Fontos, hogy a felhasználónevet és a jelszót a böngésző helyi tárolójába fogjuk menteni.",
"prefs_users_table_user_header": "Felhasználó", "prefs_users_table_user_header": "Felhasználó",
"prefs_users_table_base_url_header": "Szerver címe", "prefs_users_table_base_url_header": "Szerver címe",
"prefs_users_dialog_title_edit": "Felhasználó szerkesztése", "prefs_users_dialog_title_edit": "Felhasználó szerkesztése",
"prefs_users_dialog_username_label": "Felhasználónév, pl: jozsi", "prefs_users_dialog_username_label": "Felhasználónév, pl: jozsi",
"prefs_users_dialog_password_label": "Jelszó", "prefs_users_dialog_password_label": "Jelszó",
"prefs_users_dialog_button_add": "Hozzáadás", "prefs_users_dialog_button_add": "Hozzáadás",
"prefs_users_dialog_base_url_label": "Szerver címe, pl: https://ntfy.sh", "prefs_users_dialog_base_url_label": "Szerver címe, pl: https://ntfy.sh",
"notifications_loading": "Értesítések betöltése …", "notifications_loading": "Értesítések betöltése …",
"publish_dialog_progress_uploading": "Feltöltés …", "publish_dialog_progress_uploading": "Feltöltés …",
"notifications_click_copy_url_button": "Hivatkozás másolása", "notifications_click_copy_url_button": "Hivatkozás másolása",
"notifications_click_open_button": "Hivatkozás megnyitása", "notifications_click_open_button": "Hivatkozás megnyitása",
"publish_dialog_progress_uploading_detail": "Feltöltés folyamatban: {{loaded}}/{{total}} ({{percent}}%) …", "publish_dialog_progress_uploading_detail": "Feltöltés folyamatban: {{loaded}}/{{total}} ({{percent}}%) …",
"notifications_none_for_topic_description": "Értesítés beküldéséhez csak küldj egy PUT, vagy POST kérést a téma URL-ére.", "notifications_none_for_topic_description": "Értesítés beküldéséhez csak küldj egy PUT, vagy POST kérést a téma URL-ére.",
"prefs_notifications_delete_after_one_day": "1 nap után", "prefs_notifications_delete_after_one_day": "1 nap után",
"publish_dialog_attach_placeholder": "Csatolandó fájl címe, pl: https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "Csatolandó fájl címe, pl: https://f-droid.org/F-Droid.apk",
"publish_dialog_chip_email_label": "Továbbítás email-ben", "publish_dialog_chip_email_label": "Továbbítás email-ben",
"publish_dialog_chip_attach_url_label": "Fájl csatolása URL-lel", "publish_dialog_chip_attach_url_label": "Fájl csatolása URL-lel",
"publish_dialog_button_send": "Küldés", "publish_dialog_button_send": "Küldés",
"subscribe_dialog_subscribe_title": "Feliratkozás témára", "subscribe_dialog_subscribe_title": "Feliratkozás témára",
"subscribe_dialog_subscribe_button_cancel": "Mégsem", "subscribe_dialog_subscribe_button_cancel": "Mégsem",
"prefs_notifications_min_priority_title": "Legkisebb megjelenítendő prioritás", "prefs_notifications_min_priority_title": "Legkisebb megjelenítendő prioritás",
"prefs_notifications_min_priority_description_x_or_higher": "Csak akkor jelenik meg egy értesítés, ha a prioritása {{number}} ({{name}}), vagy fontosabb", "prefs_notifications_min_priority_description_x_or_higher": "Csak akkor jelenik meg egy értesítés, ha a prioritása {{number}} ({{name}}), vagy fontosabb",
"prefs_notifications_min_priority_default_and_higher": "Közepes prioritás, vagy magasabb", "prefs_notifications_min_priority_default_and_higher": "Közepes prioritás, vagy magasabb",
"prefs_notifications_delete_after_one_week_description": "Az egy hétnél régebbi értesítések automatikus törlése", "prefs_notifications_delete_after_one_week_description": "Az egy hétnél régebbi értesítések automatikus törlése",
"prefs_users_add_button": "Felhasználó hozzáadása", "prefs_users_add_button": "Felhasználó hozzáadása",
"subscribe_dialog_subscribe_topic_placeholder": "Téma neve, pl: jozsi_riasztasai", "subscribe_dialog_subscribe_topic_placeholder": "Téma neve, pl: jozsi_riasztasai",
"prefs_notifications_title": "Értesítések", "prefs_notifications_title": "Értesítések",
"error_boundary_button_copy_stack_trace": "Verem nyomkövetés másolása", "error_boundary_button_copy_stack_trace": "Verem nyomkövetés másolása",
"prefs_notifications_delete_after_title": "Régi értesítések törlése", "prefs_notifications_delete_after_title": "Régi értesítések törlése",
"prefs_notifications_delete_after_three_hours": "3 óra után", "prefs_notifications_delete_after_three_hours": "3 óra után",
"error_boundary_title": "Jaj ne, az ntfy összeomlott", "error_boundary_title": "Jaj ne, az ntfy összeomlott",
"prefs_notifications_delete_after_never": "Soha", "prefs_notifications_delete_after_never": "Soha",
"prefs_notifications_delete_after_one_month_description": "Az egy hónapnál régebbi értesítések automatikus törlése", "prefs_notifications_delete_after_one_month_description": "Az egy hónapnál régebbi értesítések automatikus törlése",
"prefs_appearance_title": "Megjelenés", "prefs_appearance_title": "Megjelenés",
"priority_default": "közepes", "priority_default": "közepes",
"priority_high": "magas", "priority_high": "magas",
"priority_max": "legmagasabb", "priority_max": "legmagasabb",
"priority_min": "legkisebb", "priority_min": "legkisebb",
"error_boundary_gathering_info": "Több információ…", "error_boundary_gathering_info": "Több információ…",
"publish_dialog_attachment_limits_file_reached": "túllépi a fájlméret korlátot ({{fileSizeLimit}})", "publish_dialog_attachment_limits_file_reached": "túllépi a fájlméret korlátot ({{fileSizeLimit}})",
"prefs_users_title": "Felhasználók kezelése", "prefs_users_title": "Felhasználók kezelése",
"prefs_users_dialog_button_cancel": "Mégsem", "prefs_users_dialog_button_cancel": "Mégsem",
"prefs_users_dialog_button_save": "Mentés", "prefs_users_dialog_button_save": "Mentés",
"prefs_users_dialog_title_add": "Felhasználó hozzáadása", "prefs_users_dialog_title_add": "Felhasználó hozzáadása",
"prefs_appearance_language_title": "Nyelv", "prefs_appearance_language_title": "Nyelv",
"priority_low": "alacsony", "priority_low": "alacsony",
"error_boundary_stack_trace": "Verem nyomkövetés", "error_boundary_stack_trace": "Verem nyomkövetés",
"publish_dialog_title_topic": "A {{topic}} téma értesítése", "publish_dialog_title_topic": "A {{topic}} téma értesítése",
"prefs_notifications_sound_description_some": "Az értesítéseket a(z) {{sound}} hang fogja jelezni", "prefs_notifications_sound_description_some": "Az értesítéseket a(z) {{sound}} hang fogja jelezni",
"error_boundary_description": "Ennek nem szabadott volna megtörténnie. Nagyon sajnáljuk.<br/>Ha van egy perced, <githubLink>jelentsd be GitHubon</githubLink>, vagy tudasd velünk <discordLink>Discordon</discordLink>, vagy <matrixLink>Matrixon</matrixLink>.", "error_boundary_description": "Ennek nem szabadott volna megtörténnie. Nagyon sajnáljuk.<br/>Ha van egy perced, <githubLink>jelentsd be GitHubon</githubLink>, vagy tudasd velünk <discordLink>Discordon</discordLink>, vagy <matrixLink>Matrixon</matrixLink>.",
"action_bar_show_menu": "Menü mutatása", "action_bar_show_menu": "Menü mutatása",
"action_bar_toggle_mute": "Üzenetek némítása/bekapcsolása", "action_bar_toggle_mute": "Üzenetek némítása/bekapcsolása",
"notifications_list_item": "Értesítés", "notifications_list_item": "Értesítés",
"error_boundary_unsupported_indexeddb_description": "A ntfy web alkalmazás működéséhez szükséges az IndexedDB funkció, az ön böngészője nem támogatja az IndexedDB használatát privát böngészés közben.<br/><br/>Miközben privát mód sajnos nem lehetséges, szeretnénk értesíteni hogy magabiztosan használhatja normál módban mert a böngésző minden adatot az ön gépén tárol. Tovább tájékozódhat <githubLink>ezen a Github oldalon</githubLink>, vagy beszéljen velünk <discordLink>Discord-on</discordLink> vagy <matrixLink>Matrix-on</matrixLink>.", "error_boundary_unsupported_indexeddb_description": "A ntfy web alkalmazás működéséhez szükséges az IndexedDB funkció, az ön böngészője nem támogatja az IndexedDB használatát privát böngészés közben.<br/><br/>Miközben privát mód sajnos nem lehetséges, szeretnénk értesíteni hogy magabiztosan használhatja normál módban mert a böngésző minden adatot az ön gépén tárol. Tovább tájékozódhat <githubLink>ezen a Github oldalon</githubLink>, vagy beszéljen velünk <discordLink>Discord-on</discordLink> vagy <matrixLink>Matrix-on</matrixLink>.",
"notifications_priority_x": "Prioritás {{prioritás}}", "notifications_priority_x": "Prioritás {{prioritás}}",
"message_bar_show_dialog": "Küldött üzenetek megjelenítése", "message_bar_show_dialog": "Küldött üzenetek megjelenítése",
"action_bar_logo_alt": "ntfy logó", "action_bar_logo_alt": "ntfy logó",
"action_bar_toggle_action_menu": "Tevékenységkezelő nyitása/zárása", "action_bar_toggle_action_menu": "Tevékenységkezelő nyitása/zárása",
"message_bar_publish": "Üzenet küldése", "message_bar_publish": "Üzenet küldése",
"nav_button_muted": "Értesítések némítva", "nav_button_muted": "Értesítések némítva",
"nav_button_connecting": "csatlakozás", "nav_button_connecting": "csatlakozás",
"notifications_list": "Értesítés lista", "notifications_list": "Értesítés lista",
"notifications_mark_read": "Jelölés olvasottként", "notifications_mark_read": "Jelölés olvasottként",
"notifications_delete": "Törlés", "notifications_delete": "Törlés",
"notifications_new_indicator": "Új értesítés", "notifications_new_indicator": "Új értesítés",
"notifications_attachment_image": "Csatolt kép", "notifications_attachment_image": "Csatolt kép",
"notifications_attachment_file_image": "Kép fájl", "notifications_attachment_file_image": "Kép fájl",
"notifications_attachment_file_video": "Videó fájl", "notifications_attachment_file_video": "Videó fájl",
"notifications_attachment_file_audio": "Hang fájl", "notifications_attachment_file_audio": "Hang fájl",
"notifications_attachment_file_app": "Android alkalmazás fájl", "notifications_attachment_file_app": "Android alkalmazás fájl",
"notifications_attachment_file_document": "egyéb dokumentum", "notifications_attachment_file_document": "egyéb dokumentum",
"publish_dialog_emoji_picker_show": "Emoji kiválasztása", "publish_dialog_emoji_picker_show": "Emoji kiválasztása",
"publish_dialog_topic_reset": "Téma visszaállítása", "publish_dialog_topic_reset": "Téma visszaállítása",
"publish_dialog_click_reset": "URL kattintás törlése", "publish_dialog_click_reset": "URL kattintás törlése",
"publish_dialog_email_reset": "Email továbbítás törlése", "publish_dialog_email_reset": "Email továbbítás törlése",
"publish_dialog_attach_reset": "Csatolt URL törlése", "publish_dialog_attach_reset": "Csatolt URL törlése",
"publish_dialog_delay_reset": "Késleltetett kézbesítés törlése", "publish_dialog_delay_reset": "Késleltetett kézbesítés törlése",
"publish_dialog_attached_file_remove": "Csatolt fájl törlése", "publish_dialog_attached_file_remove": "Csatolt fájl törlése",
"emoji_picker_search_clear": "Keresés törlése", "emoji_picker_search_clear": "Keresés törlése",
"prefs_notifications_sound_play": "Kijelölt hang lejátszása", "prefs_notifications_sound_play": "Kijelölt hang lejátszása",
"prefs_users_table": "Felhasználó táblázat", "prefs_users_table": "Felhasználó táblázat",
"prefs_users_edit_button": "Felhasználó szerkesztése", "prefs_users_edit_button": "Felhasználó szerkesztése",
"prefs_users_delete_button": "Felhasználó törlése", "prefs_users_delete_button": "Felhasználó törlése",
"error_boundary_unsupported_indexeddb_title": "Privát böngészés nem támogatott", "error_boundary_unsupported_indexeddb_title": "Privát böngészés nem támogatott",
"subscribe_dialog_subscribe_base_url_label": "Szolgáltató URL" "subscribe_dialog_subscribe_base_url_label": "Szolgáltató URL"
} }

View file

@ -1,191 +1,191 @@
{ {
"notifications_click_copy_url_title": "Salin URL tautan ke papan klip", "notifications_click_copy_url_title": "Salin URL tautan ke papan klip",
"alert_not_supported_title": "Notifikasi tidak didukung", "alert_not_supported_title": "Notifikasi tidak didukung",
"notifications_click_copy_url_button": "Salin tautan", "notifications_click_copy_url_button": "Salin tautan",
"notifications_no_subscriptions_description": "Klik pada tautan \"{{linktext}}\" untuk membuat atau berlangganan ke sebuah topik. Setelah itu, Anda dapat mengirim pesan via PUT atau POST dan Anda akan menerima notifikasi di sini.", "notifications_no_subscriptions_description": "Klik pada tautan \"{{linktext}}\" untuk membuat atau berlangganan ke sebuah topik. Setelah itu, Anda dapat mengirim pesan via PUT atau POST dan Anda akan menerima notifikasi di sini.",
"notifications_example": "Contoh", "notifications_example": "Contoh",
"subscribe_dialog_subscribe_description": "Topik mungkin tidak dilindungi oleh kata sandi, jadi pilih sebuah nama yang tidak mudah untuk ditebak. Setelah berlangganan, Anda dapat PUT/POST notifikasi.", "subscribe_dialog_subscribe_description": "Topik mungkin tidak dilindungi oleh kata sandi, jadi pilih sebuah nama yang tidak mudah untuk ditebak. Setelah berlangganan, Anda dapat PUT/POST notifikasi.",
"subscribe_dialog_login_title": "Login dibutuhkan", "subscribe_dialog_login_title": "Login dibutuhkan",
"prefs_appearance_language_title": "Bahasa", "prefs_appearance_language_title": "Bahasa",
"nav_button_all_notifications": "Semua notifikasi", "nav_button_all_notifications": "Semua notifikasi",
"notifications_none_for_any_title": "Anda belum menerima notifikasi apa pun.", "notifications_none_for_any_title": "Anda belum menerima notifikasi apa pun.",
"action_bar_settings": "Pengaturan", "action_bar_settings": "Pengaturan",
"action_bar_send_test_notification": "Kirim notifikasi uji coba", "action_bar_send_test_notification": "Kirim notifikasi uji coba",
"action_bar_clear_notifications": "Hapus semua notifikasi", "action_bar_clear_notifications": "Hapus semua notifikasi",
"action_bar_unsubscribe": "Batalkan langganan", "action_bar_unsubscribe": "Batalkan langganan",
"message_bar_type_message": "Ketika sebuah pesan di sini", "message_bar_type_message": "Ketika sebuah pesan di sini",
"message_bar_error_publishing": "Terjadi kesalahan mempublikasikan notifikasi", "message_bar_error_publishing": "Terjadi kesalahan mempublikasikan notifikasi",
"publish_dialog_title_label": "Judul", "publish_dialog_title_label": "Judul",
"publish_dialog_message_label": "Pesan", "publish_dialog_message_label": "Pesan",
"nav_button_settings": "Pengaturan", "nav_button_settings": "Pengaturan",
"nav_button_documentation": "Dokumentasi", "nav_button_documentation": "Dokumentasi",
"prefs_users_dialog_button_add": "Tambahkan", "prefs_users_dialog_button_add": "Tambahkan",
"nav_topics_title": "Topik yang dilanggani", "nav_topics_title": "Topik yang dilanggani",
"nav_button_subscribe": "Berlangganan ke topik", "nav_button_subscribe": "Berlangganan ke topik",
"alert_grant_title": "Notifikasi dinonaktifkan", "alert_grant_title": "Notifikasi dinonaktifkan",
"alert_grant_description": "Berikan izin ke peramban untuk menampilkan notifikasi desktop.", "alert_grant_description": "Berikan izin ke peramban untuk menampilkan notifikasi desktop.",
"alert_not_supported_description": "Notifikasi tidak didukung dalam peramban Anda.", "alert_not_supported_description": "Notifikasi tidak didukung dalam peramban Anda.",
"notifications_attachment_open_title": "Pergi ke {{url}}", "notifications_attachment_open_title": "Pergi ke {{url}}",
"notifications_attachment_open_button": "Buka lampiran", "notifications_attachment_open_button": "Buka lampiran",
"notifications_attachment_link_expires": "tautan kadaluwarsa {{date}}", "notifications_attachment_link_expires": "tautan kadaluwarsa {{date}}",
"notifications_attachment_link_expired": "tautan unduhan kadaluwarsa", "notifications_attachment_link_expired": "tautan unduhan kadaluwarsa",
"notifications_actions_open_url_title": "Pergi ke {{url}}", "notifications_actions_open_url_title": "Pergi ke {{url}}",
"notifications_click_open_button": "Buka tautan", "notifications_click_open_button": "Buka tautan",
"publish_dialog_topic_placeholder": "Nama topik, mis. pemberitahuan_andi", "publish_dialog_topic_placeholder": "Nama topik, mis. pemberitahuan_andi",
"nav_button_publish_message": "Publikasikan notifikasi", "nav_button_publish_message": "Publikasikan notifikasi",
"alert_grant_button": "Berikan sekarang", "alert_grant_button": "Berikan sekarang",
"notifications_copied_to_clipboard": "Disalin ke papan klip", "notifications_copied_to_clipboard": "Disalin ke papan klip",
"notifications_tags": "Tanda", "notifications_tags": "Tanda",
"notifications_attachment_copy_url_title": "Salin URL lampiran ke papan klip", "notifications_attachment_copy_url_title": "Salin URL lampiran ke papan klip",
"notifications_attachment_copy_url_button": "Salin URL", "notifications_attachment_copy_url_button": "Salin URL",
"notifications_none_for_topic_title": "Anda belum menerima notifikasi apa pun untuk topik ini.", "notifications_none_for_topic_title": "Anda belum menerima notifikasi apa pun untuk topik ini.",
"notifications_none_for_topic_description": "Untuk mengirimkan notifikasi ke topik ini, tinggal PUT atau POST ke URL topik.", "notifications_none_for_topic_description": "Untuk mengirimkan notifikasi ke topik ini, tinggal PUT atau POST ke URL topik.",
"notifications_none_for_any_description": "Untuk mengirimkan notifikasi ke sebuah topik, tinggal PUT atau POST ke URL topik. Ini adalah contoh menggunakan salah satu topik Anda.", "notifications_none_for_any_description": "Untuk mengirimkan notifikasi ke sebuah topik, tinggal PUT atau POST ke URL topik. Ini adalah contoh menggunakan salah satu topik Anda.",
"notifications_no_subscriptions_title": "Sepertinya Anda belum memiliki langganan apa pun.", "notifications_no_subscriptions_title": "Sepertinya Anda belum memiliki langganan apa pun.",
"publish_dialog_title_topic": "Publikasikan ke {{topic}}", "publish_dialog_title_topic": "Publikasikan ke {{topic}}",
"subscribe_dialog_login_description": "Topik ini dilindungi oleh kata sandi. Mohon masukkan nama pengguna dan kata sandi untuk berlangganan.", "subscribe_dialog_login_description": "Topik ini dilindungi oleh kata sandi. Mohon masukkan nama pengguna dan kata sandi untuk berlangganan.",
"prefs_notifications_min_priority_title": "Prioritas minimum", "prefs_notifications_min_priority_title": "Prioritas minimum",
"error_boundary_gathering_info": "Dapatkan info lanjut …", "error_boundary_gathering_info": "Dapatkan info lanjut …",
"publish_dialog_title_no_topic": "Publikasikan notifikasi", "publish_dialog_title_no_topic": "Publikasikan notifikasi",
"publish_dialog_progress_uploading": "Mengunggah …", "publish_dialog_progress_uploading": "Mengunggah …",
"notifications_more_details": "Untuk informasi lanjut, lihat <websiteLink>situs web</websiteLink> atau <docsLink>dokumentasi</docsLink>.", "notifications_more_details": "Untuk informasi lanjut, lihat <websiteLink>situs web</websiteLink> atau <docsLink>dokumentasi</docsLink>.",
"publish_dialog_progress_uploading_detail": "Mengunggah {{loaded}}/{{total}} ({{percent}}%) …", "publish_dialog_progress_uploading_detail": "Mengunggah {{loaded}}/{{total}} ({{percent}}%) …",
"publish_dialog_message_published": "Notifikasi terpublikasi", "publish_dialog_message_published": "Notifikasi terpublikasi",
"notifications_loading": "Memuat notifikasi …", "notifications_loading": "Memuat notifikasi …",
"publish_dialog_base_url_label": "URL Layanan", "publish_dialog_base_url_label": "URL Layanan",
"publish_dialog_title_placeholder": "Judul notifikasi, mis. Peringatan ruang disk", "publish_dialog_title_placeholder": "Judul notifikasi, mis. Peringatan ruang disk",
"publish_dialog_tags_label": "Tanda", "publish_dialog_tags_label": "Tanda",
"publish_dialog_priority_label": "Prioritas", "publish_dialog_priority_label": "Prioritas",
"publish_dialog_base_url_placeholder": "URL Layanan, mis. https://contoh.com", "publish_dialog_base_url_placeholder": "URL Layanan, mis. https://contoh.com",
"publish_dialog_attach_placeholder": "Lampirkan file dengan URL, mis. https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "Lampirkan file dengan URL, mis. https://f-droid.org/F-Droid.apk",
"publish_dialog_delay_label": "Jeda", "publish_dialog_delay_label": "Jeda",
"publish_dialog_chip_topic_label": "Ubah topik", "publish_dialog_chip_topic_label": "Ubah topik",
"publish_dialog_button_cancel_sending": "Batalkan pengiriman", "publish_dialog_button_cancel_sending": "Batalkan pengiriman",
"publish_dialog_button_send": "Kirim", "publish_dialog_button_send": "Kirim",
"publish_dialog_attachment_limits_file_reached": "melebihi batasan file {{fileSizeLimit}", "publish_dialog_attachment_limits_file_reached": "melebihi batasan file {{fileSizeLimit}",
"publish_dialog_attachment_limits_file_and_quota_reached": "melebihi batasan file dan kuota {{fileSizeLimit}}, hanya {{remainingBytes}}", "publish_dialog_attachment_limits_file_and_quota_reached": "melebihi batasan file dan kuota {{fileSizeLimit}}, hanya {{remainingBytes}}",
"publish_dialog_attachment_limits_quota_reached": "melebihi kuota, hanya {{remainingBytes}}", "publish_dialog_attachment_limits_quota_reached": "melebihi kuota, hanya {{remainingBytes}}",
"publish_dialog_priority_min": "Prioritas min.", "publish_dialog_priority_min": "Prioritas min.",
"publish_dialog_priority_low": "Prioritas rendah", "publish_dialog_priority_low": "Prioritas rendah",
"publish_dialog_priority_default": "Prioritas bawaan", "publish_dialog_priority_default": "Prioritas bawaan",
"publish_dialog_priority_high": "Prioritas tinggi", "publish_dialog_priority_high": "Prioritas tinggi",
"publish_dialog_priority_max": "Prioritas maks.", "publish_dialog_priority_max": "Prioritas maks.",
"publish_dialog_topic_label": "Nama topik", "publish_dialog_topic_label": "Nama topik",
"publish_dialog_message_placeholder": "Ketik sebuah pesan di sini", "publish_dialog_message_placeholder": "Ketik sebuah pesan di sini",
"publish_dialog_click_label": "Klik URL", "publish_dialog_click_label": "Klik URL",
"publish_dialog_tags_placeholder": "Daftar tanda yang dipisah dengan koma, mis. peringatan, cadangan-srv1", "publish_dialog_tags_placeholder": "Daftar tanda yang dipisah dengan koma, mis. peringatan, cadangan-srv1",
"publish_dialog_click_placeholder": "URL yang dibuka ketika notifikasi diklik", "publish_dialog_click_placeholder": "URL yang dibuka ketika notifikasi diklik",
"publish_dialog_email_label": "Email", "publish_dialog_email_label": "Email",
"publish_dialog_email_placeholder": "Alamat untuk meneruskan notifikasi, mis. andi@contoh.com", "publish_dialog_email_placeholder": "Alamat untuk meneruskan notifikasi, mis. andi@contoh.com",
"publish_dialog_attach_label": "URL Lampiran", "publish_dialog_attach_label": "URL Lampiran",
"publish_dialog_filename_label": "Nama File", "publish_dialog_filename_label": "Nama File",
"publish_dialog_filename_placeholder": "Nama file lampiran", "publish_dialog_filename_placeholder": "Nama file lampiran",
"publish_dialog_delay_placeholder": "Penjedaan pengiriman, mis. {{unixTimestamp}}, {{relativeTime}}, atau \"{{naturalLanguage}}\" (hanya Inggris)", "publish_dialog_delay_placeholder": "Penjedaan pengiriman, mis. {{unixTimestamp}}, {{relativeTime}}, atau \"{{naturalLanguage}}\" (hanya Inggris)",
"publish_dialog_other_features": "Fitur lainnya:", "publish_dialog_other_features": "Fitur lainnya:",
"publish_dialog_chip_click_label": "Klik URL", "publish_dialog_chip_click_label": "Klik URL",
"publish_dialog_chip_email_label": "Teruskan ke email", "publish_dialog_chip_email_label": "Teruskan ke email",
"publish_dialog_chip_attach_url_label": "Lampirkan file dengan URL", "publish_dialog_chip_attach_url_label": "Lampirkan file dengan URL",
"publish_dialog_chip_attach_file_label": "Lampirkan file lokal", "publish_dialog_chip_attach_file_label": "Lampirkan file lokal",
"publish_dialog_chip_delay_label": "Jeda pengiriman", "publish_dialog_chip_delay_label": "Jeda pengiriman",
"publish_dialog_button_cancel": "Batal", "publish_dialog_button_cancel": "Batal",
"publish_dialog_details_examples_description": "Untuk contoh dan deskripsi yang rinci oleh semua fitur pengiriman, lihat <docsLink>dokumentasi</docsLink>.", "publish_dialog_details_examples_description": "Untuk contoh dan deskripsi yang rinci oleh semua fitur pengiriman, lihat <docsLink>dokumentasi</docsLink>.",
"publish_dialog_checkbox_publish_another": "Publikasi yang lain", "publish_dialog_checkbox_publish_another": "Publikasi yang lain",
"publish_dialog_attached_file_title": "File yang dilampirkan:", "publish_dialog_attached_file_title": "File yang dilampirkan:",
"publish_dialog_attached_file_filename_placeholder": "Nama file lampiran", "publish_dialog_attached_file_filename_placeholder": "Nama file lampiran",
"publish_dialog_drop_file_here": "Lepaskan file di sini", "publish_dialog_drop_file_here": "Lepaskan file di sini",
"emoji_picker_search_placeholder": "Cari emoji", "emoji_picker_search_placeholder": "Cari emoji",
"subscribe_dialog_subscribe_button_cancel": "Batal", "subscribe_dialog_subscribe_button_cancel": "Batal",
"subscribe_dialog_subscribe_button_subscribe": "Berlangganan", "subscribe_dialog_subscribe_button_subscribe": "Berlangganan",
"subscribe_dialog_error_user_anonymous": "anonim", "subscribe_dialog_error_user_anonymous": "anonim",
"prefs_notifications_min_priority_any": "Prioritas apa saja", "prefs_notifications_min_priority_any": "Prioritas apa saja",
"prefs_notifications_delete_after_title": "Hapus notifikasi", "prefs_notifications_delete_after_title": "Hapus notifikasi",
"prefs_notifications_delete_after_three_hours": "Setelah tiga jam", "prefs_notifications_delete_after_three_hours": "Setelah tiga jam",
"prefs_notifications_delete_after_one_day": "Setelah satu hari", "prefs_notifications_delete_after_one_day": "Setelah satu hari",
"prefs_users_add_button": "Tambahkan pengguna", "prefs_users_add_button": "Tambahkan pengguna",
"prefs_users_dialog_username_label": "Nama pengguna, mis. andi", "prefs_users_dialog_username_label": "Nama pengguna, mis. andi",
"subscribe_dialog_subscribe_title": "Berlangganan ke topik", "subscribe_dialog_subscribe_title": "Berlangganan ke topik",
"subscribe_dialog_subscribe_topic_placeholder": "Nama topik, mis. pemberitahuan_andi", "subscribe_dialog_subscribe_topic_placeholder": "Nama topik, mis. pemberitahuan_andi",
"subscribe_dialog_subscribe_use_another_label": "Gunakan server lain", "subscribe_dialog_subscribe_use_another_label": "Gunakan server lain",
"subscribe_dialog_login_username_label": "Nama pengguna, mis. Andi", "subscribe_dialog_login_username_label": "Nama pengguna, mis. Andi",
"subscribe_dialog_login_button_login": "Masuk", "subscribe_dialog_login_button_login": "Masuk",
"subscribe_dialog_error_user_not_authorized": "Pengguna {{username}} tidak diizinkan", "subscribe_dialog_error_user_not_authorized": "Pengguna {{username}} tidak diizinkan",
"prefs_notifications_title": "Notifikasi", "prefs_notifications_title": "Notifikasi",
"prefs_notifications_sound_no_sound": "Tidak ada suara", "prefs_notifications_sound_no_sound": "Tidak ada suara",
"prefs_users_table_user_header": "Pengguna", "prefs_users_table_user_header": "Pengguna",
"prefs_users_dialog_base_url_label": "URL Layanan, mis. https://ntfy.sh", "prefs_users_dialog_base_url_label": "URL Layanan, mis. https://ntfy.sh",
"prefs_users_dialog_button_save": "Simpan", "prefs_users_dialog_button_save": "Simpan",
"prefs_appearance_title": "Tampilan", "prefs_appearance_title": "Tampilan",
"subscribe_dialog_login_password_label": "Kata sandi", "subscribe_dialog_login_password_label": "Kata sandi",
"subscribe_dialog_login_button_back": "Kembali", "subscribe_dialog_login_button_back": "Kembali",
"prefs_notifications_sound_title": "Suara notifikasi", "prefs_notifications_sound_title": "Suara notifikasi",
"prefs_notifications_min_priority_low_and_higher": "Prioritas rendah dan lebih tinggi", "prefs_notifications_min_priority_low_and_higher": "Prioritas rendah dan lebih tinggi",
"prefs_notifications_min_priority_default_and_higher": "Prioritas bawaan dan lebih tinggi", "prefs_notifications_min_priority_default_and_higher": "Prioritas bawaan dan lebih tinggi",
"prefs_notifications_min_priority_high_and_higher": "Prioritas tinggi dan lebih tinggi", "prefs_notifications_min_priority_high_and_higher": "Prioritas tinggi dan lebih tinggi",
"prefs_notifications_min_priority_max_only": "Hanya prioritas maks", "prefs_notifications_min_priority_max_only": "Hanya prioritas maks",
"prefs_notifications_delete_after_never": "Tidak pernah", "prefs_notifications_delete_after_never": "Tidak pernah",
"prefs_notifications_delete_after_one_week": "Setelah satu minggu", "prefs_notifications_delete_after_one_week": "Setelah satu minggu",
"prefs_notifications_delete_after_one_month": "Setelah satu bulan", "prefs_notifications_delete_after_one_month": "Setelah satu bulan",
"prefs_users_title": "Kelola pengguna", "prefs_users_title": "Kelola pengguna",
"prefs_users_description": "Tambahkan/hapus pengguna untuk topik yang dilindungi di sini. Dicatat bahwa nama pengguna dan kata sandi disimpan dalam penyimpanan lokal peramban.", "prefs_users_description": "Tambahkan/hapus pengguna untuk topik yang dilindungi di sini. Dicatat bahwa nama pengguna dan kata sandi disimpan dalam penyimpanan lokal peramban.",
"prefs_users_table_base_url_header": "URL Layanan", "prefs_users_table_base_url_header": "URL Layanan",
"prefs_users_dialog_title_add": "Tambahkan pengguna", "prefs_users_dialog_title_add": "Tambahkan pengguna",
"prefs_users_dialog_title_edit": "Edit pengguna", "prefs_users_dialog_title_edit": "Edit pengguna",
"prefs_users_dialog_password_label": "Kata sandi", "prefs_users_dialog_password_label": "Kata sandi",
"prefs_users_dialog_button_cancel": "Batal", "prefs_users_dialog_button_cancel": "Batal",
"error_boundary_title": "Aduh, ntfy mogok", "error_boundary_title": "Aduh, ntfy mogok",
"error_boundary_description": "Seharusnya ini tidak terjadi. Maaf sekali tentang hal ini.<br/>Jika Anda punya beberapa menit, silakan <githubLink>laporkan ini di GitHub</githubLink>, atau beritahu kami melalui <discordLink>Discord</discordLink> atau <matrixLink>Matrix</matrixLink>.", "error_boundary_description": "Seharusnya ini tidak terjadi. Maaf sekali tentang hal ini.<br/>Jika Anda punya beberapa menit, silakan <githubLink>laporkan ini di GitHub</githubLink>, atau beritahu kami melalui <discordLink>Discord</discordLink> atau <matrixLink>Matrix</matrixLink>.",
"error_boundary_stack_trace": "Jejak tumpukan", "error_boundary_stack_trace": "Jejak tumpukan",
"error_boundary_button_copy_stack_trace": "Salin jejak tumpukan", "error_boundary_button_copy_stack_trace": "Salin jejak tumpukan",
"prefs_notifications_sound_description_some": "Notifikasi memainkan suara {{sound}} ketika diterima", "prefs_notifications_sound_description_some": "Notifikasi memainkan suara {{sound}} ketika diterima",
"prefs_notifications_min_priority_description_any": "Menampilkan semua notifikasi, apa pun prioritasnya", "prefs_notifications_min_priority_description_any": "Menampilkan semua notifikasi, apa pun prioritasnya",
"prefs_notifications_min_priority_description_max": "Tampilkan notifikasi jika prioritas adalah 5 (maks)", "prefs_notifications_min_priority_description_max": "Tampilkan notifikasi jika prioritas adalah 5 (maks)",
"prefs_notifications_delete_after_three_hours_description": "Notifikasi dihapus secara otomatis setelah tiga jam", "prefs_notifications_delete_after_three_hours_description": "Notifikasi dihapus secara otomatis setelah tiga jam",
"prefs_notifications_delete_after_one_week_description": "Notifikasi dihapus secara otomatis setelah satu minggu", "prefs_notifications_delete_after_one_week_description": "Notifikasi dihapus secara otomatis setelah satu minggu",
"prefs_notifications_delete_after_one_month_description": "Notifikasi dihapus secara otomatis setelah satu bulan", "prefs_notifications_delete_after_one_month_description": "Notifikasi dihapus secara otomatis setelah satu bulan",
"priority_low": "rendah", "priority_low": "rendah",
"priority_high": "tinggi", "priority_high": "tinggi",
"priority_max": "maks", "priority_max": "maks",
"prefs_notifications_min_priority_description_x_or_higher": "Tampilkan notifikasi jika prioritas {{number}} ({{name}}) atau lebih", "prefs_notifications_min_priority_description_x_or_higher": "Tampilkan notifikasi jika prioritas {{number}} ({{name}}) atau lebih",
"prefs_notifications_sound_description_none": "Notifikasi tidak boleh memainkan suara apa pun ketika diterima", "prefs_notifications_sound_description_none": "Notifikasi tidak boleh memainkan suara apa pun ketika diterima",
"prefs_notifications_delete_after_never_description": "Notifikasi tidak pernah dihapus secara otomatis", "prefs_notifications_delete_after_never_description": "Notifikasi tidak pernah dihapus secara otomatis",
"prefs_notifications_delete_after_one_day_description": "Notifikasi dihapus secara otomatis setelah satu hari", "prefs_notifications_delete_after_one_day_description": "Notifikasi dihapus secara otomatis setelah satu hari",
"priority_default": "bawaan", "priority_default": "bawaan",
"priority_min": "min", "priority_min": "min",
"notifications_actions_not_supported": "Tindakan tidak didukung di aplikasi web", "notifications_actions_not_supported": "Tindakan tidak didukung di aplikasi web",
"notifications_actions_http_request_title": "Kirim {{method}} HTTP ke {{url}}", "notifications_actions_http_request_title": "Kirim {{method}} HTTP ke {{url}}",
"action_bar_show_menu": "Tampilkan menu", "action_bar_show_menu": "Tampilkan menu",
"action_bar_logo_alt": "logo ntfy", "action_bar_logo_alt": "logo ntfy",
"action_bar_toggle_mute": "Bisu/suarakan notifikasi", "action_bar_toggle_mute": "Bisu/suarakan notifikasi",
"action_bar_toggle_action_menu": "Buka/tutup menu tindakan", "action_bar_toggle_action_menu": "Buka/tutup menu tindakan",
"message_bar_show_dialog": "Tampilkan dialog publikasi", "message_bar_show_dialog": "Tampilkan dialog publikasi",
"message_bar_publish": "Publikasikan pesan", "message_bar_publish": "Publikasikan pesan",
"nav_button_muted": "Notifikasi dibisukan", "nav_button_muted": "Notifikasi dibisukan",
"nav_button_connecting": "menghubungkan", "nav_button_connecting": "menghubungkan",
"notifications_list": "Daftar notifikasi", "notifications_list": "Daftar notifikasi",
"notifications_list_item": "Notifikasi", "notifications_list_item": "Notifikasi",
"notifications_mark_read": "Tandai sebagai dibaca", "notifications_mark_read": "Tandai sebagai dibaca",
"notifications_delete": "Hapus", "notifications_delete": "Hapus",
"notifications_priority_x": "Prioritas {{priority}}", "notifications_priority_x": "Prioritas {{priority}}",
"notifications_new_indicator": "Notifikasi baru", "notifications_new_indicator": "Notifikasi baru",
"notifications_attachment_image": "Lampiran gambar", "notifications_attachment_image": "Lampiran gambar",
"notifications_attachment_file_image": "file gambar", "notifications_attachment_file_image": "file gambar",
"notifications_attachment_file_video": "file", "notifications_attachment_file_video": "file",
"notifications_attachment_file_audio": "file audio", "notifications_attachment_file_audio": "file audio",
"notifications_attachment_file_app": "file aplikasi Android", "notifications_attachment_file_app": "file aplikasi Android",
"notifications_attachment_file_document": "dokumen lainnya", "notifications_attachment_file_document": "dokumen lainnya",
"publish_dialog_emoji_picker_show": "Pilih emoji", "publish_dialog_emoji_picker_show": "Pilih emoji",
"publish_dialog_topic_reset": "Atur ulang topik", "publish_dialog_topic_reset": "Atur ulang topik",
"publish_dialog_click_reset": "Hapus URL klik", "publish_dialog_click_reset": "Hapus URL klik",
"publish_dialog_email_reset": "Hapus terusan email", "publish_dialog_email_reset": "Hapus terusan email",
"publish_dialog_attach_reset": "Hapus URL lampiran", "publish_dialog_attach_reset": "Hapus URL lampiran",
"publish_dialog_delay_reset": "Hapus pengiriman telat", "publish_dialog_delay_reset": "Hapus pengiriman telat",
"publish_dialog_attached_file_remove": "Hapus file yang dilampirkan", "publish_dialog_attached_file_remove": "Hapus file yang dilampirkan",
"emoji_picker_search_clear": "Hapus pencarian", "emoji_picker_search_clear": "Hapus pencarian",
"subscribe_dialog_subscribe_base_url_label": "URL layanan", "subscribe_dialog_subscribe_base_url_label": "URL layanan",
"prefs_notifications_sound_play": "Mainkan suara yang dipilih", "prefs_notifications_sound_play": "Mainkan suara yang dipilih",
"prefs_users_table": "Tabel pengguna", "prefs_users_table": "Tabel pengguna",
"prefs_users_edit_button": "Edit pengguna", "prefs_users_edit_button": "Edit pengguna",
"prefs_users_delete_button": "Hapus pengguna", "prefs_users_delete_button": "Hapus pengguna",
"error_boundary_unsupported_indexeddb_description": "Aplikasi web ntfy membutuhkan IndexedDB untuk berfungsi, dan peramban Anda tidak mendukung IndexedDB dalam mode penjelajahan pribadi.<br/><br/>Meskipun ini disayangkan, penggunaan aplikasi web ntfy juga tidak masuk akal di mode penjelajahan pribadi, karena semuanya disimpan di penyimpanan peramban. Anda dapat membaca lebih lanjut tentangnya <githubLink>di masalah GitHub ini</githubLink>, atau berbicara dengan kami di <discordLink>Discord</discordLink> atau <matrixLink>Matrix</matrixLink>.", "error_boundary_unsupported_indexeddb_description": "Aplikasi web ntfy membutuhkan IndexedDB untuk berfungsi, dan peramban Anda tidak mendukung IndexedDB dalam mode penjelajahan pribadi.<br/><br/>Meskipun ini disayangkan, penggunaan aplikasi web ntfy juga tidak masuk akal di mode penjelajahan pribadi, karena semuanya disimpan di penyimpanan peramban. Anda dapat membaca lebih lanjut tentangnya <githubLink>di masalah GitHub ini</githubLink>, atau berbicara dengan kami di <discordLink>Discord</discordLink> atau <matrixLink>Matrix</matrixLink>.",
"error_boundary_unsupported_indexeddb_title": "Penjelajahan privat tidak didukung" "error_boundary_unsupported_indexeddb_title": "Penjelajahan privat tidak didukung"
} }

View file

@ -1,191 +1,191 @@
{ {
"action_bar_logo_alt": "logo ntfy", "action_bar_logo_alt": "logo ntfy",
"action_bar_settings": "Impostazioni", "action_bar_settings": "Impostazioni",
"action_bar_clear_notifications": "Cancella tutte le notifiche", "action_bar_clear_notifications": "Cancella tutte le notifiche",
"action_bar_unsubscribe": "Annulla l'iscrizione", "action_bar_unsubscribe": "Annulla l'iscrizione",
"action_bar_toggle_action_menu": "Apri/chiudi il menu delle azioni", "action_bar_toggle_action_menu": "Apri/chiudi il menu delle azioni",
"message_bar_type_message": "Digita un messaggio qui", "message_bar_type_message": "Digita un messaggio qui",
"message_bar_error_publishing": "Errore durante la pubblicazione della notifica", "message_bar_error_publishing": "Errore durante la pubblicazione della notifica",
"message_bar_show_dialog": "Mostra la finestra di dialogo di pubblicazione", "message_bar_show_dialog": "Mostra la finestra di dialogo di pubblicazione",
"message_bar_publish": "Pubblica messaggio", "message_bar_publish": "Pubblica messaggio",
"nav_topics_title": "Topic a cui si è iscritti", "nav_topics_title": "Topic a cui si è iscritti",
"nav_button_all_notifications": "Tutte le notifiche", "nav_button_all_notifications": "Tutte le notifiche",
"nav_button_settings": "Impostazioni", "nav_button_settings": "Impostazioni",
"nav_button_publish_message": "Pubblica notifica", "nav_button_publish_message": "Pubblica notifica",
"nav_button_subscribe": "Iscriviti al topic", "nav_button_subscribe": "Iscriviti al topic",
"nav_button_muted": "Notifiche disattivate", "nav_button_muted": "Notifiche disattivate",
"nav_button_connecting": "connessione", "nav_button_connecting": "connessione",
"alert_grant_title": "Le notifiche sono disabilitate", "alert_grant_title": "Le notifiche sono disabilitate",
"alert_grant_button": "Concedi ora", "alert_grant_button": "Concedi ora",
"notifications_list": "Elenco notifiche", "notifications_list": "Elenco notifiche",
"notifications_list_item": "Notifiche", "notifications_list_item": "Notifiche",
"notifications_mark_read": "Segna come letto", "notifications_mark_read": "Segna come letto",
"notifications_delete": "Elimina", "notifications_delete": "Elimina",
"notifications_copied_to_clipboard": "Copiato negli appunti", "notifications_copied_to_clipboard": "Copiato negli appunti",
"notifications_tags": "Tags", "notifications_tags": "Tags",
"notifications_priority_x": "Priorità {{priority}}", "notifications_priority_x": "Priorità {{priority}}",
"notifications_new_indicator": "Nuova notifica", "notifications_new_indicator": "Nuova notifica",
"notifications_attachment_image": "Immagine allegata", "notifications_attachment_image": "Immagine allegata",
"notifications_attachment_copy_url_title": "Copia l'URL dell'allegato negli appunti", "notifications_attachment_copy_url_title": "Copia l'URL dell'allegato negli appunti",
"notifications_attachment_copy_url_button": "Copia URL", "notifications_attachment_copy_url_button": "Copia URL",
"notifications_attachment_open_title": "Vai a {{url}}", "notifications_attachment_open_title": "Vai a {{url}}",
"notifications_attachment_open_button": "Apri allegato", "notifications_attachment_open_button": "Apri allegato",
"notifications_attachment_link_expires": "Il collegamento scade il {{date}}", "notifications_attachment_link_expires": "Il collegamento scade il {{date}}",
"notifications_attachment_link_expired": "link per il download scaduto", "notifications_attachment_link_expired": "link per il download scaduto",
"notifications_attachment_file_image": "file immagine", "notifications_attachment_file_image": "file immagine",
"notifications_attachment_file_video": "file video", "notifications_attachment_file_video": "file video",
"action_bar_toggle_mute": "Abilita/disabilita le notifiche", "action_bar_toggle_mute": "Abilita/disabilita le notifiche",
"notifications_attachment_file_document": "altro documento", "notifications_attachment_file_document": "altro documento",
"notifications_click_copy_url_button": "Copia link", "notifications_click_copy_url_button": "Copia link",
"notifications_click_open_button": "Apri link", "notifications_click_open_button": "Apri link",
"notifications_actions_open_url_title": "Vai a {{url}}", "notifications_actions_open_url_title": "Vai a {{url}}",
"notifications_actions_not_supported": "Azione non supportata nell'app Web", "notifications_actions_not_supported": "Azione non supportata nell'app Web",
"notifications_none_for_topic_title": "Non hai ancora ricevuto alcuna notifica per questo topic.", "notifications_none_for_topic_title": "Non hai ancora ricevuto alcuna notifica per questo topic.",
"notifications_none_for_topic_description": "Per inviare notifiche a questo argomento, è sufficiente PUT o POST all'URL del topic.", "notifications_none_for_topic_description": "Per inviare notifiche a questo argomento, è sufficiente PUT o POST all'URL del topic.",
"notifications_none_for_any_title": "Non hai ricevuto alcuna notifica.", "notifications_none_for_any_title": "Non hai ricevuto alcuna notifica.",
"notifications_no_subscriptions_title": "Sembra che tu non abbia ancora abbonamenti.", "notifications_no_subscriptions_title": "Sembra che tu non abbia ancora abbonamenti.",
"notifications_example": "Esempio", "notifications_example": "Esempio",
"notifications_more_details": "Per ulteriori informazioni, consulta il <websiteLink>sito web</websiteLink> o <docsLink>documentazione</docsLink>.", "notifications_more_details": "Per ulteriori informazioni, consulta il <websiteLink>sito web</websiteLink> o <docsLink>documentazione</docsLink>.",
"notifications_loading": "Caricamento notifiche in corso…", "notifications_loading": "Caricamento notifiche in corso…",
"publish_dialog_title_topic": "Pubblica su {{topic}}", "publish_dialog_title_topic": "Pubblica su {{topic}}",
"publish_dialog_title_no_topic": "Pubblica notifica", "publish_dialog_title_no_topic": "Pubblica notifica",
"publish_dialog_progress_uploading": "Caricamento in corso…", "publish_dialog_progress_uploading": "Caricamento in corso…",
"publish_dialog_progress_uploading_detail": "Caricamento {{loaded}}/{{total}} ({{percent}}%)…", "publish_dialog_progress_uploading_detail": "Caricamento {{loaded}}/{{total}} ({{percent}}%)…",
"publish_dialog_message_published": "Notifica pubblicata", "publish_dialog_message_published": "Notifica pubblicata",
"publish_dialog_attachment_limits_file_and_quota_reached": "supera {{fileSizeLimit}} limite di file e quota, {{remainingBytes}} rimanenti", "publish_dialog_attachment_limits_file_and_quota_reached": "supera {{fileSizeLimit}} limite di file e quota, {{remainingBytes}} rimanenti",
"publish_dialog_attachment_limits_file_reached": "supera di {{fileSizeLimit}} il limite dei file", "publish_dialog_attachment_limits_file_reached": "supera di {{fileSizeLimit}} il limite dei file",
"publish_dialog_attachment_limits_quota_reached": "supera la quota, {{remainingBytes}} rimanenti", "publish_dialog_attachment_limits_quota_reached": "supera la quota, {{remainingBytes}} rimanenti",
"publish_dialog_emoji_picker_show": "Scegli emoji", "publish_dialog_emoji_picker_show": "Scegli emoji",
"publish_dialog_priority_min": "Min. priorità", "publish_dialog_priority_min": "Min. priorità",
"publish_dialog_priority_low": "Bassa priorità", "publish_dialog_priority_low": "Bassa priorità",
"publish_dialog_priority_default": "Priorità predefinita", "publish_dialog_priority_default": "Priorità predefinita",
"publish_dialog_priority_high": "Priorità alta", "publish_dialog_priority_high": "Priorità alta",
"publish_dialog_priority_max": "Max. priorità", "publish_dialog_priority_max": "Max. priorità",
"publish_dialog_base_url_label": "URL del servizio", "publish_dialog_base_url_label": "URL del servizio",
"publish_dialog_base_url_placeholder": "URL del servizio, ad es. https://esempio.com", "publish_dialog_base_url_placeholder": "URL del servizio, ad es. https://esempio.com",
"publish_dialog_topic_label": "Nome topic", "publish_dialog_topic_label": "Nome topic",
"publish_dialog_topic_placeholder": "Nome topic, ad es. avvisi_di_phil", "publish_dialog_topic_placeholder": "Nome topic, ad es. avvisi_di_phil",
"publish_dialog_topic_reset": "Reset topic", "publish_dialog_topic_reset": "Reset topic",
"publish_dialog_title_label": "Titolo", "publish_dialog_title_label": "Titolo",
"publish_dialog_title_placeholder": "Titolo della notifica, ad es. Avviso di spazio su disco", "publish_dialog_title_placeholder": "Titolo della notifica, ad es. Avviso di spazio su disco",
"publish_dialog_message_label": "Messaggio", "publish_dialog_message_label": "Messaggio",
"publish_dialog_message_placeholder": "Digita un messaggio qui", "publish_dialog_message_placeholder": "Digita un messaggio qui",
"publish_dialog_tags_label": "Tags", "publish_dialog_tags_label": "Tags",
"publish_dialog_priority_label": "Priorità", "publish_dialog_priority_label": "Priorità",
"publish_dialog_click_label": "Clicca URL", "publish_dialog_click_label": "Clicca URL",
"publish_dialog_click_reset": "Rimuovi l'URL del clic", "publish_dialog_click_reset": "Rimuovi l'URL del clic",
"publish_dialog_email_label": "Email", "publish_dialog_email_label": "Email",
"publish_dialog_email_placeholder": "Indirizzo a cui inoltrare la notifica, ad es. phil@example.com", "publish_dialog_email_placeholder": "Indirizzo a cui inoltrare la notifica, ad es. phil@example.com",
"publish_dialog_email_reset": "Rimuovi inoltro email", "publish_dialog_email_reset": "Rimuovi inoltro email",
"publish_dialog_attach_label": "URL Allegato", "publish_dialog_attach_label": "URL Allegato",
"publish_dialog_attach_reset": "Rimuovi l'URL dell'allegato", "publish_dialog_attach_reset": "Rimuovi l'URL dell'allegato",
"publish_dialog_filename_label": "Nome del file", "publish_dialog_filename_label": "Nome del file",
"publish_dialog_filename_placeholder": "Nome file allegato", "publish_dialog_filename_placeholder": "Nome file allegato",
"publish_dialog_delay_placeholder": "Consegna ritardata, ad es. {{unixTimestamp}}, {{relativeTime}} o \"{{naturalLanguage}}\" (solo in inglese)", "publish_dialog_delay_placeholder": "Consegna ritardata, ad es. {{unixTimestamp}}, {{relativeTime}} o \"{{naturalLanguage}}\" (solo in inglese)",
"publish_dialog_delay_reset": "Rimuovere la consegna ritardata", "publish_dialog_delay_reset": "Rimuovere la consegna ritardata",
"publish_dialog_other_features": "Altre funzionalità:", "publish_dialog_other_features": "Altre funzionalità:",
"publish_dialog_chip_click_label": "Fare clic su URL", "publish_dialog_chip_click_label": "Fare clic su URL",
"publish_dialog_chip_email_label": "Inoltra a e-mail", "publish_dialog_chip_email_label": "Inoltra a e-mail",
"publish_dialog_chip_attach_url_label": "Allega il file tramite URL", "publish_dialog_chip_attach_url_label": "Allega il file tramite URL",
"publish_dialog_chip_attach_file_label": "Allega file locale", "publish_dialog_chip_attach_file_label": "Allega file locale",
"publish_dialog_chip_delay_label": "Ritardo nella consegna", "publish_dialog_chip_delay_label": "Ritardo nella consegna",
"publish_dialog_button_cancel_sending": "Annulla l'invio", "publish_dialog_button_cancel_sending": "Annulla l'invio",
"publish_dialog_button_cancel": "Annulla", "publish_dialog_button_cancel": "Annulla",
"publish_dialog_button_send": "Invia", "publish_dialog_button_send": "Invia",
"publish_dialog_checkbox_publish_another": "Pubblica un altro", "publish_dialog_checkbox_publish_another": "Pubblica un altro",
"publish_dialog_attached_file_title": "File allegato:", "publish_dialog_attached_file_title": "File allegato:",
"publish_dialog_attached_file_remove": "Rimuovi il file allegato", "publish_dialog_attached_file_remove": "Rimuovi il file allegato",
"publish_dialog_drop_file_here": "Trascina il file qui", "publish_dialog_drop_file_here": "Trascina il file qui",
"emoji_picker_search_clear": "Cancella ricerca", "emoji_picker_search_clear": "Cancella ricerca",
"subscribe_dialog_subscribe_title": "Iscriviti al topic", "subscribe_dialog_subscribe_title": "Iscriviti al topic",
"subscribe_dialog_subscribe_topic_placeholder": "Nome dell'argomento, ad es. avvisi_di_phil", "subscribe_dialog_subscribe_topic_placeholder": "Nome dell'argomento, ad es. avvisi_di_phil",
"subscribe_dialog_subscribe_base_url_label": "URL del servizio", "subscribe_dialog_subscribe_base_url_label": "URL del servizio",
"subscribe_dialog_subscribe_button_cancel": "Annulla", "subscribe_dialog_subscribe_button_cancel": "Annulla",
"subscribe_dialog_login_title": "Accesso richiesto", "subscribe_dialog_login_title": "Accesso richiesto",
"subscribe_dialog_login_username_label": "Nome utente, ad es. phil", "subscribe_dialog_login_username_label": "Nome utente, ad es. phil",
"subscribe_dialog_login_button_login": "Login", "subscribe_dialog_login_button_login": "Login",
"subscribe_dialog_error_user_anonymous": "anonimo", "subscribe_dialog_error_user_anonymous": "anonimo",
"prefs_notifications_sound_title": "Suono di notifica", "prefs_notifications_sound_title": "Suono di notifica",
"prefs_notifications_sound_description_some": "Le notifiche riproducono il suono {{sound}} quando arrivano", "prefs_notifications_sound_description_some": "Le notifiche riproducono il suono {{sound}} quando arrivano",
"prefs_notifications_sound_no_sound": "Nessun suono", "prefs_notifications_sound_no_sound": "Nessun suono",
"prefs_notifications_min_priority_description_any": "Visualizzazione di tutte le notifiche, indipendentemente dalla priorità", "prefs_notifications_min_priority_description_any": "Visualizzazione di tutte le notifiche, indipendentemente dalla priorità",
"prefs_notifications_min_priority_description_max": "Mostra notifiche se la priorità è 5 (max)", "prefs_notifications_min_priority_description_max": "Mostra notifiche se la priorità è 5 (max)",
"prefs_notifications_min_priority_any": "Qualsiasi priorità", "prefs_notifications_min_priority_any": "Qualsiasi priorità",
"prefs_notifications_min_priority_low_and_higher": "Priorità bassa e superiore", "prefs_notifications_min_priority_low_and_higher": "Priorità bassa e superiore",
"prefs_notifications_min_priority_high_and_higher": "Priorità alta e superiore", "prefs_notifications_min_priority_high_and_higher": "Priorità alta e superiore",
"prefs_notifications_min_priority_max_only": "Solo priorità massima", "prefs_notifications_min_priority_max_only": "Solo priorità massima",
"prefs_notifications_delete_after_never": "Mai", "prefs_notifications_delete_after_never": "Mai",
"prefs_notifications_delete_after_three_hours": "Dopo tre ore", "prefs_notifications_delete_after_three_hours": "Dopo tre ore",
"prefs_notifications_delete_after_one_day": "Dopo un giorno", "prefs_notifications_delete_after_one_day": "Dopo un giorno",
"prefs_notifications_delete_after_never_description": "Le notifiche non vengono mai eliminate automaticamente", "prefs_notifications_delete_after_never_description": "Le notifiche non vengono mai eliminate automaticamente",
"prefs_notifications_delete_after_one_day_description": "Le notifiche vengono eliminate automaticamente dopo un giorno", "prefs_notifications_delete_after_one_day_description": "Le notifiche vengono eliminate automaticamente dopo un giorno",
"prefs_notifications_delete_after_one_week_description": "Le notifiche vengono eliminate automaticamente dopo una settimana", "prefs_notifications_delete_after_one_week_description": "Le notifiche vengono eliminate automaticamente dopo una settimana",
"prefs_notifications_delete_after_one_month_description": "Le notifiche vengono eliminate automaticamente dopo un mese", "prefs_notifications_delete_after_one_month_description": "Le notifiche vengono eliminate automaticamente dopo un mese",
"prefs_users_title": "Gestisci gli utenti", "prefs_users_title": "Gestisci gli utenti",
"prefs_users_description": "Aggiungi/rimuovi utenti per i tuoi topic protetti qui. Tieni presente che nome utente e password sono memorizzati nella memoria locale del browser.", "prefs_users_description": "Aggiungi/rimuovi utenti per i tuoi topic protetti qui. Tieni presente che nome utente e password sono memorizzati nella memoria locale del browser.",
"prefs_users_table": "Tabella utenti", "prefs_users_table": "Tabella utenti",
"prefs_users_add_button": "Aggiungi utente", "prefs_users_add_button": "Aggiungi utente",
"prefs_users_edit_button": "Modifica utente", "prefs_users_edit_button": "Modifica utente",
"prefs_users_delete_button": "Elimina utente", "prefs_users_delete_button": "Elimina utente",
"prefs_users_table_user_header": "Utente", "prefs_users_table_user_header": "Utente",
"prefs_users_table_base_url_header": "URL del servizio", "prefs_users_table_base_url_header": "URL del servizio",
"prefs_users_dialog_title_add": "Aggiungi utente", "prefs_users_dialog_title_add": "Aggiungi utente",
"prefs_users_dialog_title_edit": "Modifica utente", "prefs_users_dialog_title_edit": "Modifica utente",
"prefs_users_dialog_base_url_label": "URL del servizio, ad es. https://ntfy.sh", "prefs_users_dialog_base_url_label": "URL del servizio, ad es. https://ntfy.sh",
"prefs_users_dialog_username_label": "Nome utente, ad es. phil", "prefs_users_dialog_username_label": "Nome utente, ad es. phil",
"prefs_users_dialog_password_label": "Password", "prefs_users_dialog_password_label": "Password",
"prefs_users_dialog_button_cancel": "Annulla", "prefs_users_dialog_button_cancel": "Annulla",
"prefs_users_dialog_button_add": "Aggiungere", "prefs_users_dialog_button_add": "Aggiungere",
"prefs_users_dialog_button_save": "Salva", "prefs_users_dialog_button_save": "Salva",
"prefs_appearance_title": "Aspetto", "prefs_appearance_title": "Aspetto",
"prefs_appearance_language_title": "Lingua", "prefs_appearance_language_title": "Lingua",
"priority_min": "min", "priority_min": "min",
"priority_low": "basso", "priority_low": "basso",
"priority_default": "predefinito", "priority_default": "predefinito",
"priority_high": "alto", "priority_high": "alto",
"priority_max": "max", "priority_max": "max",
"error_boundary_title": "Oh no, ntfy è andato in crash", "error_boundary_title": "Oh no, ntfy è andato in crash",
"error_boundary_description": "Questo ovviamente non dovrebbe accadere. Mi dispiace molto per questo.<br/>Se hai un minuto, per favore <githubLink>segnala su GitHub</githubLink>, o faccelo sapere tramite <discordLink>Discord</discordLink> o <matrixLink>Matrix</matrixLink> .", "error_boundary_description": "Questo ovviamente non dovrebbe accadere. Mi dispiace molto per questo.<br/>Se hai un minuto, per favore <githubLink>segnala su GitHub</githubLink>, o faccelo sapere tramite <discordLink>Discord</discordLink> o <matrixLink>Matrix</matrixLink> .",
"error_boundary_button_copy_stack_trace": "Copia traccia dello stack", "error_boundary_button_copy_stack_trace": "Copia traccia dello stack",
"error_boundary_stack_trace": "Traccia dello stack", "error_boundary_stack_trace": "Traccia dello stack",
"error_boundary_gathering_info": "Raccogli più informazioni…", "error_boundary_gathering_info": "Raccogli più informazioni…",
"error_boundary_unsupported_indexeddb_title": "Navigazione privata non supportata", "error_boundary_unsupported_indexeddb_title": "Navigazione privata non supportata",
"action_bar_show_menu": "Mostra menu", "action_bar_show_menu": "Mostra menu",
"action_bar_send_test_notification": "Inviare una notifica di prova", "action_bar_send_test_notification": "Inviare una notifica di prova",
"alert_not_supported_description": "Le notifiche non sono supportate nel tuo browser.", "alert_not_supported_description": "Le notifiche non sono supportate nel tuo browser.",
"nav_button_documentation": "Documentazione", "nav_button_documentation": "Documentazione",
"notifications_actions_http_request_title": "Invia HTTP {{method}} a {{url}}", "notifications_actions_http_request_title": "Invia HTTP {{method}} a {{url}}",
"alert_grant_description": "Concedi al tuo browser l'autorizzazione a visualizzare le notifiche sul desktop.", "alert_grant_description": "Concedi al tuo browser l'autorizzazione a visualizzare le notifiche sul desktop.",
"alert_not_supported_title": "Notifiche non supportate", "alert_not_supported_title": "Notifiche non supportate",
"notifications_attachment_file_app": "file app Android", "notifications_attachment_file_app": "file app Android",
"notifications_no_subscriptions_description": "Fai clic sul link \"{{linktext}}\" per creare o iscriverti a un topic. Successivamente, puoi inviare messaggi tramite PUT o POST e riceverai le notifiche qui.", "notifications_no_subscriptions_description": "Fai clic sul link \"{{linktext}}\" per creare o iscriverti a un topic. Successivamente, puoi inviare messaggi tramite PUT o POST e riceverai le notifiche qui.",
"notifications_attachment_file_audio": "file audio", "notifications_attachment_file_audio": "file audio",
"notifications_none_for_any_description": "Per inviare notifiche a un topic, è sufficiente PUT o POST all'URL del topic. Ecco un esempio utilizzando uno dei tuoi topic.", "notifications_none_for_any_description": "Per inviare notifiche a un topic, è sufficiente PUT o POST all'URL del topic. Ecco un esempio utilizzando uno dei tuoi topic.",
"notifications_click_copy_url_title": "Copia l'URL del collegamento negli appunti", "notifications_click_copy_url_title": "Copia l'URL del collegamento negli appunti",
"prefs_notifications_sound_description_none": "Le notifiche non emettono alcun suono quando arrivano", "prefs_notifications_sound_description_none": "Le notifiche non emettono alcun suono quando arrivano",
"publish_dialog_delay_label": "Ritardo", "publish_dialog_delay_label": "Ritardo",
"publish_dialog_tags_placeholder": "Elenco di tag separato da virgole, ad es. avviso, backup-srv1", "publish_dialog_tags_placeholder": "Elenco di tag separato da virgole, ad es. avviso, backup-srv1",
"publish_dialog_click_placeholder": "URL che viene aperto quando si fa clic sulla notifica", "publish_dialog_click_placeholder": "URL che viene aperto quando si fa clic sulla notifica",
"publish_dialog_attach_placeholder": "Allega file tramite URL, ad es. https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "Allega file tramite URL, ad es. https://f-droid.org/F-Droid.apk",
"publish_dialog_chip_topic_label": "Cambia topic", "publish_dialog_chip_topic_label": "Cambia topic",
"publish_dialog_details_examples_description": "Per esempi e una descrizione dettagliata di tutte le funzioni di invio, fare riferimento alla <docsLink>documentazione</docsLink>.", "publish_dialog_details_examples_description": "Per esempi e una descrizione dettagliata di tutte le funzioni di invio, fare riferimento alla <docsLink>documentazione</docsLink>.",
"publish_dialog_attached_file_filename_placeholder": "Nome file allegato", "publish_dialog_attached_file_filename_placeholder": "Nome file allegato",
"emoji_picker_search_placeholder": "Cerca emoji", "emoji_picker_search_placeholder": "Cerca emoji",
"subscribe_dialog_subscribe_description": "Gli argomenti potrebbero non essere protetti da password, quindi scegli un nome che non sia facile da indovinare. Una volta iscritto, puoi inviare le notifiche tramite PUT/POST.", "subscribe_dialog_subscribe_description": "Gli argomenti potrebbero non essere protetti da password, quindi scegli un nome che non sia facile da indovinare. Una volta iscritto, puoi inviare le notifiche tramite PUT/POST.",
"subscribe_dialog_subscribe_use_another_label": "Usa un altro server", "subscribe_dialog_subscribe_use_another_label": "Usa un altro server",
"subscribe_dialog_login_password_label": "Password", "subscribe_dialog_login_password_label": "Password",
"subscribe_dialog_subscribe_button_subscribe": "Iscriviti", "subscribe_dialog_subscribe_button_subscribe": "Iscriviti",
"prefs_notifications_sound_play": "Riproduci il suono selezionato", "prefs_notifications_sound_play": "Riproduci il suono selezionato",
"prefs_notifications_min_priority_title": "Priorità minima", "prefs_notifications_min_priority_title": "Priorità minima",
"subscribe_dialog_login_description": "Questo argomento è protetto da password. Per favore inserisci username e password per iscriverti.", "subscribe_dialog_login_description": "Questo argomento è protetto da password. Per favore inserisci username e password per iscriverti.",
"subscribe_dialog_login_button_back": "Indietro", "subscribe_dialog_login_button_back": "Indietro",
"subscribe_dialog_error_user_not_authorized": "Utente {{username}} non autorizzato", "subscribe_dialog_error_user_not_authorized": "Utente {{username}} non autorizzato",
"prefs_notifications_title": "Notifiche", "prefs_notifications_title": "Notifiche",
"prefs_notifications_delete_after_title": "Elimina le notifiche", "prefs_notifications_delete_after_title": "Elimina le notifiche",
"prefs_notifications_min_priority_default_and_higher": "Priorità predefinita e superiore", "prefs_notifications_min_priority_default_and_higher": "Priorità predefinita e superiore",
"prefs_notifications_min_priority_description_x_or_higher": "Mostra le notifiche se la priorità è {{number}} ({{name}}) o superiore", "prefs_notifications_min_priority_description_x_or_higher": "Mostra le notifiche se la priorità è {{number}} ({{name}}) o superiore",
"prefs_notifications_delete_after_one_week": "Dopo una settimana", "prefs_notifications_delete_after_one_week": "Dopo una settimana",
"prefs_notifications_delete_after_one_month": "Dopo un mese", "prefs_notifications_delete_after_one_month": "Dopo un mese",
"prefs_notifications_delete_after_three_hours_description": "Le notifiche vengono eliminate automaticamente dopo tre ore", "prefs_notifications_delete_after_three_hours_description": "Le notifiche vengono eliminate automaticamente dopo tre ore",
"error_boundary_unsupported_indexeddb_description": "L'app web ntfy ha bisogno di IndexedDB per funzionare e il tuo browser non supporta IndexedDB in modalità di navigazione privata.<br/><br/>Anche se questo è un peccato, non ha molto senso usare il web ntfy app in modalità di navigazione privata comunque, perché tutto è archiviato nella memoria del browser. Puoi leggere di più a riguardo <githubLink>in questo numero di GitHub</githubLink> o parlarci su <discordLink>Discord</discordLink> o <matrixLink>Matrix</matrixLink>." "error_boundary_unsupported_indexeddb_description": "L'app web ntfy ha bisogno di IndexedDB per funzionare e il tuo browser non supporta IndexedDB in modalità di navigazione privata.<br/><br/>Anche se questo è un peccato, non ha molto senso usare il web ntfy app in modalità di navigazione privata comunque, perché tutto è archiviato nella memoria del browser. Puoi leggere di più a riguardo <githubLink>in questo numero di GitHub</githubLink> o parlarci su <discordLink>Discord</discordLink> o <matrixLink>Matrix</matrixLink>."
} }

View file

@ -1,191 +1,191 @@
{ {
"message_bar_error_publishing": "通知送信エラー", "message_bar_error_publishing": "通知送信エラー",
"nav_button_all_notifications": "全ての通知", "nav_button_all_notifications": "全ての通知",
"nav_button_settings": "設定", "nav_button_settings": "設定",
"notifications_click_open_button": "リンクを開く", "notifications_click_open_button": "リンクを開く",
"action_bar_send_test_notification": "テスト通知を送信", "action_bar_send_test_notification": "テスト通知を送信",
"action_bar_clear_notifications": "全ての通知を消去", "action_bar_clear_notifications": "全ての通知を消去",
"action_bar_unsubscribe": "購読解除", "action_bar_unsubscribe": "購読解除",
"nav_button_documentation": "ドキュメント", "nav_button_documentation": "ドキュメント",
"alert_not_supported_description": "通知機能はこのブラウザではサポートされていません。", "alert_not_supported_description": "通知機能はこのブラウザではサポートされていません。",
"notifications_copied_to_clipboard": "クリップボードにコピーしました", "notifications_copied_to_clipboard": "クリップボードにコピーしました",
"notifications_example": "例", "notifications_example": "例",
"publish_dialog_title_topic": "{{topic}}に送信", "publish_dialog_title_topic": "{{topic}}に送信",
"publish_dialog_title_no_topic": "通知を送信", "publish_dialog_title_no_topic": "通知を送信",
"publish_dialog_progress_uploading": "アップロード中…", "publish_dialog_progress_uploading": "アップロード中…",
"publish_dialog_progress_uploading_detail": "アップロード中 {{loaded}}/{{total}} ({{percent}}%) …", "publish_dialog_progress_uploading_detail": "アップロード中 {{loaded}}/{{total}} ({{percent}}%) …",
"publish_dialog_message_published": "通知を送信しました", "publish_dialog_message_published": "通知を送信しました",
"publish_dialog_title_label": "タイトル", "publish_dialog_title_label": "タイトル",
"publish_dialog_filename_label": "ファイル名", "publish_dialog_filename_label": "ファイル名",
"subscribe_dialog_login_description": "このトピックはログインする必要があります。ユーザー名とパスワードを入力してください。", "subscribe_dialog_login_description": "このトピックはログインする必要があります。ユーザー名とパスワードを入力してください。",
"subscribe_dialog_login_username_label": "ユーザー名, 例) phil", "subscribe_dialog_login_username_label": "ユーザー名, 例) phil",
"subscribe_dialog_login_password_label": "パスワード", "subscribe_dialog_login_password_label": "パスワード",
"subscribe_dialog_login_button_back": "戻る", "subscribe_dialog_login_button_back": "戻る",
"subscribe_dialog_login_button_login": "ログイン", "subscribe_dialog_login_button_login": "ログイン",
"prefs_notifications_min_priority_high_and_higher": "優先度高 およびそれ以上", "prefs_notifications_min_priority_high_and_higher": "優先度高 およびそれ以上",
"prefs_notifications_min_priority_max_only": "優先度最高のみ", "prefs_notifications_min_priority_max_only": "優先度最高のみ",
"action_bar_settings": "設定", "action_bar_settings": "設定",
"message_bar_type_message": "メッセージを入力してください", "message_bar_type_message": "メッセージを入力してください",
"nav_topics_title": "購読しているトピック", "nav_topics_title": "購読しているトピック",
"nav_button_subscribe": "トピックを購読", "nav_button_subscribe": "トピックを購読",
"alert_grant_description": "ブラウザのデスクトップ通知を許可してください。", "alert_grant_description": "ブラウザのデスクトップ通知を許可してください。",
"alert_grant_button": "許可する", "alert_grant_button": "許可する",
"notifications_attachment_link_expires": "リンクは {{date}} に失効します", "notifications_attachment_link_expires": "リンクは {{date}} に失効します",
"notifications_click_copy_url_button": "リンクをコピー", "notifications_click_copy_url_button": "リンクをコピー",
"notifications_none_for_topic_description": "トピックに通知を送信するには、トピックのURLにPUTかPOSTしてください。", "notifications_none_for_topic_description": "トピックに通知を送信するには、トピックのURLにPUTかPOSTしてください。",
"nav_button_publish_message": "通知を送信", "nav_button_publish_message": "通知を送信",
"alert_grant_title": "通知は無効化されています", "alert_grant_title": "通知は無効化されています",
"alert_not_supported_title": "通知機能はサポートされていません", "alert_not_supported_title": "通知機能はサポートされていません",
"notifications_tags": "タグ", "notifications_tags": "タグ",
"notifications_attachment_copy_url_button": "URLをコピー", "notifications_attachment_copy_url_button": "URLをコピー",
"notifications_attachment_open_title": "{{url}} に移動", "notifications_attachment_open_title": "{{url}} に移動",
"notifications_attachment_link_expired": "ダウンロードリンクは失効しました", "notifications_attachment_link_expired": "ダウンロードリンクは失効しました",
"notifications_actions_open_url_title": "{{url}} に移動", "notifications_actions_open_url_title": "{{url}} に移動",
"notifications_attachment_copy_url_title": "添付URLをクリップボードにコピー", "notifications_attachment_copy_url_title": "添付URLをクリップボードにコピー",
"notifications_attachment_open_button": "添付ファイルを開く", "notifications_attachment_open_button": "添付ファイルを開く",
"notifications_click_copy_url_title": "リンクURLをクリップボードにコピー", "notifications_click_copy_url_title": "リンクURLをクリップボードにコピー",
"notifications_none_for_topic_title": "このトピックではまだ通知を受信していません。", "notifications_none_for_topic_title": "このトピックではまだ通知を受信していません。",
"notifications_no_subscriptions_description": "「{{linktext}}」リンクをクリックしてトピックを作成または購読してください。その後、メッセージをPUTまたはPOSTで送信すると通知が受信できます。", "notifications_no_subscriptions_description": "「{{linktext}}」リンクをクリックしてトピックを作成または購読してください。その後、メッセージをPUTまたはPOSTで送信すると通知が受信できます。",
"publish_dialog_message_label": "メッセージ", "publish_dialog_message_label": "メッセージ",
"publish_dialog_email_label": "メール", "publish_dialog_email_label": "メール",
"notifications_none_for_any_title": "まだ通知を受信していません。", "notifications_none_for_any_title": "まだ通知を受信していません。",
"publish_dialog_priority_max": "優先度 最高", "publish_dialog_priority_max": "優先度 最高",
"publish_dialog_button_cancel_sending": "送信をキャンセル", "publish_dialog_button_cancel_sending": "送信をキャンセル",
"publish_dialog_attach_label": "添付URL", "publish_dialog_attach_label": "添付URL",
"notifications_none_for_any_description": "トピックに通知を送信するには、トピックURLにPUTまたはPOSTしてください。トピックのひとつを利用した例を示します。", "notifications_none_for_any_description": "トピックに通知を送信するには、トピックURLにPUTまたはPOSTしてください。トピックのひとつを利用した例を示します。",
"notifications_no_subscriptions_title": "まだ何も購読していないようです。", "notifications_no_subscriptions_title": "まだ何も購読していないようです。",
"publish_dialog_attachment_limits_file_and_quota_reached": "ファイル制限とクォータ {{fileSizeLimit}} を超えました、残り {{remainingBytes}}", "publish_dialog_attachment_limits_file_and_quota_reached": "ファイル制限とクォータ {{fileSizeLimit}} を超えました、残り {{remainingBytes}}",
"publish_dialog_priority_label": "優先度", "publish_dialog_priority_label": "優先度",
"publish_dialog_click_label": "クリックURL", "publish_dialog_click_label": "クリックURL",
"publish_dialog_email_placeholder": "通知を転送するアドレス, 例) phil@example.com", "publish_dialog_email_placeholder": "通知を転送するアドレス, 例) phil@example.com",
"notifications_more_details": "詳しい情報は、<websiteLink>ウェブサイト</websiteLink> または <docsLink>ドキュメント</docsLink> を参照してください。", "notifications_more_details": "詳しい情報は、<websiteLink>ウェブサイト</websiteLink> または <docsLink>ドキュメント</docsLink> を参照してください。",
"publish_dialog_attachment_limits_file_reached": "ファイルサイズ制限 {{fileSizeLimit}} を超えました", "publish_dialog_attachment_limits_file_reached": "ファイルサイズ制限 {{fileSizeLimit}} を超えました",
"publish_dialog_priority_min": "優先度 最低", "publish_dialog_priority_min": "優先度 最低",
"publish_dialog_priority_low": "優先度 低", "publish_dialog_priority_low": "優先度 低",
"publish_dialog_priority_default": "優先度 通常", "publish_dialog_priority_default": "優先度 通常",
"publish_dialog_base_url_label": "サービスURL", "publish_dialog_base_url_label": "サービスURL",
"publish_dialog_other_features": "他の機能:", "publish_dialog_other_features": "他の機能:",
"notifications_loading": "通知を読み込み中…", "notifications_loading": "通知を読み込み中…",
"publish_dialog_attachment_limits_quota_reached": "クォータを超過しました、残り{{remainingBytes}}", "publish_dialog_attachment_limits_quota_reached": "クォータを超過しました、残り{{remainingBytes}}",
"publish_dialog_priority_high": "優先度 高", "publish_dialog_priority_high": "優先度 高",
"publish_dialog_topic_placeholder": "トピック名の例 phil_alerts", "publish_dialog_topic_placeholder": "トピック名の例 phil_alerts",
"publish_dialog_title_placeholder": "通知タイトル 例: ディスクスペース警告", "publish_dialog_title_placeholder": "通知タイトル 例: ディスクスペース警告",
"publish_dialog_message_placeholder": "メッセージ本文を入力してください", "publish_dialog_message_placeholder": "メッセージ本文を入力してください",
"publish_dialog_tags_label": "タグ", "publish_dialog_tags_label": "タグ",
"publish_dialog_tags_placeholder": "コンマ区切りでタグを列挙してください 例: warning, srv1-backup", "publish_dialog_tags_placeholder": "コンマ区切りでタグを列挙してください 例: warning, srv1-backup",
"publish_dialog_topic_label": "トピック名", "publish_dialog_topic_label": "トピック名",
"publish_dialog_delay_label": "遅延", "publish_dialog_delay_label": "遅延",
"publish_dialog_click_placeholder": "通知をクリックしたときに開くURL", "publish_dialog_click_placeholder": "通知をクリックしたときに開くURL",
"publish_dialog_filename_placeholder": "添付ファイルの名称", "publish_dialog_filename_placeholder": "添付ファイルの名称",
"publish_dialog_button_send": "送信", "publish_dialog_button_send": "送信",
"publish_dialog_chip_click_label": "Click URL", "publish_dialog_chip_click_label": "Click URL",
"publish_dialog_chip_email_label": "メールに転送", "publish_dialog_chip_email_label": "メールに転送",
"publish_dialog_details_examples_description": "送信機能の例や詳細な説明については、<docsLink>ドキュメント</docsLink>を参照してください。", "publish_dialog_details_examples_description": "送信機能の例や詳細な説明については、<docsLink>ドキュメント</docsLink>を参照してください。",
"error_boundary_description": "明らかに起きてはならないことです。本当に申し訳ありません。<br/>もし時間があれば、<githubLink>GitHubにこれを報告</githubLink>するか、<discordLink>Discord</discordLink>または<matrixLink>Matrix</matrixLink>で我々に知らせて下さい。", "error_boundary_description": "明らかに起きてはならないことです。本当に申し訳ありません。<br/>もし時間があれば、<githubLink>GitHubにこれを報告</githubLink>するか、<discordLink>Discord</discordLink>または<matrixLink>Matrix</matrixLink>で我々に知らせて下さい。",
"publish_dialog_chip_attach_url_label": "URLでファイルを添付", "publish_dialog_chip_attach_url_label": "URLでファイルを添付",
"publish_dialog_chip_attach_file_label": "ローカルファイルを添付", "publish_dialog_chip_attach_file_label": "ローカルファイルを添付",
"publish_dialog_chip_topic_label": "トピックを変更", "publish_dialog_chip_topic_label": "トピックを変更",
"publish_dialog_chip_delay_label": "配信を遅延させる", "publish_dialog_chip_delay_label": "配信を遅延させる",
"publish_dialog_attached_file_title": "添付ファイル:", "publish_dialog_attached_file_title": "添付ファイル:",
"publish_dialog_button_cancel": "キャンセル", "publish_dialog_button_cancel": "キャンセル",
"publish_dialog_checkbox_publish_another": "送信後開いたままにする", "publish_dialog_checkbox_publish_another": "送信後開いたままにする",
"publish_dialog_attached_file_filename_placeholder": "添付ファイル名", "publish_dialog_attached_file_filename_placeholder": "添付ファイル名",
"emoji_picker_search_placeholder": "絵文字を検索", "emoji_picker_search_placeholder": "絵文字を検索",
"subscribe_dialog_subscribe_title": "トピックを購読", "subscribe_dialog_subscribe_title": "トピックを購読",
"prefs_users_title": "ユーザー管理", "prefs_users_title": "ユーザー管理",
"publish_dialog_drop_file_here": "ここにファイルをドロップしてください", "publish_dialog_drop_file_here": "ここにファイルをドロップしてください",
"subscribe_dialog_subscribe_topic_placeholder": "トピック名 例: phils_alerts", "subscribe_dialog_subscribe_topic_placeholder": "トピック名 例: phils_alerts",
"prefs_notifications_min_priority_any": "全ての優先度", "prefs_notifications_min_priority_any": "全ての優先度",
"prefs_notifications_delete_after_three_hours": "3時間後", "prefs_notifications_delete_after_three_hours": "3時間後",
"prefs_users_description": "保護トピックのユーザーを追加/削除できます。ユーザー名とパスワードはブラウザのローカルストレージに保存されることに留意してください。", "prefs_users_description": "保護トピックのユーザーを追加/削除できます。ユーザー名とパスワードはブラウザのローカルストレージに保存されることに留意してください。",
"prefs_users_add_button": "ユーザー追加", "prefs_users_add_button": "ユーザー追加",
"prefs_users_dialog_button_add": "追加", "prefs_users_dialog_button_add": "追加",
"subscribe_dialog_subscribe_use_another_label": "他のサーバーを使用", "subscribe_dialog_subscribe_use_another_label": "他のサーバーを使用",
"subscribe_dialog_error_user_not_authorized": "ユーザー名 {{username}} は許可されていません", "subscribe_dialog_error_user_not_authorized": "ユーザー名 {{username}} は許可されていません",
"prefs_notifications_delete_after_one_week": "1週間後", "prefs_notifications_delete_after_one_week": "1週間後",
"prefs_notifications_delete_after_one_month": "1か月後", "prefs_notifications_delete_after_one_month": "1か月後",
"subscribe_dialog_subscribe_description": "トピックはパスワード保護されないので、推測されにくい名前にしてください。購読した後、PUT/POSTで通知を送信できます。", "subscribe_dialog_subscribe_description": "トピックはパスワード保護されないので、推測されにくい名前にしてください。購読した後、PUT/POSTで通知を送信できます。",
"subscribe_dialog_subscribe_button_cancel": "キャンセル", "subscribe_dialog_subscribe_button_cancel": "キャンセル",
"subscribe_dialog_subscribe_button_subscribe": "購読", "subscribe_dialog_subscribe_button_subscribe": "購読",
"subscribe_dialog_login_title": "ログインが必要です", "subscribe_dialog_login_title": "ログインが必要です",
"subscribe_dialog_error_user_anonymous": "匿名", "subscribe_dialog_error_user_anonymous": "匿名",
"prefs_notifications_title": "通知", "prefs_notifications_title": "通知",
"prefs_notifications_min_priority_low_and_higher": "優先度低 およびそれ以上", "prefs_notifications_min_priority_low_and_higher": "優先度低 およびそれ以上",
"prefs_notifications_delete_after_never": "削除しない", "prefs_notifications_delete_after_never": "削除しない",
"prefs_notifications_delete_after_one_day": "1日後", "prefs_notifications_delete_after_one_day": "1日後",
"prefs_notifications_sound_title": "通知音", "prefs_notifications_sound_title": "通知音",
"prefs_notifications_sound_no_sound": "サウンドなし", "prefs_notifications_sound_no_sound": "サウンドなし",
"prefs_notifications_min_priority_title": "表示する優先度", "prefs_notifications_min_priority_title": "表示する優先度",
"prefs_notifications_min_priority_default_and_higher": "優先度通常 およびそれ以上", "prefs_notifications_min_priority_default_and_higher": "優先度通常 およびそれ以上",
"prefs_notifications_delete_after_title": "通知を削除", "prefs_notifications_delete_after_title": "通知を削除",
"prefs_users_dialog_button_cancel": "キャンセル", "prefs_users_dialog_button_cancel": "キャンセル",
"prefs_users_dialog_button_save": "保存", "prefs_users_dialog_button_save": "保存",
"prefs_users_table_user_header": "ユーザー名", "prefs_users_table_user_header": "ユーザー名",
"prefs_users_dialog_title_add": "ユーザー追加", "prefs_users_dialog_title_add": "ユーザー追加",
"prefs_users_dialog_title_edit": "ユーザー編集", "prefs_users_dialog_title_edit": "ユーザー編集",
"prefs_users_dialog_base_url_label": "サービスURL, 例) https://ntfy.sh", "prefs_users_dialog_base_url_label": "サービスURL, 例) https://ntfy.sh",
"prefs_appearance_title": "外観", "prefs_appearance_title": "外観",
"prefs_appearance_language_title": "言語", "prefs_appearance_language_title": "言語",
"prefs_users_table_base_url_header": "サービスURL", "prefs_users_table_base_url_header": "サービスURL",
"prefs_users_dialog_username_label": "ユーザー名, 例) phil", "prefs_users_dialog_username_label": "ユーザー名, 例) phil",
"prefs_users_dialog_password_label": "パスワード", "prefs_users_dialog_password_label": "パスワード",
"error_boundary_title": "おっと、ntfyがクラッシュしました", "error_boundary_title": "おっと、ntfyがクラッシュしました",
"error_boundary_button_copy_stack_trace": "スタックトレースをコピー", "error_boundary_button_copy_stack_trace": "スタックトレースをコピー",
"error_boundary_stack_trace": "スタックトレース", "error_boundary_stack_trace": "スタックトレース",
"error_boundary_gathering_info": "更に情報を集める…", "error_boundary_gathering_info": "更に情報を集める…",
"publish_dialog_base_url_placeholder": "サービスURL, 例) https://example.com", "publish_dialog_base_url_placeholder": "サービスURL, 例) https://example.com",
"publish_dialog_attach_placeholder": "添付ファイルをURLで指定, 例) https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "添付ファイルをURLで指定, 例) https://f-droid.org/F-Droid.apk",
"publish_dialog_delay_placeholder": "遅延時間, 例) {{unixTimestamp}}, {{relativeTime}}, or \"{{naturalLanguage}}\" (English only)", "publish_dialog_delay_placeholder": "遅延時間, 例) {{unixTimestamp}}, {{relativeTime}}, or \"{{naturalLanguage}}\" (English only)",
"prefs_notifications_sound_description_none": "通知受信時に音を鳴らしません", "prefs_notifications_sound_description_none": "通知受信時に音を鳴らしません",
"prefs_notifications_sound_description_some": "通知受信時に {{sound}} を鳴らします", "prefs_notifications_sound_description_some": "通知受信時に {{sound}} を鳴らします",
"prefs_notifications_min_priority_description_any": "優先度に関係なく全ての通知を表示します", "prefs_notifications_min_priority_description_any": "優先度に関係なく全ての通知を表示します",
"prefs_notifications_min_priority_description_x_or_higher": "優先度が {{number}} ({{name}}) 以上の時に通知を表示します", "prefs_notifications_min_priority_description_x_or_higher": "優先度が {{number}} ({{name}}) 以上の時に通知を表示します",
"prefs_notifications_delete_after_never_description": "通知は自動的に削除されません", "prefs_notifications_delete_after_never_description": "通知は自動的に削除されません",
"prefs_notifications_delete_after_one_day_description": "通知は1日後に自動的に削除されます", "prefs_notifications_delete_after_one_day_description": "通知は1日後に自動的に削除されます",
"prefs_notifications_delete_after_one_week_description": "通知は1週間後に自動的に削除されます", "prefs_notifications_delete_after_one_week_description": "通知は1週間後に自動的に削除されます",
"prefs_notifications_delete_after_one_month_description": "通知は1か月後に自動的に削除されます", "prefs_notifications_delete_after_one_month_description": "通知は1か月後に自動的に削除されます",
"priority_high": "高", "priority_high": "高",
"priority_max": "最高", "priority_max": "最高",
"prefs_notifications_min_priority_description_max": "優先度が 5 (最高) の時にのみ通知を表示します", "prefs_notifications_min_priority_description_max": "優先度が 5 (最高) の時にのみ通知を表示します",
"priority_default": "通常", "priority_default": "通常",
"prefs_notifications_delete_after_three_hours_description": "通知は3時間後に自動的に削除されます", "prefs_notifications_delete_after_three_hours_description": "通知は3時間後に自動的に削除されます",
"priority_low": "低", "priority_low": "低",
"priority_min": "最低", "priority_min": "最低",
"notifications_actions_not_supported": "このアクションはWebアプリではサポートされていません", "notifications_actions_not_supported": "このアクションはWebアプリではサポートされていません",
"notifications_actions_http_request_title": "{{url}}にHTTP {{method}}を送信", "notifications_actions_http_request_title": "{{url}}にHTTP {{method}}を送信",
"prefs_users_edit_button": "ユーザーを編集", "prefs_users_edit_button": "ユーザーを編集",
"publish_dialog_attached_file_remove": "添付ファイルを削除", "publish_dialog_attached_file_remove": "添付ファイルを削除",
"error_boundary_unsupported_indexeddb_description": "nfty webアプリは動作にIndexedDBを使用しますが、あなたのブラウザはプライベートブラウジングモード時にIndexedDBをサポートしていません。<br/><br/>これは残念なことですが、ntfy webアプリは全ての情報をブラウザストレージに保存して動作するため、プライベートブラウジングモードで利用するのはあまり意味がないかも知れません。詳細については <githubLink>GitHub issue</githubLink>を参照するか、<discordLink>Discord</discordLink>や<matrixLink>Matrix</matrixLink>の議論に参加してください。", "error_boundary_unsupported_indexeddb_description": "nfty webアプリは動作にIndexedDBを使用しますが、あなたのブラウザはプライベートブラウジングモード時にIndexedDBをサポートしていません。<br/><br/>これは残念なことですが、ntfy webアプリは全ての情報をブラウザストレージに保存して動作するため、プライベートブラウジングモードで利用するのはあまり意味がないかも知れません。詳細については <githubLink>GitHub issue</githubLink>を参照するか、<discordLink>Discord</discordLink>や<matrixLink>Matrix</matrixLink>の議論に参加してください。",
"action_bar_show_menu": "メニューを表示", "action_bar_show_menu": "メニューを表示",
"action_bar_logo_alt": "ntfyロゴ", "action_bar_logo_alt": "ntfyロゴ",
"action_bar_toggle_mute": "通知をミュート/解除", "action_bar_toggle_mute": "通知をミュート/解除",
"action_bar_toggle_action_menu": "動作メニューを開く/閉じる", "action_bar_toggle_action_menu": "動作メニューを開く/閉じる",
"message_bar_show_dialog": "送信ダイアログを表示", "message_bar_show_dialog": "送信ダイアログを表示",
"message_bar_publish": "メッセージを送信", "message_bar_publish": "メッセージを送信",
"nav_button_muted": "ミュートされた通知", "nav_button_muted": "ミュートされた通知",
"nav_button_connecting": "接続中", "nav_button_connecting": "接続中",
"notifications_list": "通知一覧", "notifications_list": "通知一覧",
"notifications_new_indicator": "新しい通知", "notifications_new_indicator": "新しい通知",
"notifications_list_item": "通知", "notifications_list_item": "通知",
"notifications_mark_read": "既読にする", "notifications_mark_read": "既読にする",
"notifications_delete": "削除", "notifications_delete": "削除",
"notifications_priority_x": "優先度 {{priority}}", "notifications_priority_x": "優先度 {{priority}}",
"notifications_attachment_image": "添付画像", "notifications_attachment_image": "添付画像",
"notifications_attachment_file_image": "画像ファイル", "notifications_attachment_file_image": "画像ファイル",
"notifications_attachment_file_video": "動画ファイル", "notifications_attachment_file_video": "動画ファイル",
"notifications_attachment_file_audio": "音声ファイル", "notifications_attachment_file_audio": "音声ファイル",
"notifications_attachment_file_app": "Androidアプリファイル", "notifications_attachment_file_app": "Androidアプリファイル",
"notifications_attachment_file_document": "その他文書", "notifications_attachment_file_document": "その他文書",
"publish_dialog_emoji_picker_show": "絵文字", "publish_dialog_emoji_picker_show": "絵文字",
"publish_dialog_topic_reset": "トピックをリセット", "publish_dialog_topic_reset": "トピックをリセット",
"publish_dialog_click_reset": "クリックURLを削除", "publish_dialog_click_reset": "クリックURLを削除",
"publish_dialog_email_reset": "メール転送を削除", "publish_dialog_email_reset": "メール転送を削除",
"publish_dialog_attach_reset": "添付URLを削除", "publish_dialog_attach_reset": "添付URLを削除",
"publish_dialog_delay_reset": "配信遅延を削除", "publish_dialog_delay_reset": "配信遅延を削除",
"emoji_picker_search_clear": "検索をクリア", "emoji_picker_search_clear": "検索をクリア",
"subscribe_dialog_subscribe_base_url_label": "サーバーURL", "subscribe_dialog_subscribe_base_url_label": "サーバーURL",
"prefs_notifications_sound_play": "選択されたサウンドを再生", "prefs_notifications_sound_play": "選択されたサウンドを再生",
"prefs_users_table": "ユーザー一覧", "prefs_users_table": "ユーザー一覧",
"prefs_users_delete_button": "ユーザーを削除", "prefs_users_delete_button": "ユーザーを削除",
"error_boundary_unsupported_indexeddb_title": "プライベートブラウジングはサポートされていません" "error_boundary_unsupported_indexeddb_title": "プライベートブラウジングはサポートされていません"
} }

View file

@ -1,191 +1,191 @@
{ {
"action_bar_show_menu": "메뉴 표시", "action_bar_show_menu": "메뉴 표시",
"action_bar_logo_alt": "ntfy 로고", "action_bar_logo_alt": "ntfy 로고",
"action_bar_settings": "설정", "action_bar_settings": "설정",
"action_bar_send_test_notification": "시험용 알림 발송", "action_bar_send_test_notification": "시험용 알림 발송",
"action_bar_clear_notifications": "모든 알림 초기화", "action_bar_clear_notifications": "모든 알림 초기화",
"action_bar_unsubscribe": "구독 해제", "action_bar_unsubscribe": "구독 해제",
"action_bar_toggle_mute": "알림 음소거/해제", "action_bar_toggle_mute": "알림 음소거/해제",
"action_bar_toggle_action_menu": "액션 메뉴 열기/닫기", "action_bar_toggle_action_menu": "액션 메뉴 열기/닫기",
"message_bar_type_message": "여기에 메세지를 입력하세요", "message_bar_type_message": "여기에 메세지를 입력하세요",
"message_bar_error_publishing": "메세지 발송 오류", "message_bar_error_publishing": "메세지 발송 오류",
"message_bar_show_dialog": "발송 창 표시", "message_bar_show_dialog": "발송 창 표시",
"message_bar_publish": "메세지 발송", "message_bar_publish": "메세지 발송",
"nav_topics_title": "구독한 주제", "nav_topics_title": "구독한 주제",
"nav_button_all_notifications": "모든 알림", "nav_button_all_notifications": "모든 알림",
"nav_button_publish_message": "알림 보내기", "nav_button_publish_message": "알림 보내기",
"nav_button_subscribe": "주제 구독하기", "nav_button_subscribe": "주제 구독하기",
"nav_button_muted": "알림 음소거됨", "nav_button_muted": "알림 음소거됨",
"nav_button_connecting": "연결중", "nav_button_connecting": "연결중",
"alert_grant_title": "알림이 비활성화되어 있습니다", "alert_grant_title": "알림이 비활성화되어 있습니다",
"alert_grant_description": "데스크톱 알림을 받기 위해서는 브라우저에서 권한을 부여해야 합니다.", "alert_grant_description": "데스크톱 알림을 받기 위해서는 브라우저에서 권한을 부여해야 합니다.",
"alert_grant_button": "권한 부여하기", "alert_grant_button": "권한 부여하기",
"alert_not_supported_title": "알림이 지원되지 않습니다", "alert_not_supported_title": "알림이 지원되지 않습니다",
"notifications_list_item": "알림", "notifications_list_item": "알림",
"notifications_mark_read": "읽음으로 표시", "notifications_mark_read": "읽음으로 표시",
"notifications_delete": "삭제", "notifications_delete": "삭제",
"notifications_copied_to_clipboard": "클립보드에 복사됨", "notifications_copied_to_clipboard": "클립보드에 복사됨",
"notifications_tags": "태그", "notifications_tags": "태그",
"notifications_priority_x": "우선순위 {{priority}}", "notifications_priority_x": "우선순위 {{priority}}",
"notifications_new_indicator": "새 알림", "notifications_new_indicator": "새 알림",
"notifications_attachment_image": "첨부 이미지", "notifications_attachment_image": "첨부 이미지",
"notifications_attachment_copy_url_title": "첨부 주소를 클립보드에 복사", "notifications_attachment_copy_url_title": "첨부 주소를 클립보드에 복사",
"notifications_attachment_copy_url_button": "URL 복사", "notifications_attachment_copy_url_button": "URL 복사",
"notifications_attachment_open_title": "{{url}}로 가기", "notifications_attachment_open_title": "{{url}}로 가기",
"publish_dialog_attachment_limits_file_and_quota_reached": "첨부파일 크기 제한({{fileSizeLimit}}) 초과 및 할당량 초과({{remainingBytes}} 남음)", "publish_dialog_attachment_limits_file_and_quota_reached": "첨부파일 크기 제한({{fileSizeLimit}}) 초과 및 할당량 초과({{remainingBytes}} 남음)",
"publish_dialog_attachment_limits_file_reached": "첨부파일 크기 제한({{fileSizeLimit}}) 초과", "publish_dialog_attachment_limits_file_reached": "첨부파일 크기 제한({{fileSizeLimit}}) 초과",
"publish_dialog_attachment_limits_quota_reached": "할당량 초과({{remainingBytes}} 남음)", "publish_dialog_attachment_limits_quota_reached": "할당량 초과({{remainingBytes}} 남음)",
"publish_dialog_emoji_picker_show": "이모지 선택", "publish_dialog_emoji_picker_show": "이모지 선택",
"publish_dialog_priority_min": "우선순위 최소", "publish_dialog_priority_min": "우선순위 최소",
"publish_dialog_priority_low": "우선순위 낮음", "publish_dialog_priority_low": "우선순위 낮음",
"publish_dialog_priority_default": "우선순위 기본", "publish_dialog_priority_default": "우선순위 기본",
"publish_dialog_priority_high": "우선순위 높음", "publish_dialog_priority_high": "우선순위 높음",
"publish_dialog_priority_max": "우선순위 최상", "publish_dialog_priority_max": "우선순위 최상",
"publish_dialog_base_url_label": "서비스 URL", "publish_dialog_base_url_label": "서비스 URL",
"publish_dialog_base_url_placeholder": "서비스 URL, 예를 들면 https://example.com", "publish_dialog_base_url_placeholder": "서비스 URL, 예를 들면 https://example.com",
"publish_dialog_topic_label": "주제 이름", "publish_dialog_topic_label": "주제 이름",
"publish_dialog_topic_placeholder": "주제 이름, 예를 들면 phil_alerts", "publish_dialog_topic_placeholder": "주제 이름, 예를 들면 phil_alerts",
"publish_dialog_topic_reset": "주제 초기화", "publish_dialog_topic_reset": "주제 초기화",
"publish_dialog_title_label": "제목", "publish_dialog_title_label": "제목",
"publish_dialog_title_placeholder": "알림 제목, 예를 들면 디스크 공간 경고", "publish_dialog_title_placeholder": "알림 제목, 예를 들면 디스크 공간 경고",
"publish_dialog_message_label": "메세지", "publish_dialog_message_label": "메세지",
"publish_dialog_message_placeholder": "메세지를 여기에 입력하세요", "publish_dialog_message_placeholder": "메세지를 여기에 입력하세요",
"publish_dialog_tags_label": "태그", "publish_dialog_tags_label": "태그",
"publish_dialog_tags_placeholder": "반점으로 구분된 태그 목록, 예를 들면 warning, srv1-backup", "publish_dialog_tags_placeholder": "반점으로 구분된 태그 목록, 예를 들면 warning, srv1-backup",
"publish_dialog_priority_label": "우선순위", "publish_dialog_priority_label": "우선순위",
"publish_dialog_click_label": "클릭 URL", "publish_dialog_click_label": "클릭 URL",
"publish_dialog_click_placeholder": "알림이 클릭되었을때 이동할 URL", "publish_dialog_click_placeholder": "알림이 클릭되었을때 이동할 URL",
"publish_dialog_click_reset": "클릭 URL 제거", "publish_dialog_click_reset": "클릭 URL 제거",
"publish_dialog_email_label": "이메일", "publish_dialog_email_label": "이메일",
"publish_dialog_email_placeholder": "알림을 전달할 이메일 주소, 예를 들면 phil@example.com", "publish_dialog_email_placeholder": "알림을 전달할 이메일 주소, 예를 들면 phil@example.com",
"publish_dialog_email_reset": "이메일 전달 삭제", "publish_dialog_email_reset": "이메일 전달 삭제",
"publish_dialog_attach_label": "첨부 파일 URL", "publish_dialog_attach_label": "첨부 파일 URL",
"publish_dialog_attach_placeholder": "파일을 URL로 첨부하기, 예를 들면 https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "파일을 URL로 첨부하기, 예를 들면 https://f-droid.org/F-Droid.apk",
"publish_dialog_attach_reset": "첨부 파일 URL 삭제", "publish_dialog_attach_reset": "첨부 파일 URL 삭제",
"publish_dialog_filename_label": "파일 이름", "publish_dialog_filename_label": "파일 이름",
"publish_dialog_filename_placeholder": "첨부 파일 이름", "publish_dialog_filename_placeholder": "첨부 파일 이름",
"publish_dialog_delay_label": "지연", "publish_dialog_delay_label": "지연",
"publish_dialog_chip_email_label": "이메일로 전달", "publish_dialog_chip_email_label": "이메일로 전달",
"publish_dialog_chip_attach_url_label": "URL로 파일 첨부", "publish_dialog_chip_attach_url_label": "URL로 파일 첨부",
"publish_dialog_chip_attach_file_label": "로컬 파일 첨부", "publish_dialog_chip_attach_file_label": "로컬 파일 첨부",
"publish_dialog_chip_delay_label": "발송 지연", "publish_dialog_chip_delay_label": "발송 지연",
"publish_dialog_chip_topic_label": "주제 변경", "publish_dialog_chip_topic_label": "주제 변경",
"publish_dialog_details_examples_description": "예제와 모든 전송 기능의 자세한 설명은 <docsLink>문서</docsLink>를 참고해주세요.", "publish_dialog_details_examples_description": "예제와 모든 전송 기능의 자세한 설명은 <docsLink>문서</docsLink>를 참고해주세요.",
"publish_dialog_button_cancel": "취소", "publish_dialog_button_cancel": "취소",
"publish_dialog_button_send": "보내기", "publish_dialog_button_send": "보내기",
"publish_dialog_button_cancel_sending": "보내기 취소", "publish_dialog_button_cancel_sending": "보내기 취소",
"publish_dialog_checkbox_publish_another": "다른 메세지 보내기", "publish_dialog_checkbox_publish_another": "다른 메세지 보내기",
"publish_dialog_attached_file_title": "첨부된 파일:", "publish_dialog_attached_file_title": "첨부된 파일:",
"publish_dialog_attached_file_filename_placeholder": "첨부 파일 이름", "publish_dialog_attached_file_filename_placeholder": "첨부 파일 이름",
"publish_dialog_attached_file_remove": "첨부 파일 삭제", "publish_dialog_attached_file_remove": "첨부 파일 삭제",
"publish_dialog_drop_file_here": "여기에 파일을 끌어다 놓으세요", "publish_dialog_drop_file_here": "여기에 파일을 끌어다 놓으세요",
"emoji_picker_search_placeholder": "이모지 검색", "emoji_picker_search_placeholder": "이모지 검색",
"emoji_picker_search_clear": "검색 초기화", "emoji_picker_search_clear": "검색 초기화",
"subscribe_dialog_subscribe_title": "주제 구독하기", "subscribe_dialog_subscribe_title": "주제 구독하기",
"subscribe_dialog_subscribe_description": "주제는 비밀번호로 보호되지 않을 수 있으니 추측하기 어려운 이름을 사용하십시오. 구독한 뒤 PUT/POST 알림을 보낼 수 있습니다.", "subscribe_dialog_subscribe_description": "주제는 비밀번호로 보호되지 않을 수 있으니 추측하기 어려운 이름을 사용하십시오. 구독한 뒤 PUT/POST 알림을 보낼 수 있습니다.",
"subscribe_dialog_subscribe_topic_placeholder": "주제 이름, 예를 들면 phil_alerts", "subscribe_dialog_subscribe_topic_placeholder": "주제 이름, 예를 들면 phil_alerts",
"subscribe_dialog_subscribe_use_another_label": "다른 서버 사용", "subscribe_dialog_subscribe_use_another_label": "다른 서버 사용",
"subscribe_dialog_subscribe_base_url_label": "서비스 URL", "subscribe_dialog_subscribe_base_url_label": "서비스 URL",
"subscribe_dialog_subscribe_button_cancel": "취소", "subscribe_dialog_subscribe_button_cancel": "취소",
"subscribe_dialog_subscribe_button_subscribe": "구독하기", "subscribe_dialog_subscribe_button_subscribe": "구독하기",
"subscribe_dialog_login_title": "로그인 필요함", "subscribe_dialog_login_title": "로그인 필요함",
"subscribe_dialog_error_user_anonymous": "익명", "subscribe_dialog_error_user_anonymous": "익명",
"subscribe_dialog_error_user_not_authorized": "사용자 {{username}} 은(는) 인증되지 않았습니다", "subscribe_dialog_error_user_not_authorized": "사용자 {{username}} 은(는) 인증되지 않았습니다",
"subscribe_dialog_login_username_label": "사용자 이름, 예를 들면 phil", "subscribe_dialog_login_username_label": "사용자 이름, 예를 들면 phil",
"subscribe_dialog_login_password_label": "비밀번호", "subscribe_dialog_login_password_label": "비밀번호",
"subscribe_dialog_login_button_back": "뒤로가기", "subscribe_dialog_login_button_back": "뒤로가기",
"subscribe_dialog_login_button_login": "로그인", "subscribe_dialog_login_button_login": "로그인",
"prefs_notifications_title": "알림", "prefs_notifications_title": "알림",
"prefs_notifications_sound_title": "알림 효과음", "prefs_notifications_sound_title": "알림 효과음",
"prefs_notifications_sound_description_none": "알림 도착시 효과음을 재생하지 않습니다", "prefs_notifications_sound_description_none": "알림 도착시 효과음을 재생하지 않습니다",
"prefs_notifications_sound_description_some": "알림 도착시 {{sound}} 효과음이 재생됩니다", "prefs_notifications_sound_description_some": "알림 도착시 {{sound}} 효과음이 재생됩니다",
"prefs_notifications_sound_no_sound": "효과음 없음", "prefs_notifications_sound_no_sound": "효과음 없음",
"prefs_notifications_sound_play": "선택한 효과음 재생", "prefs_notifications_sound_play": "선택한 효과음 재생",
"prefs_notifications_min_priority_title": "우선순위 최소", "prefs_notifications_min_priority_title": "우선순위 최소",
"prefs_notifications_min_priority_description_x_or_higher": "우선순위가 {{number}} ({{name}}) 이상인 알림만 보기", "prefs_notifications_min_priority_description_x_or_higher": "우선순위가 {{number}} ({{name}}) 이상인 알림만 보기",
"prefs_notifications_min_priority_description_max": "우선순위가 5 (최상)인 알림만 보기", "prefs_notifications_min_priority_description_max": "우선순위가 5 (최상)인 알림만 보기",
"prefs_notifications_min_priority_any": "아무 우선순위", "prefs_notifications_min_priority_any": "아무 우선순위",
"prefs_notifications_min_priority_default_and_higher": "우선순위 기본 이상", "prefs_notifications_min_priority_default_and_higher": "우선순위 기본 이상",
"prefs_notifications_min_priority_low_and_higher": "우선순위 낮음 이상", "prefs_notifications_min_priority_low_and_higher": "우선순위 낮음 이상",
"prefs_notifications_delete_after_three_hours": "3시간 뒤", "prefs_notifications_delete_after_three_hours": "3시간 뒤",
"prefs_notifications_delete_after_one_day": "1일 뒤", "prefs_notifications_delete_after_one_day": "1일 뒤",
"prefs_notifications_delete_after_one_week": "1주 뒤", "prefs_notifications_delete_after_one_week": "1주 뒤",
"prefs_notifications_delete_after_one_month": "1달 뒤", "prefs_notifications_delete_after_one_month": "1달 뒤",
"prefs_notifications_delete_after_never_description": "알림이 자동으로 삭제되지 않습니다", "prefs_notifications_delete_after_never_description": "알림이 자동으로 삭제되지 않습니다",
"prefs_notifications_delete_after_three_hours_description": "알림이 3시간 뒤 자동으로 삭제됩니다", "prefs_notifications_delete_after_three_hours_description": "알림이 3시간 뒤 자동으로 삭제됩니다",
"prefs_notifications_delete_after_one_day_description": "알림이 1일 뒤 자동으로 삭제됩니다", "prefs_notifications_delete_after_one_day_description": "알림이 1일 뒤 자동으로 삭제됩니다",
"prefs_notifications_delete_after_one_week_description": "알림이 1주 뒤 자동으로 삭제됩니다", "prefs_notifications_delete_after_one_week_description": "알림이 1주 뒤 자동으로 삭제됩니다",
"prefs_notifications_delete_after_one_month_description": "알림이 1달 뒤 자동으로 삭제됩니다", "prefs_notifications_delete_after_one_month_description": "알림이 1달 뒤 자동으로 삭제됩니다",
"prefs_users_title": "사용자 관리", "prefs_users_title": "사용자 관리",
"prefs_users_description": "이곳에서 보호된 주제를 위한 사용자를 추가하거나 삭제할 수 있습니다. 사용자 이름과 비밀번호는 브라우저의 로컬 저장소에 보관됩니다.", "prefs_users_description": "이곳에서 보호된 주제를 위한 사용자를 추가하거나 삭제할 수 있습니다. 사용자 이름과 비밀번호는 브라우저의 로컬 저장소에 보관됩니다.",
"prefs_users_add_button": "사용자 추가", "prefs_users_add_button": "사용자 추가",
"prefs_users_edit_button": "사용자 편집", "prefs_users_edit_button": "사용자 편집",
"prefs_users_delete_button": "사용자 삭제", "prefs_users_delete_button": "사용자 삭제",
"prefs_users_table_user_header": "사용자", "prefs_users_table_user_header": "사용자",
"prefs_users_table_base_url_header": "서비스 URL", "prefs_users_table_base_url_header": "서비스 URL",
"prefs_users_dialog_title_add": "사용자 추가", "prefs_users_dialog_title_add": "사용자 추가",
"prefs_users_dialog_title_edit": "사용자 편집", "prefs_users_dialog_title_edit": "사용자 편집",
"prefs_users_dialog_base_url_label": "서비스 URL, 예를 들면 https://ntfy.sh", "prefs_users_dialog_base_url_label": "서비스 URL, 예를 들면 https://ntfy.sh",
"prefs_users_dialog_button_cancel": "취소", "prefs_users_dialog_button_cancel": "취소",
"prefs_users_dialog_button_save": "저장", "prefs_users_dialog_button_save": "저장",
"prefs_appearance_title": "표시 설정", "prefs_appearance_title": "표시 설정",
"prefs_users_dialog_button_add": "추가", "prefs_users_dialog_button_add": "추가",
"prefs_appearance_language_title": "언어", "prefs_appearance_language_title": "언어",
"priority_min": "최하", "priority_min": "최하",
"priority_low": "낮음", "priority_low": "낮음",
"priority_default": "기본", "priority_default": "기본",
"priority_high": "높음", "priority_high": "높음",
"error_boundary_title": "이런, ntfy가 충돌했습니다", "error_boundary_title": "이런, ntfy가 충돌했습니다",
"error_boundary_button_copy_stack_trace": "스택 트레이스 복사", "error_boundary_button_copy_stack_trace": "스택 트레이스 복사",
"error_boundary_stack_trace": "스택 트레이스", "error_boundary_stack_trace": "스택 트레이스",
"error_boundary_gathering_info": "더 많은 정보 모으기 …", "error_boundary_gathering_info": "더 많은 정보 모으기 …",
"error_boundary_unsupported_indexeddb_title": "시크릿 모드는 지원되지 않습니다", "error_boundary_unsupported_indexeddb_title": "시크릿 모드는 지원되지 않습니다",
"notifications_click_copy_url_button": "링크 복사", "notifications_click_copy_url_button": "링크 복사",
"notifications_click_copy_url_title": "링크 URL을 클립보드에 복사", "notifications_click_copy_url_title": "링크 URL을 클립보드에 복사",
"notifications_attachment_file_video": "동영상 파일", "notifications_attachment_file_video": "동영상 파일",
"notifications_attachment_file_app": "안드로이드 앱 파일", "notifications_attachment_file_app": "안드로이드 앱 파일",
"notifications_attachment_file_document": "다른 문서", "notifications_attachment_file_document": "다른 문서",
"notifications_click_open_button": "링크 열기", "notifications_click_open_button": "링크 열기",
"notifications_actions_not_supported": "웹앱에서 지원되지 않는 동작입니다", "notifications_actions_not_supported": "웹앱에서 지원되지 않는 동작입니다",
"publish_dialog_title_topic": "{{topic}}에 발송", "publish_dialog_title_topic": "{{topic}}에 발송",
"alert_not_supported_description": "사용중인 브라우저에서 알림 기능을 지원하지 않습니다.", "alert_not_supported_description": "사용중인 브라우저에서 알림 기능을 지원하지 않습니다.",
"notifications_example": "예제", "notifications_example": "예제",
"notifications_more_details": "더 많은 정보가 필요하시다면 <websiteLink>웹사이트</websiteLink>나 <docsLink>문서</docsLink>를 참고하세요.", "notifications_more_details": "더 많은 정보가 필요하시다면 <websiteLink>웹사이트</websiteLink>나 <docsLink>문서</docsLink>를 참고하세요.",
"notifications_list": "알림 목록", "notifications_list": "알림 목록",
"notifications_attachment_open_button": "첨부 파일 열기", "notifications_attachment_open_button": "첨부 파일 열기",
"notifications_no_subscriptions_title": "아직 아무런 구독을 추가하지 않으신 것 같습니다.", "notifications_no_subscriptions_title": "아직 아무런 구독을 추가하지 않으신 것 같습니다.",
"nav_button_settings": "설정", "nav_button_settings": "설정",
"nav_button_documentation": "문서", "nav_button_documentation": "문서",
"notifications_attachment_link_expires": "링크가 {{date}}에 만료됨", "notifications_attachment_link_expires": "링크가 {{date}}에 만료됨",
"notifications_attachment_link_expired": "다운로드 링크 만료됨", "notifications_attachment_link_expired": "다운로드 링크 만료됨",
"notifications_attachment_file_audio": "음성 파일", "notifications_attachment_file_audio": "음성 파일",
"notifications_attachment_file_image": "사진 파일", "notifications_attachment_file_image": "사진 파일",
"notifications_actions_open_url_title": "{{url}]로 가기", "notifications_actions_open_url_title": "{{url}]로 가기",
"notifications_actions_http_request_title": "HTTP {{method}}를 {{url}}에 보내기", "notifications_actions_http_request_title": "HTTP {{method}}를 {{url}}에 보내기",
"notifications_none_for_topic_title": "아직 이 주제 관련 알림을 받지 않았습니다.", "notifications_none_for_topic_title": "아직 이 주제 관련 알림을 받지 않았습니다.",
"notifications_none_for_any_title": "아직 어떤 알림도 받지 않았습니다.", "notifications_none_for_any_title": "아직 어떤 알림도 받지 않았습니다.",
"notifications_none_for_any_description": "알림을 받으려면 아래 주소로 PUT이나 POST 요청을 보내세요. 구독중이신 주제 중 하나로 예를 들자면 다음과 같습니다.", "notifications_none_for_any_description": "알림을 받으려면 아래 주소로 PUT이나 POST 요청을 보내세요. 구독중이신 주제 중 하나로 예를 들자면 다음과 같습니다.",
"notifications_loading": "알림 불러오는중 …", "notifications_loading": "알림 불러오는중 …",
"publish_dialog_message_published": "알림 발송됨", "publish_dialog_message_published": "알림 발송됨",
"notifications_none_for_topic_description": "알림을 받으려면 아래 주소로 PUT이나 POST 요청을 보내세요.", "notifications_none_for_topic_description": "알림을 받으려면 아래 주소로 PUT이나 POST 요청을 보내세요.",
"notifications_no_subscriptions_description": "\"{{linktext}}\" 링크를 눌러서 주제를 생성하거나 구독하세요. 그 다음, 메세지를 PUT이나 POST로 보내면 여기에서 알림을 받으실 수 있습니다.", "notifications_no_subscriptions_description": "\"{{linktext}}\" 링크를 눌러서 주제를 생성하거나 구독하세요. 그 다음, 메세지를 PUT이나 POST로 보내면 여기에서 알림을 받으실 수 있습니다.",
"publish_dialog_progress_uploading": "업로드중 …", "publish_dialog_progress_uploading": "업로드중 …",
"publish_dialog_title_no_topic": "알림 발송", "publish_dialog_title_no_topic": "알림 발송",
"publish_dialog_progress_uploading_detail": "업로드중 {{loaded}}/{{total}} ({{percent}}%) …", "publish_dialog_progress_uploading_detail": "업로드중 {{loaded}}/{{total}} ({{percent}}%) …",
"publish_dialog_delay_placeholder": "알림 발송 지연, 예를 들면 {{unixTimestamp}}, {{relativeTime}} 또는 \"{{naturalLanguage}}\" (영어로 입력)", "publish_dialog_delay_placeholder": "알림 발송 지연, 예를 들면 {{unixTimestamp}}, {{relativeTime}} 또는 \"{{naturalLanguage}}\" (영어로 입력)",
"publish_dialog_delay_reset": "발송 지연 삭제", "publish_dialog_delay_reset": "발송 지연 삭제",
"publish_dialog_chip_click_label": "클릭 URL", "publish_dialog_chip_click_label": "클릭 URL",
"subscribe_dialog_login_description": "이 주제는 비밀번호로 보호되어 있습니다. 구독하시려면 사용자 이름과 비밀번호를 입력해주세요.", "subscribe_dialog_login_description": "이 주제는 비밀번호로 보호되어 있습니다. 구독하시려면 사용자 이름과 비밀번호를 입력해주세요.",
"prefs_notifications_min_priority_max_only": "우선순위 최상만", "prefs_notifications_min_priority_max_only": "우선순위 최상만",
"publish_dialog_other_features": "다른 기능:", "publish_dialog_other_features": "다른 기능:",
"prefs_notifications_min_priority_description_any": "우선순위 무관 모든 알림 보기", "prefs_notifications_min_priority_description_any": "우선순위 무관 모든 알림 보기",
"prefs_notifications_min_priority_high_and_higher": "우선순위 높음 이상", "prefs_notifications_min_priority_high_and_higher": "우선순위 높음 이상",
"error_boundary_unsupported_indexeddb_description": "ntfy 웹 앱은 동작하기 위해서 IndexedDB가 필요하지만 사용중이신 브라우저는 IndexedDB를 시크릿 모드에서 지원하지 않습니다.<br/><br/>안타깝지만 모든 정보는 브라우저에만 저장되므로 ntfy 웹앱을 시크릿 모드에서 사용할 이유는 존재하지 않습니다. <githubLink>이 깃허브 이슈</githubLink>를 참고해 보시거나, <discordLink>디스코드 서버</discordLink>나 <matrixLink>Matrix</matrixLink>에서 저희와 이야기를 나눌 수 있습니다.", "error_boundary_unsupported_indexeddb_description": "ntfy 웹 앱은 동작하기 위해서 IndexedDB가 필요하지만 사용중이신 브라우저는 IndexedDB를 시크릿 모드에서 지원하지 않습니다.<br/><br/>안타깝지만 모든 정보는 브라우저에만 저장되므로 ntfy 웹앱을 시크릿 모드에서 사용할 이유는 존재하지 않습니다. <githubLink>이 깃허브 이슈</githubLink>를 참고해 보시거나, <discordLink>디스코드 서버</discordLink>나 <matrixLink>Matrix</matrixLink>에서 저희와 이야기를 나눌 수 있습니다.",
"prefs_notifications_delete_after_title": "알림 삭제", "prefs_notifications_delete_after_title": "알림 삭제",
"prefs_notifications_delete_after_never": "삭제하지 않음", "prefs_notifications_delete_after_never": "삭제하지 않음",
"prefs_users_table": "사용자 테이블", "prefs_users_table": "사용자 테이블",
"prefs_users_dialog_username_label": "사용자 이름, 예를 들면 phil", "prefs_users_dialog_username_label": "사용자 이름, 예를 들면 phil",
"prefs_users_dialog_password_label": "비밀번호", "prefs_users_dialog_password_label": "비밀번호",
"priority_max": "최상", "priority_max": "최상",
"error_boundary_description": "이것은 당연히 발생되어서는 안됩니다. 굉장히 죄송합니다.<br/>가능하시다면 <githubLink>이 문제를 깃허브에 제보</githubLink>해 주시거나, <discordLink>디스코드 서버</discordLink>나 <matrixLink>Matrix</matrixLink>를 통해 알려주세요." "error_boundary_description": "이것은 당연히 발생되어서는 안됩니다. 굉장히 죄송합니다.<br/>가능하시다면 <githubLink>이 문제를 깃허브에 제보</githubLink>해 주시거나, <discordLink>디스코드 서버</discordLink>나 <matrixLink>Matrix</matrixLink>를 통해 알려주세요."
} }

View file

@ -1,126 +1,126 @@
{ {
"nav_button_subscribe": "Abonner på emne", "nav_button_subscribe": "Abonner på emne",
"action_bar_settings": "Innstillinger", "action_bar_settings": "Innstillinger",
"action_bar_send_test_notification": "Send testmerknad", "action_bar_send_test_notification": "Send testmerknad",
"action_bar_clear_notifications": "Tøm alle merknader", "action_bar_clear_notifications": "Tøm alle merknader",
"action_bar_unsubscribe": "Opphev abonnement", "action_bar_unsubscribe": "Opphev abonnement",
"message_bar_type_message": "Skriv en melding her", "message_bar_type_message": "Skriv en melding her",
"nav_button_all_notifications": "Alle merknader", "nav_button_all_notifications": "Alle merknader",
"nav_button_settings": "Innstillinger", "nav_button_settings": "Innstillinger",
"nav_button_documentation": "Dokumentasjon", "nav_button_documentation": "Dokumentasjon",
"nav_topics_title": "Abonnerte emner", "nav_topics_title": "Abonnerte emner",
"alert_grant_title": "Merknader er avskrudd", "alert_grant_title": "Merknader er avskrudd",
"alert_not_supported_title": "Merknader støttes ikke", "alert_not_supported_title": "Merknader støttes ikke",
"notifications_copied_to_clipboard": "Kopiert til utklippstavlen", "notifications_copied_to_clipboard": "Kopiert til utklippstavlen",
"notifications_attachment_copy_url_title": "Kopier vedleggsnettadresse til utklippstavlen", "notifications_attachment_copy_url_title": "Kopier vedleggsnettadresse til utklippstavlen",
"notifications_attachment_copy_url_button": "Kopier nettadresse", "notifications_attachment_copy_url_button": "Kopier nettadresse",
"notifications_attachment_open_button": "Åpne vedlegg", "notifications_attachment_open_button": "Åpne vedlegg",
"notifications_attachment_open_title": "Gå til {{url}}", "notifications_attachment_open_title": "Gå til {{url}}",
"notifications_attachment_link_expires": "lenken utløper {{date}}", "notifications_attachment_link_expires": "lenken utløper {{date}}",
"notifications_click_copy_url_title": "Kopier lenke-nettadresse til utklippstavlen", "notifications_click_copy_url_title": "Kopier lenke-nettadresse til utklippstavlen",
"notifications_actions_open_url_title": "Gå til {{url}}", "notifications_actions_open_url_title": "Gå til {{url}}",
"notifications_tags": "Etiketter", "notifications_tags": "Etiketter",
"notifications_attachment_link_expired": "nedlastingslenken har utløpt", "notifications_attachment_link_expired": "nedlastingslenken har utløpt",
"notifications_none_for_any_title": "Du har ikke mottatt noen merknader.", "notifications_none_for_any_title": "Du har ikke mottatt noen merknader.",
"notifications_click_open_button": "Åpne lenke", "notifications_click_open_button": "Åpne lenke",
"notifications_none_for_topic_title": "Du har ikke mottatt noen merknader for dette emnet enda.", "notifications_none_for_topic_title": "Du har ikke mottatt noen merknader for dette emnet enda.",
"notifications_example": "Eksempel", "notifications_example": "Eksempel",
"publish_dialog_title_topic": "Publiser til {{topic}}", "publish_dialog_title_topic": "Publiser til {{topic}}",
"publish_dialog_priority_min": "Min. prioritet", "publish_dialog_priority_min": "Min. prioritet",
"publish_dialog_priority_low": "Lav prioritet", "publish_dialog_priority_low": "Lav prioritet",
"publish_dialog_priority_default": "Forvalgt prioritet", "publish_dialog_priority_default": "Forvalgt prioritet",
"publish_dialog_priority_high": "Høy prioritet", "publish_dialog_priority_high": "Høy prioritet",
"publish_dialog_priority_max": "Maks. prioritet", "publish_dialog_priority_max": "Maks. prioritet",
"publish_dialog_base_url_label": "Tjeneste-nettadresse", "publish_dialog_base_url_label": "Tjeneste-nettadresse",
"publish_dialog_message_label": "Melding", "publish_dialog_message_label": "Melding",
"publish_dialog_priority_label": "Prioritet", "publish_dialog_priority_label": "Prioritet",
"publish_dialog_tags_label": "Etiketter", "publish_dialog_tags_label": "Etiketter",
"publish_dialog_click_placeholder": "Nettadresse som åpnes når merknaden klikkes", "publish_dialog_click_placeholder": "Nettadresse som åpnes når merknaden klikkes",
"publish_dialog_attach_label": "Vedleggs-nettadresse", "publish_dialog_attach_label": "Vedleggs-nettadresse",
"publish_dialog_attach_placeholder": "Legg ved fil per nettadresse, f.eks. https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "Legg ved fil per nettadresse, f.eks. https://f-droid.org/F-Droid.apk",
"publish_dialog_filename_label": "Filnavn", "publish_dialog_filename_label": "Filnavn",
"publish_dialog_delay_label": "Forsinkelse", "publish_dialog_delay_label": "Forsinkelse",
"publish_dialog_filename_placeholder": "Vedleggets filnavn", "publish_dialog_filename_placeholder": "Vedleggets filnavn",
"publish_dialog_other_features": "Andre funksjoner:", "publish_dialog_other_features": "Andre funksjoner:",
"publish_dialog_chip_email_label": "Videresend til e-post", "publish_dialog_chip_email_label": "Videresend til e-post",
"publish_dialog_chip_topic_label": "Endre emne", "publish_dialog_chip_topic_label": "Endre emne",
"publish_dialog_button_cancel_sending": "Avbryt forsendelse", "publish_dialog_button_cancel_sending": "Avbryt forsendelse",
"publish_dialog_chip_attach_file_label": "Legg ved lokal fil", "publish_dialog_chip_attach_file_label": "Legg ved lokal fil",
"publish_dialog_attached_file_title": "Vedlagt fil:", "publish_dialog_attached_file_title": "Vedlagt fil:",
"publish_dialog_attached_file_filename_placeholder": "Vedleggsfilnavn", "publish_dialog_attached_file_filename_placeholder": "Vedleggsfilnavn",
"subscribe_dialog_subscribe_use_another_label": "Bruk en annen tjener", "subscribe_dialog_subscribe_use_another_label": "Bruk en annen tjener",
"subscribe_dialog_subscribe_button_cancel": "Avbryt", "subscribe_dialog_subscribe_button_cancel": "Avbryt",
"publish_dialog_drop_file_here": "Slipp filen her", "publish_dialog_drop_file_here": "Slipp filen her",
"subscribe_dialog_subscribe_title": "Abonner på emne", "subscribe_dialog_subscribe_title": "Abonner på emne",
"emoji_picker_search_placeholder": "Søk etter emoji", "emoji_picker_search_placeholder": "Søk etter emoji",
"subscribe_dialog_login_button_login": "Logg inn", "subscribe_dialog_login_button_login": "Logg inn",
"subscribe_dialog_subscribe_button_subscribe": "Abonner", "subscribe_dialog_subscribe_button_subscribe": "Abonner",
"subscribe_dialog_login_title": "Innlogging kreves", "subscribe_dialog_login_title": "Innlogging kreves",
"subscribe_dialog_login_username_label": "Brukernavn, f.eks. phil", "subscribe_dialog_login_username_label": "Brukernavn, f.eks. phil",
"subscribe_dialog_login_password_label": "Passord", "subscribe_dialog_login_password_label": "Passord",
"prefs_notifications_title": "Merknader", "prefs_notifications_title": "Merknader",
"prefs_notifications_sound_title": "Merknadslyd", "prefs_notifications_sound_title": "Merknadslyd",
"prefs_notifications_sound_no_sound": "Ingen lyd", "prefs_notifications_sound_no_sound": "Ingen lyd",
"subscribe_dialog_error_user_anonymous": "anonym", "subscribe_dialog_error_user_anonymous": "anonym",
"error_boundary_stack_trace": "Stabelspor", "error_boundary_stack_trace": "Stabelspor",
"error_boundary_button_copy_stack_trace": "Kopier stabelspor", "error_boundary_button_copy_stack_trace": "Kopier stabelspor",
"message_bar_error_publishing": "Kunne ikke publisere merknader", "message_bar_error_publishing": "Kunne ikke publisere merknader",
"nav_button_publish_message": "Publiser merknad", "nav_button_publish_message": "Publiser merknad",
"publish_dialog_title_no_topic": "Publiser merknad", "publish_dialog_title_no_topic": "Publiser merknad",
"publish_dialog_progress_uploading": "Laster opp …", "publish_dialog_progress_uploading": "Laster opp …",
"publish_dialog_progress_uploading_detail": "Laster opp {{loaded}}/{{total}} ({{percent}}%) …", "publish_dialog_progress_uploading_detail": "Laster opp {{loaded}}/{{total}} ({{percent}}%) …",
"notifications_loading": "Laster inn merknader …", "notifications_loading": "Laster inn merknader …",
"publish_dialog_message_published": "Merknad publisert", "publish_dialog_message_published": "Merknad publisert",
"publish_dialog_email_placeholder": "Adresse å videresende merknaden til, f.eks. phil@example.com", "publish_dialog_email_placeholder": "Adresse å videresende merknaden til, f.eks. phil@example.com",
"error_boundary_gathering_info": "Hent mer info …", "error_boundary_gathering_info": "Hent mer info …",
"prefs_notifications_sound_description_some": "Merknader spiller {{sound}}-lyd når de mottas", "prefs_notifications_sound_description_some": "Merknader spiller {{sound}}-lyd når de mottas",
"prefs_notifications_min_priority_description_any": "Viser aller merknader, uavhengig av prioritet", "prefs_notifications_min_priority_description_any": "Viser aller merknader, uavhengig av prioritet",
"prefs_notifications_min_priority_description_x_or_higher": "Vis merknader hvis prioritet er {{number}} ({{name}}) eller høyere", "prefs_notifications_min_priority_description_x_or_higher": "Vis merknader hvis prioritet er {{number}} ({{name}}) eller høyere",
"prefs_notifications_min_priority_high_and_higher": "Høy prioritet og høyere", "prefs_notifications_min_priority_high_and_higher": "Høy prioritet og høyere",
"prefs_notifications_min_priority_max_only": "Kun maks. prioritet", "prefs_notifications_min_priority_max_only": "Kun maks. prioritet",
"prefs_notifications_delete_after_one_day": "Etter én dag", "prefs_notifications_delete_after_one_day": "Etter én dag",
"prefs_notifications_delete_after_one_week": "Etter én uke", "prefs_notifications_delete_after_one_week": "Etter én uke",
"prefs_notifications_delete_after_one_month": "Etter én måned", "prefs_notifications_delete_after_one_month": "Etter én måned",
"prefs_notifications_delete_after_never_description": "Merknader blir aldri slettet automatisk", "prefs_notifications_delete_after_never_description": "Merknader blir aldri slettet automatisk",
"prefs_notifications_delete_after_three_hours_description": "Merknader slettes automatisk etter tre timer", "prefs_notifications_delete_after_three_hours_description": "Merknader slettes automatisk etter tre timer",
"prefs_users_title": "Håndter brukere", "prefs_users_title": "Håndter brukere",
"prefs_users_add_button": "Legg til bruker", "prefs_users_add_button": "Legg til bruker",
"prefs_users_table_user_header": "Bruker", "prefs_users_table_user_header": "Bruker",
"prefs_users_dialog_title_add": "Legg til bruker", "prefs_users_dialog_title_add": "Legg til bruker",
"prefs_users_dialog_title_edit": "Rediger bruker", "prefs_users_dialog_title_edit": "Rediger bruker",
"prefs_users_dialog_base_url_label": "Tjeneste-nettadresse, f.eks. https://ntfy.sh", "prefs_users_dialog_base_url_label": "Tjeneste-nettadresse, f.eks. https://ntfy.sh",
"prefs_users_dialog_password_label": "Passord", "prefs_users_dialog_password_label": "Passord",
"prefs_users_dialog_button_save": "Lagre", "prefs_users_dialog_button_save": "Lagre",
"prefs_appearance_title": "Utseende", "prefs_appearance_title": "Utseende",
"prefs_appearance_language_title": "Språk", "prefs_appearance_language_title": "Språk",
"prefs_users_dialog_username_label": "Brukernavn, f.eks. phil", "prefs_users_dialog_username_label": "Brukernavn, f.eks. phil",
"priority_low": "lav", "priority_low": "lav",
"priority_default": "forvalg", "priority_default": "forvalg",
"priority_high": "høy", "priority_high": "høy",
"priority_max": "maks.", "priority_max": "maks.",
"alert_grant_button": "Innvilg nå", "alert_grant_button": "Innvilg nå",
"publish_dialog_topic_label": "Emnenavn", "publish_dialog_topic_label": "Emnenavn",
"prefs_notifications_delete_after_one_day_description": "Merknader slettes automatisk etter én dag", "prefs_notifications_delete_after_one_day_description": "Merknader slettes automatisk etter én dag",
"notifications_click_copy_url_button": "Kopier lenke", "notifications_click_copy_url_button": "Kopier lenke",
"error_boundary_title": "Oida. Ntfy krasjet.", "error_boundary_title": "Oida. Ntfy krasjet.",
"publish_dialog_message_placeholder": "Skriv en melding her", "publish_dialog_message_placeholder": "Skriv en melding her",
"publish_dialog_button_cancel": "Avbryt", "publish_dialog_button_cancel": "Avbryt",
"prefs_notifications_min_priority_title": "Minimumsprioritet", "prefs_notifications_min_priority_title": "Minimumsprioritet",
"prefs_notifications_delete_after_title": "Slett merknader", "prefs_notifications_delete_after_title": "Slett merknader",
"prefs_notifications_delete_after_never": "Aldri", "prefs_notifications_delete_after_never": "Aldri",
"publish_dialog_email_label": "E-post", "publish_dialog_email_label": "E-post",
"publish_dialog_button_send": "Send", "publish_dialog_button_send": "Send",
"prefs_notifications_delete_after_one_week_description": "Merknader slettes automatisk etter én uke", "prefs_notifications_delete_after_one_week_description": "Merknader slettes automatisk etter én uke",
"prefs_notifications_delete_after_one_month_description": "Merknader slettes automatisk etter én måned", "prefs_notifications_delete_after_one_month_description": "Merknader slettes automatisk etter én måned",
"priority_min": "min.", "priority_min": "min.",
"subscribe_dialog_login_button_back": "Tilbake", "subscribe_dialog_login_button_back": "Tilbake",
"prefs_notifications_delete_after_three_hours": "Etter tre timer", "prefs_notifications_delete_after_three_hours": "Etter tre timer",
"prefs_users_table_base_url_header": "Tjeneste-nettadresse", "prefs_users_table_base_url_header": "Tjeneste-nettadresse",
"prefs_users_dialog_button_cancel": "Avbryt", "prefs_users_dialog_button_cancel": "Avbryt",
"prefs_users_dialog_button_add": "Legg til", "prefs_users_dialog_button_add": "Legg til",
"publish_dialog_chip_attach_url_label": "Legg ved fil per nettadresse", "publish_dialog_chip_attach_url_label": "Legg ved fil per nettadresse",
"publish_dialog_tags_placeholder": "Kommainndelt liste over etiketter, f.eks. advarsel, srv1-sikkerhetskopi", "publish_dialog_tags_placeholder": "Kommainndelt liste over etiketter, f.eks. advarsel, srv1-sikkerhetskopi",
"prefs_notifications_sound_description_none": "Merknader er lydløse når de mottas", "prefs_notifications_sound_description_none": "Merknader er lydløse når de mottas",
"subscribe_dialog_subscribe_topic_placeholder": "Emnenavn, f.eks. phil_varsler", "subscribe_dialog_subscribe_topic_placeholder": "Emnenavn, f.eks. phil_varsler",
"prefs_notifications_min_priority_default_and_higher": "Forvalgt prioritet og høyere" "prefs_notifications_min_priority_default_and_higher": "Forvalgt prioritet og høyere"
} }

View file

@ -1,191 +1,191 @@
{ {
"action_bar_settings": "Instellingen", "action_bar_settings": "Instellingen",
"action_bar_send_test_notification": "Stuur test notificatie", "action_bar_send_test_notification": "Stuur test notificatie",
"action_bar_clear_notifications": "Wis alle notificaties", "action_bar_clear_notifications": "Wis alle notificaties",
"message_bar_type_message": "Typ hier een bericht", "message_bar_type_message": "Typ hier een bericht",
"action_bar_unsubscribe": "Afmelden", "action_bar_unsubscribe": "Afmelden",
"message_bar_error_publishing": "Fout bij publiceren notificatie", "message_bar_error_publishing": "Fout bij publiceren notificatie",
"nav_topics_title": "Geabonneerde onderwerpen", "nav_topics_title": "Geabonneerde onderwerpen",
"nav_button_settings": "Instellingen", "nav_button_settings": "Instellingen",
"alert_not_supported_description": "Notificaties worden niet ondersteund in je browser.", "alert_not_supported_description": "Notificaties worden niet ondersteund in je browser.",
"notifications_none_for_any_title": "Je hebt nog geen notificaties ontvangen.", "notifications_none_for_any_title": "Je hebt nog geen notificaties ontvangen.",
"publish_dialog_tags_label": "Tags", "publish_dialog_tags_label": "Tags",
"publish_dialog_chip_attach_file_label": "Lokaal bestand bijvoegen", "publish_dialog_chip_attach_file_label": "Lokaal bestand bijvoegen",
"prefs_users_dialog_title_edit": "Gebruiker bewerken", "prefs_users_dialog_title_edit": "Gebruiker bewerken",
"error_boundary_title": "Oh nee, ntfy is vastgelopen", "error_boundary_title": "Oh nee, ntfy is vastgelopen",
"error_boundary_description": "Dit hoort natuurlijk niet te gebeuren. Onze excuses.<br/>Wanneer het mogelijk is, <githubLink>meld deze fout op GitHub</githubLink>, of laat het ons weten via <discordLink>Discord</discordLink> of <matrixLink>Matrix</matrixLink>.", "error_boundary_description": "Dit hoort natuurlijk niet te gebeuren. Onze excuses.<br/>Wanneer het mogelijk is, <githubLink>meld deze fout op GitHub</githubLink>, of laat het ons weten via <discordLink>Discord</discordLink> of <matrixLink>Matrix</matrixLink>.",
"error_boundary_button_copy_stack_trace": "Stack trace kopiëren", "error_boundary_button_copy_stack_trace": "Stack trace kopiëren",
"error_boundary_stack_trace": "Stacktrace", "error_boundary_stack_trace": "Stacktrace",
"error_boundary_gathering_info": "Meer informatie verzamelen …", "error_boundary_gathering_info": "Meer informatie verzamelen …",
"prefs_users_delete_button": "Gebruiker verwijderen", "prefs_users_delete_button": "Gebruiker verwijderen",
"prefs_notifications_delete_after_one_week": "Na één week", "prefs_notifications_delete_after_one_week": "Na één week",
"prefs_notifications_delete_after_one_month": "Na één maand", "prefs_notifications_delete_after_one_month": "Na één maand",
"prefs_users_dialog_title_add": "Gebruiker toevoegen", "prefs_users_dialog_title_add": "Gebruiker toevoegen",
"prefs_users_dialog_password_label": "Wachtwoord", "prefs_users_dialog_password_label": "Wachtwoord",
"error_boundary_unsupported_indexeddb_description": "De ntfy web applicatie heeft IndexedDB nodig om correct te kunnen functioneren, helaas ondersteund jouw browser IndexedDB niet in privé / incognito modus.<br/><br/>Dit is jammer maar het is ook onlogisch om de ntfy web applicatie in privé / incognito modus te gebruiken want alle gegevens worden bewaard in de browser zijn lokale opslag. Je kan hier meer over lezen <githubLink>in deze GitHub issue</githubLink>, of praat met ons op <discordLink>Discord</discordLink> of <matrixLink>Matrix</matrixLink>.", "error_boundary_unsupported_indexeddb_description": "De ntfy web applicatie heeft IndexedDB nodig om correct te kunnen functioneren, helaas ondersteund jouw browser IndexedDB niet in privé / incognito modus.<br/><br/>Dit is jammer maar het is ook onlogisch om de ntfy web applicatie in privé / incognito modus te gebruiken want alle gegevens worden bewaard in de browser zijn lokale opslag. Je kan hier meer over lezen <githubLink>in deze GitHub issue</githubLink>, of praat met ons op <discordLink>Discord</discordLink> of <matrixLink>Matrix</matrixLink>.",
"action_bar_show_menu": "Toon menu", "action_bar_show_menu": "Toon menu",
"action_bar_logo_alt": "ntfy logo", "action_bar_logo_alt": "ntfy logo",
"action_bar_toggle_mute": "Notificaties dempen/opheffen", "action_bar_toggle_mute": "Notificaties dempen/opheffen",
"action_bar_toggle_action_menu": "Actie menu openen/sluiten", "action_bar_toggle_action_menu": "Actie menu openen/sluiten",
"message_bar_show_dialog": "Toon publicatie venster", "message_bar_show_dialog": "Toon publicatie venster",
"message_bar_publish": "Bericht publiceren", "message_bar_publish": "Bericht publiceren",
"nav_button_all_notifications": "Alle notificaties", "nav_button_all_notifications": "Alle notificaties",
"nav_button_documentation": "Documentatie", "nav_button_documentation": "Documentatie",
"nav_button_publish_message": "Notificatie publiceren", "nav_button_publish_message": "Notificatie publiceren",
"nav_button_subscribe": "Onderwerp abonneren", "nav_button_subscribe": "Onderwerp abonneren",
"nav_button_muted": "Notificaties gedempt", "nav_button_muted": "Notificaties gedempt",
"nav_button_connecting": "verbinden", "nav_button_connecting": "verbinden",
"alert_grant_title": "Notificaties zijn uitgeschakeld", "alert_grant_title": "Notificaties zijn uitgeschakeld",
"alert_grant_description": "Geef je browser toestemming om meldingen weer te geven.", "alert_grant_description": "Geef je browser toestemming om meldingen weer te geven.",
"alert_grant_button": "Nu toestaan", "alert_grant_button": "Nu toestaan",
"alert_not_supported_title": "Notificaties zijn niet ondersteund", "alert_not_supported_title": "Notificaties zijn niet ondersteund",
"notifications_list": "Notificaties lijst", "notifications_list": "Notificaties lijst",
"notifications_list_item": "Notificatie", "notifications_list_item": "Notificatie",
"notifications_mark_read": "Markeer als gelezen", "notifications_mark_read": "Markeer als gelezen",
"notifications_delete": "Verwijder", "notifications_delete": "Verwijder",
"notifications_copied_to_clipboard": "Gekopieerd naar klembord", "notifications_copied_to_clipboard": "Gekopieerd naar klembord",
"notifications_tags": "Tags", "notifications_tags": "Tags",
"notifications_priority_x": "Prioriteit {{priority}}", "notifications_priority_x": "Prioriteit {{priority}}",
"notifications_new_indicator": "Nieuwe notificatie", "notifications_new_indicator": "Nieuwe notificatie",
"notifications_attachment_image": "Afbeelding bijlage", "notifications_attachment_image": "Afbeelding bijlage",
"notifications_attachment_copy_url_title": "Kopieer URL van bijlage naar klembord", "notifications_attachment_copy_url_title": "Kopieer URL van bijlage naar klembord",
"notifications_attachment_copy_url_button": "URL kopiëren", "notifications_attachment_copy_url_button": "URL kopiëren",
"notifications_attachment_open_title": "Ga naar {{url}}", "notifications_attachment_open_title": "Ga naar {{url}}",
"notifications_attachment_open_button": "Bijlage openen", "notifications_attachment_open_button": "Bijlage openen",
"notifications_attachment_link_expires": "link vervalt op {{date}}", "notifications_attachment_link_expires": "link vervalt op {{date}}",
"notifications_attachment_link_expired": "download link is verlopen", "notifications_attachment_link_expired": "download link is verlopen",
"notifications_attachment_file_image": "afbeeldingsbestand", "notifications_attachment_file_image": "afbeeldingsbestand",
"notifications_attachment_file_video": "videobestand", "notifications_attachment_file_video": "videobestand",
"notifications_attachment_file_audio": "audiobestand", "notifications_attachment_file_audio": "audiobestand",
"notifications_attachment_file_app": "Android app bestand", "notifications_attachment_file_app": "Android app bestand",
"notifications_attachment_file_document": "overig document", "notifications_attachment_file_document": "overig document",
"notifications_click_copy_url_title": "URL naar klembord kopiëren", "notifications_click_copy_url_title": "URL naar klembord kopiëren",
"notifications_click_copy_url_button": "Link kopiëren", "notifications_click_copy_url_button": "Link kopiëren",
"notifications_click_open_button": "Link openen", "notifications_click_open_button": "Link openen",
"notifications_none_for_topic_description": "Om notificaties naar dit onderwerp te sturen, doe een PUT of POST naar de URL van het onderwerp.", "notifications_none_for_topic_description": "Om notificaties naar dit onderwerp te sturen, doe een PUT of POST naar de URL van het onderwerp.",
"notifications_none_for_any_description": "Om notificaties naar dit onderwerp te sturen, doe een PUT of POST naar de URL van het onderwerp. Hier is een voorbeeld met één van je onderwerpen.", "notifications_none_for_any_description": "Om notificaties naar dit onderwerp te sturen, doe een PUT of POST naar de URL van het onderwerp. Hier is een voorbeeld met één van je onderwerpen.",
"notifications_no_subscriptions_title": "Het lijkt erop dat je nog op geen onderwerpen geabonneerd bent.", "notifications_no_subscriptions_title": "Het lijkt erop dat je nog op geen onderwerpen geabonneerd bent.",
"notifications_no_subscriptions_description": "Klik op de \"{{linktext}}\" link om een onderwerp te maken of erop te abonneren. Daarna kan je berichten sturen via PUT of POST and ontvang je hier notificaties.", "notifications_no_subscriptions_description": "Klik op de \"{{linktext}}\" link om een onderwerp te maken of erop te abonneren. Daarna kan je berichten sturen via PUT of POST and ontvang je hier notificaties.",
"notifications_example": "Voorbeeld", "notifications_example": "Voorbeeld",
"notifications_more_details": "Voor meer informatie, bezoek de <websiteLink>website</websiteLink> of <docsLink>documentatie</docsLink>.", "notifications_more_details": "Voor meer informatie, bezoek de <websiteLink>website</websiteLink> of <docsLink>documentatie</docsLink>.",
"notifications_loading": "Notificaties laden …", "notifications_loading": "Notificaties laden …",
"publish_dialog_title_topic": "Publiceren naar {{topic}}", "publish_dialog_title_topic": "Publiceren naar {{topic}}",
"publish_dialog_title_no_topic": "Notificatie publiceren", "publish_dialog_title_no_topic": "Notificatie publiceren",
"publish_dialog_progress_uploading": "Uploaden …", "publish_dialog_progress_uploading": "Uploaden …",
"notifications_actions_open_url_title": "Ga naar {{url}}", "notifications_actions_open_url_title": "Ga naar {{url}}",
"notifications_actions_not_supported": "Deze actie is niet ondersteund in de web applicatie", "notifications_actions_not_supported": "Deze actie is niet ondersteund in de web applicatie",
"notifications_actions_http_request_title": "Stuur HTTP {{method}} naar {{url}}", "notifications_actions_http_request_title": "Stuur HTTP {{method}} naar {{url}}",
"notifications_none_for_topic_title": "Je hebt nog geen notificaties ontvangen voor dit onderwerp.", "notifications_none_for_topic_title": "Je hebt nog geen notificaties ontvangen voor dit onderwerp.",
"publish_dialog_priority_low": "Lage prioriteit", "publish_dialog_priority_low": "Lage prioriteit",
"publish_dialog_progress_uploading_detail": "Uploaden {{loaded}}/{{total}} ({{percent}}%) …", "publish_dialog_progress_uploading_detail": "Uploaden {{loaded}}/{{total}} ({{percent}}%) …",
"publish_dialog_message_published": "Notificatie gepubliceerd", "publish_dialog_message_published": "Notificatie gepubliceerd",
"publish_dialog_attachment_limits_file_and_quota_reached": "overschrijd {{fileSizeLimit}} bestandslimiet en quotum, {{remainingBytes}} resterend", "publish_dialog_attachment_limits_file_and_quota_reached": "overschrijd {{fileSizeLimit}} bestandslimiet en quotum, {{remainingBytes}} resterend",
"publish_dialog_attachment_limits_file_reached": "overschrijd {{fileSizeLimit}} bestandslimiet", "publish_dialog_attachment_limits_file_reached": "overschrijd {{fileSizeLimit}} bestandslimiet",
"publish_dialog_priority_default": "Standaard prioriteit", "publish_dialog_priority_default": "Standaard prioriteit",
"publish_dialog_attachment_limits_quota_reached": "overschrijd quotum, {{remainingBytes}} resterend", "publish_dialog_attachment_limits_quota_reached": "overschrijd quotum, {{remainingBytes}} resterend",
"publish_dialog_emoji_picker_show": "Kies een emoji", "publish_dialog_emoji_picker_show": "Kies een emoji",
"publish_dialog_priority_high": "Hoge prioriteit", "publish_dialog_priority_high": "Hoge prioriteit",
"publish_dialog_priority_max": "Maximale prioriteit", "publish_dialog_priority_max": "Maximale prioriteit",
"publish_dialog_priority_min": "Minimale prioriteit", "publish_dialog_priority_min": "Minimale prioriteit",
"publish_dialog_base_url_label": "Service URL", "publish_dialog_base_url_label": "Service URL",
"publish_dialog_base_url_placeholder": "Service URL, bijvoorbeeld: https://voorbeeld.com", "publish_dialog_base_url_placeholder": "Service URL, bijvoorbeeld: https://voorbeeld.com",
"publish_dialog_topic_label": "Onderwerp", "publish_dialog_topic_label": "Onderwerp",
"publish_dialog_topic_placeholder": "Onderwerp, bijv. phil_alerts", "publish_dialog_topic_placeholder": "Onderwerp, bijv. phil_alerts",
"publish_dialog_topic_reset": "Onderwerp resetten", "publish_dialog_topic_reset": "Onderwerp resetten",
"publish_dialog_title_label": "Titel", "publish_dialog_title_label": "Titel",
"publish_dialog_title_placeholder": "Notificatie titel , bijv. Schijfruimte alarm", "publish_dialog_title_placeholder": "Notificatie titel , bijv. Schijfruimte alarm",
"publish_dialog_message_label": "Bericht", "publish_dialog_message_label": "Bericht",
"publish_dialog_message_placeholder": "Typ hier een bericht", "publish_dialog_message_placeholder": "Typ hier een bericht",
"publish_dialog_tags_placeholder": "Komma gescheiden lijst met tags, bijv. waarschuwing, srv1-backup", "publish_dialog_tags_placeholder": "Komma gescheiden lijst met tags, bijv. waarschuwing, srv1-backup",
"publish_dialog_priority_label": "Prioriteit", "publish_dialog_priority_label": "Prioriteit",
"publish_dialog_click_label": "Klik URL", "publish_dialog_click_label": "Klik URL",
"publish_dialog_click_reset": "Verwijder klik URL", "publish_dialog_click_reset": "Verwijder klik URL",
"publish_dialog_email_label": "Email", "publish_dialog_email_label": "Email",
"publish_dialog_email_placeholder": "Adres om de notificatie naar door te sturen, bijv. phil@voorbeeld.com", "publish_dialog_email_placeholder": "Adres om de notificatie naar door te sturen, bijv. phil@voorbeeld.com",
"publish_dialog_email_reset": "Email doorsturen verwijderen", "publish_dialog_email_reset": "Email doorsturen verwijderen",
"publish_dialog_attach_label": "URL van bijlage", "publish_dialog_attach_label": "URL van bijlage",
"publish_dialog_click_placeholder": "URL die geopend zal worden wanneer op de notificatie geklikt wordt", "publish_dialog_click_placeholder": "URL die geopend zal worden wanneer op de notificatie geklikt wordt",
"publish_dialog_attach_placeholder": "Bestand bijvoegen via URL, bijv. https://f-droid.org/F-Droid.apk", "publish_dialog_attach_placeholder": "Bestand bijvoegen via URL, bijv. https://f-droid.org/F-Droid.apk",
"publish_dialog_attach_reset": "Bijlage URL verwijderen", "publish_dialog_attach_reset": "Bijlage URL verwijderen",
"publish_dialog_filename_label": "Bestandsnaam", "publish_dialog_filename_label": "Bestandsnaam",
"publish_dialog_filename_placeholder": "Bestandsnaam van bijlage", "publish_dialog_filename_placeholder": "Bestandsnaam van bijlage",
"publish_dialog_delay_label": "Uitstellen", "publish_dialog_delay_label": "Uitstellen",
"publish_dialog_delay_placeholder": "Bezorging uitstellen, bijv. {{unixTimestamp}}, {{relativeTime}}, of \"{{naturalLanguage}}\" (alleen Engels)", "publish_dialog_delay_placeholder": "Bezorging uitstellen, bijv. {{unixTimestamp}}, {{relativeTime}}, of \"{{naturalLanguage}}\" (alleen Engels)",
"publish_dialog_delay_reset": "Verwijder uitgestelde bezorging", "publish_dialog_delay_reset": "Verwijder uitgestelde bezorging",
"publish_dialog_other_features": "Andere functionaliteiten:", "publish_dialog_other_features": "Andere functionaliteiten:",
"publish_dialog_chip_click_label": "Klik URL", "publish_dialog_chip_click_label": "Klik URL",
"publish_dialog_chip_email_label": "Doorsturen naar email", "publish_dialog_chip_email_label": "Doorsturen naar email",
"publish_dialog_chip_attach_url_label": "Bestand bijvoegen via URL", "publish_dialog_chip_attach_url_label": "Bestand bijvoegen via URL",
"publish_dialog_chip_delay_label": "Uitgestelde bezorging", "publish_dialog_chip_delay_label": "Uitgestelde bezorging",
"publish_dialog_chip_topic_label": "Onderwerp veranderen", "publish_dialog_chip_topic_label": "Onderwerp veranderen",
"publish_dialog_details_examples_description": "Voor meer voorbeelden en gedetailleerde beschrijvingen van alle functionaliteiten, bekijk de <docsLink>documentatie</docsLink>.", "publish_dialog_details_examples_description": "Voor meer voorbeelden en gedetailleerde beschrijvingen van alle functionaliteiten, bekijk de <docsLink>documentatie</docsLink>.",
"publish_dialog_button_cancel_sending": "Versturen annuleren", "publish_dialog_button_cancel_sending": "Versturen annuleren",
"publish_dialog_button_cancel": "Annuleer", "publish_dialog_button_cancel": "Annuleer",
"publish_dialog_button_send": "Verstuur", "publish_dialog_button_send": "Verstuur",
"publish_dialog_checkbox_publish_another": "Nog een bericht versturen", "publish_dialog_checkbox_publish_another": "Nog een bericht versturen",
"publish_dialog_attached_file_title": "Bijgevoegd bestand:", "publish_dialog_attached_file_title": "Bijgevoegd bestand:",
"publish_dialog_attached_file_filename_placeholder": "Bijlage bestandsnaam", "publish_dialog_attached_file_filename_placeholder": "Bijlage bestandsnaam",
"publish_dialog_attached_file_remove": "Verwijder bijgevoegd bestand", "publish_dialog_attached_file_remove": "Verwijder bijgevoegd bestand",
"publish_dialog_drop_file_here": "Bestand hier slepen", "publish_dialog_drop_file_here": "Bestand hier slepen",
"emoji_picker_search_placeholder": "Emoji zoeken", "emoji_picker_search_placeholder": "Emoji zoeken",
"emoji_picker_search_clear": "Zoeken leegmaken", "emoji_picker_search_clear": "Zoeken leegmaken",
"subscribe_dialog_subscribe_topic_placeholder": "Onderwerp naam, bijv. phils_waarschuwingen", "subscribe_dialog_subscribe_topic_placeholder": "Onderwerp naam, bijv. phils_waarschuwingen",
"subscribe_dialog_subscribe_use_another_label": "Gebruik een andere server", "subscribe_dialog_subscribe_use_another_label": "Gebruik een andere server",
"subscribe_dialog_subscribe_base_url_label": "Service URL", "subscribe_dialog_subscribe_base_url_label": "Service URL",
"subscribe_dialog_subscribe_button_cancel": "Annuleren", "subscribe_dialog_subscribe_button_cancel": "Annuleren",
"subscribe_dialog_subscribe_button_subscribe": "Abonneren", "subscribe_dialog_subscribe_button_subscribe": "Abonneren",
"subscribe_dialog_login_title": "Aanmelding vereist", "subscribe_dialog_login_title": "Aanmelding vereist",
"subscribe_dialog_login_description": "Dit onderwerp is beveiligd met een wachtwoord. Geef een gebruikersnaam en wachtwoord op om te abonneren.", "subscribe_dialog_login_description": "Dit onderwerp is beveiligd met een wachtwoord. Geef een gebruikersnaam en wachtwoord op om te abonneren.",
"subscribe_dialog_login_username_label": "Gebruikersnaam, bijv. phil", "subscribe_dialog_login_username_label": "Gebruikersnaam, bijv. phil",
"subscribe_dialog_subscribe_title": "Onderwerp abonneren", "subscribe_dialog_subscribe_title": "Onderwerp abonneren",
"subscribe_dialog_subscribe_description": "Onderwerpen zijn mogelijk niet beschermd met een wachtwoord, kies daarom een moeilijk te raden naam. Na abonneren kun je notificaties via PUT/POST sturen.", "subscribe_dialog_subscribe_description": "Onderwerpen zijn mogelijk niet beschermd met een wachtwoord, kies daarom een moeilijk te raden naam. Na abonneren kun je notificaties via PUT/POST sturen.",
"subscribe_dialog_login_password_label": "Wachtwoord", "subscribe_dialog_login_password_label": "Wachtwoord",
"subscribe_dialog_login_button_back": "Terug", "subscribe_dialog_login_button_back": "Terug",
"subscribe_dialog_login_button_login": "Aanmelden", "subscribe_dialog_login_button_login": "Aanmelden",
"subscribe_dialog_error_user_not_authorized": "Gebruiker {{username}} heeft geen toegang", "subscribe_dialog_error_user_not_authorized": "Gebruiker {{username}} heeft geen toegang",
"subscribe_dialog_error_user_anonymous": "anoniem", "subscribe_dialog_error_user_anonymous": "anoniem",
"prefs_notifications_title": "Notificaties", "prefs_notifications_title": "Notificaties",
"prefs_notifications_sound_title": "Meldingsgeluid", "prefs_notifications_sound_title": "Meldingsgeluid",
"prefs_notifications_sound_description_none": "Notificaties zullen geen geluid geven", "prefs_notifications_sound_description_none": "Notificaties zullen geen geluid geven",
"prefs_notifications_sound_play": "Geselecteerd geluid afspelen", "prefs_notifications_sound_play": "Geselecteerd geluid afspelen",
"prefs_notifications_sound_description_some": "Inkomende notificaties zullen het {{sound}} geluid afspelen", "prefs_notifications_sound_description_some": "Inkomende notificaties zullen het {{sound}} geluid afspelen",
"prefs_notifications_sound_no_sound": "Geen geluid", "prefs_notifications_sound_no_sound": "Geen geluid",
"prefs_notifications_min_priority_title": "Minimale prioriteit", "prefs_notifications_min_priority_title": "Minimale prioriteit",
"prefs_notifications_min_priority_description_any": "Toon alle notificaties, ongeacht prioriteit", "prefs_notifications_min_priority_description_any": "Toon alle notificaties, ongeacht prioriteit",
"prefs_notifications_min_priority_description_x_or_higher": "Toon notificaties als prioriteit {{number}} ({{name}}) is of hoger", "prefs_notifications_min_priority_description_x_or_higher": "Toon notificaties als prioriteit {{number}} ({{name}}) is of hoger",
"prefs_notifications_min_priority_description_max": "Toon notificaties als prioriteit 5 (maximaal) is", "prefs_notifications_min_priority_description_max": "Toon notificaties als prioriteit 5 (maximaal) is",
"prefs_notifications_min_priority_any": "Elke prioriteit", "prefs_notifications_min_priority_any": "Elke prioriteit",
"prefs_notifications_min_priority_low_and_higher": "Lage prioriteit en hoger", "prefs_notifications_min_priority_low_and_higher": "Lage prioriteit en hoger",
"prefs_notifications_min_priority_default_and_higher": "Standaard prioriteit en hoger", "prefs_notifications_min_priority_default_and_higher": "Standaard prioriteit en hoger",
"prefs_notifications_min_priority_high_and_higher": "Hoge prioriteit en hoger", "prefs_notifications_min_priority_high_and_higher": "Hoge prioriteit en hoger",
"prefs_notifications_min_priority_max_only": "Alleen maximale prioriteit", "prefs_notifications_min_priority_max_only": "Alleen maximale prioriteit",
"prefs_notifications_delete_after_title": "Notificaties verwijderen", "prefs_notifications_delete_after_title": "Notificaties verwijderen",
"prefs_notifications_delete_after_never": "Nooit", "prefs_notifications_delete_after_never": "Nooit",
"prefs_notifications_delete_after_three_hours": "Na drie uur", "prefs_notifications_delete_after_three_hours": "Na drie uur",
"prefs_notifications_delete_after_one_day": "Na één dag", "prefs_notifications_delete_after_one_day": "Na één dag",
"prefs_notifications_delete_after_never_description": "Notificaties worden nooit automatisch verwijderd", "prefs_notifications_delete_after_never_description": "Notificaties worden nooit automatisch verwijderd",
"prefs_notifications_delete_after_three_hours_description": "Notificaties worden na drie uur automatisch verwijderd", "prefs_notifications_delete_after_three_hours_description": "Notificaties worden na drie uur automatisch verwijderd",
"prefs_notifications_delete_after_one_day_description": "Notificaties worden na één dag automatisch verwijderd", "prefs_notifications_delete_after_one_day_description": "Notificaties worden na één dag automatisch verwijderd",
"prefs_notifications_delete_after_one_week_description": "Notificaties worden na één week automatisch verwijderd", "prefs_notifications_delete_after_one_week_description": "Notificaties worden na één week automatisch verwijderd",
"prefs_notifications_delete_after_one_month_description": "Notificaties worden na één maand automatisch verwijderd", "prefs_notifications_delete_after_one_month_description": "Notificaties worden na één maand automatisch verwijderd",
"prefs_users_title": "Gebruikers beheren", "prefs_users_title": "Gebruikers beheren",
"prefs_users_description": "Gebruikers voor beveiligde onderwerpen kunnen hier toegevoegd of verwijderd worden. Let op: gebruikersnaam en wachtwoord worden opgeslagen in lokale browser opslag.", "prefs_users_description": "Gebruikers voor beveiligde onderwerpen kunnen hier toegevoegd of verwijderd worden. Let op: gebruikersnaam en wachtwoord worden opgeslagen in lokale browser opslag.",
"prefs_users_table": "Gebruikerstabel", "prefs_users_table": "Gebruikerstabel",
"prefs_users_add_button": "Gebruiker toevoegen", "prefs_users_add_button": "Gebruiker toevoegen",
"prefs_users_edit_button": "Gebruiker bewerken", "prefs_users_edit_button": "Gebruiker bewerken",
"prefs_users_table_user_header": "Gebruiker", "prefs_users_table_user_header": "Gebruiker",
"prefs_users_table_base_url_header": "Service URL", "prefs_users_table_base_url_header": "Service URL",
"prefs_users_dialog_base_url_label": "Service URL, bijv. https://ntfy.sh", "prefs_users_dialog_base_url_label": "Service URL, bijv. https://ntfy.sh",
"prefs_users_dialog_username_label": "Gebruikersnaam, bijv. phil", "prefs_users_dialog_username_label": "Gebruikersnaam, bijv. phil",
"prefs_users_dialog_button_cancel": "Annuleren", "prefs_users_dialog_button_cancel": "Annuleren",
"prefs_users_dialog_button_add": "Toevoegen", "prefs_users_dialog_button_add": "Toevoegen",
"prefs_users_dialog_button_save": "Bewaren", "prefs_users_dialog_button_save": "Bewaren",
"prefs_appearance_title": "Weergave", "prefs_appearance_title": "Weergave",
"prefs_appearance_language_title": "Taal", "prefs_appearance_language_title": "Taal",
"priority_min": "min", "priority_min": "min",
"priority_low": "laag", "priority_low": "laag",
"priority_default": "standaard", "priority_default": "standaard",
"priority_high": "hoog", "priority_high": "hoog",
"priority_max": "max", "priority_max": "max",
"error_boundary_unsupported_indexeddb_title": "Privé / incognito browservensters worden niet ondersteund" "error_boundary_unsupported_indexeddb_title": "Privé / incognito browservensters worden niet ondersteund"
} }

Some files were not shown because too many files have changed in this diff Show more