Compare commits
219 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6bf89f4b32 | |||
| 5a07fd8932 | |||
| 9fa086e471 | |||
| 1658db7f10 | |||
| 780c9e3696 | |||
| 74fb430697 | |||
| d118aa8649 | |||
| 953c1742e0 | |||
| a88996fb3f | |||
| 0014aac201 | |||
| 8e6babe5d4 | |||
| cdeb2a8fc0 | |||
| a6e9f88e7a | |||
| ab3fdf509f | |||
| fb585d0086 | |||
| fa8431c5c6 | |||
| ec2b911881 | |||
| 0f2b29741e | |||
| 2f26b581f4 | |||
| ad266e45ca | |||
| f6825c1c60 | |||
| 40f958c5ef | |||
| 02e975d3f3 | |||
| 40b54b458d | |||
| ca60f3cff5 | |||
| c1ece47532 | |||
| b2e5eda89e | |||
| 1eb01b39e7 | |||
| c9e0f0b3e4 | |||
| 1e357d3ced | |||
| 4831acba39 | |||
| 658b8591b6 | |||
| 950b001675 | |||
| 0b5b41acd9 | |||
| 6b4b9e9cff | |||
| da89831116 | |||
| 3243d88c9b | |||
| 824fc310a9 | |||
| c891ab2588 | |||
| 33e9b26fe9 | |||
| 6e402f60dc | |||
| 4b56c84a8c | |||
| cee70e04db | |||
| 808635e314 | |||
| 7a1429bcc1 | |||
| 21bbaf2691 | |||
| 50c5850f0d | |||
| d22c6c535e | |||
| 6a41eb382f | |||
| aa70ebcdca | |||
| 7111b3749d | |||
| 93277f4307 | |||
| 9e3ce3f3a4 | |||
| a98e479e71 | |||
| 897d8644c5 | |||
| 2f7ad3ac73 | |||
| 20318e3a79 | |||
| cc3e65dd3c | |||
| 7b0a4a7803 | |||
| bab7734582 | |||
| 3dda84bf9a | |||
| f18ded6117 | |||
| 41d47244af | |||
| b113af8472 | |||
| 2309b27458 | |||
| 8329e9b46c | |||
| 5879404fd2 | |||
| bb0d2bf675 | |||
| dcf87bd642 | |||
| 4445cdd053 | |||
| 0b3c3a1f28 | |||
| 4b6e46d9ab | |||
| 2935aaef45 | |||
| 33fd0a617e | |||
| 2fedd8f234 | |||
| 527c5f49cb | |||
| 10d2c88e88 | |||
| fd8e95c878 | |||
| 686dd92cb9 | |||
| 28d036434f | |||
| 4b12043cea | |||
| 0f6f4c8c60 | |||
| 47b47cc32c | |||
| ec4e8710f2 | |||
| b3dae675d9 | |||
| c1c3624593 | |||
| b21f12015e | |||
| ca87894ab2 | |||
| 42dcc52ed1 | |||
| 45bfbb8a2f | |||
| d6ad9a471b | |||
| b585dab6b4 | |||
| d45e1b3bed | |||
| 03fd403e38 | |||
| 2dcabc840c | |||
| 87d58987a6 | |||
| 5f9d6fd81b | |||
| c2c9db737b | |||
| 4565dd406b | |||
| 22bbe1ac50 | |||
| 72fbbe311a | |||
| 423e06cbe8 | |||
| 1f3a9dabc2 | |||
| 937899194d | |||
| cf1939f063 | |||
| edee11931d | |||
| 612f9cdbc8 | |||
| fcd18f0b9c | |||
| 78f6bbe93d | |||
| 27d170cbec | |||
| 49119eff00 | |||
| 34dd358eb0 | |||
| 93596c1218 | |||
| 9fbcfc213b | |||
| 01f678c3b1 | |||
| 2f6895e118 | |||
| b7c229f30f | |||
| b88d46ee7f | |||
| b58a46455b | |||
| ce6fa4c0fc | |||
| 9965abccfb | |||
| 8bc06a5d65 | |||
| 7f1c17e396 | |||
| c5594fdae0 | |||
| b8b16c3bdf | |||
| fc766de02d | |||
| 79810413bd | |||
| dc21991599 | |||
| cc41065d9b | |||
| e877800779 | |||
| d5efd776b7 | |||
| 164bcc2f4a | |||
| 21ffd79c63 | |||
| 638643cda7 | |||
| 6703e03ce6 | |||
| 56c3f1193f | |||
| d189df95db | |||
| 0bcfc81b1f | |||
| 571d7bf17c | |||
| 93fd98f8d4 | |||
| 238a3ee9be | |||
| 897cd7cb34 | |||
| 409d05eec8 | |||
| 4b2a25eed4 | |||
| 1fc95a83b6 | |||
| cc888e2a55 | |||
| d9f91fd919 | |||
| dd3f496d06 | |||
| 09be3d2bac | |||
| 1fd4c4ef13 | |||
| 20cd023c07 | |||
| 1655ca235d | |||
| 77dc6aaf27 | |||
| b4cdef6875 | |||
| 36868e648c | |||
| c119a2c011 | |||
| e0557d8961 | |||
| 36d3b1e9fb | |||
| 012eb61c52 | |||
| c4a56105ca | |||
| 1005fb973e | |||
| 75ac58abdf | |||
| e46b438b06 | |||
| 264f4db567 | |||
| 0c56b4d580 | |||
| 32439ca2f0 | |||
| fa49bcaf8b | |||
| 89e8e94bf1 | |||
| 5b8eb4735c | |||
| 1c9f000576 | |||
| de53d8762f | |||
| daa56efe27 | |||
| f1db010a68 | |||
| dbb5906767 | |||
| 18e414ec45 | |||
| fc00a1b3a8 | |||
| 556b74f4fc | |||
| 6e2e2d1665 | |||
| 9242350f0e | |||
| b0c14aa8f9 | |||
| 4b2516532e | |||
| 1aec8d727c | |||
| e60e0ba3c4 | |||
| 5877048749 | |||
| c8c1f05328 | |||
| 96f3e888cf | |||
| 14888f1cb8 | |||
| 49171c5e8c | |||
| 51fb9495ad | |||
| 89c1b3b4d8 | |||
| 1d80c12e18 | |||
| d092fc8436 | |||
| 8a812cd8ec | |||
| ae13b4e420 | |||
| 548c4d4efe | |||
| f6ed2feab4 | |||
| b730aa520d | |||
| 3d16c3e4e6 | |||
| 0d935a863f | |||
| 053b1d0f8d | |||
| b247f3f089 | |||
| 20ec435d6d | |||
| 53cd369b05 | |||
| ec3c604a83 | |||
| c3f871b49b | |||
| e5b2eab727 | |||
| bbf93430b7 | |||
| 3cb04b2c56 | |||
| e3c28a6c96 | |||
| c2571f9f47 | |||
| 4855fbd13f | |||
| 9569666259 | |||
| 42edd357bc | |||
| b33706006a | |||
| 0de80c2ff0 | |||
| 5d65a85bdb | |||
| a352aff93b | |||
| 713d575bad | |||
| 421bb467d0 |
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: feature request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
- [ ] I have read this document: https://miniflux.app/opinionated.html#feature-request
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Feed Problems
|
||||
about: Problems with a feed or a website
|
||||
title: ''
|
||||
labels: feed problems
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Improvement
|
||||
about: Do you have an idea to improve an existing feature?
|
||||
title: ''
|
||||
labels: improvements
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Installation Issue
|
||||
about: Do you need help to install Miniflux?
|
||||
title: ''
|
||||
labels: installation issue
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Question / Discussion
|
||||
about: Open discussions
|
||||
title: ''
|
||||
labels: question / discussion
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
Do you follow the guidelines?
|
||||
|
||||
- [ ] I have tested my changes
|
||||
- [ ] I read this document: https://miniflux.app/faq.html#pull-request
|
||||
@@ -1,40 +1,12 @@
|
||||
name: CI Workflow
|
||||
permissions: read-all
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
|
||||
linters:
|
||||
name: Linter Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.15
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Install linters
|
||||
run: |
|
||||
cd /tmp && go get -u golang.org/x/lint/golint
|
||||
sudo npm install -g jshint
|
||||
env:
|
||||
GO111MODULE: off
|
||||
- name: Run golint
|
||||
run: |
|
||||
export PATH=/home/runner/go/bin:$PATH
|
||||
make lint
|
||||
- name: Run jshint
|
||||
run: jshint ui/static/js/*.js
|
||||
|
||||
unit-tests:
|
||||
name: Unit Tests
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -42,20 +14,14 @@ jobs:
|
||||
max-parallel: 4
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
go-version: [1.14, 1.15]
|
||||
go-version: [1.16, 1.17, 1.18]
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: actions/checkout@v2
|
||||
- name: Run unit tests
|
||||
run: make test
|
||||
|
||||
@@ -74,17 +40,11 @@ jobs:
|
||||
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
go-version: 1.16
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Postgres client
|
||||
run: sudo apt-get install -y postgresql-client
|
||||
- name: Run integration tests
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
permissions: read-all
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '45 22 * * 3'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go', 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
@@ -1,4 +1,5 @@
|
||||
name: Docker
|
||||
permissions: read-all
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 1 * * *'
|
||||
@@ -14,8 +15,8 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate Docker tag
|
||||
id: docker_tag
|
||||
- name: Generate Alpine Docker tag
|
||||
id: docker_alpine_tag
|
||||
run: |
|
||||
DOCKER_IMAGE=miniflux/miniflux
|
||||
DOCKER_VERSION=dev
|
||||
@@ -28,6 +29,20 @@ jobs:
|
||||
fi
|
||||
echo ::set-output name=tags::${TAGS}
|
||||
|
||||
- name: Generate Distroless Docker tag
|
||||
id: docker_distroless_tag
|
||||
run: |
|
||||
DOCKER_IMAGE=miniflux/miniflux
|
||||
DOCKER_VERSION=dev-distroless
|
||||
if [ "${{ github.event_name }}" = "schedule" ]; then
|
||||
DOCKER_VERSION=nightly-distroless
|
||||
TAGS="${DOCKER_IMAGE}:${DOCKER_VERSION},ghcr.io/${DOCKER_IMAGE}:${DOCKER_VERSION}"
|
||||
elif [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
DOCKER_VERSION=${GITHUB_REF#refs/tags/}-distroless
|
||||
TAGS="${DOCKER_IMAGE}:${DOCKER_VERSION},ghcr.io/${DOCKER_IMAGE}:${DOCKER_VERSION},${DOCKER_IMAGE}:latest-distroless,ghcr.io/${DOCKER_IMAGE}:latest-distroless"
|
||||
fi
|
||||
echo ::set-output name=tags::${TAGS}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
@@ -47,11 +62,20 @@ jobs:
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.CR_PAT }}
|
||||
|
||||
- name: Build and push
|
||||
- name: Build and Push Alpine images
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./packaging/docker/Dockerfile
|
||||
file: ./packaging/docker/alpine/Dockerfile
|
||||
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.docker_tag.outputs.tags }}
|
||||
tags: ${{ steps.docker_alpine_tag.outputs.tags }}
|
||||
|
||||
- name: Build and Push Distroless images
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./packaging/docker/distroless/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.docker_distroless_tag.outputs.tags }}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
name: Linters
|
||||
permissions: read-all
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
jshint:
|
||||
name: Javascript Linter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install jshint
|
||||
run: |
|
||||
sudo npm install -g jshint@2.13.3
|
||||
- name: Run jshint
|
||||
run: jshint ui/static/js/*.js
|
||||
|
||||
golangci:
|
||||
name: Golang Linter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
- uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
args: --skip-dirs tests --disable errcheck --enable sqlclosecheck --enable misspell --enable gofmt --enable goimports --enable whitespace
|
||||
skip-go-installation: true
|
||||
@@ -0,0 +1,55 @@
|
||||
name: Scorecards supply-chain security
|
||||
on:
|
||||
# Only the default branch is supported.
|
||||
branch_protection_rule:
|
||||
schedule:
|
||||
- cron: '31 8 * * 6'
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecards analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2.4.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@e3e75cf2ffbf9364bbff86cdbdf52b23176fe492 # v1.0.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# Read-only PAT token. To create it,
|
||||
# follow the steps in https://github.com/ossf/scorecard-action#pat-token-creation.
|
||||
repo_token: ${{ secrets.SCORECARD_READ_TOKEN }}
|
||||
# Publish the results to enable scorecard badges. For more details, see
|
||||
# https://github.com/ossf/scorecard-action#publishing-results.
|
||||
# For private repositories, `publish_results` will automatically be set to `false`,
|
||||
# regardless of the value entered here.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional).
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@82c141cc518b40d92cc801eee768e7aafc9c2fa2 # v2.3.1
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@5f532563584d71fdef14ee64d17bafb34f751ce5 # v1.0.26
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
@@ -2,3 +2,4 @@ miniflux-*
|
||||
miniflux
|
||||
*.rpm
|
||||
*.deb
|
||||
.idea
|
||||
@@ -1,3 +1,219 @@
|
||||
Version 2.0.37 (May 27, 2022)
|
||||
-----------------------------
|
||||
|
||||
* Add rewrite rule to decode base64 content
|
||||
* Add Linkding integration
|
||||
* Add comment button to Telegram message
|
||||
* Add API endpoint to fetch unread and read counters
|
||||
* Fixes logic bug in Google Reader API sanity check
|
||||
* Reduce number of CORS preflight check to save network brandwidth
|
||||
* Add Espial integration
|
||||
* Allow API search for entries which are not starred
|
||||
* Try to use outermost element text when title is empty
|
||||
* Make swipe gestures feel more natural
|
||||
- Removes opacity transition when swiping an article read/unread
|
||||
- Adds "resistance" to the swiped entry when the 75px threshold is
|
||||
reached
|
||||
- Fixes an issue in which a swiped article couldn't be moved <15px
|
||||
* Add support for feed streams to Google Reader API IDs API
|
||||
* Fix invalid parsing of icon data URL
|
||||
* Add Traditional Chinese translation
|
||||
* Add distroless Docker image variant
|
||||
* Add Go 1.18 to GitHub Action
|
||||
* Bump `github.com/tdewolff/minify/v2` from `2.10.0` to `2.11`
|
||||
* Bump `github.com/prometheus/client_golan` from `1.12.1` to `1.12.2`
|
||||
* Bump `github.com/lib/pq` from `1.10.4` to `1.10.6`
|
||||
|
||||
Version 2.0.36 (March 8, 2022)
|
||||
------------------------------
|
||||
|
||||
* Gray out pagination buttons when they are not applicable
|
||||
* Use truncated entry description as title if unavailable
|
||||
* Do not fallback to InnerXML if XHTML title is empty
|
||||
* Add `+` keyboard shortcut for new subscription page
|
||||
* Add `(+)` action next to Feeds to quickly add new feeds
|
||||
* Fix unstar not working via Google Reader API
|
||||
* Remove circles in front of page header list items
|
||||
* Fix CSS hover style for links styled as buttons
|
||||
* Avoid showing `undefined` when clicking on read/unread
|
||||
* Add new keyboard shortcut `M` to toggle read/unread, and go to previous item
|
||||
* Add several icons to menus according to their roles
|
||||
* Add missing event argument to `onClick()` function call
|
||||
* Add links to scraper/rewrite/filtering docs when editing feeds
|
||||
* Add a rewrite rule for Castopod episodes
|
||||
* Fix regression: reset touch-item if not in `/unread` page
|
||||
* Add API endpoint to fetch original article
|
||||
* Show the category first in feed settings
|
||||
* Add pagination on top of all entries
|
||||
* Display Go version in "About" page
|
||||
* Bump `mvdan.cc/xurls/v2` from 2.3.0 to 2.4.0
|
||||
* Bump `github.com/prometheus/client_golang` from 1.11.0 to 1.12.1
|
||||
* Bump `github.com/tdewolff/minify/v2` from 2.9.28 to 2.10.0
|
||||
|
||||
Version 2.0.35 (January 21, 2022)
|
||||
---------------------------------
|
||||
|
||||
* Set `read-all` permission to `GITHUB_TOKEN` for GitHub Actions
|
||||
* Pin `jshint` version in linter job
|
||||
* Fix incorrect conversion between integer types
|
||||
* Add new GitHub Actions workflows: CodeQL and Scorecards analysis
|
||||
* Handle Atom feeds with space around CDATA
|
||||
* Bump `github.com/tdewolff/minify/v2` from 2.9.22 to 2.9.28
|
||||
* Add Documentation directive to Systemd service
|
||||
* Do not reset `touch-item` if successfully swiped
|
||||
* Add support for multiple authors in Atom feeds
|
||||
* Omit `User-Agent` header in image proxy to avoid being blocked
|
||||
* Use custom feed user agent to fetch website icon
|
||||
* Make default Invidious instance configurable
|
||||
* Add new rewrite rule `add_youtube_video_from_id` to add Youtube videos in Quanta articles
|
||||
* Add scrape and rewrite rules for `quantamagazine.org`
|
||||
* Expose entry unshare link in the entry and list views
|
||||
* Add Google Reader API implementation (experimental)
|
||||
* Add `Content-Security-Policy` header to feed icon and image proxy endpoints
|
||||
- SVG images could contain Javascript. This CSP blocks inline script.
|
||||
- Feed icons are served using `<img>` tag and Javascript is not interpreted.
|
||||
* Add Finnish translation
|
||||
* Add scraper rule for `ikiwiki.iki.fi`
|
||||
* Remove `SystemCallFilter` from `miniflux.service`
|
||||
* Fix minor typo in French translation
|
||||
|
||||
Version 2.0.34 (December 16, 2021)
|
||||
----------------------------------
|
||||
|
||||
* Add rewrite rule for comics website http://monkeyuser.com
|
||||
* Add `<head>` tag to OPML export
|
||||
* Tighten Systemd sandboxing and update comments in `miniflux.service`
|
||||
* Add `RuntimeDirectory` to Systemd service
|
||||
* Order disabled feeds at the end of the list
|
||||
* Add support for theme color based on preferred color scheme of OS
|
||||
* Bump `github.com/lib/pq` from 1.10.3 to 1.10.4
|
||||
* Bump `github.com/PuerkitoBio/goquery` from 1.7.1 to 1.8.0
|
||||
* Fix typos in `model/icon.go`
|
||||
* Add `data-srcset` support to `add_dynamic_image rewrite` rewrite rule
|
||||
* Fix Docker Compose example files compatibility to v3
|
||||
* Added the `role="article"` to `<article>` elements for better accessibility with screen readers
|
||||
* Redact secrets shown on the about page
|
||||
* Handle `srcset` images with no space after comma
|
||||
* Hide the logout link when using auth proxy
|
||||
* Fix wrong CSS variable
|
||||
* Change `-config-dump` command to use `KEY=VALUE` format
|
||||
|
||||
Version 2.0.33 (September 25, 2021)
|
||||
-----------------------------------
|
||||
|
||||
* Build RPM and Debian package with PIE mode enabled
|
||||
* Add CSS rule to hide `<template>` tag in old browsers
|
||||
* Bump `github.com/tdewolff/minify/v2 from 2.9.21 to 2.9.22`
|
||||
* Bump `github.com/lib/pq from 1.10.2 to 1.10.3`
|
||||
* Remove `RequestURI()` hack
|
||||
* Improve `zh_CN` translation
|
||||
* Add ability to change entry sort order in the UI
|
||||
* Add minor improvements in integration package
|
||||
* Add Telegram integration
|
||||
* Add rewrite rule to remove DOM elements
|
||||
* Add proxy argument to `scraper.Fetch()`
|
||||
* Add mime type `application/feed+json` to discover JSON Feed v1.1
|
||||
* Update scraper rule for `theregister.com`
|
||||
* Add Go 1.17 to GitHub Actions
|
||||
* Display option to hide feed only when category is not already hidden
|
||||
* Add option to hide feeds from the global Unread list
|
||||
|
||||
Version 2.0.32 (August 14, 2021)
|
||||
--------------------------------
|
||||
|
||||
* Bump `github.com/tdewolff/minify/v2` from 2.9.17 to 2.9.21
|
||||
* Bump `mvdan.cc/xurls/v2` from 2.2.0 to 2.3.0
|
||||
* Bump `github.com/PuerkitoBio/goquery` from 1.6.1 to 1.7.1
|
||||
* Bump `github.com/prometheus/client_golang` from 1.10.0 to 1.11.0
|
||||
* Add `/rss/` to the list of well known URLs during feed discovery
|
||||
* Use `authors` entry for JSON 1.1 feeds
|
||||
* Added Greek translation
|
||||
* Added the ability to mark an entire category as read in the web ui
|
||||
* Added "in" in "logged in" for en_US `tooltip.logged_user`
|
||||
* Added option to hide categories from the global unread list
|
||||
* Show "saving" labels for entry status button
|
||||
* Golang client: Try to parse response body on `InternalServerError` errors
|
||||
* contrib: Add support for a $MINIFLUX_IMAGE env var in docker-compose
|
||||
* contrib: Bump docker-compose version to 3.4
|
||||
|
||||
Version 2.0.31 (June 6, 2021)
|
||||
-----------------------------
|
||||
|
||||
* Expose comments_url entry field in Golang API client
|
||||
* Use unique file names for cache busting instead of query string
|
||||
* Highlight and sort feeds with unread entries in feeds list
|
||||
* Mark items as read on click/middle click of external links
|
||||
* Fix: Firefox on Windows does not show the active link as bold
|
||||
* Avoid extra HTTP request for fetching custom stylesheet
|
||||
* Remove invalid CSRF HTML meta tag
|
||||
* Add lang attribute to root HTML tag
|
||||
* Use runes instead of bytes to truncate JSON feed titles (avoid breaking Unicode strings)
|
||||
* Expose changed_at time through the API
|
||||
* Add new config option CLEANUP_ARCHIVE_BATCH_SIZE
|
||||
* Add new option DATABASE_CONNECTION_LIFETIME
|
||||
* Add database stats to Prometheus exporter
|
||||
* Add Systemd watchdog
|
||||
* Avoid custom stylesheet to be cached by third-party CDN
|
||||
* Update a shared entry label translation in zh_CN
|
||||
* Bump github.com/tdewolff/minify/v2 from 2.9.16 to 2.9.17
|
||||
* Bump github.com/lib/pq from 1.10.1 to 1.10.2
|
||||
|
||||
Version 2.0.30 (May 7, 2021)
|
||||
----------------------------
|
||||
|
||||
* Security fix: any user can delete any feed (Regression introduced in commit 51fb949)
|
||||
* Fix password reset via CLI
|
||||
* Increase default batch size value
|
||||
* Handle RSS feed title with encoded Unicode entities
|
||||
* Show number of unread per category in category list instead of number of feeds
|
||||
* Bump github.com/lib/pq from 1.10.0 to 1.10.1
|
||||
* Filtering doesn't work when selecting from multiple found feeds
|
||||
* Bump github.com/tdewolff/minify/v2 from 2.9.15 to 2.9.16
|
||||
* Use an appropriate color for visited links on dark theme
|
||||
* Fix typo in reader/json/doc.go
|
||||
* Create SECURITY.md
|
||||
* Setup golangci-lint Github Action
|
||||
* Add per feed cookies option
|
||||
* Bump github.com/prometheus/client_golang from 1.9.0 to 1.10.0
|
||||
* Bump github.com/tdewolff/minify/v2 from 2.9.13 to 2.9.15
|
||||
|
||||
Version 2.0.29 (Mar 21, 2021)
|
||||
-----------------------------
|
||||
|
||||
* Miniflux requires at least Go 1.16 now
|
||||
* Improved support of Atom text constructs
|
||||
- Improve handling of CDATA in text elements
|
||||
- Omit XHTML root element because it should not be part of the content
|
||||
- Fix incorrect parsing of HTML elements
|
||||
* Handle RDF feed with HTML encoded entry title
|
||||
* Add Turkish language
|
||||
* Improve deletion of feeds with lots of entries
|
||||
* Add support of Systemd readiness notification using the sd_notify protocol
|
||||
* Remove feed_icons service worker cache because it's causing more problems than it solves (and HTTP cache seems faster)
|
||||
* Add basic PWA offline page
|
||||
- Add basic offline mode when using the service worker
|
||||
- Starting in Chrome 93, offline mode is going to be a requirement to install the PWA
|
||||
* Replace icon for "Add to home screen" button
|
||||
* Use SVG icons for "toast" notifications
|
||||
* Use SVG sprite for icons instead of inline elements
|
||||
* Reset scroll position on mark page as read
|
||||
* Add link to mark all feed entries as read
|
||||
* Make web app display mode configurable (The change is visible after reinstalling the web app)
|
||||
* Handle RSS feeds with CDATA in author item element
|
||||
* Add read time on the article page
|
||||
* Avoid showing a broken image when there is no feed icon
|
||||
* Add option to allow self-signed or invalid certificates
|
||||
* Add new config option to scrape YouTube's website to get video duration as read time (disabled by default)
|
||||
* Send full article content to Wallabag
|
||||
* Add more extensive health check support
|
||||
- Improve endpoint to test database connection
|
||||
- Add new cli argument: -healthcheck
|
||||
- Update Docker Compose examples
|
||||
* Update iframe "allow list" to support Bilibili videos
|
||||
* Remove completely generated files and use embed package to bundle JS/CSS/Images/Translations files into the final binary
|
||||
* Remove deprecated io/ioutil package
|
||||
* Show Postgres version in "About" page
|
||||
|
||||
Version 2.0.28 (Feb 15, 2021)
|
||||
-----------------------------
|
||||
|
||||
@@ -405,7 +621,7 @@ Version 2.0.13 (Nov 25, 2018)
|
||||
|
||||
* Add man page
|
||||
* Add support for Systemd Socket Activation (experimental)
|
||||
* Add the possiblity to listen on Unix sockets
|
||||
* Add the possibility to listen on Unix sockets
|
||||
* Add config options to disable HTTP and scheduler services
|
||||
* Archive more read entries in cleanup job
|
||||
* Change default database connection string (backward compatible)
|
||||
|
||||
@@ -10,7 +10,7 @@ DEB_IMG_ARCH := amd64
|
||||
|
||||
export PGPASSWORD := postgres
|
||||
|
||||
.PHONY: generate \
|
||||
.PHONY: \
|
||||
miniflux \
|
||||
linux-amd64 \
|
||||
linux-arm64 \
|
||||
@@ -19,6 +19,7 @@ export PGPASSWORD := postgres
|
||||
linux-armv5 \
|
||||
linux-x86 \
|
||||
darwin-amd64 \
|
||||
darwin-arm64 \
|
||||
freebsd-amd64 \
|
||||
freebsd-x86 \
|
||||
openbsd-amd64 \
|
||||
@@ -35,66 +36,67 @@ export PGPASSWORD := postgres
|
||||
integration-test \
|
||||
clean-integration-test \
|
||||
docker-image \
|
||||
docker-image-distroless \
|
||||
docker-images \
|
||||
rpm \
|
||||
debian \
|
||||
debian-packages
|
||||
|
||||
generate:
|
||||
@ go generate
|
||||
miniflux:
|
||||
@ go build -buildmode=pie -ldflags=$(LD_FLAGS) -o $(APP) main.go
|
||||
|
||||
miniflux: generate
|
||||
@ go build -ldflags=$(LD_FLAGS) -o $(APP) main.go
|
||||
|
||||
linux-amd64: generate
|
||||
linux-amd64:
|
||||
@ GOOS=linux GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-amd64 main.go
|
||||
|
||||
linux-arm64: generate
|
||||
linux-arm64:
|
||||
@ GOOS=linux GOARCH=arm64 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-arm64 main.go
|
||||
|
||||
linux-armv7: generate
|
||||
linux-armv7:
|
||||
@ GOOS=linux GOARCH=arm GOARM=7 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-armv7 main.go
|
||||
|
||||
linux-armv6: generate
|
||||
linux-armv6:
|
||||
@ GOOS=linux GOARCH=arm GOARM=6 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-armv6 main.go
|
||||
|
||||
linux-armv5: generate
|
||||
linux-armv5:
|
||||
@ GOOS=linux GOARCH=arm GOARM=5 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-armv5 main.go
|
||||
|
||||
darwin-amd64: generate
|
||||
darwin-amd64:
|
||||
@ GOOS=darwin GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-darwin-amd64 main.go
|
||||
|
||||
freebsd-amd64: generate
|
||||
darwin-arm64:
|
||||
@ GOOS=darwin GOARCH=arm64 go build -ldflags=$(LD_FLAGS) -o $(APP)-darwin-arm64 main.go
|
||||
|
||||
freebsd-amd64:
|
||||
@ GOOS=freebsd GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-freebsd-amd64 main.go
|
||||
|
||||
openbsd-amd64: generate
|
||||
openbsd-amd64:
|
||||
@ GOOS=openbsd GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-openbsd-amd64 main.go
|
||||
|
||||
windows-amd64: generate
|
||||
windows-amd64:
|
||||
@ GOOS=windows GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-windows-amd64 main.go
|
||||
|
||||
build: linux-amd64 linux-arm64 linux-armv7 linux-armv6 linux-armv5 darwin-amd64 freebsd-amd64 openbsd-amd64 windows-amd64
|
||||
build: linux-amd64 linux-arm64 linux-armv7 linux-armv6 linux-armv5 darwin-amd64 darwin-arm64 freebsd-amd64 openbsd-amd64 windows-amd64
|
||||
|
||||
# NOTE: unsupported targets
|
||||
netbsd-amd64: generate
|
||||
netbsd-amd64:
|
||||
@ GOOS=netbsd GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-netbsd-amd64 main.go
|
||||
|
||||
linux-x86: generate
|
||||
linux-x86:
|
||||
@ GOOS=linux GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-x86 main.go
|
||||
|
||||
freebsd-x86: generate
|
||||
freebsd-x86:
|
||||
@ GOOS=freebsd GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-freebsd-x86 main.go
|
||||
|
||||
netbsd-x86: generate
|
||||
netbsd-x86:
|
||||
@ GOOS=netbsd GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-netbsd-x86 main.go
|
||||
|
||||
openbsd-x86: generate
|
||||
openbsd-x86:
|
||||
@ GOOS=openbsd GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-freebsd-x86 main.go
|
||||
|
||||
windows-x86: generate
|
||||
windows-x86:
|
||||
@ GOOS=windows GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-windows-x86 main.go
|
||||
|
||||
run: generate
|
||||
run:
|
||||
@ LOG_DATE_TIME=1 go run main.go -debug
|
||||
|
||||
clean:
|
||||
@@ -129,12 +131,15 @@ clean-integration-test:
|
||||
@ psql -U postgres -c 'drop database if exists miniflux_test;'
|
||||
|
||||
docker-image:
|
||||
docker build -t $(DOCKER_IMAGE):$(VERSION) -f packaging/docker/Dockerfile .
|
||||
docker build -t $(DOCKER_IMAGE):$(VERSION) -f packaging/docker/alpine/Dockerfile .
|
||||
|
||||
docker-image-distroless:
|
||||
docker build -t $(DOCKER_IMAGE):$(VERSION) -f packaging/docker/distroless/Dockerfile .
|
||||
|
||||
docker-images:
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 \
|
||||
--file packaging/docker/Dockerfile \
|
||||
--file packaging/docker/alpine/Dockerfile \
|
||||
--tag $(DOCKER_IMAGE):$(VERSION) \
|
||||
--push .
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Only the latest stable version is supported.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Send an email to `security AT miniflux DOT net` with all the steps to reproduce the problem.
|
||||
@@ -47,6 +47,7 @@ func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool) {
|
||||
sr.HandleFunc("/discover", handler.discoverSubscriptions).Methods(http.MethodPost)
|
||||
sr.HandleFunc("/feeds", handler.createFeed).Methods(http.MethodPost)
|
||||
sr.HandleFunc("/feeds", handler.getFeeds).Methods(http.MethodGet)
|
||||
sr.HandleFunc("/feeds/counters", handler.fetchCounters).Methods(http.MethodGet)
|
||||
sr.HandleFunc("/feeds/refresh", handler.refreshAllFeeds).Methods(http.MethodPut)
|
||||
sr.HandleFunc("/feeds/{feedID}/refresh", handler.refreshFeed).Methods(http.MethodPut)
|
||||
sr.HandleFunc("/feeds/{feedID}", handler.getFeed).Methods(http.MethodGet)
|
||||
@@ -62,4 +63,5 @@ func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool) {
|
||||
sr.HandleFunc("/entries", handler.setEntryStatus).Methods(http.MethodPut)
|
||||
sr.HandleFunc("/entries/{entryID}", handler.getEntry).Methods(http.MethodGet)
|
||||
sr.HandleFunc("/entries/{entryID}/bookmark", handler.toggleBookmark).Methods(http.MethodPut)
|
||||
sr.HandleFunc("/entries/{entryID}/fetch-content", handler.fetchContent).Methods(http.MethodGet)
|
||||
}
|
||||
|
||||
+46
-1
@@ -8,11 +8,13 @@ import (
|
||||
json_parser "encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"miniflux.app/http/request"
|
||||
"miniflux.app/http/response/json"
|
||||
"miniflux.app/model"
|
||||
"miniflux.app/reader/processor"
|
||||
"miniflux.app/storage"
|
||||
"miniflux.app/validator"
|
||||
)
|
||||
@@ -172,6 +174,46 @@ func (h *handler) toggleBookmark(w http.ResponseWriter, r *http.Request) {
|
||||
json.NoContent(w, r)
|
||||
}
|
||||
|
||||
func (h *handler) fetchContent(w http.ResponseWriter, r *http.Request) {
|
||||
loggedUserID := request.UserID(r)
|
||||
entryID := request.RouteInt64Param(r, "entryID")
|
||||
|
||||
entryBuilder := h.store.NewEntryQueryBuilder(loggedUserID)
|
||||
entryBuilder.WithEntryID(entryID)
|
||||
entryBuilder.WithoutStatus(model.EntryStatusRemoved)
|
||||
|
||||
entry, err := entryBuilder.GetEntry()
|
||||
if err != nil {
|
||||
json.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
if entry == nil {
|
||||
json.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
feedBuilder := storage.NewFeedQueryBuilder(h.store, loggedUserID)
|
||||
feedBuilder.WithFeedID(entry.FeedID)
|
||||
feed, err := feedBuilder.GetFeed()
|
||||
if err != nil {
|
||||
json.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
if feed == nil {
|
||||
json.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if err := processor.ProcessEntryWebPage(feed, entry); err != nil {
|
||||
json.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
json.OK(w, r, map[string]string{"content": entry.Content})
|
||||
}
|
||||
|
||||
func configureFilters(builder *storage.EntryQueryBuilder, r *http.Request) {
|
||||
beforeEntryID := request.QueryInt64Param(r, "before_entry_id", 0)
|
||||
if beforeEntryID > 0 {
|
||||
@@ -199,7 +241,10 @@ func configureFilters(builder *storage.EntryQueryBuilder, r *http.Request) {
|
||||
}
|
||||
|
||||
if request.HasQueryParam(r, "starred") {
|
||||
builder.WithStarred()
|
||||
starred, err := strconv.ParseBool(r.URL.Query().Get("starred"))
|
||||
if err == nil {
|
||||
builder.WithStarred(starred)
|
||||
}
|
||||
}
|
||||
|
||||
searchQuery := request.QueryStringParam(r, "search", "")
|
||||
|
||||
+10
@@ -170,6 +170,16 @@ func (h *handler) getFeeds(w http.ResponseWriter, r *http.Request) {
|
||||
json.OK(w, r, feeds)
|
||||
}
|
||||
|
||||
func (h *handler) fetchCounters(w http.ResponseWriter, r *http.Request) {
|
||||
counters, err := h.store.FetchCounters(request.UserID(r))
|
||||
if err != nil {
|
||||
json.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
json.OK(w, r, counters)
|
||||
}
|
||||
|
||||
func (h *handler) getFeed(w http.ResponseWriter, r *http.Request) {
|
||||
feedID := request.RouteInt64Param(r, "feedID")
|
||||
feed, err := h.store.FeedByID(request.UserID(r), feedID)
|
||||
|
||||
@@ -27,6 +27,7 @@ func (m *middleware) handleCORS(next http.Handler) http.Handler {
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "X-Auth-Token")
|
||||
if r.Method == http.MethodOptions {
|
||||
w.Header().Set("Access-Control-Max-Age", "3600")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -29,9 +29,11 @@ func (h *handler) discoverSubscriptions(w http.ResponseWriter, r *http.Request)
|
||||
subscriptions, finderErr := subscription.FindSubscriptions(
|
||||
subscriptionDiscoveryRequest.URL,
|
||||
subscriptionDiscoveryRequest.UserAgent,
|
||||
subscriptionDiscoveryRequest.Cookie,
|
||||
subscriptionDiscoveryRequest.Username,
|
||||
subscriptionDiscoveryRequest.Password,
|
||||
subscriptionDiscoveryRequest.FetchViaProxy,
|
||||
subscriptionDiscoveryRequest.AllowSelfSignedCertificates,
|
||||
)
|
||||
if finderErr != nil {
|
||||
json.ServerError(w, r, finderErr)
|
||||
|
||||
+42
-7
@@ -10,8 +10,10 @@ import (
|
||||
|
||||
"miniflux.app/config"
|
||||
"miniflux.app/database"
|
||||
"miniflux.app/locale"
|
||||
"miniflux.app/logger"
|
||||
"miniflux.app/storage"
|
||||
"miniflux.app/ui/static"
|
||||
"miniflux.app/version"
|
||||
)
|
||||
|
||||
@@ -26,6 +28,7 @@ const (
|
||||
flagDebugModeHelp = "Show debug logs"
|
||||
flagConfigFileHelp = "Load configuration file"
|
||||
flagConfigDumpHelp = "Print parsed configuration values"
|
||||
flagHealthCheckHelp = `Perform a health check on the given endpoint (the value "auto" try to guess the health check endpoint).`
|
||||
)
|
||||
|
||||
// Parse parses command line arguments.
|
||||
@@ -42,6 +45,7 @@ func Parse() {
|
||||
flagDebugMode bool
|
||||
flagConfigFile string
|
||||
flagConfigDump bool
|
||||
flagHealthCheck string
|
||||
)
|
||||
|
||||
flag.BoolVar(&flagInfo, "info", false, flagInfoHelp)
|
||||
@@ -57,6 +61,7 @@ func Parse() {
|
||||
flag.StringVar(&flagConfigFile, "config-file", "", flagConfigFileHelp)
|
||||
flag.StringVar(&flagConfigFile, "c", "", flagConfigFileHelp)
|
||||
flag.BoolVar(&flagConfigDump, "config-dump", false, flagConfigDumpHelp)
|
||||
flag.StringVar(&flagHealthCheck, "healthcheck", "", flagHealthCheckHelp)
|
||||
flag.Parse()
|
||||
|
||||
cfg := config.NewParser()
|
||||
@@ -86,6 +91,11 @@ func Parse() {
|
||||
logger.EnableDebug()
|
||||
}
|
||||
|
||||
if flagHealthCheck != "" {
|
||||
doHealthCheck(flagHealthCheck)
|
||||
return
|
||||
}
|
||||
|
||||
if flagInfo {
|
||||
info()
|
||||
return
|
||||
@@ -100,22 +110,47 @@ func Parse() {
|
||||
logger.Info("The default value for DATABASE_URL is used")
|
||||
}
|
||||
|
||||
logger.Debug("Loading translations...")
|
||||
if err := locale.LoadCatalogMessages(); err != nil {
|
||||
logger.Fatal("Unable to load translations: %v", err)
|
||||
}
|
||||
|
||||
logger.Debug("Loading static assets...")
|
||||
if err := static.CalculateBinaryFileChecksums(); err != nil {
|
||||
logger.Fatal("Unable to calculate binary files checksum: %v", err)
|
||||
}
|
||||
|
||||
if err := static.GenerateStylesheetsBundles(); err != nil {
|
||||
logger.Fatal("Unable to generate Stylesheet bundles: %v", err)
|
||||
}
|
||||
|
||||
if err := static.GenerateJavascriptBundles(); err != nil {
|
||||
logger.Fatal("Unable to generate Javascript bundles: %v", err)
|
||||
}
|
||||
|
||||
db, err := database.NewConnectionPool(
|
||||
config.Opts.DatabaseURL(),
|
||||
config.Opts.DatabaseMinConns(),
|
||||
config.Opts.DatabaseMaxConns(),
|
||||
config.Opts.DatabaseConnectionLifetime(),
|
||||
)
|
||||
if err != nil {
|
||||
logger.Fatal("Unable to connect to the database: %v", err)
|
||||
logger.Fatal("Unable to initialize database connection pool: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
if flagMigrate {
|
||||
database.Migrate(db)
|
||||
return
|
||||
store := storage.NewStorage(db)
|
||||
|
||||
if err := store.Ping(); err != nil {
|
||||
logger.Fatal("Unable to connect to the database: %v", err)
|
||||
}
|
||||
|
||||
store := storage.NewStorage(db)
|
||||
if flagMigrate {
|
||||
if err := database.Migrate(db); err != nil {
|
||||
logger.Fatal(`%v`, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if flagResetFeedErrors {
|
||||
store.ResetFeedErrors()
|
||||
@@ -137,7 +172,7 @@ func Parse() {
|
||||
return
|
||||
}
|
||||
|
||||
// Run migrations and start the deamon.
|
||||
// Run migrations and start the daemon.
|
||||
if config.Opts.RunMigrations() {
|
||||
if err := database.Migrate(db); err != nil {
|
||||
logger.Fatal(`%v`, err)
|
||||
@@ -148,7 +183,7 @@ func Parse() {
|
||||
logger.Fatal(`You must run the SQL migrations, %v`, err)
|
||||
}
|
||||
|
||||
// Create admin user and start the deamon.
|
||||
// Create admin user and start the daemon.
|
||||
if config.Opts.CreateAdmin() {
|
||||
createAdmin(store)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"miniflux.app/service/httpd"
|
||||
"miniflux.app/service/scheduler"
|
||||
"miniflux.app/storage"
|
||||
"miniflux.app/systemd"
|
||||
"miniflux.app/worker"
|
||||
)
|
||||
|
||||
@@ -44,6 +45,37 @@ func startDaemon(store *storage.Storage) {
|
||||
go collector.GatherStorageMetrics()
|
||||
}
|
||||
|
||||
if systemd.HasNotifySocket() {
|
||||
logger.Info("Sending readiness notification to Systemd")
|
||||
|
||||
if err := systemd.SdNotify(systemd.SdNotifyReady); err != nil {
|
||||
logger.Error("Unable to send readiness notification to systemd: %v", err)
|
||||
}
|
||||
|
||||
if config.Opts.HasWatchdog() && systemd.HasSystemdWatchdog() {
|
||||
logger.Info("Activating Systemd watchdog")
|
||||
|
||||
go func() {
|
||||
interval, err := systemd.WatchdogInterval()
|
||||
if err != nil {
|
||||
logger.Error("Unable to parse watchdog interval from systemd: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
err := store.Ping()
|
||||
if err != nil {
|
||||
logger.Error(`Systemd Watchdog: %v`, err)
|
||||
} else {
|
||||
systemd.SdNotify(systemd.SdNotifyWatchdog)
|
||||
}
|
||||
|
||||
time.Sleep(interval / 3)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
<-stop
|
||||
logger.Info("Shutting down the process...")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2021 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cli // import "miniflux.app/cli"
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"miniflux.app/config"
|
||||
"miniflux.app/logger"
|
||||
)
|
||||
|
||||
func doHealthCheck(healthCheckEndpoint string) {
|
||||
if healthCheckEndpoint == "auto" {
|
||||
healthCheckEndpoint = "http://" + config.Opts.ListenAddr() + config.Opts.BasePath() + "/healthcheck"
|
||||
}
|
||||
|
||||
logger.Debug(`Executing health check on %s`, healthCheckEndpoint)
|
||||
|
||||
client := &http.Client{Timeout: 3 * time.Second}
|
||||
resp, err := client.Get(healthCheckEndpoint)
|
||||
if err != nil {
|
||||
logger.Fatal(`Health check failure: %v`, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
logger.Fatal(`Health check failed with status code %d`, resp.StatusCode)
|
||||
}
|
||||
|
||||
logger.Debug(`Health check is OK`)
|
||||
}
|
||||
@@ -34,6 +34,7 @@ func resetPassword(store *storage.Storage) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
user.Password = password
|
||||
if err := store.UpdateUser(user); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
os.Exit(1)
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
miniflux "miniflux.app/client"
|
||||
)
|
||||
@@ -47,7 +47,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile("opml.xml", opml, 0644)
|
||||
err = os.WriteFile("opml.xml", opml, 0644)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
|
||||
+22
-6
@@ -8,7 +8,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
@@ -223,7 +222,7 @@ func (c *Client) MarkCategoryAsRead(categoryID int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// CategoryFeeds gets feeds of a cateogry.
|
||||
// CategoryFeeds gets feeds of a category.
|
||||
func (c *Client) CategoryFeeds(categoryID int64) (Feeds, error) {
|
||||
body, err := c.request.Get(fmt.Sprintf("/v1/categories/%d/feeds", categoryID))
|
||||
if err != nil {
|
||||
@@ -270,7 +269,7 @@ func (c *Client) Export() ([]byte, error) {
|
||||
}
|
||||
defer body.Close()
|
||||
|
||||
opml, err := ioutil.ReadAll(body)
|
||||
opml, err := io.ReadAll(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -346,7 +345,7 @@ func (c *Client) MarkFeedAsRead(feedID int64) error {
|
||||
|
||||
// RefreshAllFeeds refreshes all feeds.
|
||||
func (c *Client) RefreshAllFeeds() error {
|
||||
_, err := c.request.Put(fmt.Sprintf("/v1/feeds/refresh"), nil)
|
||||
_, err := c.request.Put("/v1/feeds/refresh", nil)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -503,6 +502,23 @@ func (c *Client) ToggleBookmark(entryID int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// FetchCounters
|
||||
func (c *Client) FetchCounters() (*FeedCounters, error) {
|
||||
body, err := c.request.Get("/v1/feeds/counters")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer body.Close()
|
||||
|
||||
var result FeedCounters
|
||||
decoder := json.NewDecoder(body)
|
||||
if err := decoder.Decode(&result); err != nil {
|
||||
return nil, fmt.Errorf("miniflux: response error (%v)", err)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func buildFilterQueryString(path string, filter *Filter) string {
|
||||
if filter != nil {
|
||||
values := url.Values{}
|
||||
@@ -543,8 +559,8 @@ func buildFilterQueryString(path string, filter *Filter) string {
|
||||
values.Set("before_entry_id", strconv.FormatInt(filter.BeforeEntryID, 10))
|
||||
}
|
||||
|
||||
if filter.Starred {
|
||||
values.Set("starred", "1")
|
||||
if filter.Starred != "" {
|
||||
values.Set("starred", filter.Starred)
|
||||
}
|
||||
|
||||
if filter.Search != "" {
|
||||
|
||||
@@ -26,6 +26,7 @@ type User struct {
|
||||
Language string `json:"language"`
|
||||
Timezone string `json:"timezone"`
|
||||
EntryDirection string `json:"entry_sorting_direction"`
|
||||
EntryOrder string `json:"entry_sorting_order"`
|
||||
Stylesheet string `json:"stylesheet"`
|
||||
GoogleID string `json:"google_id"`
|
||||
OpenIDConnectID string `json:"openid_connect_id"`
|
||||
@@ -34,6 +35,7 @@ type User struct {
|
||||
ShowReadingTime bool `json:"show_reading_time"`
|
||||
EntrySwipe bool `json:"entry_swipe"`
|
||||
LastLoginAt *time.Time `json:"last_login_at"`
|
||||
DisplayMode string `json:"display_mode"`
|
||||
}
|
||||
|
||||
func (u User) String() string {
|
||||
@@ -58,6 +60,7 @@ type UserModificationRequest struct {
|
||||
Language *string `json:"language"`
|
||||
Timezone *string `json:"timezone"`
|
||||
EntryDirection *string `json:"entry_sorting_direction"`
|
||||
EntryOrder *string `json:"entry_sorting_order"`
|
||||
Stylesheet *string `json:"stylesheet"`
|
||||
GoogleID *string `json:"google_id"`
|
||||
OpenIDConnectID *string `json:"openid_connect_id"`
|
||||
@@ -65,6 +68,7 @@ type UserModificationRequest struct {
|
||||
KeyboardShortcuts *bool `json:"keyboard_shortcuts"`
|
||||
ShowReadingTime *bool `json:"show_reading_time"`
|
||||
EntrySwipe *bool `json:"entry_swipe"`
|
||||
DisplayMode *string `json:"display_mode"`
|
||||
}
|
||||
|
||||
// Users represents a list of users.
|
||||
@@ -100,64 +104,73 @@ type Subscriptions []*Subscription
|
||||
|
||||
// Feed represents a Miniflux feed.
|
||||
type Feed struct {
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
FeedURL string `json:"feed_url"`
|
||||
SiteURL string `json:"site_url"`
|
||||
Title string `json:"title"`
|
||||
CheckedAt time.Time `json:"checked_at,omitempty"`
|
||||
EtagHeader string `json:"etag_header,omitempty"`
|
||||
LastModifiedHeader string `json:"last_modified_header,omitempty"`
|
||||
ParsingErrorMsg string `json:"parsing_error_message,omitempty"`
|
||||
ParsingErrorCount int `json:"parsing_error_count,omitempty"`
|
||||
Disabled bool `json:"disabled"`
|
||||
IgnoreHTTPCache bool `json:"ignore_http_cache"`
|
||||
FetchViaProxy bool `json:"fetch_via_proxy"`
|
||||
ScraperRules string `json:"scraper_rules"`
|
||||
RewriteRules string `json:"rewrite_rules"`
|
||||
BlocklistRules string `json:"blocklist_rules"`
|
||||
KeeplistRules string `json:"keeplist_rules"`
|
||||
Crawler bool `json:"crawler"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Category *Category `json:"category,omitempty"`
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
FeedURL string `json:"feed_url"`
|
||||
SiteURL string `json:"site_url"`
|
||||
Title string `json:"title"`
|
||||
CheckedAt time.Time `json:"checked_at,omitempty"`
|
||||
EtagHeader string `json:"etag_header,omitempty"`
|
||||
LastModifiedHeader string `json:"last_modified_header,omitempty"`
|
||||
ParsingErrorMsg string `json:"parsing_error_message,omitempty"`
|
||||
ParsingErrorCount int `json:"parsing_error_count,omitempty"`
|
||||
Disabled bool `json:"disabled"`
|
||||
IgnoreHTTPCache bool `json:"ignore_http_cache"`
|
||||
AllowSelfSignedCertificates bool `json:"allow_self_signed_certificates"`
|
||||
FetchViaProxy bool `json:"fetch_via_proxy"`
|
||||
ScraperRules string `json:"scraper_rules"`
|
||||
RewriteRules string `json:"rewrite_rules"`
|
||||
BlocklistRules string `json:"blocklist_rules"`
|
||||
KeeplistRules string `json:"keeplist_rules"`
|
||||
Crawler bool `json:"crawler"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
Cookie string `json:"cookie"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Category *Category `json:"category,omitempty"`
|
||||
HideGlobally bool `json:"hide_globally"`
|
||||
}
|
||||
|
||||
// FeedCreationRequest represents the request to create a feed.
|
||||
type FeedCreationRequest struct {
|
||||
FeedURL string `json:"feed_url"`
|
||||
CategoryID int64 `json:"category_id"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Crawler bool `json:"crawler"`
|
||||
Disabled bool `json:"disabled"`
|
||||
IgnoreHTTPCache bool `json:"ignore_http_cache"`
|
||||
FetchViaProxy bool `json:"fetch_via_proxy"`
|
||||
ScraperRules string `json:"scraper_rules"`
|
||||
RewriteRules string `json:"rewrite_rules"`
|
||||
BlocklistRules string `json:"blocklist_rules"`
|
||||
KeeplistRules string `json:"keeplist_rules"`
|
||||
FeedURL string `json:"feed_url"`
|
||||
CategoryID int64 `json:"category_id"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
Cookie string `json:"cookie"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Crawler bool `json:"crawler"`
|
||||
Disabled bool `json:"disabled"`
|
||||
IgnoreHTTPCache bool `json:"ignore_http_cache"`
|
||||
AllowSelfSignedCertificates bool `json:"allow_self_signed_certificates"`
|
||||
FetchViaProxy bool `json:"fetch_via_proxy"`
|
||||
ScraperRules string `json:"scraper_rules"`
|
||||
RewriteRules string `json:"rewrite_rules"`
|
||||
BlocklistRules string `json:"blocklist_rules"`
|
||||
KeeplistRules string `json:"keeplist_rules"`
|
||||
HideGlobally bool `json:"hide_globally"`
|
||||
}
|
||||
|
||||
// FeedModificationRequest represents the request to update a feed.
|
||||
type FeedModificationRequest struct {
|
||||
FeedURL *string `json:"feed_url"`
|
||||
SiteURL *string `json:"site_url"`
|
||||
Title *string `json:"title"`
|
||||
ScraperRules *string `json:"scraper_rules"`
|
||||
RewriteRules *string `json:"rewrite_rules"`
|
||||
BlocklistRules *string `json:"blocklist_rules"`
|
||||
KeeplistRules *string `json:"keeplist_rules"`
|
||||
Crawler *bool `json:"crawler"`
|
||||
UserAgent *string `json:"user_agent"`
|
||||
Username *string `json:"username"`
|
||||
Password *string `json:"password"`
|
||||
CategoryID *int64 `json:"category_id"`
|
||||
Disabled *bool `json:"disabled"`
|
||||
IgnoreHTTPCache *bool `json:"ignore_http_cache"`
|
||||
FetchViaProxy *bool `json:"fetch_via_proxy"`
|
||||
FeedURL *string `json:"feed_url"`
|
||||
SiteURL *string `json:"site_url"`
|
||||
Title *string `json:"title"`
|
||||
ScraperRules *string `json:"scraper_rules"`
|
||||
RewriteRules *string `json:"rewrite_rules"`
|
||||
BlocklistRules *string `json:"blocklist_rules"`
|
||||
KeeplistRules *string `json:"keeplist_rules"`
|
||||
Crawler *bool `json:"crawler"`
|
||||
UserAgent *string `json:"user_agent"`
|
||||
Cookie *string `json:"cookie"`
|
||||
Username *string `json:"username"`
|
||||
Password *string `json:"password"`
|
||||
CategoryID *int64 `json:"category_id"`
|
||||
Disabled *bool `json:"disabled"`
|
||||
IgnoreHTTPCache *bool `json:"ignore_http_cache"`
|
||||
AllowSelfSignedCertificates *bool `json:"allow_self_signed_certificates"`
|
||||
FetchViaProxy *bool `json:"fetch_via_proxy"`
|
||||
HideGlobally *bool `json:"hide_globally"`
|
||||
}
|
||||
|
||||
// FeedIcon represents the feed icon.
|
||||
@@ -167,6 +180,11 @@ type FeedIcon struct {
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
type FeedCounters struct {
|
||||
ReadCounters map[int64]int `json:"reads"`
|
||||
UnreadCounters map[int64]int `json:"unreads"`
|
||||
}
|
||||
|
||||
// Feeds represents a list of feeds.
|
||||
type Feeds []*Feed
|
||||
|
||||
@@ -179,8 +197,10 @@ type Entry struct {
|
||||
Hash string `json:"hash"`
|
||||
Title string `json:"title"`
|
||||
URL string `json:"url"`
|
||||
CommentsURL string `json:"comments_url"`
|
||||
Date time.Time `json:"published_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ChangedAt time.Time `json:"changed_at"`
|
||||
Content string `json:"content"`
|
||||
Author string `json:"author"`
|
||||
ShareCode string `json:"share_code"`
|
||||
@@ -206,6 +226,11 @@ type Enclosure struct {
|
||||
// Enclosures represents a list of attachments.
|
||||
type Enclosures []*Enclosure
|
||||
|
||||
const (
|
||||
FilterNotStarred = "0"
|
||||
FilterOnlyStarred = "1"
|
||||
)
|
||||
|
||||
// Filter is used to filter entries.
|
||||
type Filter struct {
|
||||
Status string
|
||||
@@ -213,7 +238,7 @@ type Filter struct {
|
||||
Limit int
|
||||
Order string
|
||||
Direction string
|
||||
Starred bool
|
||||
Starred string
|
||||
Before int64
|
||||
After int64
|
||||
BeforeEntryID int64
|
||||
+12
-6
@@ -10,7 +10,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -83,11 +82,11 @@ func (r *request) execute(method, path string, data interface{}) (io.ReadCloser,
|
||||
}
|
||||
|
||||
if data != nil {
|
||||
switch data.(type) {
|
||||
switch data := data.(type) {
|
||||
case io.ReadCloser:
|
||||
request.Body = data.(io.ReadCloser)
|
||||
request.Body = data
|
||||
default:
|
||||
request.Body = ioutil.NopCloser(bytes.NewBuffer(r.toJSON(data)))
|
||||
request.Body = io.NopCloser(bytes.NewBuffer(r.toJSON(data)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,8 +104,15 @@ func (r *request) execute(method, path string, data interface{}) (io.ReadCloser,
|
||||
response.Body.Close()
|
||||
return nil, ErrForbidden
|
||||
case http.StatusInternalServerError:
|
||||
response.Body.Close()
|
||||
return nil, ErrServerError
|
||||
defer response.Body.Close()
|
||||
|
||||
var resp errorResponse
|
||||
decoder := json.NewDecoder(response.Body)
|
||||
// If we failed to decode, just return a generic ErrServerError
|
||||
if err := decoder.Decode(&resp); err != nil {
|
||||
return nil, ErrServerError
|
||||
}
|
||||
return nil, errors.New("miniflux: internal server error: " + resp.ErrorMessage)
|
||||
case http.StatusNotFound:
|
||||
response.Body.Close()
|
||||
return nil, ErrNotFound
|
||||
|
||||
+54
-2
@@ -5,7 +5,6 @@
|
||||
package config // import "miniflux.app/config"
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
@@ -1309,7 +1308,7 @@ DEBUG = yes
|
||||
Invalid text
|
||||
`)
|
||||
|
||||
tmpfile, err := ioutil.TempFile(".", "miniflux.*.unit_test.conf")
|
||||
tmpfile, err := os.CreateTemp(".", "miniflux.*.unit_test.conf")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1414,3 +1413,56 @@ func TestAuthProxyUserCreationAdmin(t *testing.T) {
|
||||
t.Fatalf(`Unexpected AUTH_PROXY_USER_CREATION value, got %v instead of %v`, result, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchYouTubeWatchTime(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("FETCH_YOUTUBE_WATCH_TIME", "1")
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
expected := true
|
||||
result := opts.FetchYouTubeWatchTime()
|
||||
|
||||
if result != expected {
|
||||
t.Fatalf(`Unexpected FETCH_YOUTUBE_WATCH_TIME value, got %v instead of %v`, result, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseConfigDumpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
wantOpts := NewOptions()
|
||||
wantOpts.adminUsername = "my-username"
|
||||
|
||||
serialized := wantOpts.String()
|
||||
tmpfile, err := os.CreateTemp(".", "miniflux.*.unit_test.conf")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := tmpfile.Write([]byte(serialized)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
parser := NewParser()
|
||||
parsedOpts, err := parser.ParseFile(tmpfile.Name())
|
||||
if err != nil {
|
||||
t.Errorf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if parsedOpts.AdminUsername() != wantOpts.AdminUsername() {
|
||||
t.Fatalf(`Unexpected ADMIN_USERNAME value, got %q instead of %q`, parsedOpts.AdminUsername(), wantOpts.AdminUsername())
|
||||
}
|
||||
|
||||
if err := tmpfile.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := os.Remove(tmpfile.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
+66
-10
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"miniflux.app/version"
|
||||
)
|
||||
@@ -25,7 +26,7 @@ const (
|
||||
defaultBasePath = ""
|
||||
defaultWorkerPoolSize = 5
|
||||
defaultPollingFrequency = 60
|
||||
defaultBatchSize = 10
|
||||
defaultBatchSize = 100
|
||||
defaultPollingScheduler = "round_robin"
|
||||
defaultSchedulerEntryFrequencyMinInterval = 5
|
||||
defaultSchedulerEntryFrequencyMaxInterval = 24 * 60
|
||||
@@ -34,6 +35,7 @@ const (
|
||||
defaultDatabaseURL = "user=postgres password=postgres dbname=miniflux2 sslmode=disable"
|
||||
defaultDatabaseMaxConns = 20
|
||||
defaultDatabaseMinConns = 1
|
||||
defaultDatabaseConnectionLifetime = 5
|
||||
defaultListenAddr = "127.0.0.1:8080"
|
||||
defaultCertFile = ""
|
||||
defaultKeyFile = ""
|
||||
@@ -41,8 +43,10 @@ const (
|
||||
defaultCleanupFrequencyHours = 24
|
||||
defaultCleanupArchiveReadDays = 60
|
||||
defaultCleanupArchiveUnreadDays = 180
|
||||
defaultCleanupArchiveBatchSize = 10000
|
||||
defaultCleanupRemoveSessionsDays = 30
|
||||
defaultProxyImages = "http-only"
|
||||
defaultFetchYouTubeWatchTime = false
|
||||
defaultCreateAdmin = false
|
||||
defaultAdminUsername = ""
|
||||
defaultAdminPassword = ""
|
||||
@@ -63,6 +67,8 @@ const (
|
||||
defaultMetricsCollector = false
|
||||
defaultMetricsRefreshInterval = 60
|
||||
defaultMetricsAllowedNetworks = "127.0.0.1/8"
|
||||
defaultWatchdog = true
|
||||
defaultInvidiousInstance = "yewtu.be"
|
||||
)
|
||||
|
||||
var defaultHTTPClientUserAgent = "Mozilla/5.0 (compatible; Miniflux/" + version.Version + "; +https://miniflux.app)"
|
||||
@@ -88,6 +94,7 @@ type Options struct {
|
||||
databaseURL string
|
||||
databaseMaxConns int
|
||||
databaseMinConns int
|
||||
databaseConnectionLifetime int
|
||||
runMigrations bool
|
||||
listenAddr string
|
||||
certFile string
|
||||
@@ -96,6 +103,7 @@ type Options struct {
|
||||
cleanupFrequencyHours int
|
||||
cleanupArchiveReadDays int
|
||||
cleanupArchiveUnreadDays int
|
||||
cleanupArchiveBatchSize int
|
||||
cleanupRemoveSessionsDays int
|
||||
pollingFrequency int
|
||||
batchSize int
|
||||
@@ -108,6 +116,7 @@ type Options struct {
|
||||
adminUsername string
|
||||
adminPassword string
|
||||
proxyImages string
|
||||
fetchYouTubeWatchTime bool
|
||||
oauth2UserCreationAllowed bool
|
||||
oauth2ClientID string
|
||||
oauth2ClientSecret string
|
||||
@@ -126,6 +135,8 @@ type Options struct {
|
||||
metricsCollector bool
|
||||
metricsRefreshInterval int
|
||||
metricsAllowedNetworks []string
|
||||
watchdog bool
|
||||
invidiousInstance string
|
||||
}
|
||||
|
||||
// NewOptions returns Options with default values.
|
||||
@@ -144,6 +155,7 @@ func NewOptions() *Options {
|
||||
databaseURL: defaultDatabaseURL,
|
||||
databaseMaxConns: defaultDatabaseMaxConns,
|
||||
databaseMinConns: defaultDatabaseMinConns,
|
||||
databaseConnectionLifetime: defaultDatabaseConnectionLifetime,
|
||||
runMigrations: defaultRunMigrations,
|
||||
listenAddr: defaultListenAddr,
|
||||
certFile: defaultCertFile,
|
||||
@@ -152,6 +164,7 @@ func NewOptions() *Options {
|
||||
cleanupFrequencyHours: defaultCleanupFrequencyHours,
|
||||
cleanupArchiveReadDays: defaultCleanupArchiveReadDays,
|
||||
cleanupArchiveUnreadDays: defaultCleanupArchiveUnreadDays,
|
||||
cleanupArchiveBatchSize: defaultCleanupArchiveBatchSize,
|
||||
cleanupRemoveSessionsDays: defaultCleanupRemoveSessionsDays,
|
||||
pollingFrequency: defaultPollingFrequency,
|
||||
batchSize: defaultBatchSize,
|
||||
@@ -162,6 +175,7 @@ func NewOptions() *Options {
|
||||
workerPoolSize: defaultWorkerPoolSize,
|
||||
createAdmin: defaultCreateAdmin,
|
||||
proxyImages: defaultProxyImages,
|
||||
fetchYouTubeWatchTime: defaultFetchYouTubeWatchTime,
|
||||
oauth2UserCreationAllowed: defaultOAuth2UserCreation,
|
||||
oauth2ClientID: defaultOAuth2ClientID,
|
||||
oauth2ClientSecret: defaultOAuth2ClientSecret,
|
||||
@@ -180,6 +194,8 @@ func NewOptions() *Options {
|
||||
metricsCollector: defaultMetricsCollector,
|
||||
metricsRefreshInterval: defaultMetricsRefreshInterval,
|
||||
metricsAllowedNetworks: []string{defaultMetricsAllowedNetworks},
|
||||
watchdog: defaultWatchdog,
|
||||
invidiousInstance: defaultInvidiousInstance,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +259,11 @@ func (o *Options) DatabaseMinConns() int {
|
||||
return o.databaseMinConns
|
||||
}
|
||||
|
||||
// DatabaseConnectionLifetime returns the maximum amount of time a connection may be reused.
|
||||
func (o *Options) DatabaseConnectionLifetime() time.Duration {
|
||||
return time.Duration(o.databaseConnectionLifetime) * time.Minute
|
||||
}
|
||||
|
||||
// ListenAddr returns the listen address for the HTTP server.
|
||||
func (o *Options) ListenAddr() string {
|
||||
return o.listenAddr
|
||||
@@ -278,6 +299,11 @@ func (o *Options) CleanupArchiveUnreadDays() int {
|
||||
return o.cleanupArchiveUnreadDays
|
||||
}
|
||||
|
||||
// CleanupArchiveBatchSize returns the number of entries to archive for each interval.
|
||||
func (o *Options) CleanupArchiveBatchSize() int {
|
||||
return o.cleanupArchiveBatchSize
|
||||
}
|
||||
|
||||
// CleanupRemoveSessionsDays returns the number of days after which to remove sessions.
|
||||
func (o *Options) CleanupRemoveSessionsDays() int {
|
||||
return o.cleanupRemoveSessionsDays
|
||||
@@ -373,6 +399,12 @@ func (o *Options) AdminPassword() string {
|
||||
return o.adminPassword
|
||||
}
|
||||
|
||||
// FetchYouTubeWatchTime returns true if the YouTube video duration
|
||||
// should be fetched and used as a reading time.
|
||||
func (o *Options) FetchYouTubeWatchTime() bool {
|
||||
return o.fetchYouTubeWatchTime
|
||||
}
|
||||
|
||||
// ProxyImages returns "none" to never proxy, "http-only" to proxy non-HTTPS, "all" to always proxy.
|
||||
func (o *Options) ProxyImages() string {
|
||||
return o.proxyImages
|
||||
@@ -448,10 +480,20 @@ func (o *Options) HTTPClientUserAgent() string {
|
||||
return o.httpClientUserAgent
|
||||
}
|
||||
|
||||
// HasWatchdog returns true if the systemd watchdog is enabled.
|
||||
func (o *Options) HasWatchdog() bool {
|
||||
return o.watchdog
|
||||
}
|
||||
|
||||
// InvidiousInstance returns the invidious instance used by miniflux
|
||||
func (o *Options) InvidiousInstance() string {
|
||||
return o.invidiousInstance
|
||||
}
|
||||
|
||||
// SortedOptions returns options as a list of key value pairs, sorted by keys.
|
||||
func (o *Options) SortedOptions() []*Option {
|
||||
func (o *Options) SortedOptions(redactSecret bool) []*Option {
|
||||
var keyValues = map[string]interface{}{
|
||||
"ADMIN_PASSWORD": o.adminPassword,
|
||||
"ADMIN_PASSWORD": redactSecretValue(o.adminPassword, redactSecret),
|
||||
"ADMIN_USERNAME": o.adminUsername,
|
||||
"AUTH_PROXY_HEADER": o.authProxyHeader,
|
||||
"AUTH_PROXY_USER_CREATION": o.authProxyUserCreation,
|
||||
@@ -462,14 +504,19 @@ func (o *Options) SortedOptions() []*Option {
|
||||
"CERT_FILE": o.certFile,
|
||||
"CLEANUP_ARCHIVE_READ_DAYS": o.cleanupArchiveReadDays,
|
||||
"CLEANUP_ARCHIVE_UNREAD_DAYS": o.cleanupArchiveUnreadDays,
|
||||
"CLEANUP_ARCHIVE_BATCH_SIZE": o.cleanupArchiveBatchSize,
|
||||
"CLEANUP_FREQUENCY_HOURS": o.cleanupFrequencyHours,
|
||||
"CLEANUP_REMOVE_SESSIONS_DAYS": o.cleanupRemoveSessionsDays,
|
||||
"CREATE_ADMIN": o.createAdmin,
|
||||
"DATABASE_MAX_CONNS": o.databaseMaxConns,
|
||||
"DATABASE_MIN_CONNS": o.databaseMinConns,
|
||||
"DATABASE_URL": o.databaseURL,
|
||||
"DATABASE_CONNECTION_LIFETIME": o.databaseConnectionLifetime,
|
||||
"DATABASE_URL": redactSecretValue(o.databaseURL, redactSecret),
|
||||
"DEBUG": o.debug,
|
||||
"HSTS": o.hsts,
|
||||
"DISABLE_HSTS": !o.hsts,
|
||||
"DISABLE_SCHEDULER_SERVICE": !o.schedulerService,
|
||||
"DISABLE_HTTP_SERVICE": !o.httpService,
|
||||
"FETCH_YOUTUBE_WATCH_TIME": o.fetchYouTubeWatchTime,
|
||||
"HTTPS": o.HTTPS,
|
||||
"HTTP_CLIENT_MAX_BODY_SIZE": o.httpClientMaxBodySize,
|
||||
"HTTP_CLIENT_PROXY": o.httpClientProxy,
|
||||
@@ -477,20 +524,21 @@ func (o *Options) SortedOptions() []*Option {
|
||||
"HTTP_CLIENT_USER_AGENT": o.httpClientUserAgent,
|
||||
"HTTP_SERVICE": o.httpService,
|
||||
"KEY_FILE": o.certKeyFile,
|
||||
"INVIDIOUS_INSTANCE": o.invidiousInstance,
|
||||
"LISTEN_ADDR": o.listenAddr,
|
||||
"LOG_DATE_TIME": o.logDateTime,
|
||||
"MAINTENANCE_MESSAGE": o.maintenanceMessage,
|
||||
"MAINTENANCE_MODE": o.maintenanceMode,
|
||||
"METRICS_ALLOWED_NETWORKS": o.metricsAllowedNetworks,
|
||||
"METRICS_ALLOWED_NETWORKS": strings.Join(o.metricsAllowedNetworks, ","),
|
||||
"METRICS_COLLECTOR": o.metricsCollector,
|
||||
"METRICS_REFRESH_INTERVAL": o.metricsRefreshInterval,
|
||||
"OAUTH2_CLIENT_ID": o.oauth2ClientID,
|
||||
"OAUTH2_CLIENT_SECRET": o.oauth2ClientSecret,
|
||||
"OAUTH2_CLIENT_SECRET": redactSecretValue(o.oauth2ClientSecret, redactSecret),
|
||||
"OAUTH2_OIDC_DISCOVERY_ENDPOINT": o.oauth2OidcDiscoveryEndpoint,
|
||||
"OAUTH2_PROVIDER": o.oauth2Provider,
|
||||
"OAUTH2_REDIRECT_URL": o.oauth2RedirectURL,
|
||||
"OAUTH2_USER_CREATION": o.oauth2UserCreationAllowed,
|
||||
"POCKET_CONSUMER_KEY": o.pocketConsumerKey,
|
||||
"POCKET_CONSUMER_KEY": redactSecretValue(o.pocketConsumerKey, redactSecret),
|
||||
"POLLING_FREQUENCY": o.pollingFrequency,
|
||||
"POLLING_PARSING_ERROR_LIMIT": o.pollingParsingErrorLimit,
|
||||
"POLLING_SCHEDULER": o.pollingScheduler,
|
||||
@@ -502,6 +550,7 @@ func (o *Options) SortedOptions() []*Option {
|
||||
"SCHEDULER_SERVICE": o.schedulerService,
|
||||
"SERVER_TIMING_HEADER": o.serverTimingHeader,
|
||||
"WORKER_POOL_SIZE": o.workerPoolSize,
|
||||
"WATCHDOG": o.watchdog,
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(keyValues))
|
||||
@@ -520,9 +569,16 @@ func (o *Options) SortedOptions() []*Option {
|
||||
func (o *Options) String() string {
|
||||
var builder strings.Builder
|
||||
|
||||
for _, option := range o.SortedOptions() {
|
||||
builder.WriteString(fmt.Sprintf("%s: %v\n", option.Key, option.Value))
|
||||
for _, option := range o.SortedOptions(false) {
|
||||
fmt.Fprintf(&builder, "%s=%v\n", option.Key, option.Value)
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func redactSecretValue(value string, redactSecret bool) string {
|
||||
if redactSecret && value != "" {
|
||||
return "******"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
+13
-4
@@ -10,7 +10,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
url_parser "net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -96,6 +95,8 @@ func (p *Parser) parseLines(lines []string) (err error) {
|
||||
p.opts.databaseMaxConns = parseInt(value, defaultDatabaseMaxConns)
|
||||
case "DATABASE_MIN_CONNS":
|
||||
p.opts.databaseMinConns = parseInt(value, defaultDatabaseMinConns)
|
||||
case "DATABASE_CONNECTION_LIFETIME":
|
||||
p.opts.databaseConnectionLifetime = parseInt(value, defaultDatabaseConnectionLifetime)
|
||||
case "RUN_MIGRATIONS":
|
||||
p.opts.runMigrations = parseBool(value, defaultRunMigrations)
|
||||
case "DISABLE_HSTS":
|
||||
@@ -118,6 +119,8 @@ func (p *Parser) parseLines(lines []string) (err error) {
|
||||
p.opts.cleanupArchiveReadDays = parseInt(value, defaultCleanupArchiveReadDays)
|
||||
case "CLEANUP_ARCHIVE_UNREAD_DAYS":
|
||||
p.opts.cleanupArchiveUnreadDays = parseInt(value, defaultCleanupArchiveUnreadDays)
|
||||
case "CLEANUP_ARCHIVE_BATCH_SIZE":
|
||||
p.opts.cleanupArchiveBatchSize = parseInt(value, defaultCleanupArchiveBatchSize)
|
||||
case "CLEANUP_REMOVE_SESSIONS_DAYS":
|
||||
p.opts.cleanupRemoveSessionsDays = parseInt(value, defaultCleanupRemoveSessionsDays)
|
||||
case "WORKER_POOL_SIZE":
|
||||
@@ -188,6 +191,12 @@ func (p *Parser) parseLines(lines []string) (err error) {
|
||||
p.opts.metricsRefreshInterval = parseInt(value, defaultMetricsRefreshInterval)
|
||||
case "METRICS_ALLOWED_NETWORKS":
|
||||
p.opts.metricsAllowedNetworks = parseStringList(value, []string{defaultMetricsAllowedNetworks})
|
||||
case "FETCH_YOUTUBE_WATCH_TIME":
|
||||
p.opts.fetchYouTubeWatchTime = parseBool(value, defaultFetchYouTubeWatchTime)
|
||||
case "WATCHDOG":
|
||||
p.opts.watchdog = parseBool(value, defaultWatchdog)
|
||||
case "INVIDIOUS_INSTANCE":
|
||||
p.opts.invidiousInstance = parseString(value, defaultInvidiousInstance)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,12 +217,12 @@ func parseBaseURL(value string) (string, string, string, error) {
|
||||
|
||||
url, err := url_parser.Parse(value)
|
||||
if err != nil {
|
||||
return "", "", "", fmt.Errorf("Invalid BASE_URL: %v", err)
|
||||
return "", "", "", fmt.Errorf("config: invalid BASE_URL: %w", err)
|
||||
}
|
||||
|
||||
scheme := strings.ToLower(url.Scheme)
|
||||
if scheme != "https" && scheme != "http" {
|
||||
return "", "", "", errors.New("Invalid BASE_URL: scheme must be http or https")
|
||||
return "", "", "", errors.New("config: invalid BASE_URL: scheme must be http or https")
|
||||
}
|
||||
|
||||
basePath := url.Path
|
||||
@@ -269,7 +278,7 @@ func parseStringList(value string, fallback []string) []string {
|
||||
}
|
||||
|
||||
func readSecretFile(filename, fallback string) string {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
data, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
version: '3.3'
|
||||
version: '3.4'
|
||||
services:
|
||||
miniflux:
|
||||
image: miniflux/miniflux:latest
|
||||
image: ${MINIFLUX_IMAGE:-miniflux/miniflux:latest}
|
||||
container_name: miniflux
|
||||
restart: always
|
||||
ports:
|
||||
- "80:8080"
|
||||
depends_on:
|
||||
@@ -13,6 +14,10 @@ services:
|
||||
- CREATE_ADMIN=1
|
||||
- ADMIN_USERNAME=admin
|
||||
- ADMIN_PASSWORD=test123
|
||||
- DEBUG=1
|
||||
# Optional health check:
|
||||
# healthcheck:
|
||||
# test: ["CMD", "/usr/bin/miniflux", "-healthcheck", "auto"]
|
||||
db:
|
||||
image: postgres:latest
|
||||
container_name: postgres
|
||||
@@ -21,5 +26,9 @@ services:
|
||||
- POSTGRES_PASSWORD=secret
|
||||
volumes:
|
||||
- miniflux-db:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD", "pg_isready", "-U", "miniflux"]
|
||||
interval: 10s
|
||||
start_period: 30s
|
||||
volumes:
|
||||
miniflux-db:
|
||||
miniflux-db:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: '3.3'
|
||||
version: '3.4'
|
||||
services:
|
||||
caddy:
|
||||
image: caddy:2
|
||||
@@ -13,7 +13,7 @@ services:
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
miniflux:
|
||||
image: miniflux/miniflux:latest
|
||||
image: ${MINIFLUX_IMAGE:-miniflux/miniflux:latest}
|
||||
container_name: miniflux
|
||||
depends_on:
|
||||
- db
|
||||
@@ -32,6 +32,10 @@ services:
|
||||
- POSTGRES_PASSWORD=secret
|
||||
volumes:
|
||||
- miniflux-db:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD", "pg_isready", "-U", "miniflux"]
|
||||
interval: 10s
|
||||
start_period: 30s
|
||||
volumes:
|
||||
miniflux-db:
|
||||
caddy_data:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: '3.3'
|
||||
version: '3.4'
|
||||
services:
|
||||
traefik:
|
||||
image: "traefik:v2.3"
|
||||
@@ -18,7 +18,7 @@ services:
|
||||
- "./letsencrypt:/letsencrypt"
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
miniflux:
|
||||
image: miniflux/miniflux:latest
|
||||
image: ${MINIFLUX_IMAGE:-miniflux/miniflux:latest}
|
||||
container_name: miniflux
|
||||
depends_on:
|
||||
- db
|
||||
@@ -44,5 +44,9 @@ services:
|
||||
- POSTGRES_PASSWORD=secret
|
||||
volumes:
|
||||
- miniflux-db:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD", "pg_isready", "-U", "miniflux"]
|
||||
interval: 10s
|
||||
start_period: 30s
|
||||
volumes:
|
||||
miniflux-db:
|
||||
|
||||
@@ -7,13 +7,14 @@ package database // import "miniflux.app/database"
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
// Postgresql driver import
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
// NewConnectionPool configures the database connection pool.
|
||||
func NewConnectionPool(dsn string, minConnections, maxConnections int) (*sql.DB, error) {
|
||||
func NewConnectionPool(dsn string, minConnections, maxConnections int, connectionLifetime time.Duration) (*sql.DB, error) {
|
||||
db, err := sql.Open("postgres", dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -21,6 +22,7 @@ func NewConnectionPool(dsn string, minConnections, maxConnections int) (*sql.DB,
|
||||
|
||||
db.SetMaxOpenConns(maxConnections)
|
||||
db.SetMaxIdleConns(minConnections)
|
||||
db.SetConnMaxLifetime(connectionLifetime)
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
+89
-12
@@ -10,13 +10,14 @@ import (
|
||||
|
||||
var schemaVersion = len(migrations)
|
||||
|
||||
// Order is important. Add new migrations at the end of the list.
|
||||
var migrations = []func(tx *sql.Tx) error{
|
||||
func(tx *sql.Tx) (err error) {
|
||||
sql := `
|
||||
CREATE TABLE schema_version (
|
||||
version text not null
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE users (
|
||||
id serial not null,
|
||||
username text not null unique,
|
||||
@@ -28,7 +29,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||
last_login_at timestamp with time zone,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE sessions (
|
||||
id serial not null,
|
||||
user_id int not null,
|
||||
@@ -40,7 +41,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||
unique (user_id, token),
|
||||
foreign key (user_id) references users(id) on delete cascade
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE categories (
|
||||
id serial not null,
|
||||
user_id int not null,
|
||||
@@ -49,7 +50,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||
unique (user_id, title),
|
||||
foreign key (user_id) references users(id) on delete cascade
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE feeds (
|
||||
id bigserial not null,
|
||||
user_id int not null,
|
||||
@@ -67,9 +68,9 @@ var migrations = []func(tx *sql.Tx) error{
|
||||
foreign key (user_id) references users(id) on delete cascade,
|
||||
foreign key (category_id) references categories(id) on delete cascade
|
||||
);
|
||||
|
||||
|
||||
CREATE TYPE entry_status as enum('unread', 'read', 'removed');
|
||||
|
||||
|
||||
CREATE TABLE entries (
|
||||
id bigserial not null,
|
||||
user_id int not null,
|
||||
@@ -86,9 +87,9 @@ var migrations = []func(tx *sql.Tx) error{
|
||||
foreign key (user_id) references users(id) on delete cascade,
|
||||
foreign key (feed_id) references feeds(id) on delete cascade
|
||||
);
|
||||
|
||||
|
||||
CREATE INDEX entries_feed_idx on entries using btree(feed_id);
|
||||
|
||||
|
||||
CREATE TABLE enclosures (
|
||||
id bigserial not null,
|
||||
user_id int not null,
|
||||
@@ -100,7 +101,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||
foreign key (user_id) references users(id) on delete cascade,
|
||||
foreign key (entry_id) references entries(id) on delete cascade
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE icons (
|
||||
id bigserial not null,
|
||||
hash text not null unique,
|
||||
@@ -108,14 +109,14 @@ var migrations = []func(tx *sql.Tx) error{
|
||||
content bytea not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE feed_icons (
|
||||
feed_id bigint not null,
|
||||
icon_id bigint not null,
|
||||
primary key(feed_id, icon_id),
|
||||
foreign key (feed_id) references feeds(id) on delete cascade,
|
||||
foreign key (icon_id) references icons(id) on delete cascade
|
||||
);
|
||||
);
|
||||
`
|
||||
_, err = tx.Exec(sql)
|
||||
return err
|
||||
@@ -409,7 +410,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
sql := `
|
||||
ALTER TABLE feeds
|
||||
ALTER TABLE feeds
|
||||
ADD COLUMN blocklist_rules text not null default '',
|
||||
ADD COLUMN keeplist_rules text not null default ''
|
||||
`
|
||||
@@ -514,4 +515,80 @@ var migrations = []func(tx *sql.Tx) error{
|
||||
`)
|
||||
return err
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
_, err = tx.Exec(`
|
||||
ALTER TABLE feeds ADD COLUMN allow_self_signed_certificates boolean not null default false
|
||||
`)
|
||||
return err
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
sql := `
|
||||
CREATE TYPE webapp_display_mode AS enum('fullscreen', 'standalone', 'minimal-ui', 'browser');
|
||||
ALTER TABLE users ADD COLUMN display_mode webapp_display_mode default 'standalone';
|
||||
`
|
||||
_, err = tx.Exec(sql)
|
||||
return err
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
sql := `ALTER TABLE feeds ADD COLUMN cookie text default ''`
|
||||
_, err = tx.Exec(sql)
|
||||
return err
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
_, err = tx.Exec(`
|
||||
ALTER TABLE categories ADD COLUMN hide_globally boolean not null default false
|
||||
`)
|
||||
return err
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
_, err = tx.Exec(`
|
||||
ALTER TABLE feeds ADD COLUMN hide_globally boolean not null default false
|
||||
`)
|
||||
return err
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
sql := `
|
||||
ALTER TABLE integrations ADD COLUMN telegram_bot_enabled bool default 'f';
|
||||
ALTER TABLE integrations ADD COLUMN telegram_bot_token text default '';
|
||||
ALTER TABLE integrations ADD COLUMN telegram_bot_chat_id text default '';
|
||||
`
|
||||
_, err = tx.Exec(sql)
|
||||
return err
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
sql := `
|
||||
CREATE TYPE entry_sorting_order AS enum('published_at', 'created_at');
|
||||
ALTER TABLE users ADD COLUMN entry_order entry_sorting_order default 'published_at';
|
||||
`
|
||||
_, err = tx.Exec(sql)
|
||||
return err
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
sql := `
|
||||
ALTER TABLE integrations ADD COLUMN googlereader_enabled bool default 'f';
|
||||
ALTER TABLE integrations ADD COLUMN googlereader_username text default '';
|
||||
ALTER TABLE integrations ADD COLUMN googlereader_password text default '';
|
||||
`
|
||||
_, err = tx.Exec(sql)
|
||||
return err
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
sql := `
|
||||
ALTER TABLE integrations ADD COLUMN espial_enabled bool default 'f';
|
||||
ALTER TABLE integrations ADD COLUMN espial_url text default '';
|
||||
ALTER TABLE integrations ADD COLUMN espial_api_key text default '';
|
||||
ALTER TABLE integrations ADD COLUMN espial_tags text default 'miniflux';
|
||||
`
|
||||
_, err = tx.Exec(sql)
|
||||
return err
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
sql := `
|
||||
ALTER TABLE integrations ADD COLUMN linkding_enabled bool default 'f';
|
||||
ALTER TABLE integrations ADD COLUMN linkding_url text default '';
|
||||
ALTER TABLE integrations ADD COLUMN linkding_api_key text default '';
|
||||
`
|
||||
_, err = tx.Exec(sql)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
+1
-1
@@ -365,7 +365,7 @@ func (h *handler) handleSavedItems(w http.ResponseWriter, r *http.Request) {
|
||||
logger.Debug("[Fever] Fetching saved items for user #%d", userID)
|
||||
|
||||
builder := h.store.NewEntryQueryBuilder(userID)
|
||||
builder.WithStarred()
|
||||
builder.WithStarred(true)
|
||||
|
||||
entryIDs, err := builder.GetEntryIDs()
|
||||
if err != nil {
|
||||
|
||||
-221
@@ -1,221 +0,0 @@
|
||||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/tdewolff/minify/v2"
|
||||
"github.com/tdewolff/minify/v2/css"
|
||||
"github.com/tdewolff/minify/v2/js"
|
||||
)
|
||||
|
||||
const tpl = `// Code generated by go generate; DO NOT EDIT.
|
||||
|
||||
package {{ .Package }} // import "miniflux.app/{{ .ImportPath }}"
|
||||
|
||||
var {{ .Map }} = map[string]string{
|
||||
{{ range $constant, $content := .Files }}` + "\t" + `"{{ $constant }}": ` + "`{{ $content }}`" + `,
|
||||
{{ end }}}
|
||||
|
||||
var {{ .Map }}Checksums = map[string]string{
|
||||
{{ range $constant, $content := .Checksums }}` + "\t" + `"{{ $constant }}": "{{ $content }}",
|
||||
{{ end }}}
|
||||
`
|
||||
|
||||
var bundleTpl = template.Must(template.New("").Parse(tpl))
|
||||
|
||||
type Bundle struct {
|
||||
Package string
|
||||
Map string
|
||||
ImportPath string
|
||||
Files map[string]string
|
||||
Checksums map[string]string
|
||||
}
|
||||
|
||||
func (b *Bundle) Write(filename string) {
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
bundleTpl.Execute(f, b)
|
||||
}
|
||||
|
||||
func NewBundle(pkg, mapName, importPath string) *Bundle {
|
||||
return &Bundle{
|
||||
Package: pkg,
|
||||
Map: mapName,
|
||||
ImportPath: importPath,
|
||||
Files: make(map[string]string),
|
||||
Checksums: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func readFile(filename string) []byte {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func checksum(data []byte) string {
|
||||
return fmt.Sprintf("%x", sha256.Sum256(data))
|
||||
}
|
||||
|
||||
func basename(filename string) string {
|
||||
return path.Base(filename)
|
||||
}
|
||||
|
||||
func stripExtension(filename string) string {
|
||||
filename = strings.TrimSuffix(filename, path.Ext(filename))
|
||||
return strings.Replace(filename, " ", "_", -1)
|
||||
}
|
||||
|
||||
func glob(pattern string) []string {
|
||||
// There is no Glob function in path package, so we have to use filepath and replace in case of Windows
|
||||
files, _ := filepath.Glob(pattern)
|
||||
for i := range files {
|
||||
if strings.Contains(files[i], "\\") {
|
||||
files[i] = strings.Replace(files[i], "\\", "/", -1)
|
||||
}
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
func concat(files []string) string {
|
||||
var b strings.Builder
|
||||
for _, file := range files {
|
||||
b.Write(readFile(file))
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func generateJSBundle(bundleFile string, bundleFiles map[string][]string, prefixes, suffixes map[string]string) {
|
||||
bundle := NewBundle("static", "Javascripts", "ui/static")
|
||||
m := minify.New()
|
||||
m.AddFunc("text/javascript", js.Minify)
|
||||
|
||||
for name, srcFiles := range bundleFiles {
|
||||
var b strings.Builder
|
||||
|
||||
if prefix, found := prefixes[name]; found {
|
||||
b.WriteString(prefix)
|
||||
}
|
||||
|
||||
b.WriteString(concat(srcFiles))
|
||||
|
||||
if suffix, found := suffixes[name]; found {
|
||||
b.WriteString(suffix)
|
||||
}
|
||||
|
||||
minifiedData, err := m.String("text/javascript", b.String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bundle.Files[name] = minifiedData
|
||||
bundle.Checksums[name] = checksum([]byte(minifiedData))
|
||||
}
|
||||
|
||||
bundle.Write(bundleFile)
|
||||
}
|
||||
|
||||
func generateCSSBundle(bundleFile string, themes map[string][]string) {
|
||||
bundle := NewBundle("static", "Stylesheets", "ui/static")
|
||||
m := minify.New()
|
||||
m.AddFunc("text/css", css.Minify)
|
||||
|
||||
for theme, srcFiles := range themes {
|
||||
data := concat(srcFiles)
|
||||
minifiedData, err := m.String("text/css", data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bundle.Files[theme] = minifiedData
|
||||
bundle.Checksums[theme] = checksum([]byte(minifiedData))
|
||||
}
|
||||
|
||||
bundle.Write(bundleFile)
|
||||
}
|
||||
|
||||
func generateBinaryBundle(bundleFile string, srcFiles []string) {
|
||||
bundle := NewBundle("static", "Binaries", "ui/static")
|
||||
|
||||
for _, srcFile := range srcFiles {
|
||||
data := readFile(srcFile)
|
||||
filename := basename(srcFile)
|
||||
encodedData := base64.StdEncoding.EncodeToString(data)
|
||||
|
||||
bundle.Files[filename] = string(encodedData)
|
||||
bundle.Checksums[filename] = checksum(data)
|
||||
}
|
||||
|
||||
bundle.Write(bundleFile)
|
||||
}
|
||||
|
||||
func generateBundle(bundleFile, pkg, mapName string, srcFiles []string) {
|
||||
bundle := NewBundle(pkg, mapName, pkg)
|
||||
|
||||
for _, srcFile := range srcFiles {
|
||||
data := readFile(srcFile)
|
||||
filename := stripExtension(basename(srcFile))
|
||||
|
||||
bundle.Files[filename] = string(data)
|
||||
bundle.Checksums[filename] = checksum(data)
|
||||
}
|
||||
|
||||
bundle.Write(bundleFile)
|
||||
}
|
||||
|
||||
func main() {
|
||||
generateJSBundle("ui/static/js.go", map[string][]string{
|
||||
"app": []string{
|
||||
"ui/static/js/dom_helper.js",
|
||||
"ui/static/js/touch_handler.js",
|
||||
"ui/static/js/keyboard_handler.js",
|
||||
"ui/static/js/request_builder.js",
|
||||
"ui/static/js/modal_handler.js",
|
||||
"ui/static/js/app.js",
|
||||
"ui/static/js/bootstrap.js",
|
||||
},
|
||||
"service-worker": []string{
|
||||
"ui/static/js/service_worker.js",
|
||||
},
|
||||
}, map[string]string{
|
||||
"app": "(function(){'use strict';",
|
||||
"sw": "'use strict';",
|
||||
}, map[string]string{
|
||||
"app": "})();",
|
||||
})
|
||||
|
||||
generateCSSBundle("ui/static/css.go", map[string][]string{
|
||||
"light_serif": []string{"ui/static/css/light.css", "ui/static/css/serif.css", "ui/static/css/common.css"},
|
||||
"light_sans_serif": []string{"ui/static/css/light.css", "ui/static/css/sans_serif.css", "ui/static/css/common.css"},
|
||||
"dark_serif": []string{"ui/static/css/dark.css", "ui/static/css/serif.css", "ui/static/css/common.css"},
|
||||
"dark_sans_serif": []string{"ui/static/css/dark.css", "ui/static/css/sans_serif.css", "ui/static/css/common.css"},
|
||||
"system_serif": []string{"ui/static/css/system.css", "ui/static/css/serif.css", "ui/static/css/common.css"},
|
||||
"system_sans_serif": []string{"ui/static/css/system.css", "ui/static/css/sans_serif.css", "ui/static/css/common.css"},
|
||||
})
|
||||
|
||||
generateBinaryBundle("ui/static/bin.go", glob("ui/static/bin/*"))
|
||||
|
||||
generateBundle("template/views.go", "template", "templateViewsMap", glob("template/html/*.html"))
|
||||
generateBundle("template/common.go", "template", "templateCommonMap", glob("template/html/common/*.html"))
|
||||
generateBundle("locale/translations.go", "locale", "translations", glob("locale/translations/*.json"))
|
||||
}
|
||||
@@ -1,27 +1,27 @@
|
||||
module miniflux.app
|
||||
|
||||
// +heroku goVersion go1.15
|
||||
// +heroku goVersion go1.16
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.6.1
|
||||
github.com/PuerkitoBio/goquery v1.8.0
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
||||
github.com/golang/gddo v0.0.0-20200831202555-721e228c7686 // indirect
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/lib/pq v1.9.0
|
||||
github.com/lib/pq v1.10.6
|
||||
github.com/mitchellh/go-server-timing v1.0.2-0.20201108055052-feb680ab92c2
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||
github.com/prometheus/client_golang v1.9.0
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/rylans/getlang v0.0.0-20200505200108-4c3188ff8a2d
|
||||
github.com/stretchr/testify v1.6.1 // indirect
|
||||
github.com/tdewolff/minify/v2 v2.9.11 // indirect
|
||||
github.com/tdewolff/minify/v2 v2.11.5
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
google.golang.org/appengine v1.6.6 // indirect
|
||||
google.golang.org/protobuf v1.25.0 // indirect
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c
|
||||
gopkg.in/square/go-jose.v2 v2.5.0 // indirect
|
||||
mvdan.cc/xurls/v2 v2.2.0
|
||||
mvdan.cc/xurls/v2 v2.4.0
|
||||
)
|
||||
|
||||
go 1.15
|
||||
go 1.16
|
||||
|
||||
@@ -1,203 +1,199 @@
|
||||
cloud.google.com/go v0.16.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/goquery v1.6.1 h1:FgjbQZKl5HTmcn4sKBgvx8vv63nhyhIpv7lJpFGCWpk=
|
||||
github.com/PuerkitoBio/goquery v1.6.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
|
||||
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
|
||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/felixge/httpsnoop v1.0.0 h1:gh8fMGz0rlOv/1WmRZm7OgncIOTsAj21iNJot48omJQ=
|
||||
github.com/felixge/httpsnoop v1.0.0/go.mod h1:3+D9sFq0ahK/JeJPhCBUV1xlf4/eIYrUQaxulT0VzX8=
|
||||
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.3/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-delve/delve v1.5.0/go.mod h1:c6b3a1Gry6x8a4LGCe/CWzrocrfaHvkUxCj3k4bvSUQ=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5 h1:yrv1uUvgXH/tEat+wdvJMRJ4g51GlIydtDpU9pFjaaI=
|
||||
github.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
|
||||
github.com/golang/gddo v0.0.0-20200831202555-721e228c7686 h1:5vu7C+63KTbsSNnLhrgB98Sqy8MNVSW8FdhkcWA/3Rk=
|
||||
github.com/golang/gddo v0.0.0-20200831202555-721e228c7686/go.mod h1:sam69Hju0uq+5uvLJUMDlsKlQ21Vrs1Kd/1YFPNYdOU=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/lint v0.0.0-20170918230701-e5d664eb928e/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.1.1-0.20171103154506-982329095285/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-dap v0.2.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
|
||||
github.com/google/go-dap v0.3.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gregjones/httpcache v0.0.0-20170920190843-316c5e0ff04e/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/log15 v0.0.0-20170622235902-74a0988b5f80/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
@@ -205,170 +201,106 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
|
||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
|
||||
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
|
||||
github.com/mattn/go-colorable v0.0.0-20170327083344-ded68f7a9561/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-server-timing v1.0.2-0.20201108055052-feb680ab92c2 h1:9kYRAm87/M5VL+HWegDGIorBWDiErrZrksLKTJBF2IQ=
|
||||
github.com/mitchellh/go-server-timing v1.0.2-0.20201108055052-feb680ab92c2/go.mod h1:8mKJVJkyMI20ifXXO0zlV3sh3FrtjvltAeBqz38clBE=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||
github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||
github.com/peterh/liner v1.2.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
||||
github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.9.0 h1:Rrch9mh17XcxvEu9D9DEpb4isxjGBtcevQjKvxPRQIU=
|
||||
github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
|
||||
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM=
|
||||
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
|
||||
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/rylans/getlang v0.0.0-20200505200108-4c3188ff8a2d h1:4Jn2kzSKcpxxwpJdyWxfNWKCYe4Uki2VibkExYmBLiA=
|
||||
github.com/rylans/getlang v0.0.0-20200505200108-4c3188ff8a2d/go.mod h1:3vfmZI6aJd5Rb9W2TQ0Nmupl+qem21R05+hmCscI0Bk=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.0-20170417170307-b6cb39589372/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170417173400-9e4c21054fa1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
@@ -376,82 +308,112 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tdewolff/minify v1.1.0 h1:nxHQi1ML+g3ZbZHffiZ6eC7vMqNvSRfX3KB5Y5y/kfw=
|
||||
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
|
||||
github.com/tdewolff/minify/v2 v2.9.11 h1:8o6hclGwxm6MNwTPHabvdND5SghhHs0bn+3/+uAf0yQ=
|
||||
github.com/tdewolff/minify/v2 v2.9.11/go.mod h1:YZk0lGOc6CvQrqvm5f7V3ihaq3QUd9acS4HESdVDOaM=
|
||||
github.com/tdewolff/parse/v2 v2.5.8 h1:vutkOO9Xi3DehIzCLHqvMM2hFXo54S0iDvIG/hYznnE=
|
||||
github.com/tdewolff/parse/v2 v2.5.8/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
|
||||
github.com/tdewolff/minify/v2 v2.11.5 h1:wfRJ6JMmu87Azx+Lj7NcCTg8D/L/92SNuYF5fv31fjg=
|
||||
github.com/tdewolff/minify/v2 v2.11.5/go.mod h1:ZR6VK7tbgF0XXBVwDHXrbqM4tGYchBpdwhsbKeDmAww=
|
||||
github.com/tdewolff/parse/v2 v2.5.31 h1:PrJN/trWTUYaYxg7jRpKnKXpBK4kBjT9rAFhFAh2Lus=
|
||||
github.com/tdewolff/parse/v2 v2.5.31/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
|
||||
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
||||
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.starlark.net v0.0.0-20190702223751-32f345186213/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
|
||||
go.starlark.net v0.0.0-20201006213952-227f4aabceb5/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
||||
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d h1:dOiJ2n2cMwGLce/74I/QHMbnpk5GfY7InR8rczoMqRM=
|
||||
golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -459,88 +421,180 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e h1:AyodaIpKjppX+cBfTASF2E1US3H2JFBj920Ot3rtDjs=
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.0.0-20170921000349-586095a6e407/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20170918111702-1e559d0a00ee/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.2.1-0.20170921194603-d4b75ebd4f9f/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -549,36 +603,38 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.5.0 h1:OZ4sdq+Y+SHfYB7vfthi1Ei8b0vkP8ZPQgUfUwdUSqo=
|
||||
gopkg.in/square/go-jose.v2 v2.5.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A=
|
||||
mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=
|
||||
mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright 2022 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package googlereader implements Google Reader API endpoints.
|
||||
|
||||
*/
|
||||
package googlereader // import "miniflux.app/googlereader"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,208 @@
|
||||
// Copyright 2022 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package googlereader // import "miniflux.app/googlereader"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"miniflux.app/http/request"
|
||||
"miniflux.app/http/response"
|
||||
"miniflux.app/http/response/json"
|
||||
"miniflux.app/logger"
|
||||
"miniflux.app/model"
|
||||
"miniflux.app/storage"
|
||||
)
|
||||
|
||||
type middleware struct {
|
||||
store *storage.Storage
|
||||
}
|
||||
|
||||
func newMiddleware(s *storage.Storage) *middleware {
|
||||
return &middleware{s}
|
||||
}
|
||||
|
||||
func (m *middleware) clientLogin(w http.ResponseWriter, r *http.Request) {
|
||||
clientIP := request.ClientIP(r)
|
||||
var username, password, output string
|
||||
var integration *model.Integration
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
logger.Error("[GoogleReader][Login] [ClientIP=%s] Could not parse form", clientIP)
|
||||
json.Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
username = r.Form.Get("Email")
|
||||
password = r.Form.Get("Passwd")
|
||||
output = r.Form.Get("output")
|
||||
|
||||
if username == "" || password == "" {
|
||||
logger.Error("[GoogleReader][Login] [ClientIP=%s] Empty username or password", clientIP)
|
||||
json.Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if err = m.store.GoogleReaderUserCheckPassword(username, password); err != nil {
|
||||
logger.Error("[GoogleReader][Login] [ClientIP=%s] Invalid username or password: %s", clientIP, username)
|
||||
json.Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("[GoogleReader][Login] [ClientIP=%s] User authenticated: %s", clientIP, username)
|
||||
|
||||
if integration, err = m.store.GoogleReaderUserGetIntegration(username); err != nil {
|
||||
logger.Error("[GoogleReader][Login] [ClientIP=%s] Could not load integration: %s", clientIP, username)
|
||||
json.Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
m.store.SetLastLogin(integration.UserID)
|
||||
|
||||
token := getAuthToken(integration.GoogleReaderUsername, integration.GoogleReaderPassword)
|
||||
logger.Info("[GoogleReader][Login] [ClientIP=%s] Created token: %s", clientIP, token)
|
||||
result := login{SID: token, LSID: token, Auth: token}
|
||||
if output == "json" {
|
||||
json.OK(w, r, result)
|
||||
return
|
||||
}
|
||||
builder := response.New(w, r)
|
||||
builder.WithHeader("Content-Type", "text/plain; charset=UTF-8")
|
||||
builder.WithBody(result.String())
|
||||
builder.Write()
|
||||
}
|
||||
|
||||
func (m *middleware) token(w http.ResponseWriter, r *http.Request) {
|
||||
clientIP := request.ClientIP(r)
|
||||
|
||||
if !request.IsAuthenticated(r) {
|
||||
logger.Error("[GoogleReader][Token] [ClientIP=%s] User is not authenticated", clientIP)
|
||||
json.Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
token := request.GoolgeReaderToken(r)
|
||||
if token == "" {
|
||||
logger.Error("[GoogleReader][Token] [ClientIP=%s] User does not have token: %s", clientIP, request.UserID(r))
|
||||
json.Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
logger.Info("[GoogleReader][Token] [ClientIP=%s] token: %s", clientIP, token)
|
||||
w.Header().Add("Content-Type", "text/plain; charset=UTF-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(token))
|
||||
}
|
||||
|
||||
func (m *middleware) handleCORS(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Authorization")
|
||||
if r.Method == http.MethodOptions {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (m *middleware) apiKeyAuth(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
clientIP := request.ClientIP(r)
|
||||
|
||||
var token string
|
||||
if r.Method == http.MethodPost {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
logger.Error("[GoogleReader][Login] [ClientIP=%s] Could not parse form", clientIP)
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
token = r.Form.Get("T")
|
||||
if token == "" {
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] Post-Form T field is empty", clientIP)
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
authorization := r.Header.Get("Authorization")
|
||||
|
||||
if authorization == "" {
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] No token provided", clientIP)
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
fields := strings.Fields(authorization)
|
||||
if len(fields) != 2 {
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] Authorization header does not have the expected structure GoogleLogin auth=xxxxxx - '%s'", clientIP, authorization)
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
if fields[0] != "GoogleLogin" {
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] Authorization header does not begin with GoogleLogin - '%s'", clientIP, authorization)
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
auths := strings.Split(fields[1], "=")
|
||||
if len(auths) != 2 {
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] Authorization header does not have the expected structure GoogleLogin auth=xxxxxx - '%s'", clientIP, authorization)
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
if auths[0] != "auth" {
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] Authorization header does not have the expected structure GoogleLogin auth=xxxxxx - '%s'", clientIP, authorization)
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
token = auths[1]
|
||||
}
|
||||
|
||||
parts := strings.Split(token, "/")
|
||||
if len(parts) != 2 {
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] Auth token does not have the expected structure username/hash - '%s'", clientIP, token)
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
var integration *model.Integration
|
||||
var user *model.User
|
||||
var err error
|
||||
if integration, err = m.store.GoogleReaderUserGetIntegration(parts[0]); err != nil {
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] token: %s", clientIP, token)
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] No user found with the given google reader username: %s", clientIP, parts[0])
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
expectedToken := getAuthToken(integration.GoogleReaderUsername, integration.GoogleReaderPassword)
|
||||
if expectedToken != token {
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] Token does not match: %s", clientIP, token)
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
if user, err = m.store.UserByID(integration.UserID); err != nil {
|
||||
logger.Error("[GoogleReader][Auth] [ClientIP=%s] No user found with the userID: %d", clientIP, integration.UserID)
|
||||
Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
m.store.SetLastLogin(integration.UserID)
|
||||
|
||||
ctx := r.Context()
|
||||
ctx = context.WithValue(ctx, request.UserIDContextKey, user.ID)
|
||||
ctx = context.WithValue(ctx, request.UserTimezoneContextKey, user.Timezone)
|
||||
ctx = context.WithValue(ctx, request.IsAdminUserContextKey, user.IsAdmin)
|
||||
ctx = context.WithValue(ctx, request.IsAuthenticatedContextKey, true)
|
||||
ctx = context.WithValue(ctx, request.GoogleReaderToken, token)
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
func getAuthToken(username, password string) string {
|
||||
token := hex.EncodeToString(hmac.New(sha1.New, []byte(username+password)).Sum(nil))
|
||||
token = username + "/" + token
|
||||
return token
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright 2022 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package googlereader // import "miniflux.app/googlereader"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"miniflux.app/http/response"
|
||||
"miniflux.app/logger"
|
||||
)
|
||||
|
||||
type login struct {
|
||||
SID string `json:"SID,omitempty"`
|
||||
LSID string `json:"LSID,omitempty"`
|
||||
Auth string `json:"Auth,omitempty"`
|
||||
}
|
||||
|
||||
func (l login) String() string {
|
||||
return fmt.Sprintf("SID=%s\nLSID=%s\nAuth=%s\n", l.SID, l.LSID, l.Auth)
|
||||
}
|
||||
|
||||
type userInfo struct {
|
||||
UserID string `json:"userId"`
|
||||
UserName string `json:"userName"`
|
||||
UserProfileID string `json:"userProfileId"`
|
||||
UserEmail string `json:"userEmail"`
|
||||
}
|
||||
|
||||
type subscription struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Categories []subscriptionCategory `json:"categories"`
|
||||
URL string `json:"url"`
|
||||
HTMLURL string `json:"htmlUrl"`
|
||||
IconURL string `json:"iconUrl"`
|
||||
}
|
||||
|
||||
type quickAddResponse struct {
|
||||
NumResults int64 `json:"numResults"`
|
||||
Query string `json:"query,omitempty"`
|
||||
StreamID string `json:"streamId,omitempty"`
|
||||
StreamName string `json:"streamName,omitempty"`
|
||||
}
|
||||
|
||||
type subscriptionCategory struct {
|
||||
ID string `json:"id"`
|
||||
Label string `json:"label,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
type subscriptionsResponse struct {
|
||||
Subscriptions []subscription `json:"subscriptions"`
|
||||
}
|
||||
|
||||
type itemRef struct {
|
||||
ID string `json:"id"`
|
||||
DirectStreamIDs string `json:"directStreamIds,omitempty"`
|
||||
TimestampUsec string `json:"timestampUsec,omitempty"`
|
||||
}
|
||||
|
||||
type streamIDResponse struct {
|
||||
ItemRefs []itemRef `json:"itemRefs"`
|
||||
}
|
||||
|
||||
type tagsResponse struct {
|
||||
Tags []subscriptionCategory `json:"tags"`
|
||||
}
|
||||
|
||||
type streamContentItems struct {
|
||||
Direction string `json:"direction"`
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Self []contentHREF `json:"self"`
|
||||
Alternate []contentHREFType `json:"alternate"`
|
||||
Updated int64 `json:"updated"`
|
||||
Items []contentItem `json:"items"`
|
||||
Author string `json:"author"`
|
||||
}
|
||||
|
||||
type contentItem struct {
|
||||
ID string `json:"id"`
|
||||
Categories []string `json:"categories"`
|
||||
Title string `json:"title"`
|
||||
CrawlTimeMsec string `json:"crawlTimeMsec"`
|
||||
TimestampUsec string `json:"timestampUsec"`
|
||||
Published int64 `json:"published"`
|
||||
Updated int64 `json:"updated"`
|
||||
Author string `json:"author"`
|
||||
Alternate []contentHREFType `json:"alternate"`
|
||||
Summary contentItemContent `json:"summary"`
|
||||
Content contentItemContent `json:"content"`
|
||||
Origin contentItemOrigin `json:"origin"`
|
||||
Enclosure []contentItemEnclosure `json:"enclosure"`
|
||||
Canonical []contentHREF `json:"canonical"`
|
||||
}
|
||||
|
||||
type contentHREFType struct {
|
||||
HREF string `json:"href"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type contentHREF struct {
|
||||
HREF string `json:"href"`
|
||||
}
|
||||
|
||||
type contentItemEnclosure struct {
|
||||
URL string `json:"url"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
type contentItemContent struct {
|
||||
Direction string `json:"direction"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type contentItemOrigin struct {
|
||||
StreamID string `json:"streamId"`
|
||||
Title string `json:"title"`
|
||||
HTMLUrl string `json:"htmlUrl"`
|
||||
}
|
||||
|
||||
// Unauthorized sends a not authorized error to the client.
|
||||
func Unauthorized(w http.ResponseWriter, r *http.Request) {
|
||||
logger.Error("[HTTP:Unauthorized] %s", r.URL)
|
||||
|
||||
builder := response.New(w, r)
|
||||
builder.WithStatus(http.StatusUnauthorized)
|
||||
builder.WithHeader("Content-Type", "text/plain")
|
||||
builder.WithHeader("X-Reader-Google-Bad-Token", "true")
|
||||
builder.WithBody("Unauthorized")
|
||||
builder.Write()
|
||||
}
|
||||
|
||||
// OK sends a ok response to the client.
|
||||
func OK(w http.ResponseWriter, r *http.Request) {
|
||||
logger.Info("[HTTP:OK] %s", r.URL)
|
||||
|
||||
builder := response.New(w, r)
|
||||
builder.WithStatus(http.StatusOK)
|
||||
builder.WithHeader("Content-Type", "text/plain")
|
||||
builder.WithBody("OK")
|
||||
builder.Write()
|
||||
}
|
||||
+26
-11
@@ -6,11 +6,11 @@ package client // import "miniflux.app/http/client"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"miniflux.app/errors"
|
||||
"miniflux.app/logger"
|
||||
"miniflux.app/timer"
|
||||
url_helper "miniflux.app/url"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -40,20 +39,21 @@ var (
|
||||
type Client struct {
|
||||
inputURL string
|
||||
|
||||
requestURL string
|
||||
requestEtagHeader string
|
||||
requestLastModifiedHeader string
|
||||
requestAuthorizationHeader string
|
||||
requestUsername string
|
||||
requestPassword string
|
||||
requestUserAgent string
|
||||
requestCookie string
|
||||
|
||||
useProxy bool
|
||||
doNotFollowRedirects bool
|
||||
|
||||
ClientTimeout int
|
||||
ClientMaxBodySize int64
|
||||
ClientProxyURL string
|
||||
ClientTimeout int
|
||||
ClientMaxBodySize int64
|
||||
ClientProxyURL string
|
||||
AllowSelfSignedCertificates bool
|
||||
}
|
||||
|
||||
// New initializes a new HTTP client.
|
||||
@@ -88,13 +88,13 @@ func (c *Client) String() string {
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
`InputURL=%q RequestURL=%q ETag=%s LastModified=%s Auth=%v UserAgent=%q`,
|
||||
`InputURL=%q ETag=%s LastMod=%s Auth=%v UserAgent=%q Verify=%v`,
|
||||
c.inputURL,
|
||||
c.requestURL,
|
||||
etagHeader,
|
||||
lastModifiedHeader,
|
||||
c.requestAuthorizationHeader != "" || (c.requestUsername != "" && c.requestPassword != ""),
|
||||
c.requestUserAgent,
|
||||
!c.AllowSelfSignedCertificates,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -140,6 +140,14 @@ func (c *Client) WithUserAgent(userAgent string) *Client {
|
||||
return c
|
||||
}
|
||||
|
||||
// WithCookie defines the Cookies to use for HTTP requests.
|
||||
func (c *Client) WithCookie(cookie string) *Client {
|
||||
if cookie != "" {
|
||||
c.requestCookie = cookie
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Get performs a GET HTTP request.
|
||||
func (c *Client) Get() (*Response, error) {
|
||||
request, err := c.buildRequest(http.MethodGet, nil)
|
||||
@@ -219,7 +227,7 @@ func (c *Client) executeRequest(request *http.Request) (*Response, error) {
|
||||
return nil, fmt.Errorf("client: response too large (%d bytes)", resp.ContentLength)
|
||||
}
|
||||
|
||||
buf, err := ioutil.ReadAll(resp.Body)
|
||||
buf, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("client: error while reading body %v", err)
|
||||
}
|
||||
@@ -252,8 +260,7 @@ func (c *Client) executeRequest(request *http.Request) (*Response, error) {
|
||||
}
|
||||
|
||||
func (c *Client) buildRequest(method string, body io.Reader) (*http.Request, error) {
|
||||
c.requestURL = url_helper.RequestURI(c.inputURL)
|
||||
request, err := http.NewRequest(method, c.requestURL, body)
|
||||
request, err := http.NewRequest(method, c.inputURL, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -289,6 +296,10 @@ func (c *Client) buildClient() http.Client {
|
||||
IdleConnTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
if c.AllowSelfSignedCertificates {
|
||||
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
|
||||
if c.doNotFollowRedirects {
|
||||
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
@@ -330,6 +341,10 @@ func (c *Client) buildHeaders() http.Header {
|
||||
headers.Add("Authorization", c.requestAuthorizationHeader)
|
||||
}
|
||||
|
||||
if c.requestCookie != "" {
|
||||
headers.Add("Cookie", c.requestCookie)
|
||||
}
|
||||
|
||||
headers.Add("Connection", "close")
|
||||
return headers
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func TestClientWithDelay(t *testing.T) {
|
||||
|
||||
func TestClientWithError(t *testing.T) {
|
||||
clt := New("http://httpbin.org/status/502")
|
||||
clt.ClientTimeout = 1
|
||||
clt.ClientTimeout = 5
|
||||
response, err := clt.Get()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -30,7 +30,7 @@ func TestClientWithError(t *testing.T) {
|
||||
}
|
||||
|
||||
if !response.HasServerFailure() {
|
||||
t.Fatal(`A 500 error is considered as server failure`)
|
||||
t.Fatal(`A 502 error is considered as server failure`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
@@ -43,7 +42,7 @@ func (r *Response) String() string {
|
||||
)
|
||||
}
|
||||
|
||||
// IsNotFound returns true if the resource doesn't exists anymore.
|
||||
// IsNotFound returns true if the resource doesn't exist anymore.
|
||||
func (r *Response) IsNotFound() bool {
|
||||
return r.StatusCode == 404 || r.StatusCode == 410
|
||||
}
|
||||
@@ -87,7 +86,7 @@ func (r *Response) IsModified(etag, lastModified string) bool {
|
||||
// - Feeds with encoding specified only in XML document and not in HTTP header
|
||||
// - Feeds with wrong encoding defined and already in UTF-8
|
||||
func (r *Response) EnsureUnicodeBody() (err error) {
|
||||
buffer, err := ioutil.ReadAll(r.Body)
|
||||
buffer, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -116,6 +115,6 @@ func (r *Response) EnsureUnicodeBody() (err error) {
|
||||
|
||||
// BodyAsString returns the response body as string.
|
||||
func (r *Response) BodyAsString() string {
|
||||
bytes, _ := ioutil.ReadAll(r.Body)
|
||||
bytes, _ := io.ReadAll(r.Body)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ package client // import "miniflux.app/http/client"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
@@ -96,7 +96,7 @@ func TestToString(t *testing.T) {
|
||||
r := &Response{Body: strings.NewReader(input)}
|
||||
|
||||
if r.BodyAsString() != input {
|
||||
t.Error(`Unexpected ouput`)
|
||||
t.Error(`Unexpected output`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ func TestEnsureUnicodeWithHTMLDocuments(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range unicodeTestCases {
|
||||
content, err := ioutil.ReadFile("testdata/" + tc.filename)
|
||||
content, err := os.ReadFile("testdata/" + tc.filename)
|
||||
if err != nil {
|
||||
t.Fatalf(`Unable to read file %q: %v`, tc.filename, err)
|
||||
}
|
||||
|
||||
@@ -25,8 +25,14 @@ const (
|
||||
FlashErrorMessageContextKey
|
||||
PocketRequestTokenContextKey
|
||||
ClientIPContextKey
|
||||
GoogleReaderToken
|
||||
)
|
||||
|
||||
// GoolgeReaderToken returns the google reader token if it exists.
|
||||
func GoolgeReaderToken(r *http.Request) string {
|
||||
return getContextStringValue(r, GoogleReaderToken)
|
||||
}
|
||||
|
||||
// IsAdminUser checks if the logged user is administrator.
|
||||
func IsAdminUser(r *http.Request) bool {
|
||||
return getContextBoolValue(r, IsAdminUserContextKey)
|
||||
|
||||
+15
-1
@@ -72,7 +72,21 @@ func QueryStringParamList(r *http.Request, param string) []string {
|
||||
|
||||
// QueryIntParam returns a query string parameter as integer.
|
||||
func QueryIntParam(r *http.Request, param string, defaultValue int) int {
|
||||
return int(QueryInt64Param(r, param, int64(defaultValue)))
|
||||
value := r.URL.Query().Get(param)
|
||||
if value == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
val, err := strconv.ParseInt(value, 10, 0)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
if val < 0 {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return int(val)
|
||||
}
|
||||
|
||||
// QueryInt64Param returns a query string parameter as int64.
|
||||
|
||||
@@ -96,7 +96,6 @@ func (b *Builder) writeHeaders() {
|
||||
b.headers["X-XSS-Protection"] = "1; mode=block"
|
||||
b.headers["X-Content-Type-Options"] = "nosniff"
|
||||
b.headers["X-Frame-Options"] = "DENY"
|
||||
b.headers["Content-Security-Policy"] = "default-src 'self'; img-src * data:; media-src *; frame-src *"
|
||||
b.headers["Referrer-Policy"] = "no-referrer"
|
||||
|
||||
for key, value := range b.headers {
|
||||
|
||||
@@ -29,10 +29,9 @@ func TestResponseHasCommonHeaders(t *testing.T) {
|
||||
resp := w.Result()
|
||||
|
||||
headers := map[string]string{
|
||||
"X-XSS-Protection": "1; mode=block",
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
"X-Frame-Options": "DENY",
|
||||
"Content-Security-Policy": "default-src 'self'; img-src * data:; media-src *; frame-src *",
|
||||
"X-XSS-Protection": "1; mode=block",
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
"X-Frame-Options": "DENY",
|
||||
}
|
||||
|
||||
for header, expected := range headers {
|
||||
|
||||
+4
-5
@@ -19,13 +19,12 @@ func Path(router *mux.Router, name string, args ...interface{}) string {
|
||||
}
|
||||
|
||||
var pairs []string
|
||||
for _, param := range args {
|
||||
switch param.(type) {
|
||||
for _, arg := range args {
|
||||
switch param := arg.(type) {
|
||||
case string:
|
||||
pairs = append(pairs, param.(string))
|
||||
pairs = append(pairs, param)
|
||||
case int64:
|
||||
val := param.(int64)
|
||||
pairs = append(pairs, strconv.FormatInt(val, 10))
|
||||
pairs = append(pairs, strconv.FormatInt(param, 10))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2018 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package integration implements API clients for third-party services.
|
||||
|
||||
*/
|
||||
package integration // import "miniflux.app/integration"
|
||||
@@ -0,0 +1,69 @@
|
||||
package espial // import "miniflux.app/integration/espial"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
"miniflux.app/http/client"
|
||||
)
|
||||
|
||||
// Document structure of an Espial document
|
||||
type Document struct {
|
||||
Title string `json:"title,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
ToRead bool `json:"toread,omitempty"`
|
||||
Tags string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// Client represents an Espial client.
|
||||
type Client struct {
|
||||
baseURL string
|
||||
apiKey string
|
||||
}
|
||||
|
||||
// NewClient returns a new Espial client.
|
||||
func NewClient(baseURL, apiKey string) *Client {
|
||||
return &Client{baseURL: baseURL, apiKey: apiKey}
|
||||
}
|
||||
|
||||
// AddEntry sends an entry to Espial.
|
||||
func (c *Client) AddEntry(link, title, content, tags string) error {
|
||||
if c.baseURL == "" || c.apiKey == "" {
|
||||
return fmt.Errorf("espial: missing credentials")
|
||||
}
|
||||
|
||||
doc := &Document{
|
||||
Title: title,
|
||||
Url: link,
|
||||
ToRead: true,
|
||||
Tags: tags,
|
||||
}
|
||||
|
||||
apiURL, err := getAPIEndpoint(c.baseURL, "/api/add")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clt := client.New(apiURL)
|
||||
clt.WithAuthorization("ApiKey " + c.apiKey)
|
||||
response, err := clt.PostJSON(doc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("espial: unable to send entry: %v", err)
|
||||
}
|
||||
|
||||
if response.HasServerFailure() {
|
||||
return fmt.Errorf("espial: unable to send entry, status=%d", response.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAPIEndpoint(baseURL, pathURL string) (string, error) {
|
||||
u, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("espial: invalid API endpoint: %v", err)
|
||||
}
|
||||
u.Path = path.Join(u.Path, pathURL)
|
||||
return u.String(), nil
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2018 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package instapaper provides an integration with Instapaper.
|
||||
|
||||
*/
|
||||
package instapaper // import "miniflux.app/integration/instapaper"
|
||||
@@ -17,6 +17,11 @@ type Client struct {
|
||||
password string
|
||||
}
|
||||
|
||||
// NewClient returns a new Instapaper client.
|
||||
func NewClient(username, password string) *Client {
|
||||
return &Client{username: username, password: password}
|
||||
}
|
||||
|
||||
// AddURL sends a link to Instapaper.
|
||||
func (c *Client) AddURL(link, title string) error {
|
||||
if c.username == "" || c.password == "" {
|
||||
@@ -41,8 +46,3 @@ func (c *Client) AddURL(link, title string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewClient returns a new Instapaper client.
|
||||
func NewClient(username, password string) *Client {
|
||||
return &Client{username: username, password: password}
|
||||
}
|
||||
|
||||
@@ -6,18 +6,23 @@ package integration // import "miniflux.app/integration"
|
||||
|
||||
import (
|
||||
"miniflux.app/config"
|
||||
"miniflux.app/integration/espial"
|
||||
"miniflux.app/integration/instapaper"
|
||||
"miniflux.app/integration/linkding"
|
||||
"miniflux.app/integration/nunuxkeeper"
|
||||
"miniflux.app/integration/pinboard"
|
||||
"miniflux.app/integration/pocket"
|
||||
"miniflux.app/integration/telegrambot"
|
||||
"miniflux.app/integration/wallabag"
|
||||
"miniflux.app/logger"
|
||||
"miniflux.app/model"
|
||||
)
|
||||
|
||||
// SendEntry send the entry to the activated providers.
|
||||
// SendEntry sends the entry to third-party providers when the user click on "Save".
|
||||
func SendEntry(entry *model.Entry, integration *model.Integration) {
|
||||
if integration.PinboardEnabled {
|
||||
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Pinboard", entry.ID, entry.URL, integration.UserID)
|
||||
|
||||
client := pinboard.NewClient(integration.PinboardToken)
|
||||
err := client.AddBookmark(
|
||||
entry.URL,
|
||||
@@ -32,6 +37,8 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
|
||||
}
|
||||
|
||||
if integration.InstapaperEnabled {
|
||||
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Instapaper", entry.ID, entry.URL, integration.UserID)
|
||||
|
||||
client := instapaper.NewClient(integration.InstapaperUsername, integration.InstapaperPassword)
|
||||
if err := client.AddURL(entry.URL, entry.Title); err != nil {
|
||||
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
|
||||
@@ -39,6 +46,8 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
|
||||
}
|
||||
|
||||
if integration.WallabagEnabled {
|
||||
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Wallabag", entry.ID, entry.URL, integration.UserID)
|
||||
|
||||
client := wallabag.NewClient(
|
||||
integration.WallabagURL,
|
||||
integration.WallabagClientID,
|
||||
@@ -47,12 +56,14 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
|
||||
integration.WallabagPassword,
|
||||
)
|
||||
|
||||
if err := client.AddEntry(entry.URL, entry.Title); err != nil {
|
||||
if err := client.AddEntry(entry.URL, entry.Title, entry.Content); err != nil {
|
||||
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
|
||||
}
|
||||
}
|
||||
|
||||
if integration.NunuxKeeperEnabled {
|
||||
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to NunuxKeeper", entry.ID, entry.URL, integration.UserID)
|
||||
|
||||
client := nunuxkeeper.NewClient(
|
||||
integration.NunuxKeeperURL,
|
||||
integration.NunuxKeeperAPIKey,
|
||||
@@ -63,10 +74,49 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
|
||||
}
|
||||
}
|
||||
|
||||
if integration.EspialEnabled {
|
||||
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Espial", entry.ID, entry.URL, integration.UserID)
|
||||
|
||||
client := espial.NewClient(
|
||||
integration.EspialURL,
|
||||
integration.EspialAPIKey,
|
||||
)
|
||||
|
||||
if err := client.AddEntry(entry.URL, entry.Title, entry.Content, integration.EspialTags); err != nil {
|
||||
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
|
||||
}
|
||||
}
|
||||
|
||||
if integration.PocketEnabled {
|
||||
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Pocket", entry.ID, entry.URL, integration.UserID)
|
||||
|
||||
client := pocket.NewClient(config.Opts.PocketConsumerKey(integration.PocketConsumerKey), integration.PocketAccessToken)
|
||||
if err := client.AddURL(entry.URL, entry.Title); err != nil {
|
||||
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
|
||||
}
|
||||
}
|
||||
|
||||
if integration.LinkdingEnabled {
|
||||
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Linkding", entry.ID, entry.URL, integration.UserID)
|
||||
|
||||
client := linkding.NewClient(
|
||||
integration.LinkdingURL,
|
||||
integration.LinkdingAPIKey,
|
||||
)
|
||||
if err := client.AddEntry(entry.Title, entry.URL); err != nil {
|
||||
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PushEntry pushes an entry to third-party providers during feed refreshes.
|
||||
func PushEntry(entry *model.Entry, integration *model.Integration) {
|
||||
if integration.TelegramBotEnabled {
|
||||
logger.Debug("[Integration] Sending Entry %q for User #%d to Telegram", entry.URL, integration.UserID)
|
||||
|
||||
err := telegrambot.PushEntry(entry, integration.TelegramBotToken, integration.TelegramBotChatID)
|
||||
if err != nil {
|
||||
logger.Error("[Integration] push entry to telegram bot failed: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package linkding // import "miniflux.app/integration/linkding"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"miniflux.app/http/client"
|
||||
)
|
||||
|
||||
// Document structure of a Linkding document
|
||||
type Document struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
}
|
||||
|
||||
// Client represents an Linkding client.
|
||||
type Client struct {
|
||||
baseURL string
|
||||
apiKey string
|
||||
}
|
||||
|
||||
// NewClient returns a new Linkding client.
|
||||
func NewClient(baseURL, apiKey string) *Client {
|
||||
return &Client{baseURL: baseURL, apiKey: apiKey}
|
||||
}
|
||||
|
||||
// AddEntry sends an entry to Linkding.
|
||||
func (c *Client) AddEntry(title, url string) error {
|
||||
if c.baseURL == "" || c.apiKey == "" {
|
||||
return fmt.Errorf("linkding: missing credentials")
|
||||
}
|
||||
|
||||
doc := &Document{
|
||||
Url: url,
|
||||
Title: title,
|
||||
}
|
||||
|
||||
apiURL, err := getAPIEndpoint(c.baseURL, "/api/bookmarks/")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clt := client.New(apiURL)
|
||||
clt.WithAuthorization("Token " + c.apiKey)
|
||||
response, err := clt.PostJSON(doc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("linkding: unable to send entry: %v", err)
|
||||
}
|
||||
|
||||
if response.HasServerFailure() {
|
||||
return fmt.Errorf("linkding: unable to send entry, status=%d", response.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAPIEndpoint(baseURL, pathURL string) (string, error) {
|
||||
u, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("linkding: invalid API endpoint: %v", err)
|
||||
}
|
||||
|
||||
relative, err := url.Parse(pathURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("linkding: invalid API endpoint: %v", err)
|
||||
}
|
||||
|
||||
u = u.ResolveReference(relative)
|
||||
return u.String(), nil
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2018 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package nunuxkeeper provides an integration with the Nunux Keeper application.
|
||||
|
||||
*/
|
||||
package nunuxkeeper // import "miniflux.app/integration/nunuxkeeper"
|
||||
@@ -26,6 +26,11 @@ type Client struct {
|
||||
apiKey string
|
||||
}
|
||||
|
||||
// NewClient returns a new Nunux Keeepr client.
|
||||
func NewClient(baseURL, apiKey string) *Client {
|
||||
return &Client{baseURL: baseURL, apiKey: apiKey}
|
||||
}
|
||||
|
||||
// AddEntry sends an entry to Nunux Keeper.
|
||||
func (c *Client) AddEntry(link, title, content string) error {
|
||||
if c.baseURL == "" || c.apiKey == "" {
|
||||
@@ -58,11 +63,6 @@ func (c *Client) AddEntry(link, title, content string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewClient returns a new Nunux Keeepr client.
|
||||
func NewClient(baseURL, apiKey string) *Client {
|
||||
return &Client{baseURL: baseURL, apiKey: apiKey}
|
||||
}
|
||||
|
||||
func getAPIEndpoint(baseURL, pathURL string) (string, error) {
|
||||
u, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2018 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package pinboard provides an integration with Pinboard.
|
||||
|
||||
*/
|
||||
package pinboard // import "miniflux.app/integration/pinboard"
|
||||
@@ -16,6 +16,11 @@ type Client struct {
|
||||
authToken string
|
||||
}
|
||||
|
||||
// NewClient returns a new Pinboard client.
|
||||
func NewClient(authToken string) *Client {
|
||||
return &Client{authToken: authToken}
|
||||
}
|
||||
|
||||
// AddBookmark sends a link to Pinboard.
|
||||
func (c *Client) AddBookmark(link, title, tags string, markAsUnread bool) error {
|
||||
if c.authToken == "" {
|
||||
@@ -46,8 +51,3 @@ func (c *Client) AddBookmark(link, title, tags string, markAsUnread bool) error
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewClient returns a new Pinboard client.
|
||||
func NewClient(authToken string) *Client {
|
||||
return &Client{authToken: authToken}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ package pocket // import "miniflux.app/integration/pocket"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/url"
|
||||
|
||||
"miniflux.app/http/client"
|
||||
@@ -18,6 +18,11 @@ type Connector struct {
|
||||
consumerKey string
|
||||
}
|
||||
|
||||
// NewConnector returns a new Pocket Connector.
|
||||
func NewConnector(consumerKey string) *Connector {
|
||||
return &Connector{consumerKey}
|
||||
}
|
||||
|
||||
// RequestToken fetches a new request token from Pocket API.
|
||||
func (c *Connector) RequestToken(redirectURL string) (string, error) {
|
||||
type req struct {
|
||||
@@ -35,7 +40,7 @@ func (c *Connector) RequestToken(redirectURL string) (string, error) {
|
||||
return "", fmt.Errorf("pocket: unable to fetch request token, status=%d", response.StatusCode)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(response.Body)
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("pocket: unable to read response body: %v", err)
|
||||
}
|
||||
@@ -70,7 +75,7 @@ func (c *Connector) AccessToken(requestToken string) (string, error) {
|
||||
return "", fmt.Errorf("pocket: unable to fetch access token, status=%d", response.StatusCode)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(response.Body)
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("pocket: unable to read response body: %v", err)
|
||||
}
|
||||
@@ -96,8 +101,3 @@ func (c *Connector) AuthorizationURL(requestToken, redirectURL string) string {
|
||||
redirectURL,
|
||||
)
|
||||
}
|
||||
|
||||
// NewConnector returns a new Pocket Connector.
|
||||
func NewConnector(consumerKey string) *Connector {
|
||||
return &Connector{consumerKey}
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2018 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package pocket provides an integration with Pocket.
|
||||
|
||||
*/
|
||||
package pocket // import "miniflux.app/integration/pocket"
|
||||
@@ -16,6 +16,11 @@ type Client struct {
|
||||
accessToken string
|
||||
}
|
||||
|
||||
// NewClient returns a new Pocket client.
|
||||
func NewClient(consumerKey, accessToken string) *Client {
|
||||
return &Client{consumerKey, accessToken}
|
||||
}
|
||||
|
||||
// AddURL sends a single link to Pocket.
|
||||
func (c *Client) AddURL(link, title string) error {
|
||||
if c.consumerKey == "" || c.accessToken == "" {
|
||||
@@ -48,8 +53,3 @@ func (c *Client) AddURL(link, title string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewClient returns a new Pocket client.
|
||||
func NewClient(consumerKey, accessToken string) *Client {
|
||||
return &Client{consumerKey, accessToken}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2021 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package telegrambot // import "miniflux.app/integration/telegrambot"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"strconv"
|
||||
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"miniflux.app/model"
|
||||
)
|
||||
|
||||
// PushEntry pushes entry to telegram chat using integration settings provided
|
||||
func PushEntry(entry *model.Entry, botToken, chatID string) error {
|
||||
bot, err := tgbotapi.NewBotAPI(botToken)
|
||||
if err != nil {
|
||||
return fmt.Errorf("telegrambot: bot creation failed: %w", err)
|
||||
}
|
||||
|
||||
tpl, err := template.New("message").Parse("{{ .Title }}\n<a href=\"{{ .URL }}\">{{ .URL }}</a>")
|
||||
if err != nil {
|
||||
return fmt.Errorf("telegrambot: template parsing failed: %w", err)
|
||||
}
|
||||
|
||||
var result bytes.Buffer
|
||||
if err := tpl.Execute(&result, entry); err != nil {
|
||||
return fmt.Errorf("telegrambot: template execution failed: %w", err)
|
||||
}
|
||||
|
||||
chatIDInt, _ := strconv.ParseInt(chatID, 10, 64)
|
||||
msg := tgbotapi.NewMessage(chatIDInt, result.String())
|
||||
msg.ParseMode = tgbotapi.ModeHTML
|
||||
msg.DisableWebPagePreview = false
|
||||
|
||||
if entry.CommentsURL != "" {
|
||||
msg.ReplyMarkup = tgbotapi.NewInlineKeyboardMarkup(
|
||||
tgbotapi.NewInlineKeyboardRow(
|
||||
tgbotapi.NewInlineKeyboardButtonURL("Comments", entry.CommentsURL),
|
||||
))
|
||||
}
|
||||
|
||||
if _, err := bot.Send(msg); err != nil {
|
||||
return fmt.Errorf("telegrambot: sending message failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2018 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package wallabag provides an integration with the Wallabag application.
|
||||
|
||||
*/
|
||||
package wallabag // import "miniflux.app/integration/wallabag"
|
||||
@@ -22,8 +22,14 @@ type Client struct {
|
||||
password string
|
||||
}
|
||||
|
||||
// NewClient returns a new Wallabag client.
|
||||
func NewClient(baseURL, clientID, clientSecret, username, password string) *Client {
|
||||
return &Client{baseURL, clientID, clientSecret, username, password}
|
||||
}
|
||||
|
||||
// AddEntry sends a link to Wallabag.
|
||||
func (c *Client) AddEntry(link, title string) error {
|
||||
// Pass an empty string in `content` to let Wallabag fetch the article content.
|
||||
func (c *Client) AddEntry(link, title, content string) error {
|
||||
if c.baseURL == "" || c.clientID == "" || c.clientSecret == "" || c.username == "" || c.password == "" {
|
||||
return fmt.Errorf("wallabag: missing credentials")
|
||||
}
|
||||
@@ -33,10 +39,10 @@ func (c *Client) AddEntry(link, title string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.createEntry(accessToken, link, title)
|
||||
return c.createEntry(accessToken, link, title, content)
|
||||
}
|
||||
|
||||
func (c *Client) createEntry(accessToken, link, title string) error {
|
||||
func (c *Client) createEntry(accessToken, link, title, content string) error {
|
||||
endpoint, err := getAPIEndpoint(c.baseURL, "/api/entries.json")
|
||||
if err != nil {
|
||||
return fmt.Errorf("wallbag: unable to get entries endpoint: %v", err)
|
||||
@@ -44,7 +50,7 @@ func (c *Client) createEntry(accessToken, link, title string) error {
|
||||
|
||||
clt := client.New(endpoint)
|
||||
clt.WithAuthorization("Bearer " + accessToken)
|
||||
response, err := clt.PostJSON(map[string]string{"url": link, "title": title})
|
||||
response, err := clt.PostJSON(map[string]string{"url": link, "title": title, "content": content})
|
||||
if err != nil {
|
||||
return fmt.Errorf("wallabag: unable to post entry: %v", err)
|
||||
}
|
||||
@@ -87,11 +93,6 @@ func (c *Client) getAccessToken() (string, error) {
|
||||
return token.AccessToken, nil
|
||||
}
|
||||
|
||||
// NewClient returns a new Wallabag client.
|
||||
func NewClient(baseURL, clientID, clientSecret, username, password string) *Client {
|
||||
return &Client{baseURL, clientID, clientSecret, username, password}
|
||||
}
|
||||
|
||||
func getAPIEndpoint(baseURL, path string) (string, error) {
|
||||
u, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
|
||||
+30
-11
@@ -5,6 +5,7 @@
|
||||
package locale // import "miniflux.app/locale"
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
@@ -14,23 +15,41 @@ type catalog map[string]translationDict
|
||||
|
||||
var defaultCatalog catalog
|
||||
|
||||
func init() {
|
||||
//go:embed translations/*.json
|
||||
var translationFiles embed.FS
|
||||
|
||||
// LoadCatalogMessages loads and parses all translations encoded in JSON.
|
||||
func LoadCatalogMessages() error {
|
||||
var err error
|
||||
defaultCatalog = make(catalog)
|
||||
|
||||
for language, data := range translations {
|
||||
messages, err := parseTranslationDict(data)
|
||||
for language := range AvailableLanguages() {
|
||||
defaultCatalog[language], err = loadTranslationFile(language)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
|
||||
defaultCatalog[language] = messages
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseTranslationDict(data string) (translationDict, error) {
|
||||
var translations translationDict
|
||||
if err := json.Unmarshal([]byte(data), &translations); err != nil {
|
||||
return nil, fmt.Errorf("invalid translation file: %v", err)
|
||||
func loadTranslationFile(language string) (translationDict, error) {
|
||||
translationFileData, err := translationFiles.ReadFile(fmt.Sprintf("translations/%s.json", language))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return translations, nil
|
||||
|
||||
translationMessages, err := parseTranslationMessages(translationFileData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return translationMessages, nil
|
||||
}
|
||||
|
||||
func parseTranslationMessages(data []byte) (translationDict, error) {
|
||||
var translationMessages translationDict
|
||||
if err := json.Unmarshal(data, &translationMessages); err != nil {
|
||||
return nil, fmt.Errorf(`invalid translation file: %w`, err)
|
||||
}
|
||||
return translationMessages, nil
|
||||
}
|
||||
|
||||
+59
-2
@@ -7,14 +7,14 @@ package locale // import "miniflux.app/locale"
|
||||
import "testing"
|
||||
|
||||
func TestParserWithInvalidData(t *testing.T) {
|
||||
_, err := parseTranslationDict(`{`)
|
||||
_, err := parseTranslationMessages([]byte(`{`))
|
||||
if err == nil {
|
||||
t.Fatal(`An error should be returned when parsing invalid data`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser(t *testing.T) {
|
||||
translations, err := parseTranslationDict(`{"k": "v"}`)
|
||||
translations, err := parseTranslationMessages([]byte(`{"k": "v"}`))
|
||||
if err != nil {
|
||||
t.Fatalf(`Unexpected parsing error: %v`, err)
|
||||
}
|
||||
@@ -32,3 +32,60 @@ func TestParser(t *testing.T) {
|
||||
t.Fatal(`The translation key should contains the defined value`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCatalog(t *testing.T) {
|
||||
if err := LoadCatalogMessages(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllKeysHaveValue(t *testing.T) {
|
||||
for language := range AvailableLanguages() {
|
||||
messages, err := loadTranslationFile(language)
|
||||
if err != nil {
|
||||
t.Fatalf(`Unable to load translation messages for language %q`, language)
|
||||
}
|
||||
|
||||
if len(messages) == 0 {
|
||||
t.Fatalf(`The language %q doesn't have any messages`, language)
|
||||
}
|
||||
|
||||
for k, v := range messages {
|
||||
switch value := v.(type) {
|
||||
case string:
|
||||
if value == "" {
|
||||
t.Errorf(`The key %q for the language %q have an empty string as value`, k, language)
|
||||
}
|
||||
case []string:
|
||||
if len(value) == 0 {
|
||||
t.Errorf(`The key %q for the language %q have an empty list as value`, k, language)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMissingTranslations(t *testing.T) {
|
||||
refLang := "en_US"
|
||||
references, err := loadTranslationFile(refLang)
|
||||
if err != nil {
|
||||
t.Fatal(`Unable to parse reference language`)
|
||||
}
|
||||
|
||||
for language := range AvailableLanguages() {
|
||||
if language == refLang {
|
||||
continue
|
||||
}
|
||||
|
||||
messages, err := loadTranslationFile(language)
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing error for language %q`, language)
|
||||
}
|
||||
|
||||
for key := range references {
|
||||
if _, found := messages[key]; !found {
|
||||
t.Fatalf(`Translation key %q not found in language %q`, key, language)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,13 @@ func AvailableLanguages() map[string]string {
|
||||
"pl_PL": "Polski",
|
||||
"pt_BR": "Português Brasileiro",
|
||||
"zh_CN": "简体中文",
|
||||
"zh_TW": "繁體中文",
|
||||
"nl_NL": "Nederlands",
|
||||
"ru_RU": "Русский",
|
||||
"it_IT": "Italiano",
|
||||
"ja_JP": "日本語",
|
||||
"tr_TR": "Türkçe",
|
||||
"el_EL": "Ελληνικά",
|
||||
"fi_FI": "Suomi",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ import "testing"
|
||||
|
||||
func TestPluralRules(t *testing.T) {
|
||||
scenarios := map[string]map[int]int{
|
||||
"default": map[int]int{
|
||||
"default": {
|
||||
1: 0,
|
||||
2: 1,
|
||||
5: 1,
|
||||
},
|
||||
"ar_AR": map[int]int{
|
||||
"ar_AR": {
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
@@ -21,32 +21,32 @@ func TestPluralRules(t *testing.T) {
|
||||
11: 4,
|
||||
200: 5,
|
||||
},
|
||||
"cs_CZ": map[int]int{
|
||||
"cs_CZ": {
|
||||
1: 0,
|
||||
2: 1,
|
||||
5: 2,
|
||||
},
|
||||
"pl_PL": map[int]int{
|
||||
"pl_PL": {
|
||||
1: 0,
|
||||
2: 1,
|
||||
5: 2,
|
||||
},
|
||||
"pt_BR": map[int]int{
|
||||
"pt_BR": {
|
||||
1: 0,
|
||||
2: 1,
|
||||
5: 1,
|
||||
},
|
||||
"ru_RU": map[int]int{
|
||||
"ru_RU": {
|
||||
1: 0,
|
||||
2: 1,
|
||||
5: 2,
|
||||
},
|
||||
"sr_RS": map[int]int{
|
||||
"sr_RS": {
|
||||
1: 0,
|
||||
2: 1,
|
||||
5: 2,
|
||||
},
|
||||
"zh_CN": map[int]int{
|
||||
"zh_CN": {
|
||||
1: 0,
|
||||
5: 0,
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -92,6 +92,7 @@
|
||||
"Es gibt %d Abonnement.",
|
||||
"Es gibt %d Abonnements."
|
||||
],
|
||||
"page.categories.unread_counter": "Anzahl der ungelesenen Artikel",
|
||||
"page.new_category.title": "Neue Kategorie",
|
||||
"page.new_user.title": "Neuer Benutzer",
|
||||
"page.edit_category.title": "Kategorie bearbeiten: %s",
|
||||
@@ -114,6 +115,8 @@
|
||||
"page.about.author": "Autor:",
|
||||
"page.about.license": "Lizenz:",
|
||||
"page.about.global_config_options": "Globale Konfigurationsoptionen",
|
||||
"page.about.postgres_version": "Postgres Version:",
|
||||
"page.about.go_version": "Go Version:",
|
||||
"page.add_feed.title": "Neues Abonnement",
|
||||
"page.add_feed.no_category": "Es ist keine Kategorie vorhanden. Wenigstens eine Kategorie muss angelegt sein.",
|
||||
"page.add_feed.label.url": "URL",
|
||||
@@ -149,7 +152,8 @@
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Öffne den Original-Link in der aktuellen Registerkarte",
|
||||
"page.keyboard_shortcuts.open_comments": "Kommentare öffnen",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Öffne den Kommentare-Link in der aktuellen Registerkarte",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "Gewählten Artikel als gelesen/ungelesen markieren",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Gewählten Artikel als gelesen/ungelesen markieren, fokus als nächstes",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Gewählten Artikel als gelesen/ungelesen markieren, fokus vorherige",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Alle Abonnements im Hintergrund aktualisieren",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Aktuelle Seite als gelesen markieren",
|
||||
"page.keyboard_shortcuts.download_content": "Vollständigen Inhalt herunterladen",
|
||||
@@ -199,6 +203,9 @@
|
||||
"page.api_keys.table.actions": "Aktionen",
|
||||
"page.api_keys.never_used": "Nie benutzt",
|
||||
"page.new_api_key.title": "Neuer API-Schlüssel",
|
||||
"page.offline.title": "Offline-Modus",
|
||||
"page.offline.message": "Du bist offline",
|
||||
"page.offline.refresh_page": "Versuchen Sie, die Seite zu aktualisieren",
|
||||
"alert.no_shared_entry": "Es existieren derzeit keine geteilten Artikel.",
|
||||
"alert.no_bookmark": "Es existiert derzeit kein Lesezeichen.",
|
||||
"alert.no_category": "Es ist keine Kategorie vorhanden.",
|
||||
@@ -218,6 +225,7 @@
|
||||
"error.unlink_account_without_password": "Sie müssen ein Passwort festlegen, sonst können Sie sich nicht erneut anmelden.",
|
||||
"error.duplicate_linked_account": "Es ist bereits jemand mit diesem Anbieter assoziiert!",
|
||||
"error.duplicate_fever_username": "Es existiert bereits jemand mit diesem Fever Benutzernamen!",
|
||||
"error.duplicate_googlereader_username": "Es existiert bereits jemand mit diesem Google Reader Benutzernamen!",
|
||||
"error.pocket_request_token": "Anfrage-Token konnte nicht von Pocket abgerufen werden!",
|
||||
"error.pocket_access_token": "Zugriffstoken konnte nicht von Pocket abgerufen werden!",
|
||||
"error.category_already_exists": "Diese Kategorie existiert bereits.",
|
||||
@@ -253,6 +261,7 @@
|
||||
"error.invalid_language": "Ungültige Sprache.",
|
||||
"error.invalid_timezone": "Ungültige Zeitzone.",
|
||||
"error.invalid_entry_direction": "Ungültige Sortierreihenfolge.",
|
||||
"error.invalid_display_mode": "Ungültiger Web-App-Anzeigemodus.",
|
||||
"form.feed.label.title": "Titel",
|
||||
"form.feed.label.site_url": "Webseite-URL",
|
||||
"form.feed.label.feed_url": "Abonnement-URL",
|
||||
@@ -261,14 +270,18 @@
|
||||
"form.feed.label.feed_username": "Benutzername des Abonnements",
|
||||
"form.feed.label.feed_password": "Passwort des Abonnements",
|
||||
"form.feed.label.user_agent": "Standardbenutzeragenten überschreiben",
|
||||
"form.feed.label.cookie": "Cookies setzen",
|
||||
"form.feed.label.scraper_rules": "Extraktionsregeln",
|
||||
"form.feed.label.rewrite_rules": "Umschreiberegeln",
|
||||
"form.feed.label.blocklist_rules": "Blockierregeln",
|
||||
"form.feed.label.keeplist_rules": "Erlaubnisregeln",
|
||||
"form.feed.label.ignore_http_cache": "Ignoriere HTTP-cache",
|
||||
"form.feed.label.allow_self_signed_certificates": "Erlaube selbstsignierte oder ungültige Zertifikate",
|
||||
"form.feed.label.fetch_via_proxy": "Über Proxy abrufen",
|
||||
"form.feed.label.disabled": "Dieses Abonnement nicht aktualisieren",
|
||||
"form.feed.label.hide_globally": "Einträge in der globalen Ungelesen-Liste ausblenden",
|
||||
"form.category.label.title": "Titel",
|
||||
"form.category.hide_globally": "Einträge in der globalen Ungelesen-Liste ausblenden",
|
||||
"form.user.label.username": "Benutzername",
|
||||
"form.user.label.password": "Passwort",
|
||||
"form.user.label.confirmation": "Passwort Bestätigung",
|
||||
@@ -278,18 +291,30 @@
|
||||
"form.prefs.label.theme": "Thema",
|
||||
"form.prefs.label.entry_sorting": "Sortierung der Artikel",
|
||||
"form.prefs.label.entries_per_page": "Einträge pro Seite",
|
||||
"form.prefs.label.display_mode": "Anzeigemodus der Web-App (muss neu installiert werden)",
|
||||
"form.prefs.select.older_first": "Älteste Artikel zuerst",
|
||||
"form.prefs.select.recent_first": "Neueste Artikel zuerst",
|
||||
"form.prefs.select.fullscreen": "Vollbildschirm",
|
||||
"form.prefs.select.standalone": "Eigenständige",
|
||||
"form.prefs.select.minimal_ui": "Minimal",
|
||||
"form.prefs.select.browser": "Browser",
|
||||
"form.prefs.select.publish_time": "Eintrag veröffentlichte Zeit",
|
||||
"form.prefs.select.created_time": "Eintrag erstellt Zeit",
|
||||
"form.prefs.label.keyboard_shortcuts": "Tastaturkürzel aktivieren",
|
||||
"form.prefs.label.entry_swipe": "Wischgeste für Einträge auf dem Handy aktivieren",
|
||||
"form.prefs.label.show_reading_time": "Geschätzte Lesezeit für Artikel anzeigen",
|
||||
"form.prefs.label.custom_css": "Benutzerdefiniertes CSS",
|
||||
"form.prefs.label.entry_order": "Eintrag Sortierspalte",
|
||||
"form.import.label.file": "OPML Datei",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Fever API aktivieren",
|
||||
"form.integration.fever_username": "Fever Benutzername",
|
||||
"form.integration.fever_password": "Fever Passwort",
|
||||
"form.integration.fever_endpoint": "Fever API Endpunkt:",
|
||||
"form.integration.googlereader_activate": "Google Reader API aktivieren",
|
||||
"form.integration.googlereader_username": "Google Reader Benutzername",
|
||||
"form.integration.googlereader_password": "Google Reader Passwort",
|
||||
"form.integration.googlereader_endpoint": "Google Reader API Endpunkt:",
|
||||
"form.integration.pinboard_activate": "Artikel in Pinboard speichern",
|
||||
"form.integration.pinboard_token": "Pinboard API Token",
|
||||
"form.integration.pinboard_tags": "Pinboard Tags",
|
||||
@@ -310,6 +335,16 @@
|
||||
"form.integration.nunux_keeper_activate": "Artikel in Nunux Keeper speichern",
|
||||
"form.integration.nunux_keeper_endpoint": "Nunux Keeper API-Endpunkt",
|
||||
"form.integration.nunux_keeper_api_key": "Nunux Keeper API-Schlüssel",
|
||||
"form.integration.espial_activate": "Artikel in Espial speichern",
|
||||
"form.integration.espial_endpoint": "Espial API-Endpunkt",
|
||||
"form.integration.espial_api_key": "Espial API-Schlüssel",
|
||||
"form.integration.espial_tags": "Espial tags",
|
||||
"form.integration.telegram_bot_activate": "Pushen Sie neue Artikel in den Telegram-Chat",
|
||||
"form.integration.telegram_bot_token": "Bot token",
|
||||
"form.integration.telegram_chat_id": "Chat ID",
|
||||
"form.integration.linkding_activate": "Artikel in Linkding speichern",
|
||||
"form.integration.linkding_endpoint": "Linkding API-Endpunkt",
|
||||
"form.integration.linkding_api_key": "Linkding API-Schlüssel",
|
||||
"form.api_key.label.description": "API-Schlüsselbezeichnung",
|
||||
"form.submit.loading": "Lade...",
|
||||
"form.submit.saving": "Speichern...",
|
||||
@@ -359,5 +394,5 @@
|
||||
"Website unreachable, the request timed out after %d seconds": "Webseite nicht erreichbar, die Anfrage endete nach %d Sekunden",
|
||||
"You are not authorized to access this resource (invalid username/password)": "Sie sind nicht berechtigt, auf diese Ressource zuzugreifen (Benutzername/Passwort ungültig)",
|
||||
"Unable to fetch this resource (Status Code = %d)": "Ressource konnte nicht abgerufen werden (code=%d)",
|
||||
"Resource not found (404), this feed doesn't exists anymore, check the feed URL": "Ressource nicht gefunden (404), dieses Abonnement existiert nicht mehr, überprüfen Sie die Abonnement-URL"
|
||||
"Resource not found (404), this feed doesn't exist anymore, check the feed URL": "Ressource nicht gefunden (404), dieses Abonnement existiert nicht mehr, überprüfen Sie die Abonnement-URL"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
{
|
||||
"confirm.question": "Είστε σίγουροι;",
|
||||
"confirm.yes": "ναι",
|
||||
"confirm.no": "όχι",
|
||||
"confirm.loading": "Σε εξέλιξη...",
|
||||
"action.subscribe": "Εγγραφείτε",
|
||||
"action.save": "Αποθηκεύσετε",
|
||||
"action.or": "ή",
|
||||
"action.cancel": "ακύρωση",
|
||||
"action.remove": "Κατάργηση",
|
||||
"action.remove_feed": "Κατάργηση αυτής της ροής",
|
||||
"action.update": "Ενημέρωση",
|
||||
"action.edit": "Επεξεργασία",
|
||||
"action.download": "Λήψη",
|
||||
"action.import": "Εισαγωγή",
|
||||
"action.login": "Σύνδεση",
|
||||
"action.home_screen": "Προσθήκη στην αρχική οθόνη",
|
||||
"tooltip.keyboard_shortcuts": "Συντόμευση πληκτρολογίου: % s",
|
||||
"tooltip.logged_user": "Συνδεδεμένος/η ως %s",
|
||||
"menu.unread": "Μη αναγνωσμένα",
|
||||
"menu.starred": "Αγαπημένα",
|
||||
"menu.history": "Ιστορικό",
|
||||
"menu.feeds": "Ροές",
|
||||
"menu.categories": "Κατηγορίες",
|
||||
"menu.settings": "Ρυθμίσεις",
|
||||
"menu.logout": "Αποσύνδεση",
|
||||
"menu.preferences": "Προτιμήσεις",
|
||||
"menu.integrations": "Ενσωμάτωσεις",
|
||||
"menu.sessions": "Συνδέσεις",
|
||||
"menu.users": "Χρήστες",
|
||||
"menu.about": "Περί",
|
||||
"menu.export": "Εξαγωγή",
|
||||
"menu.import": "Εισαγωγή",
|
||||
"menu.create_category": "Δημιουργήστε μια κατηγορία",
|
||||
"menu.mark_page_as_read": "Σημείωση αυτής της σελίδας ως αναγνωσμένη",
|
||||
"menu.mark_all_as_read": "Σημείωση όλων ως αναγνωσμένα",
|
||||
"menu.show_all_entries": "Εμφάνιση όλων των καταχωρήσεων",
|
||||
"menu.show_only_unread_entries": "Εμφάνιση μόνο μη αναγνωσμένων καταχωρήσεων",
|
||||
"menu.refresh_feed": "Ανανέωση",
|
||||
"menu.refresh_all_feeds": "Ανανέωση όλων των ροών στο παρασκήνιο",
|
||||
"menu.edit_feed": "Επεξεργασία",
|
||||
"menu.edit_category": "Επεξεργασία",
|
||||
"menu.add_feed": "Προσθήκη συνδρομής",
|
||||
"menu.add_user": "Προσθήκη χρήστη",
|
||||
"menu.flush_history": "Εκκαθάριση ιστορικού",
|
||||
"menu.feed_entries": "Καταχωρήσεις",
|
||||
"menu.api_keys": "Κλειδιά API",
|
||||
"menu.create_api_key": "Δημιουργήστε ένα νέο κλειδί API",
|
||||
"menu.shared_entries": "Κοινόχρηστες καταχωρήσεις",
|
||||
"search.label": "Αναζήτηση",
|
||||
"search.placeholder": "Αναζήτηση...",
|
||||
"pagination.next": "Επόμενη",
|
||||
"pagination.previous": "Προηγούμενη",
|
||||
"entry.status.unread": "Μη αναγνωσμένο",
|
||||
"entry.status.read": "Αναγνωσμένο",
|
||||
"entry.status.toast.unread": "Επισήμανση ως μη αναγνωσμένο",
|
||||
"entry.status.toast.read": "Επισήμανση ως αναγνωσμένο",
|
||||
"entry.status.title": "Αλλαγή κατάστασης καταχώρησης",
|
||||
"entry.bookmark.toggle.on": "Αγαπημένο",
|
||||
"entry.bookmark.toggle.off": "Αναίρεση αγαπημένου",
|
||||
"entry.bookmark.toast.on": "Αγαπημένα",
|
||||
"entry.bookmark.toast.off": "Μη αγαπημένα",
|
||||
"entry.state.saving": "Aποθήκευση...",
|
||||
"entry.state.loading": "Φόρτωση...",
|
||||
"entry.save.label": "Αποθηκεύσετε",
|
||||
"entry.save.title": "Αποθηκεύστε αυτό το άρθρο",
|
||||
"entry.save.completed": "Έγινε!",
|
||||
"entry.save.toast.completed": "Το άρθρο αποθηκεύτηκε",
|
||||
"entry.scraper.label": "Λήψη",
|
||||
"entry.scraper.title": "Λήψη αρχικού περιεχομένου",
|
||||
"entry.scraper.completed": "Έγινε!",
|
||||
"entry.external_link.label": "Εξωτερικός σύνδεσμος",
|
||||
"entry.comments.label": "Σχόλια",
|
||||
"entry.comments.title": "Δείτε Σχόλια",
|
||||
"entry.share.label": "Διαμοιρασμός",
|
||||
"entry.share.title": "Μοιραστείτε αυτό το άρθρο",
|
||||
"entry.unshare.label": "Aναίρεση Διαμοιρασμού",
|
||||
"entry.shared_entry.title": "Ανοίξτε τον δημόσιο σύνδεσμο",
|
||||
"entry.shared_entry.label": "Διαμοιρασμός",
|
||||
"entry.estimated_reading_time": [
|
||||
"%d λεπτό ανάγνωση",
|
||||
"%d λεπτά ανάγνωση"
|
||||
],
|
||||
"page.shared_entries.title": "Κοινόχρηστες Καταχωρήσεις",
|
||||
"page.unread.title": "Μη αναγνωσμένα",
|
||||
"page.starred.title": "Αγαπημένo",
|
||||
"page.categories.title": "Κατηγορίες",
|
||||
"page.categories.no_feed": "Καμία ροή.",
|
||||
"page.categories.entries": "Άρθρα",
|
||||
"page.categories.feeds": "Συνδρομές",
|
||||
"page.categories.feed_count": [
|
||||
"Υπάρχει μία %d ροή.",
|
||||
"Υπάρχουν %d ροές."
|
||||
],
|
||||
"page.categories.unread_counter": "Αριθμός μη αναγνωσμένων καταχωρήσεων",
|
||||
"page.new_category.title": "Νέα Κατηγορία",
|
||||
"page.new_user.title": "Νέος Χρήστης",
|
||||
"page.edit_category.title": "Επεξεργασία κατηγορίας: % s",
|
||||
"page.edit_user.title": "Επεξεργασία χρήστη: % s",
|
||||
"page.feeds.title": "Ροές",
|
||||
"page.feeds.last_check": "Τελευταίος έλεγχος:",
|
||||
"page.feeds.unread_counter": "Αριθμός μη αναγνωσμένων καταχωρήσεων",
|
||||
"page.feeds.read_counter": "Αριθμός αναγνωσμένων καταχωρήσεων",
|
||||
"page.feeds.error_count": [
|
||||
"%d σφάλμα",
|
||||
"%d σφάλματα"
|
||||
],
|
||||
"page.history.title": "Ιστορικό",
|
||||
"page.import.title": "Εισαγωγή",
|
||||
"page.search.title": "Αποτελέσματα Αναζήτησης",
|
||||
"page.about.title": "Περί",
|
||||
"page.about.credits": "Συνεισφέροντες",
|
||||
"page.about.version": "Έκδοση:",
|
||||
"page.about.build_date": "Ημερομηνία Κατασκευής:",
|
||||
"page.about.author": "Συγγραφέας:",
|
||||
"page.about.license": "Άδεια:",
|
||||
"page.about.global_config_options": "Γενικές ρυθμίσεις",
|
||||
"page.about.postgres_version": "Έκδοση Postgres:",
|
||||
"page.about.go_version": "Έκδοση Go:",
|
||||
"page.add_feed.title": "Νέα Συνδρομή",
|
||||
"page.add_feed.no_category": "Δεν υπάρχει κατηγορία. Πρέπει να έχετε τουλάχιστον μία κατηγορία.",
|
||||
"page.add_feed.label.url": "URL",
|
||||
"page.add_feed.submit": "Βρείτε μια συνδρομή",
|
||||
"page.add_feed.legend.advanced_options": "Προχωρημένες Επιλογές",
|
||||
"page.add_feed.choose_feed": "Επιλέξτε μια συνδρομή",
|
||||
"page.edit_feed.title": "Επεξεργασία ροής: % s",
|
||||
"page.edit_feed.last_check": "Τελευταίος έλεγχος:",
|
||||
"page.edit_feed.last_modified_header": "LastModified κεφαλίδα:",
|
||||
"page.edit_feed.etag_header": "Κεφαλίδα ETag:",
|
||||
"page.edit_feed.no_header": "Καμία",
|
||||
"page.edit_feed.last_parsing_error": "Τελευταίο Σφάλμα Ανάλυσης",
|
||||
"page.entry.attachments": "Συνημμένα",
|
||||
"page.keyboard_shortcuts.title": "Συντομεύσεις Πληκτρολογίου",
|
||||
"page.keyboard_shortcuts.subtitle.sections": "Πλοήγηση Τμημάτων",
|
||||
"page.keyboard_shortcuts.subtitle.items": "Πλοήγηση Στοιχείων",
|
||||
"page.keyboard_shortcuts.subtitle.pages": "Πλοήγηση Σελίδων",
|
||||
"page.keyboard_shortcuts.subtitle.actions": "Ενέργειες",
|
||||
"page.keyboard_shortcuts.go_to_unread": "Μεταβείτε στα μη αναγνωσμένα",
|
||||
"page.keyboard_shortcuts.go_to_starred": "Μεταβείτε στους σελιδοδείκτες",
|
||||
"page.keyboard_shortcuts.go_to_history": "Μεταβείτε στο ιστορικό",
|
||||
"page.keyboard_shortcuts.go_to_feeds": "Μεταβείτε στις ροές",
|
||||
"page.keyboard_shortcuts.go_to_categories": "Μεταβείτε στις κατηγορίες",
|
||||
"page.keyboard_shortcuts.go_to_settings": "Μεταβείτε στις ρυθμίσεις",
|
||||
"page.keyboard_shortcuts.show_keyboard_shortcuts": "Εμφάνιση συντομεύσεων πληκτρολογίου",
|
||||
"page.keyboard_shortcuts.go_to_previous_item": "Μεταβείτε στο προηγούμενο στοιχείο",
|
||||
"page.keyboard_shortcuts.go_to_next_item": "Μετάβαση στο επόμενο στοιχείο",
|
||||
"page.keyboard_shortcuts.go_to_feed": "Πηγαίνετε στη ροή",
|
||||
"page.keyboard_shortcuts.go_to_previous_page": "Μετάβαση στην προηγούμενη σελίδα",
|
||||
"page.keyboard_shortcuts.go_to_next_page": "Μετάβαση στην επόμενη σελίδα",
|
||||
"page.keyboard_shortcuts.open_item": "Άνοιγμα επιλεγμένου στοιχείου",
|
||||
"page.keyboard_shortcuts.open_original": "Άνοιγμα αρχικού συνδέσμου",
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Άνοιγμα αρχικού συνδέσμου στην τρέχουσα καρτέλα",
|
||||
"page.keyboard_shortcuts.open_comments": "Άνοιγμα συνδέσμου σχολίων",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Άνοιγμα συνδέσμου σχολίων στην τρέχουσα καρτέλα",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Εναλλαγή ανάγνωσης / μη αναγνωσμένης, εστίαση στη συνέχεια",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Εναλλαγή ανάγνωσης / μη αναγνωσμένης, εστίαση στο προηγούμενο",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Ανανέωση όλων των ροών στο παρασκήνιο",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Σημείωση της τρέχουσας σελίδας ως αναγνωσμένη",
|
||||
"page.keyboard_shortcuts.download_content": "Κατεβάστε το αρχικό περιεχόμενο",
|
||||
"page.keyboard_shortcuts.toggle_bookmark_status": "Εναλλαγή σελιδοδείκτη",
|
||||
"page.keyboard_shortcuts.save_article": "Αποθήκευση άρθρου",
|
||||
"page.keyboard_shortcuts.scroll_item_to_top": "Μετακινηση στοιχείου στην κορυφή",
|
||||
"page.keyboard_shortcuts.remove_feed": "Κατάργηση αυτής της ροής",
|
||||
"page.keyboard_shortcuts.go_to_search": "Ορίστε εστίαση στη φόρμα αναζήτησης",
|
||||
"page.keyboard_shortcuts.close_modal": "Κλείσιμο παραθύρου διαλόγου",
|
||||
"page.users.title": "Χρήστες",
|
||||
"page.users.username": "Χρήστης",
|
||||
"page.users.never_logged": "Ποτέ",
|
||||
"page.users.admin.yes": "Ναι.",
|
||||
"page.users.admin.no": "Όχι",
|
||||
"page.users.actions": "Eνέργειες",
|
||||
"page.users.last_login": "Τελευταία Σύνδεση",
|
||||
"page.users.is_admin": "Διαχειριστής",
|
||||
"page.settings.title": "Ρυθμίσεις",
|
||||
"page.settings.link_google_account": "Σύνδεση του λογαριασμό μου Google",
|
||||
"page.settings.unlink_google_account": "Αποσύνδεση του λογαριασμού μου Google",
|
||||
"page.settings.link_oidc_account": "Σύνδεση του λογαριασμού μου OpenID Connect",
|
||||
"page.settings.unlink_oidc_account": "Αποσύνδεση του λογαριασμού μου OpenID Connect",
|
||||
"page.login.title": "Είσοδος",
|
||||
"page.login.google_signin": "Συνδεθείτε με τo Google",
|
||||
"page.login.oidc_signin": "Συνδεθείτε με το OpenID Connect",
|
||||
"page.integrations.title": "Ενσωμάτωση",
|
||||
"page.integration.miniflux_api": "Miniflux API",
|
||||
"page.integration.miniflux_api_endpoint": "Τελικό σημείο API",
|
||||
"page.integration.miniflux_api_username": "Χρήστης",
|
||||
"page.integration.miniflux_api_password": "Κωδικός",
|
||||
"page.integration.miniflux_api_password_value": "Ο κωδικός πρόσβασης του λογαριασμού σας",
|
||||
"page.integration.bookmarklet": "Bookmarklet",
|
||||
"page.integration.bookmarklet.name": "Προσθήκη στο Miniflux",
|
||||
"page.integration.bookmarklet.instructions": "Σύρετε και αποθέστε αυτόν τον σύνδεσμο στους σελιδοδείκτες σας.",
|
||||
"page.integration.bookmarklet.help": "Αυτός ο ειδικός σύνδεσμος σάς επιτρέπει να εγγραφείτε απευθείας σε έναν ιστότοπο χρησιμοποιώντας ένα σελιδοδείκτη στο πρόγραμμα περιήγησης ιστού σας.",
|
||||
"page.sessions.title": "Συνεδρίες",
|
||||
"page.sessions.table.date": "Ημερομηνία",
|
||||
"page.sessions.table.ip": "Διεύθυνση IP",
|
||||
"page.sessions.table.user_agent": "User Agent",
|
||||
"page.sessions.table.actions": "Eνέργειες",
|
||||
"page.sessions.table.current_session": "Τρέχουσα Συνεδρία",
|
||||
"page.api_keys.title": "Κλειδιά API",
|
||||
"page.api_keys.table.description": "Περιγραφή",
|
||||
"page.api_keys.table.token": "Token",
|
||||
"page.api_keys.table.last_used_at": "Τελευταία Χρήση",
|
||||
"page.api_keys.table.created_at": "Ημερομηνία Δημιουργίας",
|
||||
"page.api_keys.table.actions": "Eνέργειες",
|
||||
"page.api_keys.never_used": "Δεν έχει χρησιμοποιηθεί ποτέ",
|
||||
"page.new_api_key.title": "Νέο κλειδί API",
|
||||
"page.offline.title": "Λειτουργία Εκτός Σύνδεσης",
|
||||
"page.offline.message": "Είστε εκτός σύνδεσης",
|
||||
"page.offline.refresh_page": "Προσπαθήστε να ανανεώσετε τη σελίδα",
|
||||
"alert.no_shared_entry": "Δεν υπάρχει κοινόχρηστη καταχώρηση.",
|
||||
"alert.no_bookmark": "Δεν υπάρχει σελιδοδείκτης αυτή τη στιγμή.",
|
||||
"alert.no_category": "Δεν υπάρχει κατηγορία.",
|
||||
"alert.no_category_entry": "Δεν υπάρχουν άρθρα σε αυτήν την κατηγορία.",
|
||||
"alert.no_feed_entry": "Δεν υπάρχουν άρθρα για αυτήν τη ροή.",
|
||||
"alert.no_feed": "Δεν έχετε συνδρομές.",
|
||||
"alert.no_feed_in_category": "Δεν υπάρχει συνδρομή για αυτήν την κατηγορία.",
|
||||
"alert.no_history": "Δεν υπάρχει ιστορικό αυτή τη στιγμή.",
|
||||
"alert.feed_error": "Υπάρχει πρόβλημα με αυτήν τη ροή",
|
||||
"alert.no_search_result": "Δεν υπάρχουν αποτελέσματα για αυτήν την αναζήτηση.",
|
||||
"alert.no_unread_entry": "Δεν υπάρχουν μη αναγνωσμένα άρθρα.",
|
||||
"alert.no_user": "Είστε ο μόνος χρήστης.",
|
||||
"alert.account_unlinked": "Ο εξωτερικός σας λογαριασμός είναι πλέον αποσυνδεδεμένος!",
|
||||
"alert.account_linked": "Ο εξωτερικός σας λογαριασμός είναι πλέον συνδεδεμένος!",
|
||||
"alert.pocket_linked": "Ο λογαριασμός Pocket είναι τώρα συνδεδεμένος!",
|
||||
"alert.prefs_saved": "Οι προτιμήσεις αποθηκεύτηκαν!",
|
||||
"error.unlink_account_without_password": "Πρέπει να ορίσετε έναν κωδικό πρόσβασης διαφορετικά δεν θα μπορείτε να συνδεθείτε ξανά.",
|
||||
"error.duplicate_linked_account": "Υπάρχει ήδη κάποιος που σχετίζεται με αυτόν τον πάροχο!",
|
||||
"error.duplicate_fever_username": "Υπάρχει ήδη κάποιος άλλος με το ίδιο όνομα χρήστη Fever!",
|
||||
"error.duplicate_googlereader_username": "Υπάρχει ήδη κάποιος άλλος με το ίδιο όνομα χρήστη Google Reader!",
|
||||
"error.pocket_request_token": "Δεν είναι δυνατή η λήψη του request token από το Pocket!",
|
||||
"error.pocket_access_token": "Δεν είναι δυνατή η λήψη του access token από το Pocket!",
|
||||
"error.category_already_exists": "Αυτή η κατηγορία υπάρχει ήδη.",
|
||||
"error.unable_to_create_category": "Δεν είναι δυνατή η δημιουργία αυτής της κατηγορίας.",
|
||||
"error.unable_to_update_category": "Δεν είναι δυνατή η ενημέρωση αυτής της κατηγορίας.",
|
||||
"error.user_already_exists": "Αυτός ο χρήστης υπάρχει ήδη.",
|
||||
"error.unable_to_create_user": "Δεν είναι δυνατή η δημιουργία αυτού του χρήστη.",
|
||||
"error.unable_to_update_user": "Δεν είναι δυνατή η ενημέρωση αυτού του χρήστη.",
|
||||
"error.unable_to_update_feed": "Δεν είναι δυνατή η ενημέρωση αυτής της ροής.",
|
||||
"error.subscription_not_found": "Δεν είναι δυνατή η εύρεση συνδρομής.",
|
||||
"error.invalid_theme": "Μη έγκυρο θέμα.",
|
||||
"error.invalid_language": "Μη έγκυρη γλώσσα.",
|
||||
"error.invalid_timezone": "Μη έγκυρη ζώνη ώρας.",
|
||||
"error.invalid_entry_direction": "Μη έγκυρη κατεύθυνση ταξινόμησης άρθρων.",
|
||||
"error.invalid_display_mode": "Μη έγκυρη λειτουργία εμφάνισης εφαρμογών ιστού.",
|
||||
"error.empty_file": "Αυτό το αρχείο είναι κενό.",
|
||||
"error.bad_credentials": "Μη έγκυρο όνομα χρήστη ή κωδικό πρόσβασης.",
|
||||
"error.fields_mandatory": "Όλα τα πεδία είναι υποχρεωτικά.",
|
||||
"error.title_required": "Ο τίτλος είναι υποχρεωτικός.",
|
||||
"error.different_passwords": "Οι κωδικοί πρόσβασης δεν είναι οι ίδιοι.",
|
||||
"error.password_min_length": "Ο κωδικός πρόσβασης πρέπει να έχει τουλάχιστον 6 χαρακτήρες.",
|
||||
"error.settings_mandatory_fields": "Τα πεδία όνομα χρήστη, θέμα, Γλώσσα και ζώνη ώρας είναι υποχρεωτικά.",
|
||||
"error.entries_per_page_invalid": "Ο αριθμός των καταχωρήσεων ανά σελίδα δεν είναι έγκυρος.",
|
||||
"error.feed_mandatory_fields": "Η διεύθυνση URL και η κατηγορία είναι υποχρεωτικά.",
|
||||
"error.feed_already_exists": "Αυτή η ροή υπάρχει ήδη.",
|
||||
"error.invalid_feed_url": "Μη έγκυρη διεύθυνση URL ροής.",
|
||||
"error.invalid_site_url": "Μη έγκυρη διεύθυνση URL ιστότοπου.",
|
||||
"error.feed_url_not_empty": "Η διεύθυνση URL ροής δεν μπορεί να είναι κενή.",
|
||||
"error.site_url_not_empty": "Η διεύθυνση URL του ιστότοπου δεν μπορεί να είναι κενή.",
|
||||
"error.feed_title_not_empty": "Ο τίτλος ροής δεν μπορεί να είναι κενός.",
|
||||
"error.feed_category_not_found": "Αυτή η κατηγορία δεν υπάρχει ή δεν ανήκει σε αυτόν τον χρήστη.",
|
||||
"error.feed_invalid_blocklist_rule": "Ο κανόνας λίστας μπλοκ δεν είναι έγκυρος.",
|
||||
"error.feed_invalid_keeplist_rule": "Ο κανόνας keep list δεν είναι έγκυρος.",
|
||||
"error.user_mandatory_fields": "Το όνομα χρήστη είναι υποχρεωτικό.",
|
||||
"error.api_key_already_exists": "Αυτό το κλειδί API υπάρχει ήδη.",
|
||||
"error.unable_to_create_api_key": "Δεν είναι δυνατή η δημιουργία αυτού του κλειδιού API.",
|
||||
"form.feed.label.title": "Τίτλος",
|
||||
"form.feed.label.site_url": "Διεύθυνση URL ιστότοπου",
|
||||
"form.feed.label.feed_url": "Διεύθυνση URL ροής",
|
||||
"form.feed.label.category": "Κατηγορία",
|
||||
"form.feed.label.crawler": "Λήψη αρχικού περιεχομένου",
|
||||
"form.feed.label.feed_username": "Όνομα Χρήστη ροής",
|
||||
"form.feed.label.feed_password": "Κωδικός Πρόσβασης ροής",
|
||||
"form.feed.label.user_agent": "Παράκαμψη Προεπιλεγμένου User Agent Χρήστη",
|
||||
"form.feed.label.cookie": "Ορισμός Cookies",
|
||||
"form.feed.label.scraper_rules": "Κανόνες Scraper",
|
||||
"form.feed.label.rewrite_rules": "Κανόνες Μετατροπής",
|
||||
"form.feed.label.blocklist_rules": "Κανόνες Αποκλεισμού",
|
||||
"form.feed.label.keeplist_rules": "Κρατήστε Κανόνες",
|
||||
"form.feed.label.ignore_http_cache": "Αγνοήστε την προσωρινή μνήμη HTTP",
|
||||
"form.feed.label.allow_self_signed_certificates": "Να επιτρέπονται αυτο-υπογεγραμμένα ή μη έγκυρα πιστοποιητικά",
|
||||
"form.feed.label.fetch_via_proxy": "Λήψη μέσω διακομιστή μεσολάβησης",
|
||||
"form.feed.label.disabled": "Μη ανανέωση αυτής της ροής",
|
||||
"form.feed.label.hide_globally": "Απόκρυψη καταχωρήσεων σε γενική λίστα μη αναγνωσμένων",
|
||||
"form.category.label.title": "Τίτλος",
|
||||
"form.category.hide_globally": "Απόκρυψη καταχωρήσεων σε γενική λίστα μη αναγνωσμένων",
|
||||
"form.user.label.username": "Χρήστης",
|
||||
"form.user.label.password": "Κωδικός",
|
||||
"form.user.label.confirmation": "Επιβεβαίωση Κωδικού Πρόσβασης",
|
||||
"form.user.label.admin": "Διαχειριστής",
|
||||
"form.prefs.label.language": "Γλώσσα",
|
||||
"form.prefs.label.timezone": "Ζώνη Ώρας",
|
||||
"form.prefs.label.theme": "Θέμα",
|
||||
"form.prefs.label.entry_sorting": "Ταξινόμηση",
|
||||
"form.prefs.label.entries_per_page": "Καταχωρήσεις ανά σελίδα",
|
||||
"form.prefs.label.display_mode": "Λειτουργία προβολής εφαρμογών ιστού (χρειάζεται επανεγκατάσταση)",
|
||||
"form.prefs.select.older_first": "Παλαιότερες καταχωρήσεις πρώτα",
|
||||
"form.prefs.select.recent_first": "Πρόσφατες καταχωρήσεις πρώτα",
|
||||
"form.prefs.select.fullscreen": "Πλήρης οθόνη",
|
||||
"form.prefs.select.standalone": "Μεμονωμένο",
|
||||
"form.prefs.select.minimal_ui": "Ελάχιστη",
|
||||
"form.prefs.select.browser": "Περιηγητής",
|
||||
"form.prefs.select.publish_time": "Δημοσιευμένος χρόνος εισόδου",
|
||||
"form.prefs.select.created_time": "Χρόνος δημιουργίας καταχώρησης",
|
||||
"form.prefs.label.keyboard_shortcuts": "Ενεργοποίηση συντομεύσεων πληκτρολογίου",
|
||||
"form.prefs.label.entry_swipe": "Ενεργοποιήστε τη χειρονομία σάρωσης στις καταχωρήσεις στο κινητό",
|
||||
"form.prefs.label.show_reading_time": "Εμφάνιση εκτιμώμενου χρόνου ανάγνωσης για άρθρα",
|
||||
"form.prefs.label.custom_css": "Προσαρμοσμένο CSS",
|
||||
"form.prefs.label.entry_order": "Στήλη ταξινόμησης εισόδου",
|
||||
"form.import.label.file": "Αρχείο OPML",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Ενεργοποιήστε το Fever API",
|
||||
"form.integration.fever_username": "Όνομα Χρήστη Fever",
|
||||
"form.integration.fever_password": "Κωδικός Πρόσβασης Fever",
|
||||
"form.integration.fever_endpoint": "Τελικό σημείο Fever API:",
|
||||
"form.integration.googlereader_activate": "Ενεργοποιήστε το Google Reader API",
|
||||
"form.integration.googlereader_username": "Όνομα Χρήστη Google Reader",
|
||||
"form.integration.googlereader_password": "Κωδικός Πρόσβασης Google Reader",
|
||||
"form.integration.googlereader_endpoint": "Τελικό σημείο Google Reader API:",
|
||||
"form.integration.pinboard_activate": "Αποθήκευση άρθρων στο Pinboard",
|
||||
"form.integration.pinboard_token": "Pinboard API Token",
|
||||
"form.integration.pinboard_tags": "Ετικέτες Pinboard",
|
||||
"form.integration.pinboard_bookmark": "Σημείωση του σελιδοδείκτη ως μη αναγνωσμένου",
|
||||
"form.integration.instapaper_activate": "Αποθήκευση άρθρων στο Instapaper",
|
||||
"form.integration.instapaper_username": "Όνομα Χρήστη Instapaper",
|
||||
"form.integration.instapaper_password": "Κωδικός Πρόσβασης Instapaper",
|
||||
"form.integration.pocket_activate": "Αποθήκευση άρθρων στο Pocket",
|
||||
"form.integration.pocket_consumer_key": "Pocket Consumer Key",
|
||||
"form.integration.pocket_access_token": "Pocket Access Token",
|
||||
"form.integration.pocket_connect_link": "Συνδέστε τον λογαριασμό Pocket σας",
|
||||
"form.integration.wallabag_activate": "Αποθήκευση άρθρων στο Wallabag",
|
||||
"form.integration.wallabag_endpoint": "Τελικό σημείο Wallabag API ",
|
||||
"form.integration.wallabag_client_id": "Ταυτότητα πελάτη Wallabag",
|
||||
"form.integration.wallabag_client_secret": "Wallabag Μυστικό Πελάτη",
|
||||
"form.integration.wallabag_username": "Όνομα Χρήστη Wallabag",
|
||||
"form.integration.wallabag_password": "Wallabag Κωδικός Πρόσβασης",
|
||||
"form.integration.nunux_keeper_activate": "Αποθήκευση άρθρων στο Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "Τελικό σημείο Nunux Keeper API",
|
||||
"form.integration.nunux_keeper_api_key": "Κλειδί API Nunux Keeper",
|
||||
"form.integration.espial_activate": "Αποθήκευση άρθρων στο Espial",
|
||||
"form.integration.espial_endpoint": "Τελικό σημείο Espial API",
|
||||
"form.integration.espial_api_key": "Κλειδί API Espial",
|
||||
"form.integration.espial_tags": "Ετικέτες Espial",
|
||||
"form.integration.telegram_bot_activate": "Προωθήστε νέα άρθρα στη συνομιλία Telegram",
|
||||
"form.integration.telegram_bot_token": "Διακριτικό bot",
|
||||
"form.integration.telegram_chat_id": "Αναγνωριστικό συνομιλίας",
|
||||
"form.integration.linkding_activate": "Αποθήκευση άρθρων στο Linkding",
|
||||
"form.integration.linkding_endpoint": "Τελικό σημείο Linkding API",
|
||||
"form.integration.linkding_api_key": "Κλειδί API Linkding",
|
||||
"form.api_key.label.description": "Ετικέτα κλειδιού API",
|
||||
"form.submit.loading": "Φόρτωση...",
|
||||
"form.submit.saving": "Αποθήκευση...",
|
||||
"time_elapsed.not_yet": "όχι ακόμα.",
|
||||
"time_elapsed.yesterday": "χθες",
|
||||
"time_elapsed.now": "μόλις τώρα",
|
||||
"time_elapsed.minutes": [
|
||||
"πριν %d λεπτό",
|
||||
"πριν %d λεπτά"
|
||||
],
|
||||
"time_elapsed.hours": [
|
||||
"πριν %d ώρα",
|
||||
"πριν %d ώρες"
|
||||
],
|
||||
"time_elapsed.days": [
|
||||
"πριν %d ημέρα",
|
||||
"πριν %d ημέρες"
|
||||
],
|
||||
"time_elapsed.weeks": [
|
||||
"πριν %d εβδομάδα",
|
||||
"πριν %d εβδομάδες"
|
||||
],
|
||||
"time_elapsed.months": [
|
||||
"πριν %d μήνα",
|
||||
"πριν %d μήνες"
|
||||
],
|
||||
"time_elapsed.years": [
|
||||
"πριν %d έτος",
|
||||
"πριν %d έτη"
|
||||
]
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
"action.login": "Login",
|
||||
"action.home_screen": "Add to home screen",
|
||||
"tooltip.keyboard_shortcuts": "Keyboard Shortcut: %s",
|
||||
"tooltip.logged_user": "Logged as %s",
|
||||
"tooltip.logged_user": "Logged in as %s",
|
||||
"menu.unread": "Unread",
|
||||
"menu.starred": "Starred",
|
||||
"menu.history": "History",
|
||||
@@ -92,6 +92,7 @@
|
||||
"There is %d feed.",
|
||||
"There are %d feeds."
|
||||
],
|
||||
"page.categories.unread_counter": "Number of unread entries",
|
||||
"page.new_category.title": "New Category",
|
||||
"page.new_user.title": "New User",
|
||||
"page.edit_category.title": "Edit Category: %s",
|
||||
@@ -114,6 +115,8 @@
|
||||
"page.about.author": "Author:",
|
||||
"page.about.license": "License:",
|
||||
"page.about.global_config_options": "Global configuration options",
|
||||
"page.about.postgres_version": "Postgres version:",
|
||||
"page.about.go_version": "Go version:",
|
||||
"page.add_feed.title": "New Subscription",
|
||||
"page.add_feed.no_category": "There is no category. You must have at least one category.",
|
||||
"page.add_feed.label.url": "URL",
|
||||
@@ -149,7 +152,8 @@
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Open original link in current tab",
|
||||
"page.keyboard_shortcuts.open_comments": "Open comments link",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Open comments link in current tab",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "Toggle read/unread",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Toggle read/unread, focus next",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Toggle read/unread, focus previous",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Refresh all feeds in the background",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Mark current page as read",
|
||||
"page.keyboard_shortcuts.download_content": "Download original content",
|
||||
@@ -199,6 +203,9 @@
|
||||
"page.api_keys.table.actions": "Actions",
|
||||
"page.api_keys.never_used": "Never Used",
|
||||
"page.new_api_key.title": "New API Key",
|
||||
"page.offline.title": "Offline Mode",
|
||||
"page.offline.message": "You are offline",
|
||||
"page.offline.refresh_page": "Try to refresh the page",
|
||||
"alert.no_shared_entry": "There is no shared entry.",
|
||||
"alert.no_bookmark": "There is no bookmark at the moment.",
|
||||
"alert.no_category": "There is no category.",
|
||||
@@ -218,6 +225,7 @@
|
||||
"error.unlink_account_without_password": "You must define a password otherwise you won't be able to login again.",
|
||||
"error.duplicate_linked_account": "There is already someone associated with this provider!",
|
||||
"error.duplicate_fever_username": "There is already someone else with the same Fever username!",
|
||||
"error.duplicate_googlereader_username": "There is already someone else with the same Google Reader username!",
|
||||
"error.pocket_request_token": "Unable to fetch request token from Pocket!",
|
||||
"error.pocket_access_token": "Unable to fetch access token from Pocket!",
|
||||
"error.category_already_exists": "This category already exists.",
|
||||
@@ -232,6 +240,7 @@
|
||||
"error.invalid_language": "Invalid language.",
|
||||
"error.invalid_timezone": "Invalid timezone.",
|
||||
"error.invalid_entry_direction": "Invalid entry direction.",
|
||||
"error.invalid_display_mode": "Invalid web app display mode.",
|
||||
"error.empty_file": "This file is empty.",
|
||||
"error.bad_credentials": "Invalid username or password.",
|
||||
"error.fields_mandatory": "All fields are mandatory.",
|
||||
@@ -261,14 +270,18 @@
|
||||
"form.feed.label.feed_username": "Feed Username",
|
||||
"form.feed.label.feed_password": "Feed Password",
|
||||
"form.feed.label.user_agent": "Override Default User Agent",
|
||||
"form.feed.label.cookie": "Set Cookies",
|
||||
"form.feed.label.scraper_rules": "Scraper Rules",
|
||||
"form.feed.label.rewrite_rules": "Rewrite Rules",
|
||||
"form.feed.label.blocklist_rules": "Block Rules",
|
||||
"form.feed.label.keeplist_rules": "Keep Rules",
|
||||
"form.feed.label.ignore_http_cache": "Ignore HTTP cache",
|
||||
"form.feed.label.allow_self_signed_certificates": "Allow self-signed or invalid certificates",
|
||||
"form.feed.label.fetch_via_proxy": "Fetch via proxy",
|
||||
"form.feed.label.disabled": "Do not refresh this feed",
|
||||
"form.feed.label.hide_globally": "Hide entries in global unread list",
|
||||
"form.category.label.title": "Title",
|
||||
"form.category.hide_globally": "Hide entries in global unread list",
|
||||
"form.user.label.username": "Username",
|
||||
"form.user.label.password": "Password",
|
||||
"form.user.label.confirmation": "Password Confirmation",
|
||||
@@ -278,18 +291,30 @@
|
||||
"form.prefs.label.theme": "Theme",
|
||||
"form.prefs.label.entry_sorting": "Entry Sorting",
|
||||
"form.prefs.label.entries_per_page": "Entries per page",
|
||||
"form.prefs.label.display_mode": "Web app display mode (needs reinstalling)",
|
||||
"form.prefs.select.older_first": "Older entries first",
|
||||
"form.prefs.select.recent_first": "Recent entries first",
|
||||
"form.prefs.select.fullscreen": "Fullscreen",
|
||||
"form.prefs.select.standalone": "Standalone",
|
||||
"form.prefs.select.minimal_ui": "Minimal",
|
||||
"form.prefs.select.browser": "Browser",
|
||||
"form.prefs.select.publish_time": "Entry published time",
|
||||
"form.prefs.select.created_time": "Entry created time",
|
||||
"form.prefs.label.keyboard_shortcuts": "Enable keyboard shortcuts",
|
||||
"form.prefs.label.entry_swipe": "Enable swipe gesture on entries on mobile",
|
||||
"form.prefs.label.show_reading_time": "Show estimated reading time for articles",
|
||||
"form.prefs.label.custom_css": "Custom CSS",
|
||||
"form.prefs.label.entry_order": "Entry Sorting Column",
|
||||
"form.import.label.file": "OPML file",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Activate Fever API",
|
||||
"form.integration.fever_username": "Fever Username",
|
||||
"form.integration.fever_password": "Fever Password",
|
||||
"form.integration.fever_endpoint": "Fever API endpoint:",
|
||||
"form.integration.googlereader_activate": "Activate Google Reader API",
|
||||
"form.integration.googlereader_username": "Google Reader Username",
|
||||
"form.integration.googlereader_password": "Google Reader Password",
|
||||
"form.integration.googlereader_endpoint": "Google Reader API endpoint:",
|
||||
"form.integration.pinboard_activate": "Save articles to Pinboard",
|
||||
"form.integration.pinboard_token": "Pinboard API Token",
|
||||
"form.integration.pinboard_tags": "Pinboard Tags",
|
||||
@@ -310,6 +335,16 @@
|
||||
"form.integration.nunux_keeper_activate": "Save articles to Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "Nunux Keeper API Endpoint",
|
||||
"form.integration.nunux_keeper_api_key": "Nunux Keeper API key",
|
||||
"form.integration.espial_activate": "Save articles to Espial",
|
||||
"form.integration.espial_endpoint": "Espial API Endpoint",
|
||||
"form.integration.espial_api_key": "Espial API key",
|
||||
"form.integration.espial_tags": "Espial Tags",
|
||||
"form.integration.telegram_bot_activate": "Push new articles to Telegram chat",
|
||||
"form.integration.telegram_bot_token": "Bot token",
|
||||
"form.integration.telegram_chat_id": "Chat ID",
|
||||
"form.integration.linkding_activate": "Save articles to Linkding",
|
||||
"form.integration.linkding_endpoint": "Linkding API Endpoint",
|
||||
"form.integration.linkding_api_key": "Linkding API key",
|
||||
"form.api_key.label.description": "API Key Label",
|
||||
"form.submit.loading": "Loading...",
|
||||
"form.submit.saving": "Saving...",
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
"Hay %d fuente.",
|
||||
"Hay %d fuentes."
|
||||
],
|
||||
"page.categories.unread_counter": "Número de entradas no leídas",
|
||||
"page.new_category.title": "Nueva categoría",
|
||||
"page.new_user.title": "Nuevo usario",
|
||||
"page.edit_category.title": "Editar categoría: %s",
|
||||
@@ -114,6 +115,8 @@
|
||||
"page.about.author": "Autor:",
|
||||
"page.about.license": "Licencia:",
|
||||
"page.about.global_config_options": "Opciones de configuración global",
|
||||
"page.about.postgres_version": "Postgres versión:",
|
||||
"page.about.go_version": "Go versión:",
|
||||
"page.add_feed.title": "Nueva suscripción",
|
||||
"page.add_feed.no_category": "No hay categoría. Debe tener al menos una categoría.",
|
||||
"page.add_feed.label.url": "URL",
|
||||
@@ -149,7 +152,8 @@
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Abrir enlace original en la pestaña actual",
|
||||
"page.keyboard_shortcuts.open_comments": "Abrir el enlace de comentarios",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Abrir enlace de comentarios en la pestaña actual",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "Marcar como leído o no leído",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Marcar como leído o no leído, enfoque siguiente",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Marcar como leído o no leído, foco anterior",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Refrescar todas las fuentes en el fondo",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Marcar pagína actual como leída",
|
||||
"page.keyboard_shortcuts.download_content": "Descargar el contento original",
|
||||
@@ -199,6 +203,9 @@
|
||||
"page.api_keys.table.actions": "Acciones",
|
||||
"page.api_keys.never_used": "Nunca usado",
|
||||
"page.new_api_key.title": "Nueva clave API",
|
||||
"page.offline.title": "Modo offline",
|
||||
"page.offline.message": "Estas desconectado",
|
||||
"page.offline.refresh_page": "Intenta actualizar la página",
|
||||
"alert.no_shared_entry": "No hay entrada compartida.",
|
||||
"alert.no_bookmark": "No hay marcador en este momento.",
|
||||
"alert.no_category": "No hay categoría.",
|
||||
@@ -218,6 +225,7 @@
|
||||
"error.unlink_account_without_password": "Debe definir una contraseña, de lo contrario no podrá volver a iniciar sesión.",
|
||||
"error.duplicate_linked_account": "¡Ya hay alguien asociado a este servicio!",
|
||||
"error.duplicate_fever_username": "¡Ya hay alguien con el mismo nombre de usuario de Fever!",
|
||||
"error.duplicate_googlereader_username": "¡Ya hay alguien con el mismo nombre de usuario de Google Reader!",
|
||||
"error.pocket_request_token": "Incapaz de obtener un token de solicitud de Pocket!",
|
||||
"error.pocket_access_token": "Incapaz de obtener un token de acceso de Pocket!",
|
||||
"error.category_already_exists": "Esta categoría ya existe.",
|
||||
@@ -253,6 +261,7 @@
|
||||
"error.invalid_language": "Idioma no válido.",
|
||||
"error.invalid_timezone": "Zona horaria no válida.",
|
||||
"error.invalid_entry_direction": "Dirección de entrada no válida.",
|
||||
"error.invalid_display_mode": "Modo de visualización de la aplicación web no válido.",
|
||||
"form.feed.label.title": "Título",
|
||||
"form.feed.label.site_url": "URL del sitio",
|
||||
"form.feed.label.feed_url": "URL de la fuente",
|
||||
@@ -261,14 +270,18 @@
|
||||
"form.feed.label.feed_username": "Nombre de usuario de fuente",
|
||||
"form.feed.label.feed_password": "Contraseña de fuente",
|
||||
"form.feed.label.user_agent": "Invalidar el agente de usuario predeterminado",
|
||||
"form.feed.label.cookie": "Configurar las cookies",
|
||||
"form.feed.label.scraper_rules": "Reglas de raspador",
|
||||
"form.feed.label.rewrite_rules": "Reglas de reescribir",
|
||||
"form.feed.label.blocklist_rules": "Reglas de Filtrado(Bloquear)",
|
||||
"form.feed.label.keeplist_rules": "Reglas de Filtrado(Permitir)",
|
||||
"form.feed.label.ignore_http_cache": "Ignorar caché HTTP",
|
||||
"form.feed.label.allow_self_signed_certificates": "Permitir certificados autofirmados o no válidos",
|
||||
"form.feed.label.fetch_via_proxy": "Buscar a través de proxy",
|
||||
"form.feed.label.disabled": "No actualice este feed",
|
||||
"form.feed.label.hide_globally": "Ocultar entradas en la lista global de no leídos",
|
||||
"form.category.label.title": "Título",
|
||||
"form.category.hide_globally": "Ocultar entradas en la lista global de no leídos",
|
||||
"form.user.label.username": "Nombre de usuario",
|
||||
"form.user.label.password": "Contraseña",
|
||||
"form.user.label.confirmation": "Confirmación de contraseña",
|
||||
@@ -278,18 +291,30 @@
|
||||
"form.prefs.label.theme": "Tema",
|
||||
"form.prefs.label.entry_sorting": "Clasificación de entradas",
|
||||
"form.prefs.label.entries_per_page": "Entradas por página",
|
||||
"form.prefs.label.display_mode": "Modo de visualización de la aplicación web (necesita reinstalación)",
|
||||
"form.prefs.select.older_first": "Entradas más viejas primero",
|
||||
"form.prefs.select.recent_first": "Entradas recientes primero",
|
||||
"form.prefs.select.fullscreen": "Pantalla completa",
|
||||
"form.prefs.select.standalone": "Ser único",
|
||||
"form.prefs.select.minimal_ui": "Mínimo",
|
||||
"form.prefs.select.browser": "Navegador",
|
||||
"form.prefs.select.publish_time": "Hora de publicación de la entrada",
|
||||
"form.prefs.select.created_time": "Hora de creación de la entrada",
|
||||
"form.prefs.label.keyboard_shortcuts": "Habilitar atajos de teclado",
|
||||
"form.prefs.label.entry_swipe": "Habilitar el gesto de deslizar el dedo en las entradas en el móvil",
|
||||
"form.prefs.label.show_reading_time": "Mostrar el tiempo estimado de lectura de los artículos",
|
||||
"form.prefs.label.custom_css": "CSS personalizado",
|
||||
"form.prefs.label.entry_order": "Columna de clasificación de entradas",
|
||||
"form.import.label.file": "Archivo OPML",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Activar API de Fever",
|
||||
"form.integration.fever_username": "Nombre de usuario de Fever",
|
||||
"form.integration.fever_password": "Contraseña de Fever",
|
||||
"form.integration.fever_endpoint": "Extremo de API de Fever:",
|
||||
"form.integration.googlereader_activate": "Activar API de Google Reader",
|
||||
"form.integration.googlereader_username": "Nombre de usuario de Google Reader",
|
||||
"form.integration.googlereader_password": "Contraseña de Google Reader",
|
||||
"form.integration.googlereader_endpoint": "Extremo de API de Google Reader:",
|
||||
"form.integration.pinboard_activate": "Guardar artículos a Pinboard",
|
||||
"form.integration.pinboard_token": "Token de API de Pinboard",
|
||||
"form.integration.pinboard_tags": "Etiquetas de Pinboard",
|
||||
@@ -310,6 +335,16 @@
|
||||
"form.integration.nunux_keeper_activate": "Guardar artículos a Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "Extremo de API de Nunux Keeper",
|
||||
"form.integration.nunux_keeper_api_key": "Clave de API de Nunux Keeper",
|
||||
"form.integration.espial_activate": "Guardar artículos a Espial",
|
||||
"form.integration.espial_endpoint": "Extremo de API de Espial",
|
||||
"form.integration.espial_api_key": "Clave de API de Espial",
|
||||
"form.integration.espial_tags": "Etiquetas de Espial",
|
||||
"form.integration.telegram_bot_activate": "Envíe nuevos artículos al chat de Telegram",
|
||||
"form.integration.telegram_bot_token": "Token de bot",
|
||||
"form.integration.telegram_chat_id": "ID de chat",
|
||||
"form.integration.linkding_activate": "Guardar artículos a Linkding",
|
||||
"form.integration.linkding_endpoint": "Extremo de API de Linkding",
|
||||
"form.integration.linkding_api_key": "Clave de API de Linkding",
|
||||
"form.api_key.label.description": "Etiqueta de clave API",
|
||||
"form.submit.loading": "Cargando...",
|
||||
"form.submit.saving": "Guardando...",
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
{
|
||||
"confirm.question": "Oletko varma?",
|
||||
"confirm.yes": "kyllä",
|
||||
"confirm.no": "ei",
|
||||
"confirm.loading": "Käynnissä...",
|
||||
"action.subscribe": "Tilaa",
|
||||
"action.save": "Tallenna",
|
||||
"action.or": "tai",
|
||||
"action.cancel": "peru",
|
||||
"action.remove": "Poista",
|
||||
"action.remove_feed": "Poista tämä syöte",
|
||||
"action.update": "Päivitä",
|
||||
"action.edit": "Muokkaa",
|
||||
"action.download": "Lataa",
|
||||
"action.import": "Tuo",
|
||||
"action.login": "Kirjaudu sisään",
|
||||
"action.home_screen": "Lisää aloitusnäytölle",
|
||||
"tooltip.keyboard_shortcuts": "Pikanäppäin: %s",
|
||||
"tooltip.logged_user": "Kirjautunut %s-käyttäjänä",
|
||||
"menu.unread": "Lukemattomat",
|
||||
"menu.starred": "Suosikit",
|
||||
"menu.history": "Historia",
|
||||
"menu.feeds": "Syötteet",
|
||||
"menu.categories": "Kategoriat",
|
||||
"menu.settings": "Asetukset",
|
||||
"menu.logout": "Kirjaudu ulos",
|
||||
"menu.preferences": "Asetukset",
|
||||
"menu.integrations": "Integraatiot",
|
||||
"menu.sessions": "Istunnot",
|
||||
"menu.users": "Käyttäjät",
|
||||
"menu.about": "Tietoja",
|
||||
"menu.export": "Vie",
|
||||
"menu.import": "Tuo",
|
||||
"menu.create_category": "Luo kategoria",
|
||||
"menu.mark_page_as_read": "Merkitse tämä sivu luetuksi",
|
||||
"menu.mark_all_as_read": "Merkitse kaikki luetuksi",
|
||||
"menu.show_all_entries": "Näytä kaikki artikkelit",
|
||||
"menu.show_only_unread_entries": "Näytä vain lukemattomat artikkelit",
|
||||
"menu.refresh_feed": "Päivitä",
|
||||
"menu.refresh_all_feeds": "Päivitä kaikki syötteet taustalla",
|
||||
"menu.edit_feed": "Muokkaa",
|
||||
"menu.edit_category": "Muokkaa",
|
||||
"menu.add_feed": "Lisää tilaus",
|
||||
"menu.add_user": "Lisää käyttäjä",
|
||||
"menu.flush_history": "Tyhjennä historia",
|
||||
"menu.feed_entries": "Artikkelit",
|
||||
"menu.api_keys": "API-avaimet",
|
||||
"menu.create_api_key": "Luo uusi API-avain",
|
||||
"menu.shared_entries": "Jaetut artikkelit",
|
||||
"search.label": "Haku",
|
||||
"search.placeholder": "Hae...",
|
||||
"pagination.next": "Seuraava",
|
||||
"pagination.previous": "Edellinen",
|
||||
"entry.status.unread": "Lukematon",
|
||||
"entry.status.read": "Luettu",
|
||||
"entry.status.toast.unread": "Merkitty lukemattomaksi",
|
||||
"entry.status.toast.read": "Merkitty luetuksi",
|
||||
"entry.status.title": "Vaihda artikkelin tilaa",
|
||||
"entry.bookmark.toggle.on": "Lisää suosikkeihin",
|
||||
"entry.bookmark.toggle.off": "Poista suosikeista",
|
||||
"entry.bookmark.toast.on": "Tähdellä merkityt",
|
||||
"entry.bookmark.toast.off": "Tähdettömät",
|
||||
"entry.state.saving": "Tallennetaan...",
|
||||
"entry.state.loading": "Ladataan...",
|
||||
"entry.save.label": "Tallenna",
|
||||
"entry.save.title": "Tallenna tämä artikkeli",
|
||||
"entry.save.completed": "Valmis!",
|
||||
"entry.save.toast.completed": "Artikkeli tallennettu",
|
||||
"entry.scraper.label": "Lataa",
|
||||
"entry.scraper.title": "Nouda alkuperäinen sisältö",
|
||||
"entry.scraper.completed": "Valmis!",
|
||||
"entry.external_link.label": "Ulkoinen linkki",
|
||||
"entry.comments.label": "Kommentit",
|
||||
"entry.comments.title": "Näytä kommentit",
|
||||
"entry.share.label": "Jaa",
|
||||
"entry.share.title": "Jaa tämä artikkeli",
|
||||
"entry.unshare.label": "Poista jako",
|
||||
"entry.shared_entry.title": "Avaa julkinen linkki",
|
||||
"entry.shared_entry.label": "Jaa",
|
||||
"entry.estimated_reading_time": [
|
||||
"%d minuutin lukuaika",
|
||||
"%d minuutin lukuaika"
|
||||
],
|
||||
"page.shared_entries.title": "Jaetut artikkelit",
|
||||
"page.unread.title": "Lukemattomat",
|
||||
"page.starred.title": "Suosikit",
|
||||
"page.categories.title": "Kategoriat",
|
||||
"page.categories.no_feed": "Ei syötettä.",
|
||||
"page.categories.entries": "Artikkelit",
|
||||
"page.categories.feeds": "Tilaukset",
|
||||
"page.categories.feed_count": [
|
||||
"On %d syöte.",
|
||||
"On %d syötettä."
|
||||
],
|
||||
"page.categories.unread_counter": "Lukemattomien artikkeleiden määrä",
|
||||
"page.new_category.title": "Uusi kategoria",
|
||||
"page.new_user.title": "Uusi käyttäjä",
|
||||
"page.edit_category.title": "Muokkaa kategoria: %s",
|
||||
"page.edit_user.title": "Muokkaa käyttäjä: %s",
|
||||
"page.feeds.title": "Syötteet",
|
||||
"page.feeds.last_check": "Viimeisin tarkistus:",
|
||||
"page.feeds.unread_counter": "Lukemattomien artikkeleiden määrä",
|
||||
"page.feeds.read_counter": "Luettujen artikkeleiden määrä",
|
||||
"page.feeds.error_count": [
|
||||
"%d virhe",
|
||||
"%d virhettä"
|
||||
],
|
||||
"page.history.title": "Historia",
|
||||
"page.import.title": "Tuo",
|
||||
"page.search.title": "Hakutulokset",
|
||||
"page.about.title": "Tietoja",
|
||||
"page.about.credits": "Kiitokset",
|
||||
"page.about.version": "Versio:",
|
||||
"page.about.build_date": "Valmistuspäivä:",
|
||||
"page.about.author": "Tekijä:",
|
||||
"page.about.license": "Lisenssi:",
|
||||
"page.about.global_config_options": "Yleiset asetukset",
|
||||
"page.about.postgres_version": "Postgres-versio:",
|
||||
"page.about.go_version": "Go-versio:",
|
||||
"page.add_feed.title": "Uusi tilaus",
|
||||
"page.add_feed.no_category": "Ei ole ketegoriaa. Sinulla on oltava vähintään yksi ketegoria.",
|
||||
"page.add_feed.label.url": "URL-osoite",
|
||||
"page.add_feed.submit": "Etsi tilaus",
|
||||
"page.add_feed.legend.advanced_options": "Edistyneet asetukset",
|
||||
"page.add_feed.choose_feed": "Valitse tilaus",
|
||||
"page.edit_feed.title": "Muokkaa syöte: %s",
|
||||
"page.edit_feed.last_check": "Viimeisin tarkistus:",
|
||||
"page.edit_feed.last_modified_header": "LastModified-otsikko:",
|
||||
"page.edit_feed.etag_header": "ETag-otsikko:",
|
||||
"page.edit_feed.no_header": "Ei mitään",
|
||||
"page.edit_feed.last_parsing_error": "Viimeisin jäsennysvirhe",
|
||||
"page.entry.attachments": "Liitteet",
|
||||
"page.keyboard_shortcuts.title": "Pikanäppäimet",
|
||||
"page.keyboard_shortcuts.subtitle.sections": "Osion navigointi",
|
||||
"page.keyboard_shortcuts.subtitle.items": "Kohteiden navigointi",
|
||||
"page.keyboard_shortcuts.subtitle.pages": "Sivujen navigointi",
|
||||
"page.keyboard_shortcuts.subtitle.actions": "Toiminnot",
|
||||
"page.keyboard_shortcuts.go_to_unread": "Siirry lukemattomiin",
|
||||
"page.keyboard_shortcuts.go_to_starred": "Siirry kirjanmerkkeihin",
|
||||
"page.keyboard_shortcuts.go_to_history": "Siirry historiaan",
|
||||
"page.keyboard_shortcuts.go_to_feeds": "Siirry syötteisiin",
|
||||
"page.keyboard_shortcuts.go_to_categories": "Siirry kategorioihin",
|
||||
"page.keyboard_shortcuts.go_to_settings": "Siirry asetuksiin",
|
||||
"page.keyboard_shortcuts.show_keyboard_shortcuts": "Näytä pikanäppäimet",
|
||||
"page.keyboard_shortcuts.go_to_previous_item": "Siirry edelliseen kohteeseen",
|
||||
"page.keyboard_shortcuts.go_to_next_item": "Siirry seuraavaan kohteeseen",
|
||||
"page.keyboard_shortcuts.go_to_feed": "Siirry syötteeseen",
|
||||
"page.keyboard_shortcuts.go_to_previous_page": "Siirry edelliselle sivulle",
|
||||
"page.keyboard_shortcuts.go_to_next_page": "Siirry seuraavalle sivulle",
|
||||
"page.keyboard_shortcuts.open_item": "Avaa valittu kohde",
|
||||
"page.keyboard_shortcuts.open_original": "Avaa alkuperäinen linkki",
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Avaa alkuperäinen linkki nykyisessä välilehdessä",
|
||||
"page.keyboard_shortcuts.open_comments": "Avaa kommenttilinkki",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Avaa kommenttilinkki nykyisessä välilehdessä",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Vaihda luettu/lukematon, keskity seuraavaksi",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Vaihda luettu/lukematon, keskity edelliseen",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Päivitä kaikki syötteet taustalla",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Merkitse nykyinen sivu luetuksi",
|
||||
"page.keyboard_shortcuts.download_content": "Lataa alkuperäinen sisältö",
|
||||
"page.keyboard_shortcuts.toggle_bookmark_status": "Vaihda kirjanmerkki",
|
||||
"page.keyboard_shortcuts.save_article": "Tallenna artikkeli",
|
||||
"page.keyboard_shortcuts.scroll_item_to_top": "Vieritä ylös",
|
||||
"page.keyboard_shortcuts.remove_feed": "Poista tämä syöte",
|
||||
"page.keyboard_shortcuts.go_to_search": "Aseta painopiste hakukenttään",
|
||||
"page.keyboard_shortcuts.close_modal": "Sulje modaalinen valintaikkuna",
|
||||
"page.users.title": "Käyttäjät",
|
||||
"page.users.username": "Käyttäjätunnus",
|
||||
"page.users.never_logged": "Ei koskaan",
|
||||
"page.users.admin.yes": "Kyllä",
|
||||
"page.users.admin.no": "Ei",
|
||||
"page.users.actions": "Toiminnot",
|
||||
"page.users.last_login": "Viimeisin kirjautuminen",
|
||||
"page.users.is_admin": "Ylläpitäjä",
|
||||
"page.settings.title": "Asetukset",
|
||||
"page.settings.link_google_account": "Linkitä Google-tilini",
|
||||
"page.settings.unlink_google_account": "Poista Google-tilini linkitys",
|
||||
"page.settings.link_oidc_account": "Linkitä OpenID Connect -tilini",
|
||||
"page.settings.unlink_oidc_account": "Poista OpenID Connect -tilini linkitys",
|
||||
"page.login.title": "Kirjaudu sisään",
|
||||
"page.login.google_signin": "Kirjaudu sisään Googlella",
|
||||
"page.login.oidc_signin": "Kirjaudu sisään OpenID Connectilla",
|
||||
"page.integrations.title": "Integraatiot",
|
||||
"page.integration.miniflux_api": "Miniflux API",
|
||||
"page.integration.miniflux_api_endpoint": "API-päätepiste",
|
||||
"page.integration.miniflux_api_username": "Käyttäjätunnus",
|
||||
"page.integration.miniflux_api_password": "Salasana",
|
||||
"page.integration.miniflux_api_password_value": "Tilisi salasana",
|
||||
"page.integration.bookmarklet": "Sovelluskirjanmerkki",
|
||||
"page.integration.bookmarklet.name": "Lisää Minifluxiin",
|
||||
"page.integration.bookmarklet.instructions": "Vedä ja pudota tämä linkki kirjanmerkkeihisi.",
|
||||
"page.integration.bookmarklet.help": "This special link allows you to subscribe to a website directly by using a bookmark in your web browser.",
|
||||
"page.sessions.title": "Istunnot",
|
||||
"page.sessions.table.date": "Päivämäärä",
|
||||
"page.sessions.table.ip": "IP-osoite",
|
||||
"page.sessions.table.user_agent": "Käyttäjäagentti",
|
||||
"page.sessions.table.actions": "Toiminnot",
|
||||
"page.sessions.table.current_session": "Nykyinen istunto",
|
||||
"page.api_keys.title": "API-avaimet",
|
||||
"page.api_keys.table.description": "Kuvaus",
|
||||
"page.api_keys.table.token": "Tunnus",
|
||||
"page.api_keys.table.last_used_at": "Viimeksi käytetty",
|
||||
"page.api_keys.table.created_at": "Luomispäivä",
|
||||
"page.api_keys.table.actions": "Toiminnot",
|
||||
"page.api_keys.never_used": "Käyttämätön",
|
||||
"page.new_api_key.title": "Uusi API-avain",
|
||||
"page.offline.title": "Offline-tila",
|
||||
"page.offline.message": "Olet offline-tilassa",
|
||||
"page.offline.refresh_page": "Yritä päivittää sivu",
|
||||
"alert.no_shared_entry": "Jaettua artikkelia ei ole.",
|
||||
"alert.no_bookmark": "Tällä hetkellä ei ole kirjanmerkkiä.",
|
||||
"alert.no_category": "Ei ole kategoriaa.",
|
||||
"alert.no_category_entry": "Tässä kategoriassa ei ole artikkeleita.",
|
||||
"alert.no_feed_entry": "Tässä syötteessä ei ole artikkeleita.",
|
||||
"alert.no_feed": "Sinulla ei ole tilauksia.",
|
||||
"alert.no_feed_in_category": "Tälle kategorialle ei ole tilausta.",
|
||||
"alert.no_history": "Tällä hetkellä ei ole historiaa.",
|
||||
"alert.feed_error": "Tässä syötteessä on ongelma",
|
||||
"alert.no_search_result": "Ei hakua vastaavia tuloksia.",
|
||||
"alert.no_unread_entry": "Ei ole lukemattomia artikkeleita.",
|
||||
"alert.no_user": "Olet ainoa käyttäjä.",
|
||||
"alert.account_unlinked": "Ulkoinen tilisi on nyt irrotettu!",
|
||||
"alert.account_linked": "Ulkoinen tilisi on nyt linkitetty!",
|
||||
"alert.pocket_linked": "Pocket-tilisi on nyt linkitetty!",
|
||||
"alert.prefs_saved": "Asetukset tallennettu!",
|
||||
"error.unlink_account_without_password": "Sinun on määritettävä salasana, muuten et voi kirjautua uudelleen.",
|
||||
"error.duplicate_linked_account": "There is already someone associated with this provider!",
|
||||
"error.duplicate_fever_username": "There is already someone else with the same Fever username!",
|
||||
"error.duplicate_googlereader_username": "On jo joku muu, jolla on sama Google-syötteenlukijan käyttäjätunnus!",
|
||||
"error.pocket_request_token": "Unable to fetch request token from Pocket!",
|
||||
"error.pocket_access_token": "Unable to fetch access token from Pocket!",
|
||||
"error.category_already_exists": "Kategoria on jo olemassa. ",
|
||||
"error.unable_to_create_category": "Kategoriaa ei voi luoda.",
|
||||
"error.unable_to_update_category": "Kategoriaa ei voi päivittää.",
|
||||
"error.user_already_exists": "Käyttäjä on jo olemassa.",
|
||||
"error.unable_to_create_user": "Käyttäjää ei voi luoda.",
|
||||
"error.unable_to_update_user": "Käyttäjää ei voi päivittää.",
|
||||
"error.unable_to_update_feed": "Syötettä ei voi päivittää.",
|
||||
"error.subscription_not_found": "Tilausta ei löydy.",
|
||||
"error.invalid_theme": "Virheellinen teema.",
|
||||
"error.invalid_language": "Virheellinen kieli.",
|
||||
"error.invalid_timezone": "Virheellinen aikavyöhyke.",
|
||||
"error.invalid_entry_direction": "Invalid entry direction.",
|
||||
"error.invalid_display_mode": "Virheellinen verkkosovelluksen näyttötila.",
|
||||
"error.empty_file": "Tiedosto on tyhjä.",
|
||||
"error.bad_credentials": "Virheellinen käyttäjänimi tai salasana.",
|
||||
"error.fields_mandatory": "Kaikki kentät ovat pakollisia.",
|
||||
"error.title_required": "Otsikko on pakollinen.",
|
||||
"error.different_passwords": "Salasanat eivät ole samat.",
|
||||
"error.password_min_length": "Salasanassa on oltava vähintään 6 merkkiä.",
|
||||
"error.settings_mandatory_fields": "Käyttäjätunnus, teema, kieli ja aikavyöhyke ovat pakollisia.",
|
||||
"error.entries_per_page_invalid": "Artikkelien määrä sivulla ei kelpaa.",
|
||||
"error.feed_mandatory_fields": "URL-osoite ja kategoria ovat pakollisia.",
|
||||
"error.feed_already_exists": "Tämä syöte on jo olemassa.",
|
||||
"error.invalid_feed_url": "Virheellinen syötteen URL-osoite.",
|
||||
"error.invalid_site_url": "Virheellinen sivuston URL-osoite.",
|
||||
"error.feed_url_not_empty": "Syötteen URL-osoite ei voi olla tyhjä.",
|
||||
"error.site_url_not_empty": "Sivuston URL-osoite ei voi olla tyhjä.",
|
||||
"error.feed_title_not_empty": "Syötteen otsikko ei voi olla tyhjä.",
|
||||
"error.feed_category_not_found": "Tätä kategoriaa ei ole olemassa tai se ei kuulu tälle käyttäjälle.",
|
||||
"error.feed_invalid_blocklist_rule": "The block list rule is invalid.",
|
||||
"error.feed_invalid_keeplist_rule": "The keep list rule is invalid.",
|
||||
"error.user_mandatory_fields": "Käyttäjätunnus on pakollinen.",
|
||||
"error.api_key_already_exists": "API-avain on jo olemassa.",
|
||||
"error.unable_to_create_api_key": "API-avainta ei voi luoda.",
|
||||
"form.feed.label.title": "Otsikko",
|
||||
"form.feed.label.site_url": "Sivuston URL-osoite",
|
||||
"form.feed.label.feed_url": "Syötteen URL-osoite",
|
||||
"form.feed.label.category": "Kategoria",
|
||||
"form.feed.label.crawler": "Nouda alkuperäinen sisältö",
|
||||
"form.feed.label.feed_username": "Syötteen käyttäjätunnus",
|
||||
"form.feed.label.feed_password": "Syötteen salasana",
|
||||
"form.feed.label.user_agent": "Ohita oletuskäyttäjäagentti",
|
||||
"form.feed.label.cookie": "Aseta evästeet",
|
||||
"form.feed.label.scraper_rules": "Scraper-säännöt",
|
||||
"form.feed.label.rewrite_rules": "Rewrite-säännöt",
|
||||
"form.feed.label.blocklist_rules": "Block-säännöt",
|
||||
"form.feed.label.keeplist_rules": "Keep-säännöt",
|
||||
"form.feed.label.ignore_http_cache": "Ohita HTTP-välimuisti",
|
||||
"form.feed.label.allow_self_signed_certificates": "Salli itseallekirjoitetut tai virheelliset varmenteet",
|
||||
"form.feed.label.fetch_via_proxy": "Nouda välityspalvelimen kautta",
|
||||
"form.feed.label.disabled": "Älä päivitä tätä syötettä",
|
||||
"form.feed.label.hide_globally": "Piilota artikkelit lukemattomien listassa",
|
||||
"form.category.label.title": "Otsikko",
|
||||
"form.category.hide_globally": "Piilota artikkelit lukemattomien listassa",
|
||||
"form.user.label.username": "Käyttäjätunnus",
|
||||
"form.user.label.password": "Salasana",
|
||||
"form.user.label.confirmation": "Salasanan vahvistus",
|
||||
"form.user.label.admin": "Ylläpitäjä",
|
||||
"form.prefs.label.language": "Kieli",
|
||||
"form.prefs.label.timezone": "Aikavyöhyke",
|
||||
"form.prefs.label.theme": "Teema",
|
||||
"form.prefs.label.entry_sorting": "Lajittelu",
|
||||
"form.prefs.label.entries_per_page": "Artikkelia sivulla",
|
||||
"form.prefs.label.display_mode": "Verkkosovelluksen näyttötila (vaatii uudelleenasennuksen)",
|
||||
"form.prefs.select.older_first": "Vanhin ensin",
|
||||
"form.prefs.select.recent_first": "Uusin ensin",
|
||||
"form.prefs.select.fullscreen": "Kokoruututila",
|
||||
"form.prefs.select.standalone": "Itsenäinen tila",
|
||||
"form.prefs.select.minimal_ui": "Minimaalinen",
|
||||
"form.prefs.select.browser": "Selain",
|
||||
"form.prefs.select.publish_time": "Julkaisuaika",
|
||||
"form.prefs.select.created_time": "Luomisaika",
|
||||
"form.prefs.label.keyboard_shortcuts": "Ota pikanäppäimet käyttöön",
|
||||
"form.prefs.label.entry_swipe": "Ota pyyhkäisyele käyttöön mobiililaitteella",
|
||||
"form.prefs.label.show_reading_time": "Näytä artikkeleiden arvioitu lukuaika",
|
||||
"form.prefs.label.custom_css": "Mukautettu CSS",
|
||||
"form.prefs.label.entry_order": "Lajittele sarakkeen mukaan",
|
||||
"form.import.label.file": "OPML-tiedosto",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Ota Fever API käyttöön",
|
||||
"form.integration.fever_username": "Fever-käyttäjätunnus",
|
||||
"form.integration.fever_password": "Fever-salasana",
|
||||
"form.integration.fever_endpoint": "Fever API -päätepiste:",
|
||||
"form.integration.googlereader_activate": "Aktivoi Google Reader API",
|
||||
"form.integration.googlereader_username": "Google-lukijan käyttäjätunnus",
|
||||
"form.integration.googlereader_password": "Google-lukijan salasana",
|
||||
"form.integration.googlereader_endpoint": "Google Reader API -päätepiste:",
|
||||
"form.integration.pinboard_activate": "Tallenna artikkelit Pinboardiin",
|
||||
"form.integration.pinboard_token": "Pinboard API-tunnus",
|
||||
"form.integration.pinboard_tags": "Pinboard-tagit",
|
||||
"form.integration.pinboard_bookmark": "Merkitse kirjanmerkki lukemattomaksi",
|
||||
"form.integration.instapaper_activate": "Tallenna artikkelit Instapaperiin",
|
||||
"form.integration.instapaper_username": "Instapaper-käyttäjätunnus",
|
||||
"form.integration.instapaper_password": "Instapaper-salasana",
|
||||
"form.integration.pocket_activate": "Tallenna artikkelit Pocketiin",
|
||||
"form.integration.pocket_consumer_key": "Pocket Consumer Key",
|
||||
"form.integration.pocket_access_token": "Pocket-käyttöoikeustunnus",
|
||||
"form.integration.pocket_connect_link": "Yhdistä Pocket-tilisi",
|
||||
"form.integration.wallabag_activate": "Tallenna artikkelit Wallabagiin",
|
||||
"form.integration.wallabag_endpoint": "Wallabag API -päätepiste",
|
||||
"form.integration.wallabag_client_id": "Wallabag Client ID",
|
||||
"form.integration.wallabag_client_secret": "Wallabag Client Secret",
|
||||
"form.integration.wallabag_username": "Wallabag-käyttäjätunnus",
|
||||
"form.integration.wallabag_password": "Wallabag-salasana",
|
||||
"form.integration.nunux_keeper_activate": "Tallenna artikkelit Nunux Keeperiin",
|
||||
"form.integration.nunux_keeper_endpoint": "Nunux Keeper API-päätepiste",
|
||||
"form.integration.nunux_keeper_api_key": "Nunux Keeper API-avain",
|
||||
"form.integration.espial_activate": "Tallenna artikkelit Espialiin",
|
||||
"form.integration.espial_endpoint": "Espial API-päätepiste",
|
||||
"form.integration.espial_api_key": "Espial API-avain",
|
||||
"form.integration.espial_tags": "Espial-tagit",
|
||||
"form.integration.telegram_bot_activate": "Lähetä uusia artikkeleita Telegram-chatiin",
|
||||
"form.integration.telegram_bot_token": "Bot-tunnus",
|
||||
"form.integration.telegram_chat_id": "Chat ID",
|
||||
"form.integration.linkding_activate": "Tallenna artikkelit Linkkiin",
|
||||
"form.integration.linkding_endpoint": "Linkding API-päätepiste",
|
||||
"form.integration.linkding_api_key": "Linkding API-avain",
|
||||
"form.api_key.label.description": "API Key Label",
|
||||
"form.submit.loading": "Ladataan...",
|
||||
"form.submit.saving": "Tallennetaan...",
|
||||
"time_elapsed.not_yet": "ei vielä",
|
||||
"time_elapsed.yesterday": "eilen",
|
||||
"time_elapsed.now": "juuri nyt",
|
||||
"time_elapsed.minutes": [
|
||||
"%d minuutti sitten",
|
||||
"%d minuuttia sitten"
|
||||
],
|
||||
"time_elapsed.hours": [
|
||||
"%d tunti sitten",
|
||||
"%d tuntia sitten"
|
||||
],
|
||||
"time_elapsed.days": [
|
||||
"%d päivä sitten",
|
||||
"%d päivää sitten"
|
||||
],
|
||||
"time_elapsed.weeks": [
|
||||
"%d viikko sitten",
|
||||
"%d viikkoa sitten"
|
||||
],
|
||||
"time_elapsed.months": [
|
||||
"%d kuukausi sitten",
|
||||
"%d kuukautta sitten"
|
||||
],
|
||||
"time_elapsed.years": [
|
||||
"%d vuosi sitten",
|
||||
"%d vuotta sitten"
|
||||
]
|
||||
}
|
||||
@@ -92,6 +92,7 @@
|
||||
"Il y a %d abonnement.",
|
||||
"Il y a %d abonnements."
|
||||
],
|
||||
"page.categories.unread_counter": "Nombre d'entrées non lues",
|
||||
"page.new_category.title": "Nouvelle catégorie",
|
||||
"page.new_user.title": "Nouvel Utilisateur",
|
||||
"page.edit_category.title": "Modification de la catégorie : %s",
|
||||
@@ -107,13 +108,15 @@
|
||||
"page.history.title": "Historique",
|
||||
"page.import.title": "Importation",
|
||||
"page.search.title": "Résultats de la recherche",
|
||||
"page.about.title": "A propos",
|
||||
"page.about.title": "À propos",
|
||||
"page.about.credits": "Crédits",
|
||||
"page.about.version": "Version :",
|
||||
"page.about.build_date": "Date de la compilation :",
|
||||
"page.about.author": "Auteur :",
|
||||
"page.about.license": "Licence :",
|
||||
"page.about.global_config_options": "Options de configuration globales",
|
||||
"page.about.postgres_version": "Version de Postgresql :",
|
||||
"page.about.go_version": "Version de Go :",
|
||||
"page.add_feed.title": "Nouvel Abonnement",
|
||||
"page.add_feed.no_category": "Il n'y a aucune catégorie. Vous devez avoir au moins une catégorie.",
|
||||
"page.add_feed.label.url": "Lien",
|
||||
@@ -149,7 +152,8 @@
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Ouvrir le lien original dans l'onglet en cours",
|
||||
"page.keyboard_shortcuts.open_comments": "Ouvrir le lien des commentaires",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Ouvrir le lien des commentaires dans l'onglet en cours",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "Basculer entre lu/non lu",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Basculer entre lu/non lu, et changer le focus sur l'élément suivant",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Basculer entre lu/non lu, et changer le focus sur l'élément précédent",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Actualiser les abonnements en arrière-plan",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Marquer la page actuelle comme lu",
|
||||
"page.keyboard_shortcuts.download_content": "Télécharger le contenu original",
|
||||
@@ -199,6 +203,9 @@
|
||||
"page.api_keys.table.actions": "Actions",
|
||||
"page.api_keys.never_used": "Jamais utilisé",
|
||||
"page.new_api_key.title": "Nouvelle clé d'API",
|
||||
"page.offline.title": "Mode Hors-Ligne",
|
||||
"page.offline.message": "Vous n'êtes pas connecté",
|
||||
"page.offline.refresh_page": "Essayez de rafraîchir la page",
|
||||
"alert.no_shared_entry": "Il n'y a pas d'article partagé.",
|
||||
"alert.no_bookmark": "Il n'y a aucun favoris pour le moment.",
|
||||
"alert.no_category": "Il n'y a aucune catégorie.",
|
||||
@@ -218,6 +225,7 @@
|
||||
"error.unlink_account_without_password": "Vous devez définir un mot de passe sinon vous ne pourrez plus vous connecter par la suite.",
|
||||
"error.duplicate_linked_account": "Il y a déjà quelqu'un d'associé avec ce provider !",
|
||||
"error.duplicate_fever_username": "Il y a déjà quelqu'un d'autre avec le même nom d'utilisateur Fever !",
|
||||
"error.duplicate_googlereader_username": "Il y a déjà quelqu'un d'autre avec le même nom d'utilisateur Google Reader !",
|
||||
"error.pocket_request_token": "Impossible de récupérer le jeton d'accès depuis Pocket !",
|
||||
"error.pocket_access_token": "Impossible de récupérer le jeton d'accès depuis Pocket !",
|
||||
"error.category_already_exists": "Cette catégorie existe déjà.",
|
||||
@@ -253,6 +261,7 @@
|
||||
"error.invalid_language": "Langue non valide.",
|
||||
"error.invalid_timezone": "Fuseau horaire non valide.",
|
||||
"error.invalid_entry_direction": "Ordre de trie non valide.",
|
||||
"error.invalid_display_mode": "Mode d'affichage de l'application web non valide.",
|
||||
"form.feed.label.title": "Titre",
|
||||
"form.feed.label.site_url": "URL du site web",
|
||||
"form.feed.label.feed_url": "URL du flux",
|
||||
@@ -261,14 +270,18 @@
|
||||
"form.feed.label.feed_username": "Nom d'utilisateur du flux",
|
||||
"form.feed.label.feed_password": "Mot de passe du flux",
|
||||
"form.feed.label.user_agent": "Remplacer l'agent utilisateur par défaut",
|
||||
"form.feed.label.cookie": "Définir les cookies",
|
||||
"form.feed.label.scraper_rules": "Règles pour récupérer le contenu original",
|
||||
"form.feed.label.rewrite_rules": "Règles de réécriture",
|
||||
"form.feed.label.blocklist_rules": "Règles de blocage",
|
||||
"form.feed.label.keeplist_rules": "Règles d'autorisation",
|
||||
"form.feed.label.ignore_http_cache": "Ignorer le cache HTTP",
|
||||
"form.feed.label.allow_self_signed_certificates": "Autoriser les certificats auto-signés ou non valides",
|
||||
"form.feed.label.fetch_via_proxy": "Récupérer via proxy",
|
||||
"form.feed.label.disabled": "Ne pas actualiser ce flux",
|
||||
"form.feed.label.hide_globally": "Masquer les entrées dans la liste globale non lue",
|
||||
"form.category.label.title": "Titre",
|
||||
"form.category.hide_globally": "Masquer les entrées dans la liste globale non lue",
|
||||
"form.user.label.username": "Nom d'utilisateur",
|
||||
"form.user.label.password": "Mot de passe",
|
||||
"form.user.label.confirmation": "Confirmation du mot de passe",
|
||||
@@ -278,18 +291,30 @@
|
||||
"form.prefs.label.theme": "Thème",
|
||||
"form.prefs.label.entry_sorting": "Ordre des éléments",
|
||||
"form.prefs.label.entries_per_page": "Entrées par page",
|
||||
"form.prefs.label.display_mode": "Mode d'affichage de l'application web (doit être réinstallé)",
|
||||
"form.prefs.select.older_first": "Ancien éléments en premier",
|
||||
"form.prefs.select.recent_first": "Éléments récents en premier",
|
||||
"form.prefs.select.fullscreen": "Plein écran",
|
||||
"form.prefs.select.standalone": "Autonome",
|
||||
"form.prefs.select.minimal_ui": "Minimal",
|
||||
"form.prefs.select.browser": "Navigateur",
|
||||
"form.prefs.select.publish_time": "Heure de publication de l'entrée",
|
||||
"form.prefs.select.created_time": "Heure de création de l'entrée",
|
||||
"form.prefs.label.keyboard_shortcuts": "Activer les raccourcis clavier",
|
||||
"form.prefs.label.entry_swipe": "Activer le geste de balayage sur les entrées sur mobile",
|
||||
"form.prefs.label.show_reading_time": "Afficher le temps de lecture estimé des articles",
|
||||
"form.prefs.label.custom_css": "CSS personnalisé",
|
||||
"form.prefs.label.entry_order": "Colonne de tri des entrées",
|
||||
"form.import.label.file": "Fichier OPML",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Activer l'API de Fever",
|
||||
"form.integration.fever_username": "Nom d'utilisateur pour l'API de Fever",
|
||||
"form.integration.fever_password": "Mot de passe pour l'API de Fever",
|
||||
"form.integration.fever_endpoint": "Point de terminaison de l'API Fever :",
|
||||
"form.integration.googlereader_activate": "Activer l'API de Google Reader",
|
||||
"form.integration.googlereader_username": "Nom d'utilisateur pour l'API de Google Reader",
|
||||
"form.integration.googlereader_password": "Mot de passe pour l'API de Google Reader",
|
||||
"form.integration.googlereader_endpoint": "Point de terminaison de l'API Google Reader :",
|
||||
"form.integration.pinboard_activate": "Sauvegarder les articles vers Pinboard",
|
||||
"form.integration.pinboard_token": "Jeton de sécurité de l'API de Pinboard",
|
||||
"form.integration.pinboard_tags": "Libellés de Pinboard",
|
||||
@@ -310,6 +335,16 @@
|
||||
"form.integration.nunux_keeper_activate": "Sauvegarder les articles vers Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "URL de l'API de Nunux Keeper",
|
||||
"form.integration.nunux_keeper_api_key": "Clé d'API de Nunux Keeper",
|
||||
"form.integration.espial_activate": "Sauvegarder les articles vers Espial",
|
||||
"form.integration.espial_endpoint": "URL de l'API de Espial",
|
||||
"form.integration.espial_api_key": "Clé d'API de Espial",
|
||||
"form.integration.espial_tags": "Libellés de Espial",
|
||||
"form.integration.telegram_bot_activate": "Envoyer les nouveaux articles vers Telegram",
|
||||
"form.integration.telegram_bot_token": "Jeton de sécurité de l'API du Bot Telegram",
|
||||
"form.integration.telegram_chat_id": "Identifiant de discussion",
|
||||
"form.integration.linkding_activate": "Sauvegarder les articles vers Linkding",
|
||||
"form.integration.linkding_endpoint": "URL de l'API de Linkding",
|
||||
"form.integration.linkding_api_key": "Clé d'API de Linkding",
|
||||
"form.api_key.label.description": "Libellé de la clé d'API",
|
||||
"form.submit.loading": "Chargement...",
|
||||
"form.submit.saving": "Sauvegarde en cours...",
|
||||
@@ -359,5 +394,5 @@
|
||||
"Website unreachable, the request timed out after %d seconds": "Site web injoignable, la requête à échouée après %d secondes",
|
||||
"You are not authorized to access this resource (invalid username/password)": "Vous n'êtes pas autorisé à accéder à cette ressource (nom d'utilisateur / mot de passe incorrect)",
|
||||
"Unable to fetch this resource (Status Code = %d)": "Impossible de récupérer cette ressource (code=%d)",
|
||||
"Resource not found (404), this feed doesn't exists anymore, check the feed URL": "Page introuvable (404), cet abonnement n'existe plus, vérifiez l'adresse du flux"
|
||||
"Resource not found (404), this feed doesn't exist anymore, check the feed URL": "Page introuvable (404), cet abonnement n'existe plus, vérifiez l'adresse du flux"
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
"C'è %d feed.",
|
||||
"Ci sono %d feed."
|
||||
],
|
||||
"page.categories.unread_counter": "Numero di voci non lette",
|
||||
"page.new_category.title": "Nuova categoria",
|
||||
"page.new_user.title": "Nuovo utente",
|
||||
"page.edit_category.title": "Modifica categoria: %s",
|
||||
@@ -114,6 +115,8 @@
|
||||
"page.about.author": "Autore:",
|
||||
"page.about.license": "Licenza:",
|
||||
"page.about.global_config_options": "Opzioni di configurazione globali",
|
||||
"page.about.postgres_version": "Postgres versione:",
|
||||
"page.about.go_version": "Go versione:",
|
||||
"page.add_feed.title": "Nuovo feed",
|
||||
"page.add_feed.no_category": "Nessuna categoria selezionata. Devi scegliere almeno una categoria.",
|
||||
"page.add_feed.label.url": "URL",
|
||||
@@ -149,7 +152,8 @@
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Apri il link originale nella scheda corrente",
|
||||
"page.keyboard_shortcuts.open_comments": "Apri la pagina web dei commenti",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Apri il link dei commenti nella scheda corrente",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "Cambia lo stato di lettura (letto/da leggere)",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Cambia lo stato di lettura (letto/da leggere), concentrati dopo",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Cambia lo stato di lettura (letto/da leggere), focus precedente",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Aggiorna tutti i feed in background",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Segna la pagina attuale come letta",
|
||||
"page.keyboard_shortcuts.download_content": "Scarica il contenuto integrale",
|
||||
@@ -199,6 +203,9 @@
|
||||
"page.api_keys.table.actions": "Azioni",
|
||||
"page.api_keys.never_used": "Mai usato",
|
||||
"page.new_api_key.title": "Nuova chiave API",
|
||||
"page.offline.title": "Modalità offline",
|
||||
"page.offline.message": "Sei offline",
|
||||
"page.offline.refresh_page": "Prova ad aggiornare la pagina",
|
||||
"alert.no_shared_entry": "Non ci sono voci condivise.",
|
||||
"alert.no_bookmark": "Nessun preferito disponibile.",
|
||||
"alert.no_category": "Nessuna categoria disponibile.",
|
||||
@@ -218,6 +225,7 @@
|
||||
"error.unlink_account_without_password": "Devi scegliere una password altrimenti la prossima volta non riuscirai ad accedere.",
|
||||
"error.duplicate_linked_account": "Esiste già un account configurato per questo servizio!",
|
||||
"error.duplicate_fever_username": "Esiste già un account Fever con lo stesso nome utente!",
|
||||
"error.duplicate_googlereader_username": "Esiste già un account Google Reader con lo stesso nome utente!",
|
||||
"error.pocket_request_token": "Non sono riuscito ad ottenere il request token da Pocket!",
|
||||
"error.pocket_access_token": "Non sono riuscito ad ottenere l'access token da Pocket!",
|
||||
"error.category_already_exists": "Questa categoria esiste già.",
|
||||
@@ -253,6 +261,7 @@
|
||||
"error.invalid_language": "Lingua non valida.",
|
||||
"error.invalid_timezone": "Fuso orario non valido.",
|
||||
"error.invalid_entry_direction": "Ordinamento non valido.",
|
||||
"error.invalid_display_mode": "Modalità di visualizzazione web app non valida.",
|
||||
"form.feed.label.title": "Titolo",
|
||||
"form.feed.label.site_url": "URL del sito",
|
||||
"form.feed.label.feed_url": "URL del feed",
|
||||
@@ -261,14 +270,18 @@
|
||||
"form.feed.label.feed_username": "Nome utente del feed",
|
||||
"form.feed.label.feed_password": "Password del feed",
|
||||
"form.feed.label.user_agent": "Usa user agent personalizzato",
|
||||
"form.feed.label.cookie": "Installare i cookies",
|
||||
"form.feed.label.scraper_rules": "Regole di estrazione del contenuto",
|
||||
"form.feed.label.rewrite_rules": "Regole di impaginazione del contenuto",
|
||||
"form.feed.label.blocklist_rules": "Regole di blocco",
|
||||
"form.feed.label.keeplist_rules": "Regole di autorizzazione",
|
||||
"form.feed.label.ignore_http_cache": "Ignora cache HTTP",
|
||||
"form.feed.label.allow_self_signed_certificates": "Consenti certificati autofirmati o non validi",
|
||||
"form.feed.label.fetch_via_proxy": "Recuperare tramite proxy",
|
||||
"form.feed.label.disabled": "Non aggiornare questo feed",
|
||||
"form.feed.label.hide_globally": "Nascondere le voci nella lista globale dei non letti",
|
||||
"form.category.label.title": "Titolo",
|
||||
"form.category.hide_globally": "Nascondere le voci nella lista globale dei non letti",
|
||||
"form.user.label.username": "Nome utente",
|
||||
"form.user.label.password": "Password",
|
||||
"form.user.label.confirmation": "Conferma password",
|
||||
@@ -278,18 +291,30 @@
|
||||
"form.prefs.label.theme": "Tema",
|
||||
"form.prefs.label.entry_sorting": "Ordinamento articoli",
|
||||
"form.prefs.label.entries_per_page": "Articoli per pagina",
|
||||
"form.prefs.label.display_mode": "Modalità di visualizzazione web app (necessita la reinstallazione)",
|
||||
"form.prefs.select.older_first": "Prima i più vecchi",
|
||||
"form.prefs.select.recent_first": "Prima i più recenti",
|
||||
"form.prefs.select.fullscreen": "Schermo intero",
|
||||
"form.prefs.select.standalone": "Autonoma",
|
||||
"form.prefs.select.minimal_ui": "Minimale",
|
||||
"form.prefs.select.browser": "Browser",
|
||||
"form.prefs.select.publish_time": "Ora di pubblicazione dell'entrata",
|
||||
"form.prefs.select.created_time": "Tempo di creazione dell'entrata",
|
||||
"form.prefs.label.keyboard_shortcuts": "Abilita le scorciatoie da tastiera",
|
||||
"form.prefs.label.entry_swipe": "Abilita il gesto di scorrimento sulle voci sul cellulare",
|
||||
"form.prefs.label.show_reading_time": "Mostra il tempo di lettura stimato per gli articoli",
|
||||
"form.prefs.label.custom_css": "CSS personalizzati",
|
||||
"form.prefs.label.entry_order": "Colonna di ordinamento delle voci",
|
||||
"form.import.label.file": "File OPML",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Abilita l'API di Fever",
|
||||
"form.integration.fever_username": "Nome utente dell'account Fever",
|
||||
"form.integration.fever_password": "Password dell'account Fever",
|
||||
"form.integration.fever_endpoint": "Endpoint dell'API di Fever:",
|
||||
"form.integration.googlereader_activate": "Abilita l'API di Google Reader",
|
||||
"form.integration.googlereader_username": "Nome utente dell'account Google Reader",
|
||||
"form.integration.googlereader_password": "Password dell'account Google Reader",
|
||||
"form.integration.googlereader_endpoint": "Endpoint dell'API di Google Reader:",
|
||||
"form.integration.pinboard_activate": "Salva gli articoli su Pinboard",
|
||||
"form.integration.pinboard_token": "Token dell'API di Pinboard",
|
||||
"form.integration.pinboard_tags": "Tag di Pinboard",
|
||||
@@ -310,6 +335,16 @@
|
||||
"form.integration.nunux_keeper_activate": "Salva gli articoli su Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "Endpoint dell'API di Nunux Keeper",
|
||||
"form.integration.nunux_keeper_api_key": "API key dell'account Nunux Keeper",
|
||||
"form.integration.espial_activate": "Salva gli articoli su Espial",
|
||||
"form.integration.espial_endpoint": "Endpoint dell'API di Espial",
|
||||
"form.integration.espial_api_key": "API key dell'account Espial",
|
||||
"form.integration.espial_tags": "Tag di Espial",
|
||||
"form.integration.telegram_bot_activate": "Invia nuovi articoli alla chat di Telegram",
|
||||
"form.integration.telegram_bot_token": "Token bot",
|
||||
"form.integration.telegram_chat_id": "ID chat",
|
||||
"form.integration.linkding_activate": "Salva gli articoli su Linkding",
|
||||
"form.integration.linkding_endpoint": "Endpoint dell'API di Linkding",
|
||||
"form.integration.linkding_api_key": "API key dell'account Linkding",
|
||||
"form.api_key.label.description": "Etichetta chiave API",
|
||||
"form.submit.loading": "Caricamento in corso...",
|
||||
"form.submit.saving": "Salvataggio in corso...",
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
"%d 個の記事があります。",
|
||||
"%d 個の記事があります。"
|
||||
],
|
||||
"page.categories.unread_counter": "未読記事の数",
|
||||
"page.new_category.title": "新規カテゴリ",
|
||||
"page.new_user.title": "新規ユーザー",
|
||||
"page.edit_category.title": "カテゴリーを編集: %s",
|
||||
@@ -114,6 +115,8 @@
|
||||
"page.about.author": "作者:",
|
||||
"page.about.license": "ライセンス:",
|
||||
"page.about.global_config_options": "グローバル構成オプション",
|
||||
"page.about.postgres_version": "Postgres バージョン:",
|
||||
"page.about.go_version": "Go バージョン:",
|
||||
"page.add_feed.title": "新規購読",
|
||||
"page.add_feed.no_category": "カテゴリが存在しません。 少なくとも1つのカテゴリが必要です。",
|
||||
"page.add_feed.label.url": "URL",
|
||||
@@ -149,7 +152,8 @@
|
||||
"page.keyboard_shortcuts.open_original_same_window": "現在のタブでオリジナルのリンクを開く",
|
||||
"page.keyboard_shortcuts.open_comments": "コメントリンクを開く",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "現在のタブでコメントリンクを開く",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "既読/未読 切り替え",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "既読/未読 切り替え, 次に焦点を合わせる",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "既読/未読 切り替え, 前にフォーカス",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "全てのフィードをバックグラウンドで更新",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "現在のページを既読にする",
|
||||
"page.keyboard_shortcuts.download_content": "オリジナルの内容をダウンロード",
|
||||
@@ -199,6 +203,9 @@
|
||||
"page.api_keys.table.actions": "アクション",
|
||||
"page.api_keys.never_used": "使われたことがない",
|
||||
"page.new_api_key.title": "新しいAPIキー",
|
||||
"page.offline.title": "オフラインモード",
|
||||
"page.offline.message": "オフラインです",
|
||||
"page.offline.refresh_page": "ページを更新してみてください",
|
||||
"alert.no_shared_entry": "共有エントリはありません。",
|
||||
"alert.no_bookmark": "現在星付きはありません。",
|
||||
"alert.no_category": "カテゴリが存在しません。",
|
||||
@@ -218,6 +225,7 @@
|
||||
"error.unlink_account_without_password": "パスワードを設定しなければ再びログインすることはできません。",
|
||||
"error.duplicate_linked_account": "別なユーザーが既にこのサービスの同じユーザーとリンクしています。",
|
||||
"error.duplicate_fever_username": "既に同じ名前の Fever ユーザー名が使われています!",
|
||||
"error.duplicate_googlereader_username": "既に同じ名前の Google Reader ユーザー名が使われています!",
|
||||
"error.pocket_request_token": "Pocket の request token が取得できません!",
|
||||
"error.pocket_access_token": "Pocket の access token が取得できません!",
|
||||
"error.category_already_exists": "このカテゴリは既に存在しています。",
|
||||
@@ -253,6 +261,7 @@
|
||||
"error.invalid_language": "言語が無効です。",
|
||||
"error.invalid_timezone": "タイムゾーンが無効です。",
|
||||
"error.invalid_entry_direction": "ソート順が無効です。",
|
||||
"error.invalid_display_mode": "Webアプリの表示モードが無効です。",
|
||||
"form.feed.label.title": "タイトル",
|
||||
"form.feed.label.site_url": "サイト URL",
|
||||
"form.feed.label.feed_url": "フィード URL",
|
||||
@@ -261,14 +270,18 @@
|
||||
"form.feed.label.feed_username": "フィードのユーザー名",
|
||||
"form.feed.label.feed_password": "フィードのパスワード",
|
||||
"form.feed.label.user_agent": "ディフォルトの User Agent を上書きする",
|
||||
"form.feed.label.cookie": "クッキーの設定",
|
||||
"form.feed.label.scraper_rules": "スクラップルール",
|
||||
"form.feed.label.rewrite_rules": "Rewrite ルール",
|
||||
"form.feed.label.blocklist_rules": "ブロックルール",
|
||||
"form.feed.label.keeplist_rules": "許可規則",
|
||||
"form.feed.label.ignore_http_cache": "HTTPキャッシュを無視",
|
||||
"form.feed.label.allow_self_signed_certificates": "自己署名証明書または無効な証明書を許可する",
|
||||
"form.feed.label.fetch_via_proxy": "プロキシ経由でフェッチ",
|
||||
"form.feed.label.disabled": "このフィードを更新しない",
|
||||
"form.feed.label.hide_globally": "グローバル未読リストのエントリーを隠す",
|
||||
"form.category.label.title": "タイトル",
|
||||
"form.category.hide_globally": "グローバル未読リストのエントリーを隠す",
|
||||
"form.user.label.username": "ユーザー名",
|
||||
"form.user.label.password": "パスワード",
|
||||
"form.user.label.confirmation": "パスワード確認",
|
||||
@@ -278,18 +291,30 @@
|
||||
"form.prefs.label.theme": "テーマ",
|
||||
"form.prefs.label.entry_sorting": "記事の並べ替え",
|
||||
"form.prefs.label.entries_per_page": "ページあたりのエントリ",
|
||||
"form.prefs.label.display_mode": "Webアプリの表示モード (再インストールが必要)",
|
||||
"form.prefs.select.older_first": "古い記事を最初に",
|
||||
"form.prefs.select.recent_first": "新しい記事を最初に",
|
||||
"form.prefs.select.fullscreen": "全画面表示",
|
||||
"form.prefs.select.standalone": "スタンドアロン",
|
||||
"form.prefs.select.minimal_ui": "最小限",
|
||||
"form.prefs.select.browser": "ブラウザ",
|
||||
"form.prefs.select.publish_time": "エントリー公開時間",
|
||||
"form.prefs.select.created_time": "エントリー作成時間",
|
||||
"form.prefs.label.keyboard_shortcuts": "キーボード・ショートカットを有効にする",
|
||||
"form.prefs.label.entry_swipe": "モバイルのエントリでスワイプジェスチャーを有効にする",
|
||||
"form.prefs.label.show_reading_time": "記事の推定読書時間を表示する",
|
||||
"form.prefs.label.custom_css": "カスタムCSS",
|
||||
"form.prefs.label.entry_order": "エントリーソートカラム",
|
||||
"form.import.label.file": "OPML ファイル",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Fever API を有効にする",
|
||||
"form.integration.fever_username": "Fever の ユーザー名",
|
||||
"form.integration.fever_password": "Fever の パスワード",
|
||||
"form.integration.fever_endpoint": "Fever API endpoint:",
|
||||
"form.integration.googlereader_activate": "Google Reader API を有効にする",
|
||||
"form.integration.googlereader_username": "Google Reader の ユーザー名",
|
||||
"form.integration.googlereader_password": "Google Reader の パスワード",
|
||||
"form.integration.googlereader_endpoint": "Google Reader API endpoint:",
|
||||
"form.integration.pinboard_activate": "Pinboard に記事を保存する",
|
||||
"form.integration.pinboard_token": "Pinboard の API Token",
|
||||
"form.integration.pinboard_tags": "Pinboard の Tag",
|
||||
@@ -310,6 +335,16 @@
|
||||
"form.integration.nunux_keeper_activate": "Nunux Keeper に記事を保存する",
|
||||
"form.integration.nunux_keeper_endpoint": "Nunux Keeper の API Endpoint",
|
||||
"form.integration.nunux_keeper_api_key": "Nunux Keeper の API key",
|
||||
"form.integration.espial_activate": "Espial に記事を保存する",
|
||||
"form.integration.espial_endpoint": "Espial の API Endpoint",
|
||||
"form.integration.espial_api_key": "Espial の API key",
|
||||
"form.integration.espial_tags": "Espial の Tag",
|
||||
"form.integration.telegram_bot_activate": "新しい記事をTelegramチャットにプッシュする",
|
||||
"form.integration.telegram_bot_token": "ボットトークン",
|
||||
"form.integration.telegram_chat_id": "チャットID",
|
||||
"form.integration.linkding_activate": "Linkding に記事を保存する",
|
||||
"form.integration.linkding_endpoint": "Linkding の API Endpoint",
|
||||
"form.integration.linkding_api_key": "Linkding の API key",
|
||||
"form.api_key.label.description": "APIキーラベル",
|
||||
"form.submit.loading": "読み込み中…",
|
||||
"form.submit.saving": "保存中…",
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
"Er is %d feed.",
|
||||
"Er zijn %d feeds."
|
||||
],
|
||||
"page.categories.unread_counter": "Aantal ongelezen vermeldingen",
|
||||
"page.new_category.title": "Nieuwe categorie",
|
||||
"page.new_user.title": "Nieuwe gebruiker",
|
||||
"page.edit_category.title": "Bewerken van categorie: %s",
|
||||
@@ -115,6 +116,8 @@
|
||||
"page.about.author": "Auteur:",
|
||||
"page.about.license": "Licentie:",
|
||||
"page.about.global_config_options": "globale configuratie-opties",
|
||||
"page.about.postgres_version": "Postgres versie:",
|
||||
"page.about.go_version": "Go versie:",
|
||||
"page.add_feed.title": "Nieuwe feed",
|
||||
"page.add_feed.no_category": "Er zijn geen categorieën. Je moet op zijn minst één caterogie hebben.",
|
||||
"page.add_feed.label.url": "URL",
|
||||
@@ -150,7 +153,8 @@
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Oorspronkelijke koppeling op huidig tabblad openen",
|
||||
"page.keyboard_shortcuts.open_comments": "Open opmerkingen link",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Open de reactiekoppeling op het huidige tabblad",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "Markeer gelezen/ongelezen",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Markeer gelezen/ongelezen, focus volgende",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Markeer gelezen/ongelezen, focus vorige",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Vernieuw alle feeds in de achtergrond",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Markeer deze pagina als gelezen",
|
||||
"page.keyboard_shortcuts.download_content": "Download originele content",
|
||||
@@ -199,6 +203,9 @@
|
||||
"page.api_keys.table.actions": "Acties",
|
||||
"page.api_keys.never_used": "Nooit gebruikt",
|
||||
"page.new_api_key.title": "Nieuwe API-sleutel",
|
||||
"page.offline.title": "Offline modus",
|
||||
"page.offline.message": "Je bent offline",
|
||||
"page.offline.refresh_page": "Probeer de pagina te vernieuwen",
|
||||
"alert.no_shared_entry": "Er is geen gedeelde toegang.",
|
||||
"alert.no_bookmark": "Er zijn op dit moment geen favorieten.",
|
||||
"alert.no_category": "Er zijn geen categorieën.",
|
||||
@@ -218,6 +225,7 @@
|
||||
"error.unlink_account_without_password": "U moet een wachtwoord definiëren anders kunt u zich niet opnieuw aanmelden.",
|
||||
"error.duplicate_linked_account": "Er is al iemand geregistreerd met deze provider!",
|
||||
"error.duplicate_fever_username": "Er is al iemand met dezelfde Fever gebruikersnaam!",
|
||||
"error.duplicate_googlereader_username": "Er is al iemand met dezelfde Google Reader gebruikersnaam!",
|
||||
"error.pocket_request_token": "Kon geen aanvraagtoken ophalen van Pocket!",
|
||||
"error.pocket_access_token": "Kon geen toegangstoken ophalen van Pocket!",
|
||||
"error.category_already_exists": "Deze categorie bestaat al.",
|
||||
@@ -253,6 +261,7 @@
|
||||
"error.invalid_language": "Ongeldige taal.",
|
||||
"error.invalid_timezone": "Ongeldige tijdzone.",
|
||||
"error.invalid_entry_direction": "Ongeldige sorteervolgorde.",
|
||||
"error.invalid_display_mode": "Ongeldige weergavemodus voor webapp.",
|
||||
"form.feed.label.title": "Naam",
|
||||
"form.feed.label.site_url": "Website URL",
|
||||
"form.feed.label.feed_url": "Feed URL",
|
||||
@@ -261,14 +270,18 @@
|
||||
"form.feed.label.feed_username": "Feed-gebruikersnaam",
|
||||
"form.feed.label.feed_password": "Feed wachtwoord",
|
||||
"form.feed.label.user_agent": "Standaard User Agent overschrijven",
|
||||
"form.feed.label.cookie": "Cookies instellen",
|
||||
"form.feed.label.scraper_rules": "Scraper regels",
|
||||
"form.feed.label.rewrite_rules": "Rewrite regels",
|
||||
"form.feed.label.blocklist_rules": "Blokkeer regels",
|
||||
"form.feed.label.keeplist_rules": "toestemmingsregels",
|
||||
"form.feed.label.ignore_http_cache": "Negeer HTTP-cache",
|
||||
"form.feed.label.allow_self_signed_certificates": "Sta zelfondertekende of ongeldige certificaten toe",
|
||||
"form.feed.label.fetch_via_proxy": "Ophalen via proxy",
|
||||
"form.feed.label.disabled": "Vernieuw deze feed niet",
|
||||
"form.feed.label.hide_globally": "Verberg items in de globale ongelezen lijst",
|
||||
"form.category.label.title": "Naam",
|
||||
"form.category.hide_globally": "Verberg items in de globale ongelezen lijst",
|
||||
"form.user.label.username": "Gebruikersnaam",
|
||||
"form.user.label.password": "Wachtwoord",
|
||||
"form.user.label.confirmation": "Bevestig wachtwoord",
|
||||
@@ -278,18 +291,30 @@
|
||||
"form.prefs.label.theme": "Skin",
|
||||
"form.prefs.label.entry_sorting": "Volgorde van items",
|
||||
"form.prefs.label.entries_per_page": "Inzendingen per pagina",
|
||||
"form.prefs.label.display_mode": "Weergavemodus voor webapp (moet opnieuw worden geïnstalleerd)",
|
||||
"form.prefs.select.older_first": "Oudere items eerst",
|
||||
"form.prefs.select.recent_first": "Recente items eerst",
|
||||
"form.prefs.select.fullscreen": "Volledig scherm",
|
||||
"form.prefs.select.standalone": "Standalone",
|
||||
"form.prefs.select.minimal_ui": "Minimaal",
|
||||
"form.prefs.select.browser": "Browser",
|
||||
"form.prefs.select.publish_time": "Tijd van binnenkomst",
|
||||
"form.prefs.select.created_time": "Tijdstip van binnenkomst",
|
||||
"form.prefs.label.keyboard_shortcuts": "Schakel sneltoetsen in",
|
||||
"form.prefs.label.entry_swipe": "Schakel veegbewegingen in voor items op mobiel",
|
||||
"form.prefs.label.show_reading_time": "Toon geschatte leestijd voor artikelen",
|
||||
"form.prefs.label.custom_css": "Aangepaste CSS",
|
||||
"form.prefs.label.entry_order": "Ingang Sorteerkolom",
|
||||
"form.import.label.file": "OPML-bestand",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Activeer Fever API",
|
||||
"form.integration.fever_username": "Fever gebruikersnaam",
|
||||
"form.integration.fever_password": "Fever wachtwoord",
|
||||
"form.integration.fever_endpoint": "Fever URL:",
|
||||
"form.integration.googlereader_activate": "Activeer Google Reader API",
|
||||
"form.integration.googlereader_username": "Google Reader gebruikersnaam",
|
||||
"form.integration.googlereader_password": "Google Reader wachtwoord",
|
||||
"form.integration.googlereader_endpoint": "Google Reader URL:",
|
||||
"form.integration.pinboard_activate": "Artikelen opslaan naar Pinboard",
|
||||
"form.integration.pinboard_token": "Pinboard API token",
|
||||
"form.integration.pinboard_tags": "Pinboard tags",
|
||||
@@ -310,6 +335,16 @@
|
||||
"form.integration.nunux_keeper_activate": "Opslaan naar Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "Nunux Keeper URL",
|
||||
"form.integration.nunux_keeper_api_key": "Nunux Keeper API-sleutel",
|
||||
"form.integration.espial_activate": "Opslaan naar Espial",
|
||||
"form.integration.espial_endpoint": "Espial URL",
|
||||
"form.integration.espial_api_key": "Espial API-sleutel",
|
||||
"form.integration.espial_tags": "Espial tags",
|
||||
"form.integration.telegram_bot_activate": "Push nieuwe artikelen naar Telegram-chat",
|
||||
"form.integration.telegram_bot_token": "Bot token",
|
||||
"form.integration.telegram_chat_id": "Chat ID",
|
||||
"form.integration.linkding_activate": "Opslaan naar Linkding",
|
||||
"form.integration.linkding_endpoint": "Linkding URL",
|
||||
"form.integration.linkding_api_key": "Linkding API-sleutel",
|
||||
"form.api_key.label.description": "API-sleutellabel",
|
||||
"form.submit.loading": "Laden...",
|
||||
"form.submit.saving": "Opslaag...",
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
"Są %d kanały.",
|
||||
"Jest %d kanałów."
|
||||
],
|
||||
"page.categories.unread_counter": "Liczba nieprzeczytanych wpisów",
|
||||
"page.new_category.title": "Nowa kategoria",
|
||||
"page.new_user.title": "Nowy użytkownik",
|
||||
"page.edit_category.title": "Edycja Kategorii: %s",
|
||||
@@ -115,6 +116,8 @@
|
||||
"page.about.build_date": "Data opracowania:",
|
||||
"page.about.author": "Autor:",
|
||||
"page.about.license": "Licencja:",
|
||||
"page.about.postgres_version": "Postgres wersja:",
|
||||
"page.about.go_version": "Go wersja:",
|
||||
"page.about.global_config_options": "globalne opcje konfiguracji",
|
||||
"page.add_feed.title": "Nowa subskrypcja",
|
||||
"page.add_feed.no_category": "Nie ma żadnej kategorii. Musisz mieć co najmniej jedną kategorię.",
|
||||
@@ -151,7 +154,8 @@
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Otwórz oryginalny link w bieżącej karcie",
|
||||
"page.keyboard_shortcuts.open_comments": "Otwórz link do komentarzy",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Otwórz link do komentarzy w bieżącej karcie",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "Oznacz jako przeczytane/nieprzeczytane",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Oznacz jako przeczytane/nieprzeczytane, skup się dalej",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Oznacz jako przeczytane/nieprzeczytane, skup poprzednie",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Odśwież wszystkie subskrypcje w tle",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Zaznacz aktualną stronę jako przeczytaną",
|
||||
"page.keyboard_shortcuts.download_content": "Pobierz oryginalną zawartość",
|
||||
@@ -201,6 +205,9 @@
|
||||
"page.api_keys.table.actions": "Działania",
|
||||
"page.api_keys.never_used": "Nigdy nie używany",
|
||||
"page.new_api_key.title": "Nowy klucz API",
|
||||
"page.offline.title": "Tryb offline",
|
||||
"page.offline.message": "Jesteś odłączony od sieci",
|
||||
"page.offline.refresh_page": "Spróbuj odświeżyć stronę",
|
||||
"alert.no_shared_entry": "Brak wspólnego wpisu.",
|
||||
"alert.no_bookmark": "Obecnie nie ma żadnych zakładek.",
|
||||
"alert.no_category": "Nie ma żadnej kategorii!",
|
||||
@@ -220,6 +227,7 @@
|
||||
"error.unlink_account_without_password": "Musisz zdefiniować hasło, inaczej nie będziesz mógł się ponownie zalogować.",
|
||||
"error.duplicate_linked_account": "Już ktoś jest powiązany z tym dostawcą!",
|
||||
"error.duplicate_fever_username": "Już ktoś inny używa tej nazwy użytkownika Fever!",
|
||||
"error.duplicate_googlereader_username": "Już ktoś inny używa tej nazwy użytkownika Google Reader!",
|
||||
"error.pocket_request_token": "Nie można pobrać tokena żądania z Pocket!",
|
||||
"error.pocket_access_token": "Nie można pobrać tokena dostępu z Pocket!",
|
||||
"error.category_already_exists": "Ta kategoria już istnieje.",
|
||||
@@ -255,6 +263,7 @@
|
||||
"error.invalid_language": "Nieprawidłowy język.",
|
||||
"error.invalid_timezone": "Nieprawidłowa strefa czasowa.",
|
||||
"error.invalid_entry_direction": "Nieprawidłowa kolejność sortowania.",
|
||||
"error.invalid_display_mode": "Nieprawidłowy tryb wyświetlania aplikacji internetowej.",
|
||||
"form.feed.label.title": "Tytuł",
|
||||
"form.feed.label.site_url": "URL strony",
|
||||
"form.feed.label.feed_url": "URL kanału",
|
||||
@@ -263,14 +272,18 @@
|
||||
"form.feed.label.feed_username": "Subskrypcję nazwa użytkownika",
|
||||
"form.feed.label.feed_password": "Subskrypcję Hasło",
|
||||
"form.feed.label.user_agent": "Zastąp domyślny agent użytkownika",
|
||||
"form.feed.label.cookie": "Ustawianie ciasteczek",
|
||||
"form.feed.label.scraper_rules": "Zasady ekstrakcji",
|
||||
"form.feed.label.rewrite_rules": "Reguły zapisu",
|
||||
"form.feed.label.blocklist_rules": "Zasady blokowania",
|
||||
"form.feed.label.keeplist_rules": "Zasady zezwoleń",
|
||||
"form.feed.label.ignore_http_cache": "Zignoruj pamięć podręczną HTTP",
|
||||
"form.feed.label.allow_self_signed_certificates": "Zezwalaj na certyfikaty z podpisem własnym lub nieprawidłowe certyfikaty",
|
||||
"form.feed.label.fetch_via_proxy": "Pobierz przez proxy",
|
||||
"form.feed.label.disabled": "Не обновлять этот канал",
|
||||
"form.feed.label.hide_globally": "Ukryj wpisy na globalnej liście nieprzeczytanych",
|
||||
"form.category.label.title": "Tytuł",
|
||||
"form.category.hide_globally": "Ukryj wpisy na globalnej liście nieprzeczytanych",
|
||||
"form.user.label.username": "Nazwa użytkownika",
|
||||
"form.user.label.password": "Hasło",
|
||||
"form.user.label.confirmation": "Potwierdzenie hasła",
|
||||
@@ -280,18 +293,30 @@
|
||||
"form.prefs.label.theme": "Wygląd",
|
||||
"form.prefs.label.entry_sorting": "Sortowanie artykułów",
|
||||
"form.prefs.label.entries_per_page": "Wpisy na stronie",
|
||||
"form.prefs.label.display_mode": "Tryb wyświetlania aplikacji internetowej (wymaga ponownej instalacji)",
|
||||
"form.prefs.select.older_first": "Najstarsze wpisy jako pierwsze",
|
||||
"form.prefs.label.keyboard_shortcuts": "Włącz skróty klawiaturowe",
|
||||
"form.prefs.label.entry_swipe": "Włącz gest przesuwania na wpisach na telefonie komórkowym",
|
||||
"form.prefs.label.show_reading_time": "Pokaż szacowany czas czytania artykułów",
|
||||
"form.prefs.select.recent_first": "Najnowsze wpisy jako pierwsze",
|
||||
"form.prefs.select.fullscreen": "Pełny ekran",
|
||||
"form.prefs.select.standalone": "Samodzielny",
|
||||
"form.prefs.select.minimal_ui": "Minimalny",
|
||||
"form.prefs.select.browser": "Przeglądarka",
|
||||
"form.prefs.select.publish_time": "Czas publikacji wpisu",
|
||||
"form.prefs.select.created_time": "Czas utworzenia wpisu",
|
||||
"form.prefs.label.custom_css": "Niestandardowy CSS",
|
||||
"form.prefs.label.entry_order": "Kolumna sortowania wpisów",
|
||||
"form.import.label.file": "Plik OPML",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Aktywuj Fever API",
|
||||
"form.integration.fever_username": "Login do Fever",
|
||||
"form.integration.fever_password": "Hasło do Fever",
|
||||
"form.integration.fever_endpoint": "Punkt końcowy API gorączka:",
|
||||
"form.integration.googlereader_activate": "Aktywuj Google Reader API",
|
||||
"form.integration.googlereader_username": "Login do Google Reader",
|
||||
"form.integration.googlereader_password": "Hasło do Google Reader",
|
||||
"form.integration.googlereader_endpoint": "Punkt końcowy API gorączka:",
|
||||
"form.integration.pinboard_activate": "Zapisz artykuł w Pinboard",
|
||||
"form.integration.pinboard_token": "Token Pinboard API",
|
||||
"form.integration.pinboard_tags": "Pinboard Tags",
|
||||
@@ -312,6 +337,16 @@
|
||||
"form.integration.nunux_keeper_activate": "Zapisz artykuly do Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "Nunux Keeper URL",
|
||||
"form.integration.nunux_keeper_api_key": "Nunux Keeper API key",
|
||||
"form.integration.espial_activate": "Zapisz artykuly do Espial",
|
||||
"form.integration.espial_endpoint": "Espial URL",
|
||||
"form.integration.espial_api_key": "Espial API key",
|
||||
"form.integration.espial_tags": "Espial Tags",
|
||||
"form.integration.telegram_bot_activate": "Przesyłaj nowe artykuły do czatu Telegram",
|
||||
"form.integration.telegram_bot_token": "Token bota",
|
||||
"form.integration.telegram_chat_id": "Identyfikator czatu",
|
||||
"form.integration.linkding_activate": "Zapisz artykuły do Linkding",
|
||||
"form.integration.linkding_endpoint": "Linkding URL",
|
||||
"form.integration.linkding_api_key": "Linkding API key",
|
||||
"form.api_key.label.description": "Etykieta klucza API",
|
||||
"form.submit.loading": "Ładowanie...",
|
||||
"form.submit.saving": "Zapisywanie...",
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
"Existe %d fonte.",
|
||||
"Existem %d fontes."
|
||||
],
|
||||
"page.categories.unread_counter": "Numero de itens não lidos",
|
||||
"page.new_category.title": "Nova categoria",
|
||||
"page.new_user.title": "Novo usuário",
|
||||
"page.edit_category.title": "Editar categoria: %s",
|
||||
@@ -114,6 +115,8 @@
|
||||
"page.about.author": "Autor:",
|
||||
"page.about.license": "Licença:",
|
||||
"page.about.global_config_options": "opções de configuração global",
|
||||
"page.about.postgres_version": "Postgres versão:",
|
||||
"page.about.go_version": "Go versão:",
|
||||
"page.add_feed.title": "Nova inscrição",
|
||||
"page.add_feed.no_category": "Não existe uma categoria. Deve existir pelo menos uma categoria.",
|
||||
"page.add_feed.label.url": "URL",
|
||||
@@ -149,7 +152,8 @@
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Abrir o conteúdo original na janela atual",
|
||||
"page.keyboard_shortcuts.open_comments": "Abrir os comentários",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Abrir os comentários na janela atual",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "Inverter estado de leitura do item",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Inverter estado de leitura do item, focar próximo item",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Inverter estado de leitura do item, focar item anterior",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Atualizar todas as fontes",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Marcar página atual como lida",
|
||||
"page.keyboard_shortcuts.download_content": "Buscar o conteúdo original",
|
||||
@@ -199,6 +203,9 @@
|
||||
"page.api_keys.table.actions": "Ações",
|
||||
"page.api_keys.never_used": "Nunca usado",
|
||||
"page.new_api_key.title": "Nova chave de API",
|
||||
"page.offline.title": "Modo offline",
|
||||
"page.offline.message": "Você está offline",
|
||||
"page.offline.refresh_page": "Tente atualizar a página",
|
||||
"alert.no_shared_entry": "Não há itens compartilhados.",
|
||||
"alert.no_bookmark": "Não há favorito neste momento.",
|
||||
"alert.no_category": "Não há categoria.",
|
||||
@@ -218,6 +225,7 @@
|
||||
"error.unlink_account_without_password": "Você deve definir uma senha, senão não será possível efetuar a sessão novamente.",
|
||||
"error.duplicate_linked_account": "Alguém já está vinculado a esse serviço!",
|
||||
"error.duplicate_fever_username": "Alguém já está utilizando esse nome de usuário do Fever!",
|
||||
"error.duplicate_googlereader_username": "Alguém já está utilizando esse nome de usuário do Google Reader!",
|
||||
"error.pocket_request_token": "Não foi possível obter um pedido de token no Pocket!",
|
||||
"error.pocket_access_token": "Não foi possível obter um token de acesso no Pocket!",
|
||||
"error.category_already_exists": "Esta categoria já existe.",
|
||||
@@ -253,6 +261,7 @@
|
||||
"error.invalid_language": "Idioma inválido.",
|
||||
"error.invalid_timezone": "Fuso horário inválido.",
|
||||
"error.invalid_entry_direction": "Direção de entrada inválida.",
|
||||
"error.invalid_display_mode": "Modo de exibição de aplicativo inválido da web.",
|
||||
"form.feed.label.title": "Título",
|
||||
"form.feed.label.site_url": "URL do site",
|
||||
"form.feed.label.feed_url": "URL da fonte",
|
||||
@@ -261,14 +270,18 @@
|
||||
"form.feed.label.feed_username": "Nome de usuário da fonte",
|
||||
"form.feed.label.feed_password": "Senha da fonte",
|
||||
"form.feed.label.user_agent": "Sobrescrever o agente de usuário (user-agent) padrão",
|
||||
"form.feed.label.cookie": "Definir Cookies",
|
||||
"form.feed.label.scraper_rules": "Regras do scraper",
|
||||
"form.feed.label.rewrite_rules": "Regras para o Rewrite",
|
||||
"form.feed.label.blocklist_rules": "Regras de bloqueio",
|
||||
"form.feed.label.keeplist_rules": "Regras de permissão",
|
||||
"form.feed.label.ignore_http_cache": "Ignorar cache HTTP",
|
||||
"form.feed.label.allow_self_signed_certificates": "Permitir certificados autoassinados ou inválidos",
|
||||
"form.feed.label.disabled": "Não atualizar esta fonte",
|
||||
"form.feed.label.fetch_via_proxy": "Buscar via proxy",
|
||||
"form.feed.label.hide_globally": "Ocultar entradas na lista global não lida",
|
||||
"form.category.label.title": "Título",
|
||||
"form.category.hide_globally": "Ocultar entradas na lista global não lida",
|
||||
"form.user.label.username": "Nome de usuário",
|
||||
"form.user.label.password": "Senha",
|
||||
"form.user.label.confirmation": "Confirmação de senha",
|
||||
@@ -278,18 +291,30 @@
|
||||
"form.prefs.label.theme": "Tema",
|
||||
"form.prefs.label.entry_sorting": "Ordenação dos itens",
|
||||
"form.prefs.label.entries_per_page": "Itens por página",
|
||||
"form.prefs.label.display_mode": "Modo de exibição do aplicativo Web (precisa ser reinstalado)",
|
||||
"form.prefs.select.older_first": "Itens mais velhos primeiro",
|
||||
"form.prefs.select.recent_first": "Itens mais recentes",
|
||||
"form.prefs.select.fullscreen": "Tela completa",
|
||||
"form.prefs.select.standalone": "Autônomo",
|
||||
"form.prefs.select.minimal_ui": "Mínimo",
|
||||
"form.prefs.select.browser": "Navegador",
|
||||
"form.prefs.select.publish_time": "Entrada hora de publicação",
|
||||
"form.prefs.select.created_time": "Entrada tempo criado",
|
||||
"form.prefs.label.keyboard_shortcuts": "Habilitar atalhos do teclado",
|
||||
"form.prefs.label.entry_swipe": "Ativar gesto de deslizar nas entradas no celular",
|
||||
"form.prefs.label.show_reading_time": "Mostrar tempo estimado de leitura de artigos",
|
||||
"form.prefs.label.custom_css": "CSS customizado",
|
||||
"form.prefs.label.entry_order": "Coluna de Ordenação de Entrada",
|
||||
"form.import.label.file": "Arquivo OPML",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Ativar API do Fever",
|
||||
"form.integration.fever_username": "Nome de usuário do Fever",
|
||||
"form.integration.fever_password": "Senha do Fever",
|
||||
"form.integration.fever_endpoint": "Endpoint da API do Fever:",
|
||||
"form.integration.googlereader_activate": "Ativar API do Google Reader",
|
||||
"form.integration.googlereader_username": "Nome de usuário do Google Reader",
|
||||
"form.integration.googlereader_password": "Senha do Google Reader",
|
||||
"form.integration.googlereader_endpoint": "Endpoint da API do Google Reader:",
|
||||
"form.integration.pinboard_activate": "Salvar itens no Pinboard",
|
||||
"form.integration.pinboard_token": "Token de API do Pinboard",
|
||||
"form.integration.pinboard_tags": "Etiquetas (tags) do Pinboard",
|
||||
@@ -310,6 +335,16 @@
|
||||
"form.integration.nunux_keeper_activate": "Salvar itens no Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "Endpoint de API do Nunux Keeper",
|
||||
"form.integration.nunux_keeper_api_key": "Chave de API do Nunux Keeper",
|
||||
"form.integration.espial_activate": "Salvar itens no Espial",
|
||||
"form.integration.espial_endpoint": "Endpoint de API do Espial",
|
||||
"form.integration.espial_api_key": "Chave de API do Espial",
|
||||
"form.integration.espial_tags": "Etiquetas (tags) do Espial",
|
||||
"form.integration.telegram_bot_activate": "Envie novos artigos para o chat do Telegram",
|
||||
"form.integration.telegram_bot_token": "Token de bot",
|
||||
"form.integration.telegram_chat_id": "ID de bate-papo",
|
||||
"form.integration.linkding_activate": "Salvar itens no Linkding",
|
||||
"form.integration.linkding_endpoint": "Endpoint de API do Linkding",
|
||||
"form.integration.linkding_api_key": "Chave de API do Linkding",
|
||||
"form.api_key.label.description": "Etiqueta da chave de API",
|
||||
"form.submit.loading": "Carregando...",
|
||||
"form.submit.saving": "Salvando...",
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
"Есть %d подписки.",
|
||||
"Есть %d подписок."
|
||||
],
|
||||
"page.categories.unread_counter": "Количество непрочитанных записей",
|
||||
"page.new_category.title": "Новая категория",
|
||||
"page.new_user.title": "Новый пользователь",
|
||||
"page.edit_category.title": "Изменить категорию: %s",
|
||||
@@ -115,6 +116,8 @@
|
||||
"page.about.build_date": "Дата сборки:",
|
||||
"page.about.author": "Автор:",
|
||||
"page.about.license": "Лицензия:",
|
||||
"page.about.postgres_version": "Postgres bерсия:",
|
||||
"page.about.go_version": "Go bерсия:",
|
||||
"page.about.global_config_options": "глобальные параметры конфигурации",
|
||||
"page.add_feed.title": "Новая подписка",
|
||||
"page.add_feed.no_category": "Категории отсутствуют. У вас должна быть хотя бы одна категория.",
|
||||
@@ -151,7 +154,8 @@
|
||||
"page.keyboard_shortcuts.open_original": "Открыть оригинальную ссылку",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Открыть ссылку на комментарии в текущей вкладке",
|
||||
"page.keyboard_shortcuts.open_comments": "Открыть ссылку для комментариев",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "Переключатель прочитанного",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Переключатель прочитанного, сосредоточиться на следующем",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Переключатель прочитанного, фокус предыдущий",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Обновить все подписки в фоне",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Отметить текущую страницу прочитанной",
|
||||
"page.keyboard_shortcuts.download_content": "Загрузить оригинальное содержимое",
|
||||
@@ -201,6 +205,9 @@
|
||||
"page.api_keys.table.actions": "Действия",
|
||||
"page.api_keys.never_used": "Никогда не использовался",
|
||||
"page.new_api_key.title": "Новый API-ключ",
|
||||
"page.offline.title": "Автономный режим",
|
||||
"page.offline.message": "Ты не в сети",
|
||||
"page.offline.refresh_page": "Попробуйте обновить страницу",
|
||||
"alert.no_shared_entry": "Общедоступные записи отсутствуют.",
|
||||
"alert.no_bookmark": "Избранное отсутствует.",
|
||||
"alert.no_category": "Категории отсутствуют.",
|
||||
@@ -220,6 +227,7 @@
|
||||
"error.unlink_account_without_password": "Вы должны установить пароль, иначе вы не сможете войти снова.",
|
||||
"error.duplicate_linked_account": "Уже есть кто-то, кто ассоциирован с этим аккаунтом!",
|
||||
"error.duplicate_fever_username": "Уже есть кто-то с таким же именем пользователя Fever!",
|
||||
"error.duplicate_googlereader_username": "Уже есть кто-то с таким же именем пользователя Google Reader!",
|
||||
"error.pocket_request_token": "Не удается извлечь request token из Pocket!",
|
||||
"error.pocket_access_token": "Не удается извлечь access token из Pocket!",
|
||||
"error.category_already_exists": "Эта категория уже существует.",
|
||||
@@ -255,6 +263,7 @@
|
||||
"error.invalid_language": "Неверный язык.",
|
||||
"error.invalid_timezone": "Неверный часовой пояс.",
|
||||
"error.invalid_entry_direction": "Неверное направление входа.",
|
||||
"error.invalid_display_mode": "Недопустимый режим отображения веб-приложения.",
|
||||
"form.feed.label.title": "Название",
|
||||
"form.feed.label.site_url": "URL сайта",
|
||||
"form.feed.label.feed_url": "URL подписки",
|
||||
@@ -263,14 +272,18 @@
|
||||
"form.feed.label.feed_username": "Имя пользователя подписки",
|
||||
"form.feed.label.feed_password": "Пароль подписки",
|
||||
"form.feed.label.user_agent": "Переопределить User Agent по умолчанию",
|
||||
"form.feed.label.cookie": "Установить Ку́ки",
|
||||
"form.feed.label.scraper_rules": "Правила Scraper",
|
||||
"form.feed.label.rewrite_rules": "Правила Rewrite",
|
||||
"form.feed.label.blocklist_rules": "Правила блокировки",
|
||||
"form.feed.label.keeplist_rules": "правила разрешений",
|
||||
"form.feed.label.ignore_http_cache": "Игнорировать HTTP-кеш",
|
||||
"form.feed.label.allow_self_signed_certificates": "Разрешить самоподписанные или недействительные сертификаты",
|
||||
"form.feed.label.fetch_via_proxy": "Получить через прокси",
|
||||
"form.feed.label.disabled": "Не обновлять этот канал",
|
||||
"form.feed.label.hide_globally": "Скрыть записи в глобальном списке непрочитанных",
|
||||
"form.category.label.title": "Название",
|
||||
"form.category.hide_globally": "Скрыть записи в глобальном списке непрочитанных",
|
||||
"form.user.label.username": "Имя пользователя",
|
||||
"form.user.label.password": "Пароль",
|
||||
"form.user.label.confirmation": "Подтверждение пароля",
|
||||
@@ -280,18 +293,30 @@
|
||||
"form.prefs.label.theme": "Тема",
|
||||
"form.prefs.label.entry_sorting": "Сортировка записей",
|
||||
"form.prefs.label.entries_per_page": "Записи на странице",
|
||||
"form.prefs.label.display_mode": "Режим отображения веб-приложения (требуется переустановка)",
|
||||
"form.prefs.select.older_first": "Сначала старые записи",
|
||||
"form.prefs.select.recent_first": "Сначала последние записи",
|
||||
"form.prefs.select.fullscreen": "Полноэкранный",
|
||||
"form.prefs.select.standalone": "Автономный",
|
||||
"form.prefs.select.minimal_ui": "Минимальный",
|
||||
"form.prefs.select.browser": "Браузер",
|
||||
"form.prefs.select.publish_time": "Время публикации заявки",
|
||||
"form.prefs.select.created_time": "Время создания записи",
|
||||
"form.prefs.label.keyboard_shortcuts": "Включить сочетания клавиш",
|
||||
"form.prefs.label.entry_swipe": "Включить жест смахивания для записей на мобильном устройстве",
|
||||
"form.prefs.label.show_reading_time": "Показать примерное время чтения статей",
|
||||
"form.prefs.label.custom_css": "Пользовательские CSS",
|
||||
"form.prefs.label.entry_order": "Колонка сортировки ввода",
|
||||
"form.import.label.file": "OPML файл",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Активировать Fever API",
|
||||
"form.integration.fever_username": "Имя пользователя Fever",
|
||||
"form.integration.fever_password": "Пароль Fever",
|
||||
"form.integration.fever_endpoint": "Конечная точка Fever API:",
|
||||
"form.integration.googlereader_activate": "Активировать Google Reader API",
|
||||
"form.integration.googlereader_username": "Имя пользователя Google Reader",
|
||||
"form.integration.googlereader_password": "Пароль Google Reader",
|
||||
"form.integration.googlereader_endpoint": "Конечная точка Google Reader API:",
|
||||
"form.integration.pinboard_activate": "Сохранять статьи в Pinboard",
|
||||
"form.integration.pinboard_token": "Pinboard API Token",
|
||||
"form.integration.pinboard_tags": "Теги Pinboard",
|
||||
@@ -312,6 +337,16 @@
|
||||
"form.integration.nunux_keeper_activate": "Сохранять статьи в Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "Конечная точка Nunux Keeper API",
|
||||
"form.integration.nunux_keeper_api_key": "Nunux Keeper API Key",
|
||||
"form.integration.espial_activate": "Сохранять статьи в Espial",
|
||||
"form.integration.espial_endpoint": "Конечная точка Espial API",
|
||||
"form.integration.espial_api_key": "Espial API key",
|
||||
"form.integration.espial_tags": "Теги Espial",
|
||||
"form.integration.telegram_bot_activate": "Публикуйте новые статьи в Telegram-чате",
|
||||
"form.integration.telegram_bot_token": "Токен бота",
|
||||
"form.integration.telegram_chat_id": "ID чата",
|
||||
"form.integration.linkding_activate": "Сохранять статьи в Linkding",
|
||||
"form.integration.linkding_endpoint": "Конечная точка Linkding API",
|
||||
"form.integration.linkding_api_key": "Linkding API key",
|
||||
"form.api_key.label.description": "Описание API-ключа",
|
||||
"form.submit.loading": "Загрузка…",
|
||||
"form.submit.saving": "Сохранение…",
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
{
|
||||
"confirm.question": "Emin misiniz?",
|
||||
"confirm.yes": "evet",
|
||||
"confirm.no": "hayır",
|
||||
"confirm.loading": "Devam ediyor...",
|
||||
"action.subscribe": "Abone Ol",
|
||||
"action.save": "Kaydet",
|
||||
"action.or": "veya",
|
||||
"action.cancel": "iptal",
|
||||
"action.remove": "Kaldır",
|
||||
"action.remove_feed": "Bu beslemeyi kaldır",
|
||||
"action.update": "Güncelle",
|
||||
"action.edit": "Düzenle",
|
||||
"action.download": "İndir",
|
||||
"action.import": "İçeri Aktar",
|
||||
"action.login": "Giriş",
|
||||
"action.home_screen": "Ana ekrana ekle",
|
||||
"tooltip.keyboard_shortcuts": "Klavye Kısayolu: %s",
|
||||
"tooltip.logged_user": "%s olarak giriş yapıldı",
|
||||
"menu.unread": "Okunmadı",
|
||||
"menu.starred": "Yıldız",
|
||||
"menu.history": "Geçmiş",
|
||||
"menu.feeds": "Beslemeler",
|
||||
"menu.categories": "Kategoriler",
|
||||
"menu.settings": "Ayarlar",
|
||||
"menu.logout": "Çıkış",
|
||||
"menu.preferences": "Tercihler",
|
||||
"menu.integrations": "Bütünleşmeler",
|
||||
"menu.sessions": "Oturumlar",
|
||||
"menu.users": "Kullanıcılar",
|
||||
"menu.about": "Hakkında",
|
||||
"menu.export": "Dışarı Aktar",
|
||||
"menu.import": "İçeri Aktar",
|
||||
"menu.create_category": "Kategori oluştur",
|
||||
"menu.mark_page_as_read": "Bu sayfayı okundu olarak işaretle",
|
||||
"menu.mark_all_as_read": "Tümünü okundu olarak işaretle",
|
||||
"menu.show_all_entries": "Tüm iletileri göster",
|
||||
"menu.show_only_unread_entries": "Sadece okunmamış iletileri göster",
|
||||
"menu.refresh_feed": "Yenile",
|
||||
"menu.refresh_all_feeds": "Tüm beslemeleri arka planda yenile",
|
||||
"menu.edit_feed": "Düzenle",
|
||||
"menu.edit_category": "Düzenle",
|
||||
"menu.add_feed": "Abonelik ekle",
|
||||
"menu.add_user": "Kullanıcı ekle",
|
||||
"menu.flush_history": "Geçmişi temizle",
|
||||
"menu.feed_entries": "İletiler",
|
||||
"menu.api_keys": "API Anahtarları",
|
||||
"menu.create_api_key": "Yeni bir API anahtarı oluştur",
|
||||
"menu.shared_entries": "Paylaşılan iletiler",
|
||||
"search.label": "Ara",
|
||||
"search.placeholder": "Ara...",
|
||||
"pagination.next": "Sonraki",
|
||||
"pagination.previous": "Önceki",
|
||||
"entry.status.unread": "Okunmadı",
|
||||
"entry.status.read": "Okundu",
|
||||
"entry.status.toast.unread": "Okunmadı olarak işaretle",
|
||||
"entry.status.toast.read": "Okundu olarak işaretle",
|
||||
"entry.status.title": "İleti durumunu değiştir",
|
||||
"entry.bookmark.toggle.on": "Yıldız ekle",
|
||||
"entry.bookmark.toggle.off": "Yıldızı kaldır",
|
||||
"entry.bookmark.toast.on": "Yıldızlı",
|
||||
"entry.bookmark.toast.off": "Yıldızsız",
|
||||
"entry.state.saving": "Kaydediliyor...",
|
||||
"entry.state.loading": "Yükleniyor...",
|
||||
"entry.save.label": "Kaydet",
|
||||
"entry.save.title": "Bu makaleyi kaydet",
|
||||
"entry.save.completed": "Bitti!",
|
||||
"entry.save.toast.completed": "Makale kaydedildi",
|
||||
"entry.scraper.label": "İndir",
|
||||
"entry.scraper.title": "Orijinal içeriği çek",
|
||||
"entry.scraper.completed": "Bitti!",
|
||||
"entry.external_link.label": "Dış bağlantı",
|
||||
"entry.comments.label": "Yorumlar",
|
||||
"entry.comments.title": "Yorumları Göster",
|
||||
"entry.share.label": "Paylaş",
|
||||
"entry.share.title": "Bu makaleyi paylaş",
|
||||
"entry.unshare.label": "Paylaşma",
|
||||
"entry.shared_entry.title": "Herkese açık bağlantıyı aç",
|
||||
"entry.shared_entry.label": "Paylaş",
|
||||
"entry.estimated_reading_time": [
|
||||
"%d dakikalık okuma",
|
||||
"%d dakikalık okuma"
|
||||
],
|
||||
"page.shared_entries.title": "Paylaşılan iletiler",
|
||||
"page.unread.title": "Okunmadı",
|
||||
"page.starred.title": "Yıldızlı",
|
||||
"page.categories.title": "Kategoriler",
|
||||
"page.categories.no_feed": "Besleme yok.",
|
||||
"page.categories.entries": "Makaleler",
|
||||
"page.categories.feeds": "Abonelikler",
|
||||
"page.categories.feed_count": [
|
||||
"%d besleme var.",
|
||||
"%d besleme var."
|
||||
],
|
||||
"page.categories.unread_counter": "Okunmamış iletilerin sayısı",
|
||||
"page.new_category.title": "Yeni Kategori",
|
||||
"page.new_user.title": "Yeni Kullanıcı",
|
||||
"page.edit_category.title": "Kategoriyi Düzenle: %s",
|
||||
"page.edit_user.title": "Kullanıcıyı Düzenle: %s",
|
||||
"page.feeds.title": "Beslemeler",
|
||||
"page.feeds.last_check": "Son kontrol:",
|
||||
"page.feeds.unread_counter": "Okunmamış iletilerin sayısı",
|
||||
"page.feeds.read_counter": "Okunmuş iletilerin sayısı",
|
||||
"page.feeds.error_count": [
|
||||
"%d hata",
|
||||
"%d hata"
|
||||
],
|
||||
"page.history.title": "Geçmiş",
|
||||
"page.import.title": "İçeri Aktar",
|
||||
"page.search.title": "Arama Sonuçları",
|
||||
"page.about.title": "Hakkında",
|
||||
"page.about.credits": "Katkıda Bulunanlar",
|
||||
"page.about.version": "Sürüm:",
|
||||
"page.about.build_date": "Oluşturulma Tarihi:",
|
||||
"page.about.author": "Yazar:",
|
||||
"page.about.license": "Lisans:",
|
||||
"page.about.global_config_options": "Global yapılandırma seçenekleri",
|
||||
"page.about.postgres_version": "Postgres sürümü:",
|
||||
"page.about.go_version": "Go sürümü:",
|
||||
"page.add_feed.title": "Yeni Abonelik",
|
||||
"page.add_feed.no_category": "Kategori yok. En az bir kategoriye sahip olmalısınız.",
|
||||
"page.add_feed.label.url": "URL",
|
||||
"page.add_feed.submit": "Bir abonelik bul",
|
||||
"page.add_feed.legend.advanced_options": "Gelişmiş Seçenekler",
|
||||
"page.add_feed.choose_feed": "Bir Abonelik Seçin",
|
||||
"page.edit_feed.title": "Beslemeyi düzenle: %s",
|
||||
"page.edit_feed.last_check": "Son kontrol:",
|
||||
"page.edit_feed.last_modified_header": "LastModified başlığı:",
|
||||
"page.edit_feed.etag_header": "ETag başlığı:",
|
||||
"page.edit_feed.no_header": "Hiçbiri",
|
||||
"page.edit_feed.last_parsing_error": "Son Ayrıştırma Hatası",
|
||||
"page.entry.attachments": "Ekler",
|
||||
"page.keyboard_shortcuts.title": "Klavye Kısayolları",
|
||||
"page.keyboard_shortcuts.subtitle.sections": "Bölüm Gezinmesi",
|
||||
"page.keyboard_shortcuts.subtitle.items": "Öğe Gezinmesi",
|
||||
"page.keyboard_shortcuts.subtitle.pages": "Sayfa Gezinmesi",
|
||||
"page.keyboard_shortcuts.subtitle.actions": "Hareketler",
|
||||
"page.keyboard_shortcuts.go_to_unread": "Okunmamışa git",
|
||||
"page.keyboard_shortcuts.go_to_starred": "Yer imlerine git",
|
||||
"page.keyboard_shortcuts.go_to_history": "Geçmişe git",
|
||||
"page.keyboard_shortcuts.go_to_feeds": "Beslemelere git",
|
||||
"page.keyboard_shortcuts.go_to_categories": "Kategorilere git",
|
||||
"page.keyboard_shortcuts.go_to_settings": "Ayarlara git",
|
||||
"page.keyboard_shortcuts.show_keyboard_shortcuts": "Klavye kısayollarını göster",
|
||||
"page.keyboard_shortcuts.go_to_previous_item": "Önceki öğeye git",
|
||||
"page.keyboard_shortcuts.go_to_next_item": "Sonraki öğeye git",
|
||||
"page.keyboard_shortcuts.go_to_feed": "Beslemeye git",
|
||||
"page.keyboard_shortcuts.go_to_previous_page": "Önceki sayfaya git",
|
||||
"page.keyboard_shortcuts.go_to_next_page": "Sonraki sayfaya git",
|
||||
"page.keyboard_shortcuts.open_item": "Seçili öğeyi aç",
|
||||
"page.keyboard_shortcuts.open_original": "Orijinal bağlantıyı aç",
|
||||
"page.keyboard_shortcuts.open_original_same_window": "Orijinal bağlantıyı mevcut sekmede aç",
|
||||
"page.keyboard_shortcuts.open_comments": "Yorumlar bağlantısını aç",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "Yorumlar bağlantısını mevcut sekmede aç",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "Okundu/okunmadı arasında geçiş yap, sonrakine odaklan",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "Okundu/okunmadı arasında geçiş yap, öncekine odaklan",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "Tüm beslemeleri arka planda yenile",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "Mevcut sayfayı okundu olarak işaretle",
|
||||
"page.keyboard_shortcuts.download_content": "Orijinal içeriği indir",
|
||||
"page.keyboard_shortcuts.toggle_bookmark_status": "Yer işaretini değiştir",
|
||||
"page.keyboard_shortcuts.save_article": "Makaleyi kaydet",
|
||||
"page.keyboard_shortcuts.scroll_item_to_top": "Öğeyi en üste kaydır",
|
||||
"page.keyboard_shortcuts.remove_feed": "Bu beslemeyi kaldır",
|
||||
"page.keyboard_shortcuts.go_to_search": "Arama formuna odakla",
|
||||
"page.keyboard_shortcuts.close_modal": "İletişim kutusunu kapat",
|
||||
"page.users.title": "Kullanıcılar",
|
||||
"page.users.username": "Kullanıcı adı",
|
||||
"page.users.never_logged": "Asla",
|
||||
"page.users.admin.yes": "Evet",
|
||||
"page.users.admin.no": "Hayır",
|
||||
"page.users.actions": "Hareketler",
|
||||
"page.users.last_login": "Son Giriş",
|
||||
"page.users.is_admin": "Yönetici",
|
||||
"page.settings.title": "Ayarlar",
|
||||
"page.settings.link_google_account": "Google hesabımı bağla",
|
||||
"page.settings.unlink_google_account": "Google hesabımın bağlantısını kaldır",
|
||||
"page.settings.link_oidc_account": "OpenID Connect hesabımı bağla",
|
||||
"page.settings.unlink_oidc_account": "OpenID Connect hesabımın bağlantısını kaldır",
|
||||
"page.login.title": "Oturum aç",
|
||||
"page.login.google_signin": "Google ile oturum aç",
|
||||
"page.login.oidc_signin": "OpenID Connect ile oturum aç",
|
||||
"page.integrations.title": "Bütünleşmeler",
|
||||
"page.integration.miniflux_api": "Miniflux API",
|
||||
"page.integration.miniflux_api_endpoint": "API Uç Noktası",
|
||||
"page.integration.miniflux_api_username": "Kullanıcı adı",
|
||||
"page.integration.miniflux_api_password": "Parola",
|
||||
"page.integration.miniflux_api_password_value": "Hesap parolan",
|
||||
"page.integration.bookmarklet": "Bookmarklet",
|
||||
"page.integration.bookmarklet.name": "Miniflux'a Ekle",
|
||||
"page.integration.bookmarklet.instructions": "Bu bağlantıyı yer imlerinize sürükleyip bırakın",
|
||||
"page.integration.bookmarklet.help": "Bu özel bağlantı, web tarayıcınızdaki yer imini kullanarak bir web sitesine doğrudan abone olmanızı sağlar.",
|
||||
"page.sessions.title": "Oturumlar",
|
||||
"page.sessions.table.date": "Tarih",
|
||||
"page.sessions.table.ip": "IP Adresi",
|
||||
"page.sessions.table.user_agent": "User Agent",
|
||||
"page.sessions.table.actions": "Hareketler",
|
||||
"page.sessions.table.current_session": "Mevcut Oturum",
|
||||
"page.api_keys.title": "API Anahtarları",
|
||||
"page.api_keys.table.description": "Açıklama",
|
||||
"page.api_keys.table.token": "Token",
|
||||
"page.api_keys.table.last_used_at": "Son Kullanılma",
|
||||
"page.api_keys.table.created_at": "Oluşturulma Tarihi",
|
||||
"page.api_keys.table.actions": "Hareketler",
|
||||
"page.api_keys.never_used": "Hiç Kullanılmadı",
|
||||
"page.new_api_key.title": "Yeni API Anahtarı",
|
||||
"page.offline.title": "Çevrimdışı Modu",
|
||||
"page.offline.message": "Çevrimdışısınız",
|
||||
"page.offline.refresh_page": "Sayfayı yenilemeyi dene",
|
||||
"alert.no_shared_entry": "Paylaşılan ileti yok.",
|
||||
"alert.no_bookmark": "Şu anda hiç yer imi yok.",
|
||||
"alert.no_category": "Hiç kategori yok.",
|
||||
"alert.no_category_entry": "Bu kategoride hiç makale yok.",
|
||||
"alert.no_feed_entry": "Bu besleme için makale yok.",
|
||||
"alert.no_feed": "Hiç aboneliğiniz yok.",
|
||||
"alert.no_feed_in_category": "Bu kategori için aboneliğiniz yok.",
|
||||
"alert.no_history": "Şu anda hiç geçmiş yok.",
|
||||
"alert.feed_error": "Bu beslemeyle ilgili bir problem var",
|
||||
"alert.no_search_result": "Bu arama için sonuç yok",
|
||||
"alert.no_unread_entry": "Okunmamış makale yok",
|
||||
"alert.no_user": "Tek kullanıcı sizsiniz",
|
||||
"alert.account_unlinked": "Harici hesabınızın bağlantısı kaldırıldı!",
|
||||
"alert.account_linked": "Harici hesabınız bağlandı.",
|
||||
"alert.pocket_linked": "Pocket hesabınız bağlandı.",
|
||||
"alert.prefs_saved": "Tercihler kaydedildi!",
|
||||
"error.unlink_account_without_password": "Bir şifre belirlemelisiniz, aksi takdirde tekrar oturum açamazsınız.",
|
||||
"error.duplicate_linked_account": "Bu sağlayıcıyla ilişkilendirilmiş biri zaten var!",
|
||||
"error.duplicate_fever_username": "Aynı Fever kullanıcı adına sahip başka biri zaten var!",
|
||||
"error.duplicate_googlereader_username": "Aynı Google Reader kullanıcı adına sahip başka biri zaten var!",
|
||||
"error.pocket_request_token": "Pocket'tan istek tokeni alınamıyor!",
|
||||
"error.pocket_access_token": "Pocket'tan erişim tokeni alınamıyor!",
|
||||
"error.category_already_exists": "Bu kategori zaten mevcut.",
|
||||
"error.unable_to_create_category": "Bu kategori oluşturulamıyor.",
|
||||
"error.unable_to_update_category": "Bu kategori güncellenemiyor.",
|
||||
"error.user_already_exists": "Bu kullanıcı zaten mevcut.",
|
||||
"error.unable_to_create_user": "Bu kullanıcı oluşturulamıyor.",
|
||||
"error.unable_to_update_user": "Bu kullanıcı güncellenemiyor.",
|
||||
"error.unable_to_update_feed": "Bu besleme güncellenemiyor.",
|
||||
"error.subscription_not_found": "Herhangi bir abonelik bulunamadı.",
|
||||
"error.invalid_theme": "Geçersiz tema.",
|
||||
"error.invalid_language": "Geçersiz dil.",
|
||||
"error.invalid_timezone": "Geçersiz saat dilimi",
|
||||
"error.invalid_entry_direction": "Geçersiz giriş yönü.",
|
||||
"error.invalid_display_mode": "Geçersiz web uygulaması görüntüleme modu.",
|
||||
"error.empty_file": "Bu dosya boş.",
|
||||
"error.bad_credentials": "Geçersiz kullanıcı veya parola.",
|
||||
"error.fields_mandatory": "Tüm alanlar zorunlu.",
|
||||
"error.title_required": "Başlık zorunlu.",
|
||||
"error.different_passwords": "Parolalar eşleşmiyor.",
|
||||
"error.password_min_length": "Parola en az 6 karakter içermeli.",
|
||||
"error.settings_mandatory_fields": "Kullanıcı ad, tema, dil ve saat dilimi zorunlu.",
|
||||
"error.entries_per_page_invalid": "Sayfa başına ileti sayısı geçersiz.",
|
||||
"error.feed_mandatory_fields": "URL ve kategori zorunlu.",
|
||||
"error.feed_already_exists": "Bu besleme zaten mevcut.",
|
||||
"error.invalid_feed_url": "Geçersiz besleme URL'si.",
|
||||
"error.invalid_site_url": "Geçersiz site URL'si.",
|
||||
"error.feed_url_not_empty": "Besleme URL'si boş olamaz.",
|
||||
"error.site_url_not_empty": "Site URL'si boş olamaz.",
|
||||
"error.feed_title_not_empty": "Besleme başlığı boş olamaz.",
|
||||
"error.feed_category_not_found": "Bu kategori mevcut değil ya da bu kullanıcıya ait değil.",
|
||||
"error.feed_invalid_blocklist_rule": "Engelleme listesi kuralı geçersiz.",
|
||||
"error.feed_invalid_keeplist_rule": "Saklama listesi kuralı geçersiz.",
|
||||
"error.user_mandatory_fields": "Kullanıcı adı zorunlu.",
|
||||
"error.api_key_already_exists": "Bu API anahtarı zaten mevcut.",
|
||||
"error.unable_to_create_api_key": "Bu API anahtarı oluşturulamıyor.",
|
||||
"form.feed.label.title": "Başlık",
|
||||
"form.feed.label.site_url": "Site URL'si",
|
||||
"form.feed.label.feed_url": "Besleme URL'si",
|
||||
"form.feed.label.category": "Kategori",
|
||||
"form.feed.label.crawler": "Orijinal içeriği çek",
|
||||
"form.feed.label.feed_username": "Besleme Kullanıcı Adı",
|
||||
"form.feed.label.feed_password": "Besleme Parolası",
|
||||
"form.feed.label.user_agent": "Varsayılan User Agent'i Geçersiz Kıl",
|
||||
"form.feed.label.cookie": "Çerezleri Ayarla",
|
||||
"form.feed.label.scraper_rules": "Scrapper Kuralları",
|
||||
"form.feed.label.rewrite_rules": "Yeniden Yazma Kuralları",
|
||||
"form.feed.label.blocklist_rules": "Engelleme Kuralları",
|
||||
"form.feed.label.keeplist_rules": "Saklama Kuralları",
|
||||
"form.feed.label.ignore_http_cache": "HTTP önbelleğini yoksay",
|
||||
"form.feed.label.allow_self_signed_certificates": "Kendinden imzalı veya geçersiz sertifikalara izin ver",
|
||||
"form.feed.label.fetch_via_proxy": "Proxy ile çek",
|
||||
"form.feed.label.disabled": "Bu beslemeyi yenileme",
|
||||
"form.feed.label.hide_globally": "Genel okunmamış listesindeki girişleri gizle",
|
||||
"form.category.label.title": "Başlık",
|
||||
"form.category.hide_globally": "Genel okunmamış listesindeki girişleri gizle",
|
||||
"form.user.label.username": "Kullanıcı Adı",
|
||||
"form.user.label.password": "Parola",
|
||||
"form.user.label.confirmation": "Parola Doğrulama",
|
||||
"form.user.label.admin": "Yönetici",
|
||||
"form.prefs.label.language": "Dil",
|
||||
"form.prefs.label.timezone": "Saat Dilimi",
|
||||
"form.prefs.label.theme": "Tema",
|
||||
"form.prefs.label.entry_sorting": "İleti Sıralaması",
|
||||
"form.prefs.label.entries_per_page": "Sayfa başına ileti",
|
||||
"form.prefs.label.display_mode": "Web uygulaması görüntüleme modu (yeniden kurulum gerektirir)",
|
||||
"form.prefs.select.older_first": "Önce eski iletiler",
|
||||
"form.prefs.select.recent_first": "Önce yeni iletiler",
|
||||
"form.prefs.select.fullscreen": "Tam Ekran",
|
||||
"form.prefs.select.standalone": "Bağımsız",
|
||||
"form.prefs.select.minimal_ui": "Minimal",
|
||||
"form.prefs.select.browser": "Tarayıcı",
|
||||
"form.prefs.select.publish_time": "Giriş yayınlanma zamanı",
|
||||
"form.prefs.select.created_time": "Girişin oluşturulma zamanı",
|
||||
"form.prefs.label.keyboard_shortcuts": "Klavye kısayollarını etkinleştir",
|
||||
"form.prefs.label.entry_swipe": "Mobil cihazlarda iletiler için kaydırma hareketlerini etkinleştir",
|
||||
"form.prefs.label.show_reading_time": "Makaleler için tahmini okuma süresini göster",
|
||||
"form.prefs.label.custom_css": "Özel CSS",
|
||||
"form.prefs.label.entry_order": "Giriş Sıralama Sütunu",
|
||||
"form.import.label.file": "OPML dosyası",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Fever API'yi Etkinleştir",
|
||||
"form.integration.fever_username": "Fever Kullanıcı Adı",
|
||||
"form.integration.fever_password": "Fever Parolası",
|
||||
"form.integration.fever_endpoint": "Fever API uç noktası:",
|
||||
"form.integration.googlereader_activate": "Google Reader API'yi Etkinleştir",
|
||||
"form.integration.googlereader_username": "Google Reader Kullanıcı Adı",
|
||||
"form.integration.googlereader_password": "Google Reader Parolası",
|
||||
"form.integration.googlereader_endpoint": "Google Reader API uç noktası:",
|
||||
"form.integration.pinboard_activate": "Makaleleri Pinboard'a kaydet",
|
||||
"form.integration.pinboard_token": "Pinboard API Token",
|
||||
"form.integration.pinboard_tags": "Pinboard Etiketleri",
|
||||
"form.integration.pinboard_bookmark": "Yer imini okunmadı olarak işaretle",
|
||||
"form.integration.instapaper_activate": "Makaleleri Instapaper'a kaydet",
|
||||
"form.integration.instapaper_username": "Instapaper Kullanıcı Adı",
|
||||
"form.integration.instapaper_password": "Instapaper Parolası",
|
||||
"form.integration.pocket_activate": "Makaleleri Pocket'a kaydet",
|
||||
"form.integration.pocket_consumer_key": "Pocket Consumer Anahtarı",
|
||||
"form.integration.pocket_access_token": "Pocket Access Token",
|
||||
"form.integration.pocket_connect_link": "Pocket hesabını bağla",
|
||||
"form.integration.wallabag_activate": "Makaleleri Wallabag'e kaydet",
|
||||
"form.integration.wallabag_endpoint": "Wallabag API Uç Noktası",
|
||||
"form.integration.wallabag_client_id": "Wallabag Client ID",
|
||||
"form.integration.wallabag_client_secret": "Wallabag Client Secret",
|
||||
"form.integration.wallabag_username": "Wallabag Kullanıcı Adı",
|
||||
"form.integration.wallabag_password": "Wallabag Parolası",
|
||||
"form.integration.nunux_keeper_activate": "Makaleleri Nunux Keeper'a kaydet",
|
||||
"form.integration.nunux_keeper_endpoint": "Nunux Keeper API Uç Noktası",
|
||||
"form.integration.nunux_keeper_api_key": "Nunux Keeper API anahtarı",
|
||||
"form.integration.espial_activate": "Makaleleri Espial'e kaydet",
|
||||
"form.integration.espial_endpoint": "Espial API Uç Noktası",
|
||||
"form.integration.espial_api_key": "Espial API Anahtarı",
|
||||
"form.integration.espial_tags": "Espial Etiketleri",
|
||||
"form.integration.telegram_bot_activate": "Yeni makaleleri Telegram sohbetine gönderin",
|
||||
"form.integration.telegram_bot_token": "Bot jetonu",
|
||||
"form.integration.telegram_chat_id": "Sohbet kimliği",
|
||||
"form.integration.linkding_activate": "Makaleleri Linkding'e kaydet",
|
||||
"form.integration.linkding_endpoint": "Linkding API Uç Noktası",
|
||||
"form.integration.linkding_api_key": "Linkding API Anahtarı",
|
||||
"form.api_key.label.description": "API Anahtar Etiketi",
|
||||
"form.submit.loading": "Yükleniyor...",
|
||||
"form.submit.saving": "Kaydediliyor...",
|
||||
"time_elapsed.not_yet": "henüz değil",
|
||||
"time_elapsed.yesterday": "dün",
|
||||
"time_elapsed.now": "şimdi",
|
||||
"time_elapsed.minutes": [
|
||||
"%d dakika önce",
|
||||
"%d dakika önce"
|
||||
],
|
||||
"time_elapsed.hours": [
|
||||
"%d saat önce",
|
||||
"%d saat önce"
|
||||
],
|
||||
"time_elapsed.days": [
|
||||
"%d gün önce",
|
||||
"%d gün önce"
|
||||
],
|
||||
"time_elapsed.weeks": [
|
||||
"%d hafta önce",
|
||||
"%d hafta önce"
|
||||
],
|
||||
"time_elapsed.months": [
|
||||
"%d ay önce",
|
||||
"%d ay önce"
|
||||
],
|
||||
"time_elapsed.years": [
|
||||
"%d yıl önce",
|
||||
"%d yıl önce"
|
||||
]
|
||||
}
|
||||
+138
-103
@@ -13,12 +13,12 @@
|
||||
"action.edit": "编辑",
|
||||
"action.download": "下载",
|
||||
"action.import": "导入",
|
||||
"action.login": "登陆",
|
||||
"action.login": "登录",
|
||||
"action.home_screen": "添加到主屏幕",
|
||||
"tooltip.keyboard_shortcuts": "快捷键: %s",
|
||||
"tooltip.logged_user": "当前登录 %s",
|
||||
"menu.unread": "未读",
|
||||
"menu.starred": "星标",
|
||||
"menu.starred": "收藏",
|
||||
"menu.history": "历史",
|
||||
"menu.feeds": "源",
|
||||
"menu.categories": "分类",
|
||||
@@ -34,41 +34,41 @@
|
||||
"menu.create_category": "新建分类",
|
||||
"menu.mark_page_as_read": "标记为已读",
|
||||
"menu.mark_all_as_read": "全部标为已读",
|
||||
"menu.show_all_entries": "显示所有条目",
|
||||
"menu.show_all_entries": "显示所有文章",
|
||||
"menu.show_only_unread_entries": "仅显示未读文章",
|
||||
"menu.refresh_feed": "更新",
|
||||
"menu.refresh_all_feeds": "在后台更新全部源",
|
||||
"menu.edit_feed": "编辑",
|
||||
"menu.edit_category": "编辑",
|
||||
"menu.add_feed": "新增订阅",
|
||||
"menu.add_feed": "新增源",
|
||||
"menu.add_user": "新建用户",
|
||||
"menu.flush_history": "清理历史",
|
||||
"menu.feed_entries": "文章",
|
||||
"menu.api_keys": "API密钥",
|
||||
"menu.create_api_key": "创建一个新的API密钥",
|
||||
"menu.shared_entries": "共享条目",
|
||||
"menu.api_keys": "API 密钥",
|
||||
"menu.create_api_key": "创建一个新的 API 密钥",
|
||||
"menu.shared_entries": "分享文章",
|
||||
"search.label": "搜索",
|
||||
"search.placeholder": "搜索…",
|
||||
"pagination.next": "下一页",
|
||||
"pagination.previous": "上一页",
|
||||
"entry.status.unread": "未读",
|
||||
"entry.status.unread": "标为未读",
|
||||
"entry.status.read": "标为已读",
|
||||
"entry.status.toast.unread": "已标为未读",
|
||||
"entry.status.toast.read": "已标为已读",
|
||||
"entry.status.title": "更改状态",
|
||||
"entry.bookmark.toggle.on": "标记星标",
|
||||
"entry.bookmark.toggle.off": "去掉星标",
|
||||
"entry.bookmark.toast.on": "已标记星标",
|
||||
"entry.bookmark.toast.off": "已去掉星标",
|
||||
"entry.bookmark.toggle.on": "添加收藏",
|
||||
"entry.bookmark.toggle.off": "取消收藏",
|
||||
"entry.bookmark.toast.on": "已添加收藏",
|
||||
"entry.bookmark.toast.off": "已取消收藏",
|
||||
"entry.state.saving": "保存中…",
|
||||
"entry.state.loading": "载入中…",
|
||||
"entry.save.label": "保存",
|
||||
"entry.save.title": "保存这篇文章",
|
||||
"entry.save.completed": "完成",
|
||||
"entry.save.toast.completed": "已保存文章",
|
||||
"entry.scraper.label": "下载",
|
||||
"entry.scraper.title": "抓取原内容",
|
||||
"entry.scraper.completed": "完成",
|
||||
"entry.scraper.label": "抓取全文",
|
||||
"entry.scraper.title": "抓取全文内容",
|
||||
"entry.scraper.completed": "抓取完成",
|
||||
"entry.external_link.label": "外部链接",
|
||||
"entry.comments.label": "评论",
|
||||
"entry.comments.title": "查看评论",
|
||||
@@ -76,29 +76,30 @@
|
||||
"entry.share.title": "分享这篇文章",
|
||||
"entry.unshare.label": "取消分享",
|
||||
"entry.shared_entry.title": "打开公共链接",
|
||||
"entry.shared_entry.label": "分享分享",
|
||||
"entry.shared_entry.label": "分享",
|
||||
"entry.estimated_reading_time": [
|
||||
"%d分钟阅读",
|
||||
"%d分钟阅读"
|
||||
"需要 %d 分钟阅读",
|
||||
"需要 %d 分钟阅读"
|
||||
],
|
||||
"page.shared_entries.title": "共享条目",
|
||||
"page.shared_entries.title": "分享文章",
|
||||
"page.unread.title": "未读",
|
||||
"page.starred.title": "星标",
|
||||
"page.starred.title": "收藏",
|
||||
"page.categories.title": "分类",
|
||||
"page.categories.no_feed": "没有源",
|
||||
"page.categories.entries": "文章",
|
||||
"page.categories.feeds": "查看订阅",
|
||||
"page.categories.entries": "查看内容",
|
||||
"page.categories.feeds": "查看源",
|
||||
"page.categories.feed_count": [
|
||||
"有 %d 个源"
|
||||
],
|
||||
"page.categories.unread_counter": "未读文章数",
|
||||
"page.new_category.title": "新分类",
|
||||
"page.new_user.title": "新用户",
|
||||
"page.edit_category.title": "编辑分类 : %s",
|
||||
"page.edit_user.title": "编辑用户 : %s",
|
||||
"page.feeds.title": "源",
|
||||
"page.feeds.last_check": "最后检查时间:",
|
||||
"page.feeds.unread_counter": "未读条目数",
|
||||
"page.feeds.read_counter": "读取条目数",
|
||||
"page.feeds.unread_counter": "未读文章数",
|
||||
"page.feeds.read_counter": "已读文章数",
|
||||
"page.feeds.error_count": [
|
||||
"%d 错误"
|
||||
],
|
||||
@@ -111,55 +112,58 @@
|
||||
"page.about.build_date": "构建日期:",
|
||||
"page.about.author": "作者:",
|
||||
"page.about.license": "协议:",
|
||||
"page.about.postgres_version": "Postgres 版本号:",
|
||||
"page.about.go_version": "Go 版本号:",
|
||||
"page.about.global_config_options": "全局配置选项",
|
||||
"page.add_feed.title": "新增订阅",
|
||||
"page.add_feed.no_category": "没有类别,您必须至少有一个类别",
|
||||
"page.add_feed.title": "新增源",
|
||||
"page.add_feed.no_category": "没有类别,至少需要有一个类别",
|
||||
"page.add_feed.label.url": "网址",
|
||||
"page.add_feed.submit": "查找订阅",
|
||||
"page.add_feed.submit": "查找源",
|
||||
"page.add_feed.legend.advanced_options": "高级选项",
|
||||
"page.add_feed.choose_feed": "选择一个订阅",
|
||||
"page.add_feed.choose_feed": "选择一个源",
|
||||
"page.edit_feed.title": "编辑源 : %s",
|
||||
"page.edit_feed.last_check": "最后检查时间:",
|
||||
"page.edit_feed.last_modified_header": "最后修改的 Header:",
|
||||
"page.edit_feed.etag_header": "ETag 标题:",
|
||||
"page.edit_feed.no_header": "无",
|
||||
"page.edit_feed.no_header": "无 Header",
|
||||
"page.edit_feed.last_parsing_error": "最后一次解析错误",
|
||||
"page.entry.attachments": "附件",
|
||||
"page.keyboard_shortcuts.title": "快捷键",
|
||||
"page.keyboard_shortcuts.subtitle.sections": "分区导航",
|
||||
"page.keyboard_shortcuts.subtitle.items": "条目导航",
|
||||
"page.keyboard_shortcuts.subtitle.items": "文章导航",
|
||||
"page.keyboard_shortcuts.subtitle.pages": "页面导航",
|
||||
"page.keyboard_shortcuts.subtitle.actions": "操作",
|
||||
"page.keyboard_shortcuts.go_to_unread": "去往未读",
|
||||
"page.keyboard_shortcuts.go_to_starred": "去往书签",
|
||||
"page.keyboard_shortcuts.go_to_history": "去往历史",
|
||||
"page.keyboard_shortcuts.go_to_feeds": "去往源",
|
||||
"page.keyboard_shortcuts.go_to_categories": "去往分类",
|
||||
"page.keyboard_shortcuts.go_to_settings": "去往设置",
|
||||
"page.keyboard_shortcuts.show_keyboard_shortcuts": "显示快捷键",
|
||||
"page.keyboard_shortcuts.go_to_previous_item": "上一条目",
|
||||
"page.keyboard_shortcuts.go_to_next_item": "下一条目",
|
||||
"page.keyboard_shortcuts.go_to_feed": "转到订阅",
|
||||
"page.keyboard_shortcuts.go_to_unread": "打开未读页面",
|
||||
"page.keyboard_shortcuts.go_to_starred": "打开收藏页面",
|
||||
"page.keyboard_shortcuts.go_to_history": "打开历史页面",
|
||||
"page.keyboard_shortcuts.go_to_feeds": "打开源页面",
|
||||
"page.keyboard_shortcuts.go_to_categories": "打开分类页面",
|
||||
"page.keyboard_shortcuts.go_to_settings": "打开设置页面",
|
||||
"page.keyboard_shortcuts.show_keyboard_shortcuts": "显示快捷键帮助",
|
||||
"page.keyboard_shortcuts.go_to_previous_item": "上一文章",
|
||||
"page.keyboard_shortcuts.go_to_next_item": "下一文章",
|
||||
"page.keyboard_shortcuts.go_to_feed": "转到源页面",
|
||||
"page.keyboard_shortcuts.go_to_previous_page": "上一页",
|
||||
"page.keyboard_shortcuts.go_to_next_page": "下一页",
|
||||
"page.keyboard_shortcuts.open_item": "打开选定的条目",
|
||||
"page.keyboard_shortcuts.open_item": "打开选定的文章",
|
||||
"page.keyboard_shortcuts.open_original": "打开原始链接",
|
||||
"page.keyboard_shortcuts.open_original_same_window": "在当前标签页中打开原始链接",
|
||||
"page.keyboard_shortcuts.open_comments": "打开评论链接",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "在当前标签页中打开评论链接",
|
||||
"page.keyboard_shortcuts.toggle_read_status": "切换已读/未读状态",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "切换已读/未读状态, 关注下一个",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "切换已读/未读状态, 关注前一个",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "在后台更新全部源",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "标记当前页已读",
|
||||
"page.keyboard_shortcuts.download_content": "下载原始内容",
|
||||
"page.keyboard_shortcuts.download_content": "抓取全文内容",
|
||||
"page.keyboard_shortcuts.toggle_bookmark_status": "切换收藏状态",
|
||||
"page.keyboard_shortcuts.save_article": "保存文章",
|
||||
"page.keyboard_shortcuts.scroll_item_to_top": "滚动到顶部",
|
||||
"page.keyboard_shortcuts.remove_feed": "删除此Feed",
|
||||
"page.keyboard_shortcuts.go_to_search": "将重点放在搜索表单上",
|
||||
"page.keyboard_shortcuts.close_modal": "关闭模态对话窗口",
|
||||
"page.keyboard_shortcuts.remove_feed": "删除此源",
|
||||
"page.keyboard_shortcuts.go_to_search": "将焦点放在搜索表单上",
|
||||
"page.keyboard_shortcuts.close_modal": "关闭对话窗口",
|
||||
"page.users.title": "用户",
|
||||
"page.users.username": "用户名",
|
||||
"page.users.never_logged": "从未登陆",
|
||||
"page.users.never_logged": "从未登录",
|
||||
"page.users.admin.yes": "是",
|
||||
"page.users.admin.no": "否",
|
||||
"page.users.actions": "操作",
|
||||
@@ -170,9 +174,9 @@
|
||||
"page.settings.unlink_google_account": "解除 Google 账号关联",
|
||||
"page.settings.link_oidc_account": "关联我的 OpenID Connect 账户",
|
||||
"page.settings.unlink_oidc_account": "解除 OpenID Connect 账号关联",
|
||||
"page.login.title": "登陆",
|
||||
"page.login.google_signin": "使用 Google 登陆",
|
||||
"page.login.oidc_signin": "使用 OpenID Connect 登陆",
|
||||
"page.login.title": "登录",
|
||||
"page.login.google_signin": "使用 Google 登录",
|
||||
"page.login.oidc_signin": "使用 OpenID Connect 登录",
|
||||
"page.integrations.title": "集成",
|
||||
"page.integration.miniflux_api": "Miniflux API",
|
||||
"page.integration.miniflux_api_endpoint": "API Endpoint",
|
||||
@@ -180,42 +184,46 @@
|
||||
"page.integration.miniflux_api_password": "密码",
|
||||
"page.integration.miniflux_api_password_value": "您账户的密码",
|
||||
"page.integration.bookmarklet": "书签小应用",
|
||||
"page.integration.bookmarklet.name": "新增到Miniflux",
|
||||
"page.integration.bookmarklet.instructions": "拖动这个链接到书签",
|
||||
"page.integration.bookmarklet.help": "你可以打开这个特殊的书签来直接订阅网站",
|
||||
"page.integration.bookmarklet.name": "收藏 Miniflux",
|
||||
"page.integration.bookmarklet.instructions": "拖动这个链接到浏览器书签栏",
|
||||
"page.integration.bookmarklet.help": "你可以打开这个特殊的书签来直接收藏网站",
|
||||
"page.sessions.title": "会话",
|
||||
"page.sessions.table.date": "日期",
|
||||
"page.sessions.table.ip": "IP 地址",
|
||||
"page.sessions.table.user_agent": "User-Agent",
|
||||
"page.sessions.table.user_agent": "用户代理",
|
||||
"page.sessions.table.actions": "操作",
|
||||
"page.sessions.table.current_session": "当前会话",
|
||||
"page.api_keys.title": "API密钥",
|
||||
"page.api_keys.title": "API 密钥",
|
||||
"page.api_keys.table.description": "描述",
|
||||
"page.api_keys.table.token": "密钥",
|
||||
"page.api_keys.table.last_used_at": "最后使用",
|
||||
"page.api_keys.table.created_at": "创立日期",
|
||||
"page.api_keys.table.created_at": "创建日期",
|
||||
"page.api_keys.table.actions": "操作",
|
||||
"page.api_keys.never_used": "没用过",
|
||||
"page.new_api_key.title": "新的API密钥",
|
||||
"alert.no_shared_entry": "没有共享条目。",
|
||||
"alert.no_bookmark": "目前没有书签",
|
||||
"page.new_api_key.title": "新的 API 密钥",
|
||||
"page.offline.title": "离线模式",
|
||||
"page.offline.message": "您已离线",
|
||||
"page.offline.refresh_page": "尝试刷新页面",
|
||||
"alert.no_shared_entry": "没有分享文章。",
|
||||
"alert.no_bookmark": "目前没有收藏",
|
||||
"alert.no_category": "目前没有分类",
|
||||
"alert.no_category_entry": "该分类下没有文章",
|
||||
"alert.no_feed_entry": "该源中没有文章",
|
||||
"alert.no_feed": "目前没有订阅",
|
||||
"alert.no_feed": "目前没有源",
|
||||
"alert.no_history": "目前没有历史",
|
||||
"alert.feed_error": "该源存在问题",
|
||||
"alert.no_search_result": "该搜索没有结果",
|
||||
"alert.no_feed_in_category": "没有该类别的订阅。",
|
||||
"alert.no_feed_in_category": "没有该类别的源。",
|
||||
"alert.no_unread_entry": "目前没有未读文章",
|
||||
"alert.no_user": "您是目前仅有的用户",
|
||||
"alert.account_unlinked": "您的外部帐户现已解除关联!",
|
||||
"alert.account_linked": "您的外部账号已关联!",
|
||||
"alert.pocket_linked": "您的Pocket帐户现已关联",
|
||||
"alert.pocket_linked": "您的 Pocket 帐户现已关联",
|
||||
"alert.prefs_saved": "设置已存储!",
|
||||
"error.unlink_account_without_password": "您必须定义密码,否则您将无法再次登录。",
|
||||
"error.unlink_account_without_password": "您必须设置密码,否则您将无法再次登录。",
|
||||
"error.duplicate_linked_account": "该 Provider 已被关联!",
|
||||
"error.duplicate_fever_username": "Fever 用户名已被占用!",
|
||||
"error.duplicate_googlereader_username": "Google Reader 用户名已被占用!",
|
||||
"error.pocket_request_token": "无法从 Pocket 获取请求令牌!",
|
||||
"error.pocket_access_token": "无法从 Pocket 获取访问令牌!",
|
||||
"error.category_already_exists": "分类已存在",
|
||||
@@ -225,93 +233,120 @@
|
||||
"error.unable_to_create_user": "无法创建此用户",
|
||||
"error.unable_to_update_user": "无法更新此用户",
|
||||
"error.unable_to_update_feed": "无法更新此源",
|
||||
"error.subscription_not_found": "找不到任何订阅",
|
||||
"error.subscription_not_found": "找不到任何源",
|
||||
"error.empty_file": "该文件为空",
|
||||
"error.bad_credentials": "用户名或密码无效",
|
||||
"error.fields_mandatory": "必须填写全部信息",
|
||||
"error.title_required": "必须填写标题",
|
||||
"error.different_passwords": "两次输入的密码不同",
|
||||
"error.password_min_length": "请至少使用6个字符",
|
||||
"error.password_min_length": "请至少输入 6 个字符",
|
||||
"error.settings_mandatory_fields": "必须填写用户名、主题、语言以及时区",
|
||||
"error.entries_per_page_invalid": "每页的条目数无效。",
|
||||
"error.feed_mandatory_fields": "必须填写 URL 和分类",
|
||||
"error.feed_already_exists": "此供稿已存在。",
|
||||
"error.invalid_feed_url": "供稿网址无效。",
|
||||
"error.invalid_site_url": "无效的网站网址。",
|
||||
"error.feed_url_not_empty": "供稿网址不能为空。",
|
||||
"error.site_url_not_empty": "网站网址不能为空。",
|
||||
"error.feed_title_not_empty": "供稿标题不能为空。",
|
||||
"error.entries_per_page_invalid": "每页的文章数无效。",
|
||||
"error.feed_mandatory_fields": "必须填写网址和分类",
|
||||
"error.feed_already_exists": "此源已存在。",
|
||||
"error.invalid_feed_url": "订阅源的网址无效。",
|
||||
"error.invalid_site_url": "源网站的网址无效。",
|
||||
"error.feed_url_not_empty": "订阅源的网址不能为空。",
|
||||
"error.site_url_not_empty": "源网站的网址不能为空。",
|
||||
"error.feed_title_not_empty": "订阅源的标题不能为空。",
|
||||
"error.feed_category_not_found": "此类别不存在或不属于该用户。",
|
||||
"error.feed_invalid_blocklist_rule": "阻止列表规则无效。",
|
||||
"error.feed_invalid_keeplist_rule": "保留列表规则无效。",
|
||||
"error.user_mandatory_fields": "必须填写用户名",
|
||||
"error.api_key_already_exists": "此API密钥已存在。",
|
||||
"error.unable_to_create_api_key": "无法创建此API密钥。",
|
||||
"error.api_key_already_exists": "此 API 密钥已存在。",
|
||||
"error.unable_to_create_api_key": "无法创建此 API 密钥。",
|
||||
"error.invalid_theme": "无效的主题。",
|
||||
"error.invalid_language": "语言无效。",
|
||||
"error.invalid_language": "无效的语言。",
|
||||
"error.invalid_timezone": "无效的时区。",
|
||||
"error.invalid_entry_direction": "无效的输入方向。",
|
||||
"error.invalid_display_mode": "无效的网页应用显示模式。",
|
||||
"form.feed.label.title": "标题",
|
||||
"form.feed.label.site_url": "站点 URL",
|
||||
"form.feed.label.feed_url": "源 URL",
|
||||
"form.feed.label.site_url": "源网站 URL",
|
||||
"form.feed.label.feed_url": "订阅源 URL",
|
||||
"form.feed.label.category": "类别",
|
||||
"form.feed.label.crawler": "获取原始内容",
|
||||
"form.feed.label.crawler": "抓取全文内容",
|
||||
"form.feed.label.feed_username": "源用户名",
|
||||
"form.feed.label.feed_password": "源密码",
|
||||
"form.feed.label.user_agent": "覆盖默认 User-Agent",
|
||||
"form.feed.label.scraper_rules": "Scraper 规则",
|
||||
"form.feed.label.user_agent": "覆盖默认的用户代理",
|
||||
"form.feed.label.cookie": "设置 Cookies",
|
||||
"form.feed.label.scraper_rules": "抓取规则",
|
||||
"form.feed.label.rewrite_rules": "重写规则",
|
||||
"form.feed.label.blocklist_rules": "封锁规则",
|
||||
"form.feed.label.keeplist_rules": "许可规则",
|
||||
"form.feed.label.ignore_http_cache": "忽略HTTP缓存",
|
||||
"form.feed.label.blocklist_rules": "阻止规则",
|
||||
"form.feed.label.keeplist_rules": "保留规则",
|
||||
"form.feed.label.ignore_http_cache": "忽略 HTTP 缓存",
|
||||
"form.feed.label.allow_self_signed_certificates": "允许自签名证书或无效证书",
|
||||
"form.feed.label.fetch_via_proxy": "通过代理获取",
|
||||
"form.feed.label.disabled": "请勿刷新此Feed",
|
||||
"form.feed.label.disabled": "请勿刷新此源",
|
||||
"form.feed.label.hide_globally": "隐藏全局未读列表中的文章",
|
||||
"form.category.label.title": "标题",
|
||||
"form.category.hide_globally": "隐藏全局未读列表中的文章",
|
||||
"form.user.label.username": "用户名",
|
||||
"form.user.label.password": "密码",
|
||||
"form.user.label.confirmation": "确认",
|
||||
"form.user.label.confirmation": "再次输入密码",
|
||||
"form.user.label.admin": "管理员",
|
||||
"form.prefs.label.language": "语言",
|
||||
"form.prefs.label.timezone": "时区",
|
||||
"form.prefs.label.theme": "主题",
|
||||
"form.prefs.label.entry_sorting": "内容排序",
|
||||
"form.prefs.label.entries_per_page": "每页条目",
|
||||
"form.prefs.label.entry_sorting": "文章排序",
|
||||
"form.prefs.label.entries_per_page": "每页文章数",
|
||||
"form.prefs.label.display_mode": "渐进式网页应用显示模式(需要重新添加)",
|
||||
"form.prefs.select.older_first": "旧->新",
|
||||
"form.prefs.select.recent_first": "新->旧",
|
||||
"form.prefs.select.fullscreen": "全屏",
|
||||
"form.prefs.select.standalone": "独立",
|
||||
"form.prefs.select.minimal_ui": "最小",
|
||||
"form.prefs.select.browser": "浏览器",
|
||||
"form.prefs.select.publish_time": "文章发布时间",
|
||||
"form.prefs.select.created_time": "文章创建时间",
|
||||
"form.prefs.label.keyboard_shortcuts": "启用键盘快捷键",
|
||||
"form.prefs.label.entry_swipe": "在移动设备上的条目上启用滑动手势",
|
||||
"form.prefs.label.entry_swipe": "在移动设备上启用滑动手势",
|
||||
"form.prefs.label.show_reading_time": "显示文章的预计阅读时间",
|
||||
"form.prefs.label.custom_css": "自定义CSS",
|
||||
"form.prefs.label.custom_css": "自定义 CSS",
|
||||
"form.prefs.label.entry_order": "文章排序依据",
|
||||
"form.import.label.file": "OPML 文件",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "启用 Fever API",
|
||||
"form.integration.fever_username": "Fever 用户名",
|
||||
"form.integration.fever_password": "Fever 密码",
|
||||
"form.integration.fever_endpoint": "Fever API endpoint:",
|
||||
"form.integration.fever_endpoint": "Fever API 端点",
|
||||
"form.integration.googlereader_activate": "启用 Google Reader API",
|
||||
"form.integration.googlereader_username": "Google Reader 用户名",
|
||||
"form.integration.googlereader_password": "Google Reader 密码",
|
||||
"form.integration.googlereader_endpoint": "Google Reader API 端点:",
|
||||
"form.integration.pinboard_activate": "保存文章到 Pinboard",
|
||||
"form.integration.pinboard_token": "Pinboard API Token",
|
||||
"form.integration.pinboard_tags": "Pinboard 标签",
|
||||
"form.integration.pinboard_bookmark": "标记为未读",
|
||||
"form.integration.instapaper_activate": "保存文章到Instapaper",
|
||||
"form.integration.instapaper_activate": "保存文章到 Instapaper",
|
||||
"form.integration.instapaper_username": "Instapaper 用户名",
|
||||
"form.integration.instapaper_password": "Instapaper 密码",
|
||||
"form.integration.pocket_activate": "将文章保存到Pocket",
|
||||
"form.integration.pocket_activate": "将文章保存到 Pocket",
|
||||
"form.integration.pocket_consumer_key": "Pocket 用户密钥",
|
||||
"form.integration.pocket_access_token": "Pocket Access Token",
|
||||
"form.integration.pocket_access_token": "Pocket 访问密钥",
|
||||
"form.integration.pocket_connect_link": "连接您的 Pocket 帐户",
|
||||
"form.integration.wallabag_activate": "保存文章到 Wallabag",
|
||||
"form.integration.wallabag_endpoint": "Wallabag URL",
|
||||
"form.integration.wallabag_client_id": "Wallabag 客户端ID",
|
||||
"form.integration.wallabag_client_id": "Wallabag 客户端 ID",
|
||||
"form.integration.wallabag_client_secret": "Wallabag 客户端 Secret",
|
||||
"form.integration.wallabag_username": "Wallabag 用户名",
|
||||
"form.integration.wallabag_password": "Wallabag 密码",
|
||||
"form.integration.nunux_keeper_activate": "保存文章到 Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "Nunux Keeper API Endpoint",
|
||||
"form.integration.nunux_keeper_endpoint": "Nunux Keeper API 端点",
|
||||
"form.integration.nunux_keeper_api_key": "Nunux Keeper API 密钥",
|
||||
"form.integration.espial_activate": "保存文章到 Espial",
|
||||
"form.integration.espial_endpoint": "Espial API 端点",
|
||||
"form.integration.espial_api_key": "Espial API 密钥",
|
||||
"form.integration.espial_tags": "Espial 标签",
|
||||
"form.integration.telegram_bot_activate": "将新文章推送到 Telegram",
|
||||
"form.integration.telegram_bot_token": "机器人令牌",
|
||||
"form.integration.telegram_chat_id": "聊天ID",
|
||||
"form.integration.linkding_activate": "保存文章到 Linkding",
|
||||
"form.integration.linkding_endpoint": "Linkding API 端点",
|
||||
"form.integration.linkding_api_key": "Linkding API 密钥",
|
||||
"form.api_key.label.description": "API密钥标签",
|
||||
"form.submit.loading": "载入中…",
|
||||
"form.submit.saving": "保存中…",
|
||||
"time_elapsed.not_yet": "尚未",
|
||||
"time_elapsed.not_yet": "未来",
|
||||
"time_elapsed.yesterday": "昨天",
|
||||
"time_elapsed.now": "刚刚",
|
||||
"time_elapsed.minutes": [
|
||||
@@ -337,17 +372,17 @@
|
||||
"Unable to open this link: %v": "无法打开这一链接: %v",
|
||||
"Unable to analyze this page: %v": "无法分析这一页面: %v",
|
||||
"Unable to execute request: %v": "无法执行这一请求: %v",
|
||||
"Unable to parse OPML file: %q": "无法解析OPML文件: %q",
|
||||
"Unable to parse RSS feed: %q": "无法解析RSS源: %q",
|
||||
"Unable to parse Atom feed: %q": "无法解析Atom源: %q",
|
||||
"Unable to parse JSON feed: %q": "无法解析JSON源: %q",
|
||||
"Unable to parse RDF feed: %q": "无法解析RDF源: %q",
|
||||
"Unable to parse OPML file: %q": "无法解析 OPML 文件: %q",
|
||||
"Unable to parse RSS feed: %q": "无法解析 RSS 源: %q",
|
||||
"Unable to parse Atom feed: %q": "无法解析 Atom 源: %q",
|
||||
"Unable to parse JSON feed: %q": "无法解析 JSON 源: %q",
|
||||
"Unable to parse RDF feed: %q": "无法解析 RDF 源: %q",
|
||||
"Unable to read data: %q": "无法读取数据: %q",
|
||||
"Unable to normalize encoding: %q": "无法正则化编码: %q",
|
||||
"Category not found for this user": "未找到该用户的这一分类",
|
||||
"This feed is empty": "该源是空的",
|
||||
"This web page is empty": "该网页是空的",
|
||||
"Invalid SSL certificate (original error: %q)": "无效的SSL证书 (原始错误: %q)",
|
||||
"Invalid SSL certificate (original error: %q)": "无效的 SSL 证书 (原始错误: %q)",
|
||||
"This website is temporarily unreachable (original error: %q)": "该网站暂时不可达 (原始错误: %q)",
|
||||
"This website is permanently unreachable (original error: %q)": "该网站永久不可达 (原始错误: %q)",
|
||||
"Website unreachable, the request timed out after %d seconds": "网站不可达, 请求已在 %d 秒后超时"
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
{
|
||||
"confirm.question": "您確認嗎?",
|
||||
"confirm.yes": "是",
|
||||
"confirm.no": "否",
|
||||
"confirm.loading": "執行中…",
|
||||
"action.subscribe": "訂閱",
|
||||
"action.save": "儲存",
|
||||
"action.or": "或",
|
||||
"action.cancel": "取消",
|
||||
"action.remove": "刪除",
|
||||
"action.remove_feed": "刪除此Feed",
|
||||
"action.update": "更新",
|
||||
"action.edit": "編輯",
|
||||
"action.download": "下載",
|
||||
"action.import": "匯入",
|
||||
"action.login": "登入",
|
||||
"action.home_screen": "新增到主螢幕",
|
||||
"tooltip.keyboard_shortcuts": "快捷鍵: %s",
|
||||
"tooltip.logged_user": "當前登入 %s",
|
||||
"menu.unread": "未讀",
|
||||
"menu.starred": "收藏",
|
||||
"menu.history": "歷史",
|
||||
"menu.feeds": "Feeds",
|
||||
"menu.categories": "分類",
|
||||
"menu.settings": "設定",
|
||||
"menu.logout": "登出",
|
||||
"menu.preferences": "設定",
|
||||
"menu.integrations": "整合",
|
||||
"menu.sessions": "會話",
|
||||
"menu.users": "使用者",
|
||||
"menu.about": "關於",
|
||||
"menu.export": "匯出",
|
||||
"menu.import": "匯入",
|
||||
"menu.create_category": "新建分類",
|
||||
"menu.mark_page_as_read": "將此頁面標記為已讀",
|
||||
"menu.mark_all_as_read": "全部標為已讀",
|
||||
"menu.show_all_entries": "顯示所有文章",
|
||||
"menu.show_only_unread_entries": "僅顯示未讀文章",
|
||||
"menu.refresh_feed": "更新",
|
||||
"menu.refresh_all_feeds": "背景更新全部Feeds",
|
||||
"menu.edit_feed": "編輯",
|
||||
"menu.edit_category": "編輯",
|
||||
"menu.add_feed": "新增Feed",
|
||||
"menu.add_user": "新建使用者",
|
||||
"menu.flush_history": "清理歷史",
|
||||
"menu.feed_entries": "文章",
|
||||
"menu.api_keys": "API 金鑰",
|
||||
"menu.create_api_key": "建立一個新的 API 金鑰",
|
||||
"menu.shared_entries": "分享文章",
|
||||
"search.label": "搜尋",
|
||||
"search.placeholder": "搜尋…",
|
||||
"pagination.next": "下一頁",
|
||||
"pagination.previous": "上一頁",
|
||||
"entry.status.unread": "標為未讀",
|
||||
"entry.status.read": "標為已讀",
|
||||
"entry.status.toast.unread": "已標為未讀",
|
||||
"entry.status.toast.read": "已標為已讀",
|
||||
"entry.status.title": "更改狀態",
|
||||
"entry.bookmark.toggle.on": "新增收藏",
|
||||
"entry.bookmark.toggle.off": "取消收藏",
|
||||
"entry.bookmark.toast.on": "已新增收藏",
|
||||
"entry.bookmark.toast.off": "已取消收藏",
|
||||
"entry.state.saving": "儲存中…",
|
||||
"entry.state.loading": "載入中…",
|
||||
"entry.save.label": "儲存",
|
||||
"entry.save.title": "儲存這篇文章",
|
||||
"entry.save.completed": "完成",
|
||||
"entry.save.toast.completed": "已儲存文章",
|
||||
"entry.scraper.label": "下載原文",
|
||||
"entry.scraper.title": "下載原文內容",
|
||||
"entry.scraper.completed": "下載完成",
|
||||
"entry.external_link.label": "外部連結",
|
||||
"entry.comments.label": "評論",
|
||||
"entry.comments.title": "檢視評論",
|
||||
"entry.share.label": "分享",
|
||||
"entry.share.title": "分享這篇文章",
|
||||
"entry.unshare.label": "取消分享",
|
||||
"entry.shared_entry.title": "開啟公共連結",
|
||||
"entry.shared_entry.label": "分享",
|
||||
"entry.estimated_reading_time": [
|
||||
"需要 %d 分鐘閱讀",
|
||||
"需要 %d 分鐘閱讀"
|
||||
],
|
||||
"page.shared_entries.title": "分享文章",
|
||||
"page.unread.title": "未讀",
|
||||
"page.starred.title": "收藏",
|
||||
"page.categories.title": "分類",
|
||||
"page.categories.no_feed": "沒有Feed",
|
||||
"page.categories.entries": "檢視內容",
|
||||
"page.categories.feeds": "檢視Feeds",
|
||||
"page.categories.feed_count": [
|
||||
"有 %d 個Feed",
|
||||
"有 %d 個Feeds"
|
||||
],
|
||||
"page.categories.unread_counter": "未讀文章數",
|
||||
"page.new_category.title": "新分類",
|
||||
"page.new_user.title": "新使用者",
|
||||
"page.edit_category.title": "編輯分類 : %s",
|
||||
"page.edit_user.title": "編輯使用者 : %s",
|
||||
"page.feeds.title": "Feeds",
|
||||
"page.feeds.last_check": "最後檢查時間:",
|
||||
"page.feeds.unread_counter": "未讀文章數",
|
||||
"page.feeds.read_counter": "已讀文章數",
|
||||
"page.feeds.error_count": [
|
||||
"%d 錯誤",
|
||||
"%d 錯誤"
|
||||
],
|
||||
"page.history.title": "歷史",
|
||||
"page.import.title": "匯入",
|
||||
"page.search.title": "搜尋結果",
|
||||
"page.about.title": "關於",
|
||||
"page.about.credits": "版權",
|
||||
"page.about.version": "版本號:",
|
||||
"page.about.build_date": "構建日期:",
|
||||
"page.about.author": "作者:",
|
||||
"page.about.license": "授權:",
|
||||
"page.about.postgres_version": "Postgres 版本號:",
|
||||
"page.about.go_version": "Go 版本號:",
|
||||
"page.about.global_config_options": "全域性配置選項",
|
||||
"page.add_feed.title": "新增Feed",
|
||||
"page.add_feed.no_category": "沒有類別,至少需要有一個類別",
|
||||
"page.add_feed.label.url": "網址",
|
||||
"page.add_feed.submit": "查詢Feed",
|
||||
"page.add_feed.legend.advanced_options": "高階選項",
|
||||
"page.add_feed.choose_feed": "選擇一個Feed",
|
||||
"page.edit_feed.title": "編輯Feed : %s",
|
||||
"page.edit_feed.last_check": "最後檢查時間:",
|
||||
"page.edit_feed.last_modified_header": "最後修改的 Header:",
|
||||
"page.edit_feed.etag_header": "ETag 標題:",
|
||||
"page.edit_feed.no_header": "無 Header",
|
||||
"page.edit_feed.last_parsing_error": "最後一次解析錯誤",
|
||||
"page.entry.attachments": "附件",
|
||||
"page.keyboard_shortcuts.title": "快捷鍵",
|
||||
"page.keyboard_shortcuts.subtitle.sections": "分割槽導航",
|
||||
"page.keyboard_shortcuts.subtitle.items": "文章導航",
|
||||
"page.keyboard_shortcuts.subtitle.pages": "頁面導航",
|
||||
"page.keyboard_shortcuts.subtitle.actions": "操作",
|
||||
"page.keyboard_shortcuts.go_to_unread": "開啟未讀頁面",
|
||||
"page.keyboard_shortcuts.go_to_starred": "開啟收藏頁面",
|
||||
"page.keyboard_shortcuts.go_to_history": "開啟歷史頁面",
|
||||
"page.keyboard_shortcuts.go_to_feeds": "開啟Feed頁面",
|
||||
"page.keyboard_shortcuts.go_to_categories": "開啟分類頁面",
|
||||
"page.keyboard_shortcuts.go_to_settings": "開啟設定頁面",
|
||||
"page.keyboard_shortcuts.show_keyboard_shortcuts": "顯示快捷鍵幫助",
|
||||
"page.keyboard_shortcuts.go_to_previous_item": "上一文章",
|
||||
"page.keyboard_shortcuts.go_to_next_item": "下一文章",
|
||||
"page.keyboard_shortcuts.go_to_feed": "轉到Feed頁面",
|
||||
"page.keyboard_shortcuts.go_to_previous_page": "上一頁",
|
||||
"page.keyboard_shortcuts.go_to_next_page": "下一頁",
|
||||
"page.keyboard_shortcuts.open_item": "開啟選定的文章",
|
||||
"page.keyboard_shortcuts.open_original": "開啟原始連結",
|
||||
"page.keyboard_shortcuts.open_original_same_window": "在當前標籤頁中開啟原始連結",
|
||||
"page.keyboard_shortcuts.open_comments": "開啟評論連結",
|
||||
"page.keyboard_shortcuts.open_comments_same_window": "在當前標籤頁中開啟評論連結",
|
||||
"page.keyboard_shortcuts.toggle_read_status_next": "切換已讀/未讀狀態, 關注下一個",
|
||||
"page.keyboard_shortcuts.toggle_read_status_prev": "切換已讀/未讀狀態, 關注前一個",
|
||||
"page.keyboard_shortcuts.refresh_all_feeds": "背景更新全部Feeds",
|
||||
"page.keyboard_shortcuts.mark_page_as_read": "將此頁面標記為已讀",
|
||||
"page.keyboard_shortcuts.download_content": "下載原文內容",
|
||||
"page.keyboard_shortcuts.toggle_bookmark_status": "切換收藏狀態",
|
||||
"page.keyboard_shortcuts.save_article": "儲存文章",
|
||||
"page.keyboard_shortcuts.scroll_item_to_top": "滾動到頂部",
|
||||
"page.keyboard_shortcuts.remove_feed": "刪除此Feed",
|
||||
"page.keyboard_shortcuts.go_to_search": "將焦點放在搜尋表單上",
|
||||
"page.keyboard_shortcuts.close_modal": "關閉對話視窗",
|
||||
"page.users.title": "使用者",
|
||||
"page.users.username": "使用者名稱",
|
||||
"page.users.never_logged": "從未登入",
|
||||
"page.users.admin.yes": "是",
|
||||
"page.users.admin.no": "否",
|
||||
"page.users.actions": "操作",
|
||||
"page.users.last_login": "最後登入時間",
|
||||
"page.users.is_admin": "管理員",
|
||||
"page.settings.title": "設定",
|
||||
"page.settings.link_google_account": "關聯我的 Google 賬戶",
|
||||
"page.settings.unlink_google_account": "解除 Google 帳號關聯",
|
||||
"page.settings.link_oidc_account": "關聯我的 OpenID Connect 賬戶",
|
||||
"page.settings.unlink_oidc_account": "解除 OpenID Connect 帳號關聯",
|
||||
"page.login.title": "登入",
|
||||
"page.login.google_signin": "使用 Google 登入",
|
||||
"page.login.oidc_signin": "使用 OpenID Connect 登入",
|
||||
"page.integrations.title": "整合",
|
||||
"page.integration.miniflux_api": "Miniflux API",
|
||||
"page.integration.miniflux_api_endpoint": "API Endpoint",
|
||||
"page.integration.miniflux_api_username": "使用者名稱",
|
||||
"page.integration.miniflux_api_password": "密碼",
|
||||
"page.integration.miniflux_api_password_value": "您帳號的密碼",
|
||||
"page.integration.bookmarklet": "書籤小應用",
|
||||
"page.integration.bookmarklet.name": "收藏 Miniflux",
|
||||
"page.integration.bookmarklet.instructions": "拖動這個連結到瀏覽器書籤欄",
|
||||
"page.integration.bookmarklet.help": "你可以開啟這個特殊的書籤來直接收藏網站",
|
||||
"page.sessions.title": "會話",
|
||||
"page.sessions.table.date": "日期",
|
||||
"page.sessions.table.ip": "IP 地址",
|
||||
"page.sessions.table.user_agent": "使用者代理",
|
||||
"page.sessions.table.actions": "操作",
|
||||
"page.sessions.table.current_session": "當前會話",
|
||||
"page.api_keys.title": "API 金鑰",
|
||||
"page.api_keys.table.description": "描述",
|
||||
"page.api_keys.table.token": "金鑰",
|
||||
"page.api_keys.table.last_used_at": "最後使用",
|
||||
"page.api_keys.table.created_at": "建立日期",
|
||||
"page.api_keys.table.actions": "操作",
|
||||
"page.api_keys.never_used": "沒用過",
|
||||
"page.new_api_key.title": "新的 API 金鑰",
|
||||
"page.offline.title": "離線模式",
|
||||
"page.offline.message": "您已離線",
|
||||
"page.offline.refresh_page": "嘗試重新整理頁面",
|
||||
"alert.no_shared_entry": "沒有分享文章。",
|
||||
"alert.no_bookmark": "目前沒有收藏",
|
||||
"alert.no_category": "目前沒有分類",
|
||||
"alert.no_category_entry": "該分類下沒有文章",
|
||||
"alert.no_feed_entry": "該Feed中沒有文章",
|
||||
"alert.no_feed": "目前沒有Feed",
|
||||
"alert.no_history": "目前沒有歷史",
|
||||
"alert.feed_error": "該Feed存在問題",
|
||||
"alert.no_search_result": "該搜尋沒有結果",
|
||||
"alert.no_feed_in_category": "沒有該類別的Feed。",
|
||||
"alert.no_unread_entry": "目前沒有未讀文章",
|
||||
"alert.no_user": "您是唯一的使用者",
|
||||
"alert.account_unlinked": "您的外部帳戶現已解除關聯!",
|
||||
"alert.account_linked": "您的外部帳號已關聯!",
|
||||
"alert.pocket_linked": "您的 Pocket 帳戶現已關聯",
|
||||
"alert.prefs_saved": "設定已儲存!",
|
||||
"error.unlink_account_without_password": "您必須設定密碼,否則您將無法再次登入。",
|
||||
"error.duplicate_linked_account": "該 Provider 已被關聯!",
|
||||
"error.duplicate_fever_username": "Fever 使用者名稱已被佔用!",
|
||||
"error.duplicate_googlereader_username": "Google Reader 使用者名稱已被佔用!",
|
||||
"error.pocket_request_token": "無法從 Pocket 獲取請求令牌!",
|
||||
"error.pocket_access_token": "無法從 Pocket 獲取訪問令牌!",
|
||||
"error.category_already_exists": "分類已存在",
|
||||
"error.unable_to_create_category": "無法建立這個分類",
|
||||
"error.unable_to_update_category": "無法更新該分類",
|
||||
"error.user_already_exists": "使用者已存在",
|
||||
"error.unable_to_create_user": "無法建立此使用者",
|
||||
"error.unable_to_update_user": "無法更新此使用者",
|
||||
"error.unable_to_update_feed": "無法更新此源",
|
||||
"error.subscription_not_found": "找不到任何源",
|
||||
"error.empty_file": "該檔案為空",
|
||||
"error.bad_credentials": "使用者名稱或密碼無效",
|
||||
"error.fields_mandatory": "必須填寫全部資訊",
|
||||
"error.title_required": "必須填寫標題",
|
||||
"error.different_passwords": "兩次輸入的密碼不同",
|
||||
"error.password_min_length": "請至少輸入 6 個字元",
|
||||
"error.settings_mandatory_fields": "必須填寫使用者名稱、主題、語言以及時區",
|
||||
"error.entries_per_page_invalid": "每頁的文章數無效。",
|
||||
"error.feed_mandatory_fields": "必須填寫網址和分類",
|
||||
"error.feed_already_exists": "此Feed已存在。",
|
||||
"error.invalid_feed_url": "訂閱Feed的網址無效。",
|
||||
"error.invalid_site_url": "Feed網站的網址無效。",
|
||||
"error.feed_url_not_empty": "訂閱Feed的網址不能為空。",
|
||||
"error.site_url_not_empty": "Feed網站的網址不能為空。",
|
||||
"error.feed_title_not_empty": "訂閱Feed的標題不能為空。",
|
||||
"error.feed_category_not_found": "此類別不存在或不屬於該使用者。",
|
||||
"error.feed_invalid_blocklist_rule": "阻止列表規則無效。",
|
||||
"error.feed_invalid_keeplist_rule": "保留列表規則無效。",
|
||||
"error.user_mandatory_fields": "必須填寫使用者名稱",
|
||||
"error.api_key_already_exists": "此 API 金鑰已存在。",
|
||||
"error.unable_to_create_api_key": "無法建立此 API 金鑰。",
|
||||
"error.invalid_theme": "無效的主題。",
|
||||
"error.invalid_language": "無效的語言。",
|
||||
"error.invalid_timezone": "無效的時區。",
|
||||
"error.invalid_entry_direction": "無效的輸入方向。",
|
||||
"error.invalid_display_mode": "無效的網頁應用顯示模式。",
|
||||
"form.feed.label.title": "標題",
|
||||
"form.feed.label.site_url": "網站 URL",
|
||||
"form.feed.label.feed_url": "訂閱Feed URL",
|
||||
"form.feed.label.category": "類別",
|
||||
"form.feed.label.crawler": "下載原文內容",
|
||||
"form.feed.label.feed_username": "Feed使用者名稱",
|
||||
"form.feed.label.feed_password": "Feed密碼",
|
||||
"form.feed.label.user_agent": "覆蓋預設的使用者代理",
|
||||
"form.feed.label.cookie": "設定 Cookies",
|
||||
"form.feed.label.scraper_rules": "抓取規則",
|
||||
"form.feed.label.rewrite_rules": "重寫規則",
|
||||
"form.feed.label.blocklist_rules": "過濾規則",
|
||||
"form.feed.label.keeplist_rules": "保留規則",
|
||||
"form.feed.label.ignore_http_cache": "忽略 HTTP 快取",
|
||||
"form.feed.label.allow_self_signed_certificates": "允許自簽章憑證或無效憑證",
|
||||
"form.feed.label.fetch_via_proxy": "透過代理獲取",
|
||||
"form.feed.label.disabled": "請勿重新整理此Feed",
|
||||
"form.feed.label.hide_globally": "隱藏全域性未讀列表中的文章",
|
||||
"form.category.label.title": "標題",
|
||||
"form.category.hide_globally": "隱藏全域性未讀列表中的文章",
|
||||
"form.user.label.username": "使用者名稱",
|
||||
"form.user.label.password": "密碼",
|
||||
"form.user.label.confirmation": "再次輸入密碼",
|
||||
"form.user.label.admin": "管理員",
|
||||
"form.prefs.label.language": "語言",
|
||||
"form.prefs.label.timezone": "時區",
|
||||
"form.prefs.label.theme": "主題",
|
||||
"form.prefs.label.entry_sorting": "文章排序",
|
||||
"form.prefs.label.entries_per_page": "每頁文章數",
|
||||
"form.prefs.label.display_mode": "漸進式網頁應用顯示模式(需要重新新增)",
|
||||
"form.prefs.select.older_first": "舊->新",
|
||||
"form.prefs.select.recent_first": "新->舊",
|
||||
"form.prefs.select.fullscreen": "全屏",
|
||||
"form.prefs.select.standalone": "獨立",
|
||||
"form.prefs.select.minimal_ui": "最小",
|
||||
"form.prefs.select.browser": "瀏覽器",
|
||||
"form.prefs.select.publish_time": "文章釋出時間",
|
||||
"form.prefs.select.created_time": "文章建立時間",
|
||||
"form.prefs.label.keyboard_shortcuts": "啟用鍵盤快捷鍵",
|
||||
"form.prefs.label.entry_swipe": "在移動裝置上啟用滑動手勢",
|
||||
"form.prefs.label.show_reading_time": "顯示文章的預計閱讀時間",
|
||||
"form.prefs.label.custom_css": "自定義 CSS",
|
||||
"form.prefs.label.entry_order": "文章排序依據",
|
||||
"form.import.label.file": "OPML 檔案",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "啟用 Fever API",
|
||||
"form.integration.fever_username": "Fever 使用者名稱",
|
||||
"form.integration.fever_password": "Fever 密碼",
|
||||
"form.integration.fever_endpoint": "Fever API 端點",
|
||||
"form.integration.googlereader_activate": "啟用 Google Reader API",
|
||||
"form.integration.googlereader_username": "Google Reader 使用者名稱",
|
||||
"form.integration.googlereader_password": "Google Reader 密碼",
|
||||
"form.integration.googlereader_endpoint": "Google Reader API 端點:",
|
||||
"form.integration.pinboard_activate": "儲存文章到 Pinboard",
|
||||
"form.integration.pinboard_token": "Pinboard API Token",
|
||||
"form.integration.pinboard_tags": "Pinboard 標籤",
|
||||
"form.integration.pinboard_bookmark": "標記為未讀",
|
||||
"form.integration.instapaper_activate": "儲存文章到 Instapaper",
|
||||
"form.integration.instapaper_username": "Instapaper 使用者名稱",
|
||||
"form.integration.instapaper_password": "Instapaper 密碼",
|
||||
"form.integration.pocket_activate": "將文章儲存到 Pocket",
|
||||
"form.integration.pocket_consumer_key": "Pocket 使用者金鑰",
|
||||
"form.integration.pocket_access_token": "Pocket 訪問金鑰",
|
||||
"form.integration.pocket_connect_link": "連線您的 Pocket 帳戶",
|
||||
"form.integration.wallabag_activate": "儲存文章到 Wallabag",
|
||||
"form.integration.wallabag_endpoint": "Wallabag URL",
|
||||
"form.integration.wallabag_client_id": "Wallabag 客戶端 ID",
|
||||
"form.integration.wallabag_client_secret": "Wallabag 客戶端 Secret",
|
||||
"form.integration.wallabag_username": "Wallabag 使用者名稱",
|
||||
"form.integration.wallabag_password": "Wallabag 密碼",
|
||||
"form.integration.nunux_keeper_activate": "儲存文章到 Nunux Keeper",
|
||||
"form.integration.nunux_keeper_endpoint": "Nunux Keeper API 端點",
|
||||
"form.integration.nunux_keeper_api_key": "Nunux Keeper API 金鑰",
|
||||
"form.integration.espial_activate": "儲存文章到 Espial",
|
||||
"form.integration.espial_endpoint": "Espial API 端點",
|
||||
"form.integration.espial_api_key": "Espial API 金鑰",
|
||||
"form.integration.espial_tags": "Espial 標籤",
|
||||
"form.integration.telegram_bot_activate": "將新文章推送到 Telegram",
|
||||
"form.integration.telegram_bot_token": "Bot token",
|
||||
"form.integration.telegram_chat_id": "Chat ID",
|
||||
"form.integration.linkding_activate": "儲存文章到 Linkding",
|
||||
"form.integration.linkding_endpoint": "Linkding API 端點",
|
||||
"form.integration.linkding_api_key": "Linkding API 金鑰",
|
||||
"form.api_key.label.description": "API金鑰標籤",
|
||||
"form.submit.loading": "載入中…",
|
||||
"form.submit.saving": "儲存中…",
|
||||
"time_elapsed.not_yet": "未來",
|
||||
"time_elapsed.yesterday": "昨天",
|
||||
"time_elapsed.now": "剛剛",
|
||||
"time_elapsed.minutes": [
|
||||
"%d 分鐘前",
|
||||
"%d 分鐘前"
|
||||
],
|
||||
"time_elapsed.hours": [
|
||||
"%d 小時前",
|
||||
"%d 小時前"
|
||||
],
|
||||
"time_elapsed.days": [
|
||||
"%d 天前",
|
||||
"%d 天前"
|
||||
],
|
||||
"time_elapsed.weeks": [
|
||||
"%d 周前",
|
||||
"%d 周前"
|
||||
],
|
||||
"time_elapsed.months": [
|
||||
"%d 月前",
|
||||
"%d 月前"
|
||||
],
|
||||
"time_elapsed.years": [
|
||||
"%d 年前",
|
||||
"%d 年前"
|
||||
],
|
||||
"This feed already exists (%s)": "Feed已存在 (%s)",
|
||||
"Unable to fetch feed (Status Code = %d)": "無法獲取Feed (錯誤程式碼=%d)",
|
||||
"Unable to open this link: %v": "無法開啟這一連結: %v",
|
||||
"Unable to analyze this page: %v": "無法分析這一頁面: %v",
|
||||
"Unable to execute request: %v": "無法執行這一請求: %v",
|
||||
"Unable to parse OPML file: %q": "無法解析 OPML 檔案: %q",
|
||||
"Unable to parse RSS feed: %q": "無法解析 RSS Feed: %q",
|
||||
"Unable to parse Atom feed: %q": "無法解析 Atom Feed: %q",
|
||||
"Unable to parse JSON feed: %q": "無法解析 JSON Feed: %q",
|
||||
"Unable to parse RDF feed: %q": "無法解析 RDF Feed: %q",
|
||||
"Unable to read data: %q": "無法讀取資料: %q",
|
||||
"Unable to normalize encoding: %q": "無法正則化編碼: %q",
|
||||
"Category not found for this user": "未找到該使用者的這一分類",
|
||||
"This feed is empty": "該Feed是空的",
|
||||
"This web page is empty": "該網頁是空的",
|
||||
"Invalid SSL certificate (original error: %q)": "無效的 SSL 憑證 (錯誤: %q)",
|
||||
"This website is temporarily unreachable (original error: %q)": "該網站暫時無法訪問 (原始錯誤: %q)",
|
||||
"This website is permanently unreachable (original error: %q)": "該網站永久無法訪問(原始錯誤: %q)",
|
||||
"Website unreachable, the request timed out after %d seconds": "網站無法訪問, 請求已在 %d 秒後超時"
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright 2018 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package locale // import "miniflux.app/locale"
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestAllLanguagesHaveCatalog(t *testing.T) {
|
||||
for language := range AvailableLanguages() {
|
||||
if _, found := translations[language]; !found {
|
||||
t.Fatalf(`This language do not have a catalog: %q`, language)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllKeysHaveValue(t *testing.T) {
|
||||
for language := range AvailableLanguages() {
|
||||
messages, err := parseTranslationDict(translations[language])
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing error for language %q`, language)
|
||||
}
|
||||
|
||||
if len(messages) == 0 {
|
||||
t.Fatalf(`The language %q doesn't have any messages`, language)
|
||||
}
|
||||
|
||||
for k, v := range messages {
|
||||
switch value := v.(type) {
|
||||
case string:
|
||||
if value == "" {
|
||||
t.Errorf(`The key %q for the language %q have an empty string as value`, k, language)
|
||||
}
|
||||
case []string:
|
||||
if len(value) == 0 {
|
||||
t.Errorf(`The key %q for the language %q have an empty list as value`, k, language)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMissingTranslations(t *testing.T) {
|
||||
refLang := "en_US"
|
||||
references, err := parseTranslationDict(translations[refLang])
|
||||
if err != nil {
|
||||
t.Fatal(`Unable to parse reference language`)
|
||||
}
|
||||
|
||||
for language := range AvailableLanguages() {
|
||||
if language == refLang {
|
||||
continue
|
||||
}
|
||||
|
||||
messages, err := parseTranslationDict(translations[language])
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing error for language %q`, language)
|
||||
}
|
||||
|
||||
for key := range references {
|
||||
if _, found := messages[key]; !found {
|
||||
t.Fatalf(`Translation key %q not found in language %q`, key, language)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,6 @@
|
||||
|
||||
package main // import "miniflux.app"
|
||||
|
||||
//go:generate go run generate.go
|
||||
//go:generate gofmt -s -w ui/static/css.go
|
||||
//go:generate gofmt -s -w ui/static/bin.go
|
||||
//go:generate gofmt -s -w ui/static/js.go
|
||||
//go:generate gofmt -s -w template/views.go
|
||||
//go:generate gofmt -s -w template/common.go
|
||||
//go:generate gofmt -s -w locale/translations.go
|
||||
|
||||
import (
|
||||
"miniflux.app/cli"
|
||||
)
|
||||
|
||||
@@ -78,6 +78,62 @@ var (
|
||||
},
|
||||
[]string{"status"},
|
||||
)
|
||||
|
||||
dbOpenConnectionsGauge = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: "miniflux",
|
||||
Name: "db_open_connections",
|
||||
Help: "The number of established connections both in use and idle",
|
||||
},
|
||||
)
|
||||
|
||||
dbConnectionsInUseGauge = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: "miniflux",
|
||||
Name: "db_connections_in_use",
|
||||
Help: "The number of connections currently in use",
|
||||
},
|
||||
)
|
||||
|
||||
dbConnectionsIdleGauge = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: "miniflux",
|
||||
Name: "db_connections_idle",
|
||||
Help: "The number of idle connections",
|
||||
},
|
||||
)
|
||||
|
||||
dbConnectionsWaitCountGauge = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: "miniflux",
|
||||
Name: "db_connections_wait_count",
|
||||
Help: "The total number of connections waited for",
|
||||
},
|
||||
)
|
||||
|
||||
dbConnectionsMaxIdleClosedGauge = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: "miniflux",
|
||||
Name: "db_connections_max_idle_closed",
|
||||
Help: "The total number of connections closed due to SetMaxIdleConns",
|
||||
},
|
||||
)
|
||||
|
||||
dbConnectionsMaxIdleTimeClosedGauge = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: "miniflux",
|
||||
Name: "db_connections_max_idle_time_closed",
|
||||
Help: "The total number of connections closed due to SetConnMaxIdleTime",
|
||||
},
|
||||
)
|
||||
|
||||
dbConnectionsMaxLifetimeClosedGauge = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: "miniflux",
|
||||
Name: "db_connections_max_lifetime_closed",
|
||||
Help: "The total number of connections closed due to SetConnMaxLifetime",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
// Collector represents a metric collector.
|
||||
@@ -95,6 +151,13 @@ func NewCollector(store *storage.Storage, refreshInterval int) *Collector {
|
||||
prometheus.MustRegister(feedsGauge)
|
||||
prometheus.MustRegister(brokenFeedsGauge)
|
||||
prometheus.MustRegister(entriesGauge)
|
||||
prometheus.MustRegister(dbOpenConnectionsGauge)
|
||||
prometheus.MustRegister(dbConnectionsInUseGauge)
|
||||
prometheus.MustRegister(dbConnectionsIdleGauge)
|
||||
prometheus.MustRegister(dbConnectionsWaitCountGauge)
|
||||
prometheus.MustRegister(dbConnectionsMaxIdleClosedGauge)
|
||||
prometheus.MustRegister(dbConnectionsMaxIdleTimeClosedGauge)
|
||||
prometheus.MustRegister(dbConnectionsMaxLifetimeClosedGauge)
|
||||
|
||||
return &Collector{store, refreshInterval}
|
||||
}
|
||||
@@ -116,5 +179,14 @@ func (c *Collector) GatherStorageMetrics() {
|
||||
for status, count := range entriesCount {
|
||||
entriesGauge.WithLabelValues(status).Set(float64(count))
|
||||
}
|
||||
|
||||
dbStats := c.store.DBStats()
|
||||
dbOpenConnectionsGauge.Set(float64(dbStats.OpenConnections))
|
||||
dbConnectionsInUseGauge.Set(float64(dbStats.InUse))
|
||||
dbConnectionsIdleGauge.Set(float64(dbStats.Idle))
|
||||
dbConnectionsWaitCountGauge.Set(float64(dbStats.WaitCount))
|
||||
dbConnectionsMaxIdleClosedGauge.Set(float64(dbStats.MaxIdleClosed))
|
||||
dbConnectionsMaxIdleTimeClosedGauge.Set(float64(dbStats.MaxIdleTimeClosed))
|
||||
dbConnectionsMaxLifetimeClosedGauge.Set(float64(dbStats.MaxLifetimeClosed))
|
||||
}
|
||||
}
|
||||
|
||||
+36
-3
@@ -1,5 +1,5 @@
|
||||
.\" Manpage for miniflux.
|
||||
.TH "MINIFLUX" "1" "September 28, 2020" "\ \&" "\ \&"
|
||||
.TH "MINIFLUX" "1" "January 5, 2022" "\ \&" "\ \&"
|
||||
|
||||
.SH NAME
|
||||
miniflux \- Minimalist and opinionated feed reader
|
||||
@@ -43,6 +43,13 @@ Show debug logs\&.
|
||||
Flush all sessions (disconnect users)\&.
|
||||
.RE
|
||||
.PP
|
||||
.B \-healthcheck
|
||||
.RS 4
|
||||
Perform a health check on the given endpoint\&.
|
||||
.br
|
||||
The value "auto" try to guess the health check endpoint\&.
|
||||
.RE
|
||||
.PP
|
||||
.B \-i
|
||||
.RS 4
|
||||
Show application information\&.
|
||||
@@ -100,6 +107,12 @@ Set the value to 1 to enable debug logs\&.
|
||||
.br
|
||||
Disabled by default\&.
|
||||
.TP
|
||||
.B FETCH_YOUTUBE_WATCH_TIME
|
||||
Set the value to 1 to scrape video duration from YouTube website and
|
||||
use it as a reading time\&.
|
||||
.br
|
||||
Disabled by default\&.
|
||||
.TP
|
||||
.B SERVER_TIMING_HEADER
|
||||
Set the value to 1 to enable server-timing headers\&.
|
||||
.br
|
||||
@@ -123,7 +136,7 @@ Default is 60 minutes\&.
|
||||
.B BATCH_SIZE
|
||||
Number of feeds to send to the queue for each interval\&.
|
||||
.br
|
||||
Default is 10 feeds\&.
|
||||
Default is 100 feeds\&.
|
||||
.TP
|
||||
.B POLLING_SCHEDULER
|
||||
Scheduler used for polling feeds. Possible values are "round_robin" or "entry_frequency"\&.
|
||||
@@ -161,6 +174,11 @@ Path to a secret key exposed as a file, it should contain $DATABASE_URL value\&.
|
||||
.br
|
||||
Default is empty\&.
|
||||
.TP
|
||||
.B DATABASE_CONNECTION_LIFETIME
|
||||
Set the maximum amount of time a connection may be reused\&.
|
||||
.br
|
||||
Default is 5 minutes\&.
|
||||
.TP
|
||||
.B DATABASE_MAX_CONNS
|
||||
Maximum number of database connections\&.
|
||||
.br
|
||||
@@ -205,6 +223,11 @@ Set to -1 to keep all unread entries.
|
||||
.br
|
||||
Default is 180 days\&.
|
||||
.TP
|
||||
.B CLEANUP_ARCHIVE_BATCH_SIZE
|
||||
Number of entries to archive for each job interval\&.
|
||||
.br
|
||||
Default is 10000 entries\&.
|
||||
.TP
|
||||
.B CLEANUP_REMOVE_SESSIONS_DAYS
|
||||
Number of days after removing old sessions from the database\&.
|
||||
.br
|
||||
@@ -387,7 +410,17 @@ Disabled by default\&.
|
||||
.B MAINTENANCE_MESSAGE
|
||||
Define a custom maintenance message\&.
|
||||
.br
|
||||
Default is "Miniflux is currently under maintenance".
|
||||
Default is "Miniflux is currently under maintenance"\&.
|
||||
.TP
|
||||
.B WATCHDOG
|
||||
Enable or disable Systemd watchdog\&.
|
||||
.br
|
||||
Enabled by default\&.
|
||||
.TP
|
||||
.B INVIDIOUS_INSTANCE
|
||||
Set a custom invidious instance to use\&.
|
||||
.br
|
||||
Default is yewtu.be\&.
|
||||
|
||||
.SH AUTHORS
|
||||
.P
|
||||
|
||||
+9
-5
@@ -8,10 +8,12 @@ import "fmt"
|
||||
|
||||
// Category represents a feed category.
|
||||
type Category struct {
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
UserID int64 `json:"user_id"`
|
||||
FeedCount int `json:"-"`
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
UserID int64 `json:"user_id"`
|
||||
HideGlobally bool `json:"hide_globally"`
|
||||
FeedCount int `json:"-"`
|
||||
TotalUnread int `json:"-"`
|
||||
}
|
||||
|
||||
func (c *Category) String() string {
|
||||
@@ -20,12 +22,14 @@ func (c *Category) String() string {
|
||||
|
||||
// CategoryRequest represents the request to create or update a category.
|
||||
type CategoryRequest struct {
|
||||
Title string `json:"title"`
|
||||
Title string `json:"title"`
|
||||
HideGlobally string `json:"hide_globally"`
|
||||
}
|
||||
|
||||
// Patch updates category fields.
|
||||
func (cr *CategoryRequest) Patch(category *Category) {
|
||||
category.Title = cr.Title
|
||||
category.HideGlobally = cr.HideGlobally != ""
|
||||
}
|
||||
|
||||
// Categories represents a list of categories.
|
||||
|
||||
@@ -29,6 +29,7 @@ type Entry struct {
|
||||
CommentsURL string `json:"comments_url"`
|
||||
Date time.Time `json:"published_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ChangedAt time.Time `json:"changed_at"`
|
||||
Content string `json:"content"`
|
||||
Author string `json:"author"`
|
||||
ShareCode string `json:"share_code"`
|
||||
|
||||
+81
-55
@@ -24,33 +24,41 @@ const (
|
||||
|
||||
// Feed represents a feed in the application.
|
||||
type Feed struct {
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
FeedURL string `json:"feed_url"`
|
||||
SiteURL string `json:"site_url"`
|
||||
Title string `json:"title"`
|
||||
CheckedAt time.Time `json:"checked_at"`
|
||||
NextCheckAt time.Time `json:"next_check_at"`
|
||||
EtagHeader string `json:"etag_header"`
|
||||
LastModifiedHeader string `json:"last_modified_header"`
|
||||
ParsingErrorMsg string `json:"parsing_error_message"`
|
||||
ParsingErrorCount int `json:"parsing_error_count"`
|
||||
ScraperRules string `json:"scraper_rules"`
|
||||
RewriteRules string `json:"rewrite_rules"`
|
||||
Crawler bool `json:"crawler"`
|
||||
BlocklistRules string `json:"blocklist_rules"`
|
||||
KeeplistRules string `json:"keeplist_rules"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Disabled bool `json:"disabled"`
|
||||
IgnoreHTTPCache bool `json:"ignore_http_cache"`
|
||||
FetchViaProxy bool `json:"fetch_via_proxy"`
|
||||
Category *Category `json:"category,omitempty"`
|
||||
Entries Entries `json:"entries,omitempty"`
|
||||
Icon *FeedIcon `json:"icon"`
|
||||
UnreadCount int `json:"-"`
|
||||
ReadCount int `json:"-"`
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
FeedURL string `json:"feed_url"`
|
||||
SiteURL string `json:"site_url"`
|
||||
Title string `json:"title"`
|
||||
CheckedAt time.Time `json:"checked_at"`
|
||||
NextCheckAt time.Time `json:"next_check_at"`
|
||||
EtagHeader string `json:"etag_header"`
|
||||
LastModifiedHeader string `json:"last_modified_header"`
|
||||
ParsingErrorMsg string `json:"parsing_error_message"`
|
||||
ParsingErrorCount int `json:"parsing_error_count"`
|
||||
ScraperRules string `json:"scraper_rules"`
|
||||
RewriteRules string `json:"rewrite_rules"`
|
||||
Crawler bool `json:"crawler"`
|
||||
BlocklistRules string `json:"blocklist_rules"`
|
||||
KeeplistRules string `json:"keeplist_rules"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
Cookie string `json:"cookie"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Disabled bool `json:"disabled"`
|
||||
IgnoreHTTPCache bool `json:"ignore_http_cache"`
|
||||
AllowSelfSignedCertificates bool `json:"allow_self_signed_certificates"`
|
||||
FetchViaProxy bool `json:"fetch_via_proxy"`
|
||||
Category *Category `json:"category,omitempty"`
|
||||
Entries Entries `json:"entries,omitempty"`
|
||||
Icon *FeedIcon `json:"icon"`
|
||||
HideGlobally bool `json:"hide_globally"`
|
||||
UnreadCount int `json:"-"`
|
||||
ReadCount int `json:"-"`
|
||||
}
|
||||
|
||||
type FeedCounters struct {
|
||||
ReadCounters map[int64]int `json:"reads"`
|
||||
UnreadCounters map[int64]int `json:"unreads"`
|
||||
}
|
||||
|
||||
func (f *Feed) String() string {
|
||||
@@ -117,38 +125,44 @@ func (f *Feed) ScheduleNextCheck(weeklyCount int) {
|
||||
|
||||
// FeedCreationRequest represents the request to create a feed.
|
||||
type FeedCreationRequest struct {
|
||||
FeedURL string `json:"feed_url"`
|
||||
CategoryID int64 `json:"category_id"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Crawler bool `json:"crawler"`
|
||||
Disabled bool `json:"disabled"`
|
||||
IgnoreHTTPCache bool `json:"ignore_http_cache"`
|
||||
FetchViaProxy bool `json:"fetch_via_proxy"`
|
||||
ScraperRules string `json:"scraper_rules"`
|
||||
RewriteRules string `json:"rewrite_rules"`
|
||||
BlocklistRules string `json:"blocklist_rules"`
|
||||
KeeplistRules string `json:"keeplist_rules"`
|
||||
FeedURL string `json:"feed_url"`
|
||||
CategoryID int64 `json:"category_id"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
Cookie string `json:"cookie"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Crawler bool `json:"crawler"`
|
||||
Disabled bool `json:"disabled"`
|
||||
IgnoreHTTPCache bool `json:"ignore_http_cache"`
|
||||
AllowSelfSignedCertificates bool `json:"allow_self_signed_certificates"`
|
||||
FetchViaProxy bool `json:"fetch_via_proxy"`
|
||||
ScraperRules string `json:"scraper_rules"`
|
||||
RewriteRules string `json:"rewrite_rules"`
|
||||
BlocklistRules string `json:"blocklist_rules"`
|
||||
KeeplistRules string `json:"keeplist_rules"`
|
||||
HideGlobally bool `json:"hide_globally"`
|
||||
}
|
||||
|
||||
// FeedModificationRequest represents the request to update a feed.
|
||||
type FeedModificationRequest struct {
|
||||
FeedURL *string `json:"feed_url"`
|
||||
SiteURL *string `json:"site_url"`
|
||||
Title *string `json:"title"`
|
||||
ScraperRules *string `json:"scraper_rules"`
|
||||
RewriteRules *string `json:"rewrite_rules"`
|
||||
BlocklistRules *string `json:"blocklist_rules"`
|
||||
KeeplistRules *string `json:"keeplist_rules"`
|
||||
Crawler *bool `json:"crawler"`
|
||||
UserAgent *string `json:"user_agent"`
|
||||
Username *string `json:"username"`
|
||||
Password *string `json:"password"`
|
||||
CategoryID *int64 `json:"category_id"`
|
||||
Disabled *bool `json:"disabled"`
|
||||
IgnoreHTTPCache *bool `json:"ignore_http_cache"`
|
||||
FetchViaProxy *bool `json:"fetch_via_proxy"`
|
||||
FeedURL *string `json:"feed_url"`
|
||||
SiteURL *string `json:"site_url"`
|
||||
Title *string `json:"title"`
|
||||
ScraperRules *string `json:"scraper_rules"`
|
||||
RewriteRules *string `json:"rewrite_rules"`
|
||||
BlocklistRules *string `json:"blocklist_rules"`
|
||||
KeeplistRules *string `json:"keeplist_rules"`
|
||||
Crawler *bool `json:"crawler"`
|
||||
UserAgent *string `json:"user_agent"`
|
||||
Cookie *string `json:"cookie"`
|
||||
Username *string `json:"username"`
|
||||
Password *string `json:"password"`
|
||||
CategoryID *int64 `json:"category_id"`
|
||||
Disabled *bool `json:"disabled"`
|
||||
IgnoreHTTPCache *bool `json:"ignore_http_cache"`
|
||||
AllowSelfSignedCertificates *bool `json:"allow_self_signed_certificates"`
|
||||
FetchViaProxy *bool `json:"fetch_via_proxy"`
|
||||
HideGlobally *bool `json:"hide_globally"`
|
||||
}
|
||||
|
||||
// Patch updates a feed with modified values.
|
||||
@@ -189,6 +203,10 @@ func (f *FeedModificationRequest) Patch(feed *Feed) {
|
||||
feed.UserAgent = *f.UserAgent
|
||||
}
|
||||
|
||||
if f.Cookie != nil {
|
||||
feed.Cookie = *f.Cookie
|
||||
}
|
||||
|
||||
if f.Username != nil {
|
||||
feed.Username = *f.Username
|
||||
}
|
||||
@@ -209,9 +227,17 @@ func (f *FeedModificationRequest) Patch(feed *Feed) {
|
||||
feed.IgnoreHTTPCache = *f.IgnoreHTTPCache
|
||||
}
|
||||
|
||||
if f.AllowSelfSignedCertificates != nil {
|
||||
feed.AllowSelfSignedCertificates = *f.AllowSelfSignedCertificates
|
||||
}
|
||||
|
||||
if f.FetchViaProxy != nil {
|
||||
feed.FetchViaProxy = *f.FetchViaProxy
|
||||
}
|
||||
|
||||
if f.HideGlobally != nil {
|
||||
feed.HideGlobally = *f.HideGlobally
|
||||
}
|
||||
}
|
||||
|
||||
// Feeds is a list of feed
|
||||
|
||||
+2
-2
@@ -22,10 +22,10 @@ func (i *Icon) DataURL() string {
|
||||
return fmt.Sprintf("%s;base64,%s", i.MimeType, base64.StdEncoding.EncodeToString(i.Content))
|
||||
}
|
||||
|
||||
// Icons represents a list of icon.
|
||||
// Icons represents a list of icons.
|
||||
type Icons []*Icon
|
||||
|
||||
// FeedIcon is a jonction table between feeds and icons
|
||||
// FeedIcon is a junction table between feeds and icons.
|
||||
type FeedIcon struct {
|
||||
FeedID int64 `json:"feed_id"`
|
||||
IconID int64 `json:"icon_id"`
|
||||
|
||||
@@ -17,6 +17,9 @@ type Integration struct {
|
||||
FeverEnabled bool
|
||||
FeverUsername string
|
||||
FeverToken string
|
||||
GoogleReaderEnabled bool
|
||||
GoogleReaderUsername string
|
||||
GoogleReaderPassword string
|
||||
WallabagEnabled bool
|
||||
WallabagURL string
|
||||
WallabagClientID string
|
||||
@@ -26,7 +29,17 @@ type Integration struct {
|
||||
NunuxKeeperEnabled bool
|
||||
NunuxKeeperURL string
|
||||
NunuxKeeperAPIKey string
|
||||
EspialEnabled bool
|
||||
EspialURL string
|
||||
EspialAPIKey string
|
||||
EspialTags string
|
||||
PocketEnabled bool
|
||||
PocketAccessToken string
|
||||
PocketConsumerKey string
|
||||
TelegramBotEnabled bool
|
||||
TelegramBotToken string
|
||||
TelegramBotChatID string
|
||||
LinkdingEnabled bool
|
||||
LinkdingURL string
|
||||
LinkdingAPIKey string
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user