Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
885b796f85 | ||
|
|
fa47806c93 | ||
|
|
5997666bad | ||
|
|
40186ce155 | ||
|
|
9cfdb35224 | ||
|
|
64860c4624 | ||
|
|
32bd2a89a3 | ||
|
|
1e6eca307b | ||
|
|
fc23fcd7c1 | ||
|
|
ab52825c71 | ||
|
|
28def30510 | ||
|
|
8f4d017180 | ||
|
|
df302ad517 | ||
|
|
357d99ac7c | ||
|
|
7e3fecc44a | ||
|
|
e0b3dd9795 | ||
|
|
6a52a2bc46 | ||
|
|
cd2b087006 | ||
|
|
ef2940142c | ||
|
|
e13b8b8827 | ||
|
|
43fce2e89a | ||
|
|
7856f0d602 | ||
|
|
bcc6ab50e2 | ||
|
|
23aa8c05ab | ||
|
|
986d898217 | ||
|
|
654c0e5e56 | ||
|
|
fed0edbf16 | ||
|
|
ede91da6f8 | ||
|
|
1f18d4291f | ||
|
|
d066e8939d | ||
|
|
e4c3435d34 | ||
|
|
fc80b180bc | ||
|
|
0d9dca99e9 | ||
|
|
2ff921cc1a | ||
|
|
e0e66fa6af | ||
|
|
110e29ec5a | ||
|
|
a2b6d622de | ||
|
|
0887789f5e | ||
|
|
3c4574f2ec | ||
|
|
62029f6164 | ||
|
|
ba986847d6 | ||
|
|
fded78ce6f | ||
|
|
8d44649a1e | ||
|
|
f4d0c51dc2 | ||
|
|
ba60db9977 | ||
|
|
0a5a7a684d | ||
|
|
7181c46ed5 | ||
|
|
afa7e69347 | ||
|
|
5050dda4d2 | ||
|
|
9ea1e16ac8 | ||
|
|
922f44f605 | ||
|
|
6ea3fc918b | ||
|
|
0c201533f0 | ||
|
|
b1e99b96c4 | ||
|
|
de1c8485ae | ||
|
|
565d1d0388 | ||
|
|
a15fea1d65 | ||
|
|
da3cf6ca27 | ||
|
|
d8dbbc6832 | ||
|
|
3563a964ef | ||
|
|
208f0c248d | ||
|
|
c0e034726a | ||
|
|
d676a7071a | ||
|
|
a681b2c944 | ||
|
|
c53701d56b | ||
|
|
a8c1f2eccc | ||
|
|
cf7ee44efc | ||
|
|
2e4a9eaaeb | ||
|
|
569a2b5694 | ||
|
|
baa84773a5 | ||
|
|
a39e642b5a | ||
|
|
e42cb49cbe | ||
|
|
b40c12efbd | ||
|
|
3c5ddad133 | ||
|
|
1ca4cb40dd | ||
|
|
678b0b9db1 | ||
|
|
e633fa41ac | ||
|
|
dac303e33b | ||
|
|
fd77d672c5 | ||
|
|
a991d9f512 | ||
|
|
674b3b54dc | ||
|
|
09948845ca | ||
|
|
0b8a0695f7 | ||
|
|
a7c95d5718 | ||
|
|
8a05597e52 | ||
|
|
145d45f800 | ||
|
|
0476b67b2f | ||
|
|
2751a828e0 | ||
|
|
a3f5dbfe07 | ||
|
|
60e09c0dd7 | ||
|
|
a23297e56a | ||
|
|
b05163632b | ||
|
|
f59be31ded | ||
|
|
2e527250de | ||
|
|
91dd378f5d | ||
|
|
f5b3d033a3 | ||
|
|
db98e3b722 | ||
|
|
586cf16fdc | ||
|
|
064d877205 | ||
|
|
fbf8cc87c9 | ||
|
|
bebabf84a0 | ||
|
|
36f169635a | ||
|
|
3f509f44a1 | ||
|
|
9bc8a8ac2b | ||
|
|
abfe98283b | ||
|
|
ded0224f51 | ||
|
|
0060a634d2 | ||
|
|
d34005e04f | ||
|
|
c734bd48b5 | ||
|
|
174c814541 | ||
|
|
993b6e9d0a | ||
|
|
273c9f7b99 | ||
|
|
822deb2867 | ||
|
|
132e2afce0 | ||
|
|
2a888f0bce | ||
|
|
f8202a7add | ||
|
|
87e8d0b775 | ||
|
|
569c00ff5f | ||
|
|
15457e1db4 | ||
|
|
0ae1eb9578 | ||
|
|
aa1d0161d3 | ||
|
|
a2d8b88337 | ||
|
|
a1b4306954 | ||
|
|
88e07031a6 | ||
|
|
cb4daa1ba1 | ||
|
|
46cfa79e89 | ||
|
|
a480f47cea | ||
|
|
4ef789e7b9 | ||
|
|
05d6d8399d | ||
|
|
8bc81d6b5e | ||
|
|
6c5cb8f07d | ||
|
|
70e79e50d6 | ||
|
|
d2c6c6cc4d | ||
|
|
ba5e22bd21 | ||
|
|
9d0bfdea44 | ||
|
|
92ae681517 | ||
|
|
3afa8c4441 | ||
|
|
547fdef9c4 | ||
|
|
152c250300 | ||
|
|
04161284a7 | ||
|
|
14d4818867 | ||
|
|
9f42e91088 | ||
|
|
79ac3b9700 | ||
|
|
7a3178896b | ||
|
|
ee95512321 | ||
|
|
55519b1855 | ||
|
|
89b99614a0 | ||
|
|
7bbd9a1a4f | ||
|
|
0dfb48593e | ||
|
|
3abe0803d6 | ||
|
|
1e0a919dc7 | ||
|
|
489e8aa4b3 | ||
|
|
5058f2f8d8 | ||
|
|
49aff9f22e | ||
|
|
775d4accf7 | ||
|
|
703a1baf8b | ||
|
|
51fdad2ae2 | ||
|
|
86545e5f99 | ||
|
|
5a0413b3e4 | ||
|
|
a0ff2b8ae4 | ||
|
|
6b6c390cb8 | ||
|
|
cd937c4844 | ||
|
|
cc1a5783fd | ||
|
|
5631caad36 | ||
|
|
d0144fb0d0 | ||
|
|
5d1870c1cf | ||
|
|
fb87460bc7 | ||
|
|
cb122cbc61 | ||
|
|
efc4e299ac | ||
|
|
848caa275b | ||
|
|
03754c56c6 | ||
|
|
471f6ff93b | ||
|
|
c53ad56a6d | ||
|
|
646439d86a | ||
|
|
ae7f65e938 | ||
|
|
b2d71a037c | ||
|
|
019ec8972f | ||
|
|
e25e411ebe | ||
|
|
911dcbac9f | ||
|
|
25195c972c | ||
|
|
304c92f733 | ||
|
|
336b9a126e | ||
|
|
01efbf5c79 | ||
|
|
866fa6a758 | ||
|
|
b8bb5e6d82 | ||
|
|
cc4b3cce55 | ||
|
|
5699562133 | ||
|
|
dae064d2bb | ||
|
|
d54e15cd15 | ||
|
|
dbdf56d494 | ||
|
|
b07cd5515a | ||
|
|
73929f2d25 | ||
|
|
acaa06749e | ||
|
|
1bd6efc0c1 | ||
|
|
936960269d | ||
|
|
5780df20ad | ||
|
|
14e5f33f2a | ||
|
|
7aa86bcec4 | ||
|
|
c77a1e85a4 | ||
|
|
093b8cb6df | ||
|
|
6460198e1d | ||
|
|
662dc3fa85 | ||
|
|
5a4bce2816 | ||
|
|
d5ea0d5a17 | ||
|
|
9e525727fd | ||
|
|
95b6995649 | ||
|
|
745064c5ce | ||
|
|
223a3b46bf | ||
|
|
fee3e320ab | ||
|
|
e068cff37b | ||
|
|
28f08ed196 | ||
|
|
056d971000 | ||
|
|
aa5195e5a9 | ||
|
|
85aaaf80ac | ||
|
|
5d467a22d0 | ||
|
|
bcc1cfb67b | ||
|
|
70a24fba69 | ||
|
|
c3121bef84 | ||
|
|
8c25be7d05 | ||
|
|
7463e9d42c | ||
|
|
e4dd9f5bb3 | ||
|
|
4e59d648ef | ||
|
|
7538e76537 | ||
|
|
20ddc54edc | ||
|
|
ac75205933 | ||
|
|
17b58b159a | ||
|
|
191cf445ef | ||
|
|
65a0c08cb3 | ||
|
|
4da68ff89c | ||
|
|
a7da4525fd | ||
|
|
92dfbce45a | ||
|
|
bfdd6b5f7c | ||
|
|
a8a8c09b90 | ||
|
|
4bd13b81cf | ||
|
|
5a07600664 | ||
|
|
f2bc4b21cb | ||
|
|
778975fbde | ||
|
|
57f920624f | ||
|
|
3d87940da9 | ||
|
|
c33d0836eb | ||
|
|
a01cf21f2c | ||
|
|
10fc1d4a2a | ||
|
|
4fa973007d | ||
|
|
c27f5ec02e | ||
|
|
5d6cf3d17d | ||
|
|
f6c7731377 | ||
|
|
bcd739da76 | ||
|
|
bea4915317 | ||
|
|
f695ba4605 | ||
|
|
24983ba3af | ||
|
|
0a2a3b3377 | ||
|
|
d8d7193cbc | ||
|
|
042c9eed9c | ||
|
|
b0c94dd998 | ||
|
|
4c8cc9e823 | ||
|
|
132c9bbdff | ||
|
|
cc0caff8d0 | ||
|
|
3496df24f8 | ||
|
|
e4e35e4c57 | ||
|
|
838320785e | ||
|
|
91bea85519 | ||
|
|
88ea081661 | ||
|
|
39c0a0dba5 | ||
|
|
9d64d3e30d | ||
|
|
39ff238716 | ||
|
|
7c96152f3f | ||
|
|
a2440c19e1 | ||
|
|
24dff5ce85 | ||
|
|
1ca8e15d19 | ||
|
|
f77a8f09bb | ||
|
|
48a7c8140f | ||
|
|
b03ff46767 | ||
|
|
e66e6364c3 | ||
|
|
89ef7ac4f6 | ||
|
|
27e74ee064 | ||
|
|
83c44aa12c | ||
|
|
17da62d53b | ||
|
|
d43fc268f4 | ||
|
|
5a7ab9795d | ||
|
|
cfcdba5aea | ||
|
|
aaca6a6704 | ||
|
|
5f7c822deb | ||
|
|
53be091a31 | ||
|
|
04c68ba013 | ||
|
|
518ea9c8b5 | ||
|
|
6bb2142f35 | ||
|
|
6aa931c866 | ||
|
|
67ab54f820 | ||
|
|
cc9fc80328 | ||
|
|
3e8a8a6b85 | ||
|
|
70a2d0e5f3 | ||
|
|
09e8d7e1da | ||
|
|
3c3d6c1e7f | ||
|
|
0dcc95cd34 | ||
|
|
edae1b0480 | ||
|
|
5fb2cb7e76 | ||
|
|
403bb71c5d | ||
|
|
9e23b16ae7 | ||
|
|
60a93a2433 | ||
|
|
14dfafcb7c | ||
|
|
dcc06cf8c6 | ||
|
|
54c084040c | ||
|
|
a9c38f5a03 | ||
|
|
bce80cca0b | ||
|
|
f56fac6877 | ||
|
|
ef2286dca4 | ||
|
|
a4a012368e | ||
|
|
1b623ef346 | ||
|
|
f661d24544 | ||
|
|
cfe10553b2 | ||
|
|
cf1042f40d | ||
|
|
e77000076b | ||
|
|
49241664dc | ||
|
|
ffa3e9ec9a | ||
|
|
fbbe0d9ca9 | ||
|
|
001eeecc09 | ||
|
|
454a9c7076 | ||
|
|
fc934ce8e1 | ||
|
|
b9bcc28e0f | ||
|
|
b5ddca65f5 | ||
|
|
536805791e | ||
|
|
5a6c73c4c1 | ||
|
|
d50f5a0488 | ||
|
|
671a31a95a | ||
|
|
5e38f41530 | ||
|
|
7569465a61 | ||
|
|
5913166a13 | ||
|
|
6036562af2 | ||
|
|
39e6c258d5 | ||
|
|
1ab0291483 | ||
|
|
fe024502d4 | ||
|
|
9a76c6428a | ||
|
|
2d4053c792 | ||
|
|
a69254612c | ||
|
|
09a14c1270 | ||
|
|
b343068805 | ||
|
|
ecf50dde2b |
+12
-3
@@ -1,10 +1,19 @@
|
||||
target/
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
.vscode
|
||||
*.ui~
|
||||
resources.gresource
|
||||
_build
|
||||
_build/
|
||||
build/
|
||||
vendor/
|
||||
.criterion
|
||||
.criterion/
|
||||
org.gnome.*.json~
|
||||
podcasts-gtk/po/gnome-podcasts.pot
|
||||
|
||||
# scripts/test.sh
|
||||
target_*/
|
||||
|
||||
# flatpak-builder stuff
|
||||
.flatpak-builder/
|
||||
app/
|
||||
repo/
|
||||
|
||||
+39
-86
@@ -4,90 +4,56 @@ stages:
|
||||
- review
|
||||
|
||||
variables:
|
||||
BUNDLE: "hammond-dev.flatpak"
|
||||
|
||||
.cargo_cache_template: &cargo_cache
|
||||
cache:
|
||||
# JOB_NAME - Each job will have it's own cache
|
||||
# COMMIT_REF_SLUG = Lowercase name of the branch
|
||||
# ^ Keep diffrerent caches for each branch
|
||||
key: "$CI_JOB_NAME"
|
||||
paths:
|
||||
- target/
|
||||
- .cargo_cache/
|
||||
|
||||
.cargo_test_template: &cargo_test
|
||||
stage: test
|
||||
|
||||
variables:
|
||||
RUSTFLAGS: "--cfg rayon_unstable"
|
||||
RUST_BACKTRACE: "FULL"
|
||||
|
||||
before_script:
|
||||
- apt-get update -yqq
|
||||
- apt-get install -yqq --no-install-recommends build-essential libgtk-3-dev meson libgstreamer1.0-dev
|
||||
|
||||
- mkdir -p .cargo_cache
|
||||
# Only stuff inside the repo directory can be cached
|
||||
# Override the CARGO_HOME variable to force it location
|
||||
- export CARGO_HOME="${PWD}/.cargo_cache"
|
||||
script:
|
||||
- rustc -Vv && cargo -Vv
|
||||
# Force regeneration of gresources regardless of artifacts chage
|
||||
- cd hammond-gtk/resources/ && glib-compile-resources --generate resources.xml && cd ../../
|
||||
|
||||
- cargo build
|
||||
- cargo test -- --test-threads=1
|
||||
- cargo test -- --test-threads=1 --ignored
|
||||
<<: *cargo_cache
|
||||
|
||||
.rust:stable:
|
||||
# https://hub.docker.com/_/rust/
|
||||
image: "rust"
|
||||
<<: *cargo_test
|
||||
|
||||
.rust:nightly:
|
||||
# https://hub.docker.com/r/rustlang/rust/
|
||||
image: "rustlang/rust:nightly"
|
||||
<<: *cargo_test
|
||||
only:
|
||||
- schedule
|
||||
- web
|
||||
BUNDLE: "org.gnome.Podcasts.Devel.flatpak"
|
||||
|
||||
flatpak:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/rust_bundle:3.28
|
||||
stage: test
|
||||
image: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/rust_bundle:master"
|
||||
stage: "test"
|
||||
variables:
|
||||
MANIFEST_PATH: "org.gnome.PodcastsDevel.json"
|
||||
FLATPAK_MODULE: "gnome-podcasts"
|
||||
CONFIGURE_ARGS: "-Dprofile=development"
|
||||
DBUS_ID: "org.gnome.PodcastsDevel"
|
||||
|
||||
script:
|
||||
- flatpak-builder --stop-at=hammond app org.gnome.Hammond.json
|
||||
# https://gitlab.gnome.org/World/hammond/issues/55
|
||||
- flatpak-builder --stop-at=${FLATPAK_MODULE} app ${MANIFEST_PATH}
|
||||
# https://gitlab.gnome.org/World/podcasts/issues/55
|
||||
# Force regeneration of gresources regardless of artifacts chage
|
||||
- flatpak-builder --run app org.gnome.Hammond.json glib-compile-resources --sourcedir=hammond-gtk/resources/ hammond-gtk/resources/resources.xml
|
||||
- flatpak-builder --run app ${MANIFEST_PATH} glib-compile-resources --sourcedir=podcasts-gtk/resources/ podcasts-gtk/resources/resources.xml
|
||||
|
||||
# Build the flatpak repo
|
||||
- flatpak-builder --run app org.gnome.Hammond.json meson --prefix=/app --libdir=/app/lib _build
|
||||
- flatpak-builder --run app org.gnome.Hammond.json ninja -C _build install
|
||||
- flatpak-builder --finish-only app org.gnome.Hammond.json
|
||||
- flatpak build-export repo app
|
||||
- flatpak-builder --run app ${MANIFEST_PATH} meson --prefix=/app ${CONFIGURE_ARGS} _build
|
||||
- flatpak-builder --run app ${MANIFEST_PATH} ninja -C _build install
|
||||
|
||||
# Run the tests
|
||||
- |
|
||||
xvfb-run -a -s "-screen 0 1024x768x24" \
|
||||
flatpak-builder --run \
|
||||
--env=APP_ID="org.gnome.PodcastsDevel" \
|
||||
--env=LOCALEDIR="./podcasts-gtk/po" \
|
||||
--env=VERSION="0.0.0" \
|
||||
--env=CARGO_HOME="target/cargo-home" \
|
||||
--env=CARGO_TARGET_DIR="target_test/" \
|
||||
app ${MANIFEST_PATH} \
|
||||
cargo test -j 1 -- --test-threads=1
|
||||
|
||||
# Create a flatpak bundle
|
||||
- flatpak build-bundle repo ${BUNDLE} org.gnome.Hammond
|
||||
# Run the tests
|
||||
# - flatpak-builder --run app org.gnome.Hammond.json cargo test -- --test-threads=1
|
||||
# - flatpak-builder --run app org.gnome.Hammond.json cargo test -- --test-threads=1 --ignored
|
||||
- flatpak-builder --finish-only app ${MANIFEST_PATH}
|
||||
- flatpak build-export repo app
|
||||
- flatpak build-bundle repo ${BUNDLE} ${DBUS_ID}
|
||||
|
||||
artifacts:
|
||||
paths:
|
||||
- $BUNDLE
|
||||
expire_in: 30 days
|
||||
expire_in: 2 days
|
||||
|
||||
cache:
|
||||
# JOB_NAME - Each job will have it's own cache
|
||||
# COMMIT_REF_SLUG = Lowercase name of the branch
|
||||
# ^ Keep diffrerent caches for each branch
|
||||
key: "$CI_JOB_NAME"
|
||||
key: "flatpak"
|
||||
paths:
|
||||
- .flatpak-builder/cache/
|
||||
- .flatpak-builder/downloads/
|
||||
- .flatpak-builder/git/
|
||||
- target/
|
||||
- target_test/
|
||||
|
||||
review:
|
||||
stage: review
|
||||
@@ -104,7 +70,8 @@ review:
|
||||
url: https://gitlab.gnome.org/$CI_PROJECT_PATH/-/jobs/$CI_JOB_ID/artifacts/raw/${BUNDLE}
|
||||
on_stop: stop_review
|
||||
except:
|
||||
- master@World/hammond
|
||||
- master@World/podcasts
|
||||
- tags
|
||||
|
||||
stop_review:
|
||||
stage: review
|
||||
@@ -115,7 +82,8 @@ stop_review:
|
||||
name: review/$CI_COMMIT_REF_NAME
|
||||
action: stop
|
||||
except:
|
||||
- master@World/hammond
|
||||
- master@World/podcasts
|
||||
- tags
|
||||
|
||||
# Configure and run rustfmt on nightly
|
||||
# Exits and builds fails if on bad format
|
||||
@@ -126,19 +94,4 @@ rustfmt:
|
||||
- rustc -Vv && cargo -Vv
|
||||
- cargo fmt --version
|
||||
- cargo fmt --all -- --check
|
||||
|
||||
# Configure and run clippy on nightly
|
||||
# Only fails on errors atm.
|
||||
.clippy:
|
||||
image: "registry.gitlab.gnome.org/alatiera/hammond-container-images/clippy:nightly"
|
||||
stage: lint
|
||||
variables:
|
||||
RUSTFLAGS: "--cfg rayon_unstable"
|
||||
CARGO_HOME: ".cargo_cache"
|
||||
script:
|
||||
- rustc --version && cargo --version
|
||||
- cargo clippy --version
|
||||
# Force regeneration of gresources regardless of artifacts chage
|
||||
- cd hammond-gtk/resources/ && glib-compile-resources --generate resources.xml && cd ../../
|
||||
- cargo clippy --all
|
||||
<<: *cargo_cache
|
||||
allow_failure: true
|
||||
@@ -18,7 +18,7 @@ Some common cases might be:
|
||||
|
||||
Steps to reproduce:
|
||||
|
||||
1. Open Hammond
|
||||
1. Open GNOME Podcasts
|
||||
2. Do an action
|
||||
3. ...
|
||||
|
||||
|
||||
@@ -11,9 +11,7 @@ Reproducible in:
|
||||
Please test if the issue was already fixed in the unstable version of the app.
|
||||
For that, follow these steps:
|
||||
1. Make sure Flatpak is installed or install it following these steps https://flatpak.org/setup
|
||||
2. Install the unstable version of the app following this link
|
||||
https://gitlab.gnome.org/GNOME/gnome-apps-nightly/raw/master/nautilus.flatpakref and save
|
||||
it as a ".flatpakref" file
|
||||
2. Install the unstable version of the app following, flatpak bundles can be found in the CI artifacts.
|
||||
|
||||
If these steps failed, write in 'Other' the distribution you’re using and
|
||||
the version of the app.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
### Please attach a relevant issue to this MR, if this doesn't exist please create one.
|
||||
+144
-19
@@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added:
|
||||
|
||||
### Changed:
|
||||
@@ -13,24 +14,148 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
|
||||
### Removed:
|
||||
|
||||
## [0.4.6] - 2018-10-07
|
||||
|
||||
### Added:
|
||||
- Felix, @haecker-felix, wrote an [mpris crate](https://crates.io/crates/mpris-player) and implemented MPRIS2 client side support! !74 #68
|
||||
|
||||
### Changed:
|
||||
- Download Cancel button was changed to an Icon instead of a label !72
|
||||
- The applciation will no longer scale below 360p in width 1933c79f7a87d8261d91ca4e14eb51c1ddc66624
|
||||
- Update to the latest HIG 5050dda4d2f75b706842de8507d115dd5a1bd0a9
|
||||
- Chris, @brainblasted, upgraded hyper to 0.12, this brings openssl 1.1 support !75
|
||||
- Pipeline backend is now completly migrated to tokio-runtime 0887789f5e653dd92ad397fb39561df6dffcb45c
|
||||
- Resume playing an episode will attempt to rewind the track only if more than a minute has passed since the last pause !76
|
||||
|
||||
### Fixed:
|
||||
- Fixed a regression where indexing feeds was blocking the `tokio reactor` #88 !70
|
||||
- Episodeds Listbox no longer resizes when a download starts #89 !72
|
||||
- The `total_size` label of the `EpisodeWidget` now behaves correctly if the request fails #90 !73
|
||||
- The Pipeline will no longer log things in stderr for Requests that returned 304 and are expected to be skipped da361d0cb93cd8edd076859b2c607509a96dac8d
|
||||
- A bug where the HomeView wold get into an invalid state if your only shows had no episodes 32bd2a89a34e8e940b3b260c6be76defe11835ed
|
||||
|
||||
### Translations:
|
||||
|
||||
**Added**
|
||||
- Brazilian Portuguese translation 586cf16f
|
||||
- Swedish translation 2e527250
|
||||
- Italian translation a23297e5
|
||||
- Friulian translation 60e09c0d
|
||||
- Hungarian translation 2751a828
|
||||
- Croatian translation 0476b67b
|
||||
- Latvian translation a681b2c9
|
||||
- Czech translation 3563a964
|
||||
- Catalan translation 6ea3fc91
|
||||
|
||||
**Updated**
|
||||
- German translation
|
||||
- Finnish translation
|
||||
- Polish translation
|
||||
- Turkish translation
|
||||
- Croatian translation
|
||||
- Indonesian translation
|
||||
- Spanish translation
|
||||
|
||||
|
||||
## [0.4.5] - 2018-08-31
|
||||
|
||||
### Added:
|
||||
- [OARS](https://hughsie.github.io/oars/) Tags where added for compatibility with Store clients b0c94dd9
|
||||
- Daniel added support for Translations !46
|
||||
- Svitozar Cherepii(@svito) created a [wiki page](https://wiki.gnome.org/Apps/Podcasts) 70e79e50
|
||||
- Libhandy was added as a dependancy #70
|
||||
- Development builds can now be installed in parallel with stable builds !64
|
||||
|
||||
### Changed:
|
||||
- The update indication was moved to an In-App notification #72
|
||||
- The app icon's accent color was changed from orange to red 0dfb4859
|
||||
- The stack switcher in the Headerbar is now insesitive on Empty Views !63
|
||||
|
||||
### Fixed:
|
||||
- Improved handling of HTTP redirections #64 !61 !62
|
||||
- Fixed a major performance regression when loading show covers !67
|
||||
- More refference cycles have been fixed !59
|
||||
- OPML import dialog now exits properly and no longer keeps the application from shuting down !65
|
||||
- Update action is disabled if there isn't something to update #71
|
||||
|
||||
### Translations:
|
||||
- Added Finish 93696026
|
||||
- Added Polish 1bd6efc0
|
||||
- Added Turkish 73929f2d
|
||||
- Added Spanish !46
|
||||
- Added German 6b6c390c
|
||||
- Added Galician 0060a634
|
||||
- Added Indonesian ded0224f
|
||||
- Added Korean 36f16963
|
||||
|
||||
|
||||
## [0.4.4] - 2018-07-31
|
||||
|
||||
### Changed:
|
||||
- `SendCell` crate was replaced with `Fragile`. (Jorda Petridis) 838320785ebbea94e009698b473495cfec076f54
|
||||
- Update dependancies (Jorda Petridis) 91bea8551998b16e44e5358fdd43c53422bcc6f3
|
||||
|
||||
### Fixed:
|
||||
- Fix more refference cycles. (Jorda Petridis) 3496df24f8d8bfa8c8a53d8f00262d42ee39b41c
|
||||
- Actually fix cargo-vendor (Jorda Petridis)
|
||||
|
||||
## [0.4.3] - 2018-07-27
|
||||
|
||||
### Fixed:
|
||||
|
||||
- Fix the cargo vendor config for the tarball releash script. (Jorda Petridis) a2440c19e11ca4dcdbcb67cd85259a41fe3754d6
|
||||
|
||||
## [0.4.2] - 2018-07-27
|
||||
|
||||
### Changed:
|
||||
|
||||
- Minimum size requested by the Views. (Jorda Petridis) 7c96152f3f53f271247230dccf1c9cd5947b685f
|
||||
|
||||
### Fixed:
|
||||
|
||||
- Screenshot metadata in appstream data. (Jorda Petridis) a2440c19e11ca4dcdbcb67cd85259a41fe3754d6
|
||||
|
||||
## [0.4.1] - 2018-07-26
|
||||
### Added:
|
||||
|
||||
- Custom icons for the fast-forward and rewind actions in the Player were added. (Tobias Bernard) e77000076b3d78b8625f4c7ef367376d0130ece6
|
||||
- Hicolor and symbolic icons for the Application. (Tobias Bernard and Sam Hewitt) edae1b04801dba9d91d5d4145db79b287f0eec2c
|
||||
- Basic prefferences dialog (Zander Brown). [34](https://gitlab.gnome.org/World/podcasts/merge_requests/34)
|
||||
- Dbus service preperation. Not used till the MPRIS2 integration has landed. (Zander Brown) [42](https://gitlab.gnome.org/World/podcasts/merge_requests/42)
|
||||
- Episodes and Images will only get drawn when needed. Big Performance impact. (Jordan Petridis) [43](https://gitlab.gnome.org/World/podcasts/merge_requests/43)
|
||||
|
||||
### Changed:
|
||||
|
||||
- The `ShowWidget` control button were moved to a secondary menu in the Headerbar. (Jordan Petridis) 536805791e336a3e112799be554706bb804d2bef
|
||||
- EmptyView layout improvements. (Jorda Petridis) 3c3d6c1e7f15b88308a9054b15a6ca0d8fa233ce 518ea9c8b57885c44bda9c418b19fef26ae0e55d
|
||||
- Improved the `AddButton` behavior. (Jorda Petridis) 67ab54f8203f19aad198dc49e935127d25432b41
|
||||
|
||||
### Fixed:
|
||||
|
||||
- A couple reffence cycles where fixed. (Jorda Petridis)
|
||||
|
||||
### Removed:
|
||||
|
||||
- The delay between the application startup and the `update_on_startup` action. (Jorda Petridis) 7569465a612ee5ef84d0e58f4e1010c8d14080d4
|
||||
|
||||
## [0.4.0] - 2018-07-04
|
||||
### Added:
|
||||
- Keyboard Shortcuts and a Shortcuts dialog were implemented. (ZanderBrown)
|
||||
[!33](https://gitlab.gnome.org/World/hammond/merge_requests/33)
|
||||
[!33](https://gitlab.gnome.org/World/podcasts/merge_requests/33)
|
||||
|
||||
### Changed:
|
||||
- The `FileChooser` of the OPML import was changed to use the `FileChooserNative` widget/API. (ZanderBrown)
|
||||
[!33](https://gitlab.gnome.org/World/hammond/merge_requests/33)
|
||||
[!33](https://gitlab.gnome.org/World/podcasts/merge_requests/33)
|
||||
- The `EpisdeWidget` was refactored.
|
||||
[!38](https://gitlab.gnome.org/World/hammond/merge_requests/38)
|
||||
[!38](https://gitlab.gnome.org/World/podcasts/merge_requests/38)
|
||||
- `EpisdeWidget`'s progressbar was changed to be non-blocking and should feel way more responsive now. 9b0ac5b83dadecdff51cd398293afdf0d5276012
|
||||
- An embeded audio player was implemented!
|
||||
[!40](https://gitlab.gnome.org/World/hammond/merge_requests/40)
|
||||
[!40](https://gitlab.gnome.org/World/podcasts/merge_requests/40)
|
||||
- Various Database changes.
|
||||
[!41](https://gitlab.gnome.org/World/hammond/merge_requests/41)
|
||||
[!41](https://gitlab.gnome.org/World/podcasts/merge_requests/41)
|
||||
|
||||
### Fixed:
|
||||
- Fixed a bug whre the about dialog would be unclosable. (ZanderBrown) [!37](https://gitlab.gnome.org/World/hammond/merge_requests/37)
|
||||
- Fixed a bug whre the about dialog would be unclosable. (ZanderBrown) [!37](https://gitlab.gnome.org/World/podcasts/merge_requests/37)
|
||||
|
||||
## [0.3.4] - 2018-05-20
|
||||
### Fixed:
|
||||
@@ -56,9 +181,9 @@ not being able to access any file.
|
||||
|
||||
### Changed:
|
||||
- Downlaoding and loading images now is done asynchronously and is not blocking programs execution.
|
||||
[#7](https://gitlab.gnome.org/World/hammond/issues/7)
|
||||
[#7](https://gitlab.gnome.org/World/podcasts/issues/7)
|
||||
- Bold, italics links and some other `html` tags can now be rendered in the Show Description.
|
||||
[#25](https://gitlab.gnome.org/World/hammond/issues/25)
|
||||
[#25](https://gitlab.gnome.org/World/podcasts/issues/25)
|
||||
- `Rayon` Threadpools are now used instead of unlimited one-off threads.
|
||||
- `EpisdeWidget`s are now loaded asynchronously accross views.
|
||||
- `EpisodeWidget`s no longer trigger a `View` refresh for trivial stuff 03bd95184808ccab3e0ea0e3713a52ee6b7c9ab4
|
||||
@@ -66,7 +191,7 @@ not being able to access any file.
|
||||
- `ShowWidget` Description is inside a scrolled window now
|
||||
|
||||
### Fixed:
|
||||
- `EpisodeWidget` Height now is consistent accros views [#57](https://gitlab.gnome.org/World/hammond/issues/57)
|
||||
- `EpisodeWidget` Height now is consistent accros views [#57](https://gitlab.gnome.org/World/podcasts/issues/57)
|
||||
- Implemented a tail-recursion loop to follow-up when a feed redirects to another url. c6a24e839a8ba77d09673f299cfc1e64ba7078f3
|
||||
|
||||
### Removed:
|
||||
@@ -75,27 +200,27 @@ not being able to access any file.
|
||||
## [0.3.1] - 2018-03-28
|
||||
### Added:
|
||||
- Ability to mark all episodes of a Show as watched.
|
||||
[#47](https://gitlab.gnome.org/World/hammond/issues/47)
|
||||
[#47](https://gitlab.gnome.org/World/podcasts/issues/47)
|
||||
- Now you are able to subscribe to itunes™ podcasts by using the itunes link of the show.
|
||||
[#49](https://gitlab.gnome.org/World/hammond/issues/49)
|
||||
[#49](https://gitlab.gnome.org/World/podcasts/issues/49)
|
||||
- Hammond now remembers the window size and position. (Rowan Lewis)
|
||||
[#50](https://gitlab.gnome.org/World/hammond/issues/50)
|
||||
[#50](https://gitlab.gnome.org/World/podcasts/issues/50)
|
||||
- Implemnted the initial work for integrating with GSettings and storing preferences. (Rowan Lewis)
|
||||
[!22](https://gitlab.gnome.org/World/hammond/merge_requests/22) [!23](https://gitlab.gnome.org/World/hammond/merge_requests/23)
|
||||
[!22](https://gitlab.gnome.org/World/podcasts/merge_requests/22) [!23](https://gitlab.gnome.org/World/podcasts/merge_requests/23)
|
||||
- Shows without episodes now display an empty message similar to EmptyView.
|
||||
[#44](https://gitlab.gnome.org/World/hammond/issues/44)
|
||||
[#44](https://gitlab.gnome.org/World/podcasts/issues/44)
|
||||
|
||||
### Changed:
|
||||
- EpisdeWidget has been reimplemented as a compile time state machine.
|
||||
[!18](https://gitlab.gnome.org/World/hammond/merge_requests/18)
|
||||
[!18](https://gitlab.gnome.org/World/podcasts/merge_requests/18)
|
||||
- Content Views no longer scroll horizontally when shrunk bellow their minimum size.
|
||||
[#35](https://gitlab.gnome.org/World/hammond/issues/35)
|
||||
[#35](https://gitlab.gnome.org/World/podcasts/issues/35)
|
||||
- Some requests now use the Tor Browser's user agent. (Rowan Lewis)
|
||||
[#53](https://gitlab.gnome.org/World/hammond/issues/53)
|
||||
[#53](https://gitlab.gnome.org/World/podcasts/issues/53)
|
||||
|
||||
### Fixed:
|
||||
- Double border aroun the main window was fixed. (Rowan Lewis)
|
||||
[#52](https://gitlab.gnome.org/World/hammond/issues/52)
|
||||
[#52](https://gitlab.gnome.org/World/podcasts/issues/52)
|
||||
|
||||
## [0.3.0] - 2018-02-11
|
||||
- Tobias Bernard Redesigned the whole Gtk+ client.
|
||||
@@ -115,4 +240,4 @@ not being able to access any file.
|
||||
- Added appdata.xml file
|
||||
|
||||
## [0.1.0] - 2017-11-13
|
||||
- Initial Release
|
||||
- Initial Release
|
||||
|
||||
+8
-8
@@ -1,18 +1,18 @@
|
||||
## Contributing to Hammond
|
||||
## Contributing to GNOME Podcasts
|
||||
|
||||
Thank you for looking in this file!
|
||||
|
||||
When contributing to the development of Hammond, please first discuss the change you wish to make via issue, email, or any other method with the maintainers before making a change.
|
||||
When contributing to the development of GNOME Podcasts, please first discuss the change you wish to make via issue, email, or any other method with the maintainers before making a change.
|
||||
|
||||
If you have any questions regarding the use or development of Hammond,
|
||||
If you have any questions regarding the use or development of GNOME Podcasts,
|
||||
want to discuss design or simply hang out, please join us in [#hammond on irc.gnome.org.](irc://irc.gnome.org/#hammond)
|
||||
|
||||
Please note we have a [code of conduct](https://wiki.gnome.org/Foundation/CodeOfConduc), please follow it in all your interactions with the project.
|
||||
|
||||
## Source repository
|
||||
|
||||
Hammond's main source repository is at gitlab.gnome.org. You can view
|
||||
the web interface [here](https://gitlab.gnome.org/World/hammond)
|
||||
GNOME Podcasts's main source repository is at gitlab.gnome.org. You can view
|
||||
the web interface [here](https://gitlab.gnome.org/World/podcasts)
|
||||
|
||||
Development happens in the master branch.
|
||||
|
||||
@@ -50,8 +50,8 @@ In order to run the test suite use the following: `cargo test -- --test-threads=
|
||||
|
||||
# Issues, issues and more issues!
|
||||
|
||||
There are many ways you can contribute to Hammond, and all of them involve creating issues
|
||||
in [Hammond issue tracker](https://gitlab.gnome.org/World/hammond/issues). This is the entry point for your contribution.
|
||||
There are many ways you can contribute to GNOME Podcasts, and all of them involve creating issues
|
||||
in [GNOME Podcasts issue tracker](https://gitlab.gnome.org/World/podcasts/issues). This is the entry point for your contribution.
|
||||
|
||||
To create an effective and high quality ticket, try to put the following information on your
|
||||
ticket:
|
||||
@@ -74,7 +74,7 @@ If it's an issue, add the steps to reproduce like this:
|
||||
|
||||
Steps to reproduce:
|
||||
|
||||
1. Open Hammond
|
||||
1. Open GNOME Podcasts
|
||||
2. Do an Action
|
||||
3. ...
|
||||
|
||||
|
||||
Generated
+1213
-1258
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -1,8 +1,8 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"hammond-data",
|
||||
"hammond-downloader",
|
||||
"hammond-gtk"
|
||||
"podcasts-data",
|
||||
"podcasts-downloader",
|
||||
"podcasts-gtk"
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
|
||||
@@ -631,7 +631,7 @@ to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
Hammond
|
||||
GNOME Podcasts
|
||||
Copyright (C) 2017 Jordan Petridis
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
Hammond Copyright (C) 2017 Jordan Petridis
|
||||
GNOME Podcasts Copyright (C) 2017 Jordan Petridis
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
@@ -1,66 +1,63 @@
|
||||
# Hammond
|
||||
# GNOME Podcasts
|
||||
|
||||
### A Podcast Client for GNOME written in Rust.
|
||||
### A Podcast application for GNOME.
|
||||
Listen to your favorite podcasts, right from your desktop.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Available on Flathub
|
||||
|
||||
[](https://flathub.org/apps/details/org.gnome.Podcasts)
|
||||
|
||||
## Quick start
|
||||
|
||||
Hammond can be built and run with [Gnome Builder](https://wiki.gnome.org/Apps/Builder) >= 3.28.
|
||||
GNOME Podcasts can be built and run with [Gnome Builder][builder] >= 3.28.
|
||||
Just clone the repo and hit the run button!
|
||||
|
||||
Get Builder [here](https://wiki.gnome.org/Apps/Builder/Downloads)
|
||||
You can get Builder from [here][get_builder].
|
||||
|
||||
## Broken Feeds
|
||||
|
||||
Found a feed that does not work in Hammond?
|
||||
Please [open an issue](https://gitlab.gnome.org/World/hammond/issues/new) and choose the `BrokenFeed` template so we will know and fix it!
|
||||
Found a feed that does not work in GNOME Podcasts?
|
||||
Please [open an issue][new_issue] and choose the `BrokenFeed` template so we will know and fix it!
|
||||
|
||||
## Getting in Touch
|
||||
|
||||
If you have any questions regarding the use or development of Hammond,
|
||||
want to discuss design or simply hang out, please join us in `#hammond` on
|
||||
[irc.gnome.org.][irc] or [matrix][matrix].
|
||||
|
||||
Note:
|
||||
|
||||
There isn't much documentation yet, so you will probably have question about parts of the Code.
|
||||
If you have any questions regarding the use or development of GNOME Podcasts,
|
||||
want to discuss design or simply hang out, please join us on our [irc][irc] or [matrix][matrix] channel.
|
||||
|
||||
## Building
|
||||
|
||||
### Flatpak
|
||||
|
||||
Flatpak is the reccomended way of building and installing Hammond.
|
||||
Flatpak is the recommended way of building and installing GNOME Podcasts.
|
||||
Here are the depencancies you will need.
|
||||
|
||||
#### Building a Flatpak
|
||||
```sh
|
||||
# Add flathub and the gnome-nightly repo
|
||||
flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||
flatpak remote-add --user --if-not-exists gnome-nightly https://sdk.gnome.org/gnome-nightly.flatpakrepo
|
||||
|
||||
Download the `org.gnome.Hammond.json` flatpak manifest from this repo.
|
||||
# Install the gnome-nightly Sdk and Platform runtime
|
||||
flatpak install --user gnome-nightly org.gnome.Sdk org.gnome.Platform
|
||||
|
||||
```bash
|
||||
# Add flathub repo
|
||||
flatpak --user remote-add flathub --if-not-exists https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||
# Add the gnome-nightly repo
|
||||
flatpak --user remote-add gnome-nightly --if-not-exists https://sdk.gnome.org/gnome-nightly.flatpakrepo
|
||||
# Install the gnome-nightly Sdk and Platform runtim
|
||||
flatpak --user install gnome-nightly org.gnome.Sdk org.gnome.Platform
|
||||
# Install the required rust-stable extension from flathub
|
||||
flatpak --user install flathub org.freedesktop.Sdk.Extension.rust-stable
|
||||
flatpak-builder --user --repo=repo hammond org.gnome.Hammond.json --force-clean
|
||||
flatpak install --user flathub org.freedesktop.Sdk.Extension.rust-stable//18.08
|
||||
```
|
||||
|
||||
To install the resulting flatpak you can do:
|
||||
|
||||
```bash
|
||||
flatpak build-bundle repo hammond.flatpak org.gnome.Hammond
|
||||
flatpak install --user --bundle hammond.flatpak
|
||||
flatpak-builder --user --install --force-clean --repo=repo podcasts org.gnome.Podcasts.json
|
||||
```
|
||||
|
||||
### Building from soure
|
||||
### Building from source
|
||||
|
||||
```sh
|
||||
git clone https://gitlab.gnome.org/World/hammond.git
|
||||
cd hammond/
|
||||
git clone https://gitlab.gnome.org/World/podcasts.git
|
||||
cd gnome-podcasts/
|
||||
meson --prefix=/usr build
|
||||
ninja -C build
|
||||
sudo ninja -C build install
|
||||
@@ -71,47 +68,30 @@ sudo ninja -C build install
|
||||
* Rust stable 1.27 or later along with cargo.
|
||||
* Gtk+ 3.22 or later
|
||||
* Gstreamer 1.12 or later
|
||||
* libhandy
|
||||
* Meson
|
||||
* A network connection
|
||||
|
||||
Offline build are possible too, but [`cargo-vendor`][vendor] would have to be setup first
|
||||
|
||||
**Debian/Ubuntu**
|
||||
|
||||
```sh
|
||||
apt-get install -yqq cargo rustc libsqlite3-dev libssl-dev libgtk-3-dev meson \
|
||||
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
|
||||
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
||||
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
||||
gstreamer1.0-libav libgstrtspserver-1.0-dev ibgstreamer-plugins-bad1.0-dev
|
||||
```
|
||||
|
||||
**Fedora**
|
||||
|
||||
```sh
|
||||
dnf install -y rust cargo gtk3-devel glib2-devel openssl-devel sqlite-devel meson \
|
||||
gstreamer1-devel gstreamer1-plugins-base-tools gstreamer1-devel-docs \
|
||||
gstreamer1-plugins-base-devel gstreamer1-plugins-base-devel-docs \
|
||||
gstreamer1-plugins-good gstreamer1-plugins-good-extras \
|
||||
gstreamer1-plugins-bad-free gstreamer1-plugins-bad-free-devel \
|
||||
gstreamer1-plugins-bad-free-extras
|
||||
|
||||
```
|
||||
|
||||
If you happen to build it on other distributions please let me know the names
|
||||
of the corresponding libraries. Feel free to open a MR or an Issue to note it.
|
||||
|
||||
## Contributing
|
||||
|
||||
There alot of thins yet to be done.
|
||||
There are a lot of things yet to be done.
|
||||
|
||||
If you want to contribute, please check the [Contributions Guidelines][contribution-guidelines].
|
||||
|
||||
You can start by taking a look at [Issues](https://gitlab.gnome.org/World/hammond/issues) or by opening a [New issue](https://gitlab.gnome.org/World/hammond/issues/new?issue%5Bassignee_id%5D=&issue%5Bmilestone_id%5D=).
|
||||
You can start by taking a look at [Issues][issues] or by opening a [New issue][new_issue].
|
||||
|
||||
There are also some minor tasks tagged with `TODO:` and `FIXME:` in the source code.
|
||||
|
||||
[contribution-guidelines]: https://gitlab.gnome.org/World/hammond/blob/master/CONTRIBUTING.md
|
||||
[contribution-guidelines]: https://gitlab.gnome.org/World/podcasts/blob/master/CONTRIBUTING.md
|
||||
|
||||
### Translations
|
||||
|
||||
Translation of this project takes place on the GNOME translation platform,
|
||||
[Damned Lies](https://l10n.gnome.org/module/podcasts). For further
|
||||
information on how to join a language team, or even to create one, please see
|
||||
[GNOME Translation Project wiki page](https://wiki.gnome.org/TranslationProject).
|
||||
|
||||
|
||||
## Overview
|
||||
@@ -119,15 +99,15 @@ There are also some minor tasks tagged with `TODO:` and `FIXME:` in the source c
|
||||
```sh
|
||||
$ tree -d
|
||||
├── screenshots # png's used in the README.md
|
||||
├── hammond-data # Storate related stuff, SQLite, XDG setup, RSS Parser.
|
||||
├── podcasts-data # Storate related stuff, SQLite, XDG setup, RSS Parser.
|
||||
│ ├── migrations # Diesel SQL migrations.
|
||||
│ │ └── ...
|
||||
│ ├── src
|
||||
│ └── tests
|
||||
│ └── feeds # Raw RSS Feeds used for tests.
|
||||
├── hammond-downloader # Really basic, Really crappy downloader.
|
||||
├── podcasts-downloader # Really basic, Really crappy downloader.
|
||||
│ └── src
|
||||
├── hammond-gtk # The Gtk+ Client
|
||||
├── podcasts-gtk # The Gtk+ Client
|
||||
│ ├── resources # GResources folder
|
||||
│ │ └── gtk # Contains the glade.ui files.
|
||||
│ └── src
|
||||
@@ -137,18 +117,27 @@ $ tree -d
|
||||
|
||||
## A note about the project's name
|
||||
|
||||
The project was named after Allan Moore's character [Evey Hammond](https://en.wikipedia.org/wiki/Evey_Hammond) from the graphic novel V for Vendetta.
|
||||
|
||||
It has nothing to do with the horrible headlines on the news.
|
||||
The project used to be called Hammond, after Allan Moore's character [Evey Hammond][hammond] from the graphic novel V for Vendetta.
|
||||
It was renamed to GNOME Podcasts on 2018/07/24 shortly before its first public release.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
Hammond's design is heavily insired by [GNOME Music](https://wiki.gnome.org/Design/Apps/Music) and [Vocal](http://vocalproject.net/).
|
||||
GNOME Podcasts's design is heavily inspired by [GNOME Music][music] and [Vocal][vocal].
|
||||
|
||||
We also copied some elements from [GNOME News](https://wiki.gnome.org/Design/Apps/Potential/News).
|
||||
We also copied some elements from [GNOME News][news].
|
||||
|
||||
And almost the entirety of the build system is copied from the [Fractal](https://gitlab.gnome.org/danigm/fractal) project.
|
||||
And almost the entirety of the build system is copied from the [Fractal][fractal] project.
|
||||
|
||||
[vendor]: https://github.com/alexcrichton/cargo-vendor
|
||||
[irc]: irc://irc.gnome.org/#hammond
|
||||
[matrix]: https://matrix.to/#/#hammond:matrix.org
|
||||
[matrix]: https://matrix.to/#/#gnome-podcasts:matrix.org
|
||||
[flatpak_setup]: https://flatpak.org/setup/
|
||||
[music]: https://wiki.gnome.org/Design/Apps/Music
|
||||
[vocal]: http://vocalproject.net/
|
||||
[news]: https://wiki.gnome.org/Design/Apps/Potential/News
|
||||
[fractal]: https://gitlab.gnome.org/World/fractal
|
||||
[hammond]: https://en.wikipedia.org/wiki/Evey_Hammond
|
||||
[issues]: https://gitlab.gnome.org/World/podcasts/issues
|
||||
[new_issue]: https://gitlab.gnome.org/World/podcasts/issues/new
|
||||
[builder]: https://wiki.gnome.org/Apps/Builder
|
||||
[get_builder]: https://wiki.gnome.org/Apps/Builder/Downloads
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
[package]
|
||||
authors = ["Jordan Petridis <jordanpetridis@protonmail.com>"]
|
||||
name = "hammond-data"
|
||||
version = "0.1.0"
|
||||
workspace = "../"
|
||||
|
||||
[dependencies]
|
||||
ammonia = "1.1.0"
|
||||
chrono = "0.4.4"
|
||||
derive_builder = "0.5.1"
|
||||
lazy_static = "1.0.1"
|
||||
log = "0.4.2"
|
||||
rayon = "1.0.1"
|
||||
rayon-futures = "0.1.0"
|
||||
rfc822_sanitizer = "0.3.3"
|
||||
rss = "1.5.0"
|
||||
url = "1.7.0"
|
||||
xdg = "2.1.0"
|
||||
xml-rs = "0.8.0"
|
||||
futures = "0.1.21"
|
||||
hyper = "0.11.27"
|
||||
tokio-core = "0.1.17"
|
||||
hyper-tls = "0.1.3"
|
||||
native-tls = "0.1.5"
|
||||
num_cpus = "1.8.0"
|
||||
failure = "0.1.1"
|
||||
failure_derive = "0.1.1"
|
||||
|
||||
[dependencies.diesel]
|
||||
features = ["sqlite", "r2d2"]
|
||||
version = "1.3.2"
|
||||
|
||||
[dependencies.diesel_migrations]
|
||||
features = ["sqlite"]
|
||||
version = "1.3.0"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.5.2"
|
||||
tempdir = "0.3.7"
|
||||
criterion = "0.2.3"
|
||||
pretty_assertions = "0.5.1"
|
||||
maplit = "1.0.1"
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
harness = false
|
||||
@@ -1,104 +0,0 @@
|
||||
#![allow(unused)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate criterion;
|
||||
use criterion::Criterion;
|
||||
|
||||
// extern crate futures;
|
||||
extern crate hammond_data;
|
||||
extern crate hyper;
|
||||
extern crate hyper_tls;
|
||||
extern crate rand;
|
||||
extern crate tokio_core;
|
||||
// extern crate rayon;
|
||||
extern crate rss;
|
||||
|
||||
// use rayon::prelude::*;
|
||||
|
||||
// use futures::future::*;
|
||||
use tokio_core::reactor::Core;
|
||||
|
||||
use hammond_data::database::truncate_db;
|
||||
use hammond_data::pipeline;
|
||||
use hammond_data::FeedBuilder;
|
||||
use hammond_data::Source;
|
||||
// use hammond_data::errors::*;
|
||||
|
||||
use std::io::BufReader;
|
||||
|
||||
// RSS feeds
|
||||
const INTERCEPTED: &[u8] = include_bytes!("../tests/feeds/2018-01-20-Intercepted.xml");
|
||||
const INTERCEPTED_URL: &str = "https://web.archive.org/web/20180120083840if_/https://feeds.\
|
||||
feedburner.com/InterceptedWithJeremyScahill";
|
||||
|
||||
const UNPLUGGED: &[u8] = include_bytes!("../tests/feeds/2018-01-20-LinuxUnplugged.xml");
|
||||
const UNPLUGGED_URL: &str =
|
||||
"https://web.archive.org/web/20180120110314if_/https://feeds.feedburner.com/linuxunplugged";
|
||||
|
||||
const TIPOFF: &[u8] = include_bytes!("../tests/feeds/2018-01-20-TheTipOff.xml");
|
||||
const TIPOFF_URL: &str =
|
||||
"https://web.archive.org/web/20180120110727if_/https://rss.acast.com/thetipoff";
|
||||
|
||||
// This feed has HUGE descripion and summary fields which can be very
|
||||
// very expensive to parse.
|
||||
const CODE: &[u8] = include_bytes!("../tests/feeds/2018-01-20-GreaterThanCode.xml");
|
||||
const CODE_URL: &str =
|
||||
"https://web.archive.org/web/20180120104741if_/https://www.greaterthancode.com/feed/podcast";
|
||||
|
||||
// Relative small feed
|
||||
const STARS: &[u8] = include_bytes!("../tests/feeds/2018-01-20-StealTheStars.xml");
|
||||
const STARS_URL: &str =
|
||||
"https://web.archive.org/web/20180120104957if_/https://rss.art19.com/steal-the-stars";
|
||||
|
||||
static FEEDS: &[(&[u8], &str)] = &[
|
||||
(INTERCEPTED, INTERCEPTED_URL),
|
||||
(UNPLUGGED, UNPLUGGED_URL),
|
||||
(TIPOFF, TIPOFF_URL),
|
||||
(CODE, CODE_URL),
|
||||
(STARS, STARS_URL),
|
||||
];
|
||||
|
||||
fn bench_index_large_feed(c: &mut Criterion) {
|
||||
truncate_db().unwrap();
|
||||
let url = "https://www.greaterthancode.com/feed/podcast";
|
||||
let mut core = Core::new().unwrap();
|
||||
|
||||
c.bench_function("index_large_feed", move |b| {
|
||||
b.iter(|| {
|
||||
let s = Source::from_url(url).unwrap();
|
||||
// parse it into a channel
|
||||
let chan = rss::Channel::read_from(BufReader::new(CODE)).unwrap();
|
||||
let feed = FeedBuilder::default()
|
||||
.channel(chan)
|
||||
.source_id(s.id())
|
||||
.build()
|
||||
.unwrap();
|
||||
core.run(feed.index()).unwrap();
|
||||
})
|
||||
});
|
||||
truncate_db().unwrap();
|
||||
}
|
||||
|
||||
fn bench_index_small_feed(c: &mut Criterion) {
|
||||
truncate_db().unwrap();
|
||||
let url = "https://rss.art19.com/steal-the-stars";
|
||||
let mut core = Core::new().unwrap();
|
||||
|
||||
c.bench_function("index_small_feed", move |b| {
|
||||
b.iter(|| {
|
||||
let s = Source::from_url(url).unwrap();
|
||||
// parse it into a channel
|
||||
let chan = rss::Channel::read_from(BufReader::new(STARS)).unwrap();
|
||||
let feed = FeedBuilder::default()
|
||||
.channel(chan)
|
||||
.source_id(s.id())
|
||||
.build()
|
||||
.unwrap();
|
||||
core.run(feed.index()).unwrap();
|
||||
})
|
||||
});
|
||||
truncate_db().unwrap();
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_index_large_feed, bench_index_small_feed);
|
||||
criterion_main!(benches);
|
||||
@@ -1,128 +0,0 @@
|
||||
// FIXME:
|
||||
//! Docs.
|
||||
|
||||
use futures::future::*;
|
||||
use futures::prelude::*;
|
||||
use futures::stream::*;
|
||||
|
||||
use hyper::client::HttpConnector;
|
||||
use hyper::Client;
|
||||
use hyper_tls::HttpsConnector;
|
||||
use tokio_core::reactor::Core;
|
||||
|
||||
use num_cpus;
|
||||
use rayon;
|
||||
use rayon_futures::ScopeFutureExt;
|
||||
|
||||
use errors::DataError;
|
||||
use Source;
|
||||
|
||||
// use std::sync::{Arc, Mutex};
|
||||
|
||||
// http://gtk-rs.org/tuto/closures
|
||||
#[macro_export]
|
||||
macro_rules! clone {
|
||||
(@param _) => ( _ );
|
||||
(@param $x:ident) => ( $x );
|
||||
($($n:ident),+ => move || $body:expr) => (
|
||||
{
|
||||
$( let $n = $n.clone(); )+
|
||||
move || $body
|
||||
}
|
||||
);
|
||||
($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
|
||||
{
|
||||
$( let $n = $n.clone(); )+
|
||||
move |$(clone!(@param $p),)+| $body
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
type HttpsClient = Client<HttpsConnector<HttpConnector>>;
|
||||
|
||||
/// The pipline to be run for indexing and updating a Podcast feed that originates from
|
||||
/// `Source.uri`.
|
||||
///
|
||||
/// Messy temp diagram:
|
||||
/// Source -> GET Request -> Update Etags -> Check Status -> Parse `xml/Rss` ->
|
||||
/// Convert `rss::Channel` into `Feed` -> Index Podcast -> Index Episodes.
|
||||
pub fn pipeline<'a, S>(
|
||||
sources: S,
|
||||
ignore_etags: bool,
|
||||
client: &HttpsClient,
|
||||
) -> impl Future<Item = Vec<()>, Error = DataError> + 'a
|
||||
where
|
||||
S: Stream<Item = Source, Error = DataError> + 'a,
|
||||
{
|
||||
sources
|
||||
.and_then(clone!(client => move |s| s.into_feed(client.clone(), ignore_etags)))
|
||||
.and_then(|feed| rayon::scope(|s| s.spawn_future(feed.index())))
|
||||
// the stream will stop at the first error so
|
||||
// we ensure that everything will succeded regardless.
|
||||
.map_err(|err| error!("Error: {}", err))
|
||||
.then(|_| ok::<(), DataError>(()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Creates a tokio `reactor::Core`, and a `hyper::Client` and
|
||||
/// runs the pipeline to completion. The `reactor::Core` is dropped afterwards.
|
||||
pub fn run<S>(sources: S, ignore_etags: bool) -> Result<(), DataError>
|
||||
where
|
||||
S: IntoIterator<Item = Source>,
|
||||
{
|
||||
let mut core = Core::new()?;
|
||||
let handle = core.handle();
|
||||
let client = Client::configure()
|
||||
.connector(HttpsConnector::new(num_cpus::get(), &handle)?)
|
||||
.build(&handle);
|
||||
|
||||
let stream = iter_ok::<_, DataError>(sources);
|
||||
let p = pipeline(stream, ignore_etags, &client);
|
||||
core.run(p).map(|_| ())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use database::truncate_db;
|
||||
use dbqueries;
|
||||
use Source;
|
||||
|
||||
// (path, url) tuples.
|
||||
const URLS: &[&str] = &[
|
||||
"https://web.archive.org/web/20180120083840if_/https://feeds.feedburner.\
|
||||
com/InterceptedWithJeremyScahill",
|
||||
"https://web.archive.org/web/20180120110314if_/https://feeds.feedburner.com/linuxunplugged",
|
||||
"https://web.archive.org/web/20180120110727if_/https://rss.acast.com/thetipoff",
|
||||
"https://web.archive.org/web/20180120104957if_/https://rss.art19.com/steal-the-stars",
|
||||
"https://web.archive.org/web/20180120104741if_/https://www.greaterthancode.\
|
||||
com/feed/podcast",
|
||||
];
|
||||
|
||||
#[test]
|
||||
/// Insert feeds and update/index them.
|
||||
fn test_pipeline() {
|
||||
truncate_db().unwrap();
|
||||
let bad_url = "https://gitlab.gnome.org/World/hammond.atom";
|
||||
// if a stream returns error/None it stops
|
||||
// bad we want to parse all feeds regardless if one fails
|
||||
Source::from_url(bad_url).unwrap();
|
||||
|
||||
URLS.iter().for_each(|url| {
|
||||
// Index the urls into the source table.
|
||||
Source::from_url(url).unwrap();
|
||||
});
|
||||
|
||||
let sources = dbqueries::get_sources().unwrap();
|
||||
run(sources, true).unwrap();
|
||||
|
||||
let sources = dbqueries::get_sources().unwrap();
|
||||
// Run again to cover Unique constrains erros.
|
||||
run(sources, true).unwrap();
|
||||
|
||||
// Assert the index rows equal the controlled results
|
||||
assert_eq!(dbqueries::get_sources().unwrap().len(), 6);
|
||||
assert_eq!(dbqueries::get_podcasts().unwrap().len(), 5);
|
||||
assert_eq!(dbqueries::get_episodes().unwrap().len(), 354);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
[package]
|
||||
authors = ["Jordan Petridis <jordanpetridis@protonmail.com>"]
|
||||
name = "hammond-downloader"
|
||||
version = "0.1.0"
|
||||
workspace = "../"
|
||||
|
||||
[dependencies]
|
||||
error-chain = "0.12.0"
|
||||
hyper = "0.11.27"
|
||||
log = "0.4.2"
|
||||
mime_guess = "1.8.4"
|
||||
reqwest = "0.8.6"
|
||||
tempdir = "0.3.7"
|
||||
glob = "0.2.11"
|
||||
failure = "0.1.1"
|
||||
failure_derive = "0.1.1"
|
||||
|
||||
[dependencies.hammond-data]
|
||||
path = "../hammond-data"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.5.1"
|
||||
@@ -1,33 +0,0 @@
|
||||
#![recursion_limit = "1024"]
|
||||
#![allow(unknown_lints)]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(blacklisted_name, option_map_unit_fn))]
|
||||
// Enable lint group collections
|
||||
#![warn(nonstandard_style, edition_2018, rust_2018_idioms, bad_style, unused)]
|
||||
// standalone lints
|
||||
#![warn(
|
||||
const_err, improper_ctypes, non_shorthand_field_patterns, no_mangle_generic_items,
|
||||
overflowing_literals, plugin_as_library, private_no_mangle_fns, private_no_mangle_statics,
|
||||
unconditional_recursion, unions_with_drop_fields, while_true, missing_debug_implementations,
|
||||
trivial_casts, trivial_numeric_casts, elided_lifetime_in_paths, missing_copy_implementations
|
||||
)]
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
extern crate failure_derive;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate pretty_assertions;
|
||||
|
||||
extern crate glob;
|
||||
extern crate hammond_data;
|
||||
extern crate hyper;
|
||||
extern crate mime_guess;
|
||||
extern crate reqwest;
|
||||
extern crate tempdir;
|
||||
|
||||
pub mod downloader;
|
||||
pub mod errors;
|
||||
@@ -1,46 +0,0 @@
|
||||
[package]
|
||||
authors = ["Jordan Petridis <jordanpetridis@protonmail.com>"]
|
||||
build = "build.rs"
|
||||
name = "hammond-gtk"
|
||||
version = "0.1.0"
|
||||
workspace = "../"
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.4"
|
||||
crossbeam-channel = "0.2.1"
|
||||
gdk = "0.8.0"
|
||||
gdk-pixbuf = "0.4.0"
|
||||
glib = "0.5.0"
|
||||
gstreamer = "0.11.3"
|
||||
gstreamer-player = "0.11.3"
|
||||
humansize = "1.1.0"
|
||||
lazy_static = "1.0.1"
|
||||
log = "0.4.2"
|
||||
loggerv = "0.7.1"
|
||||
open = "1.2.1"
|
||||
rayon = "1.0.1"
|
||||
send-cell = "0.1.3"
|
||||
url = "1.7.0"
|
||||
failure = "0.1.1"
|
||||
failure_derive = "0.1.1"
|
||||
regex = "1.0.1"
|
||||
reqwest = "0.8.6"
|
||||
serde_json = "1.0.22"
|
||||
html2text = "0.1.7"
|
||||
|
||||
[dependencies.gtk]
|
||||
features = ["v3_22"]
|
||||
version = "0.4.1"
|
||||
|
||||
[dependencies.gio]
|
||||
features = ["v2_50"]
|
||||
version = "0.4.1"
|
||||
|
||||
[dependencies.hammond-data]
|
||||
path = "../hammond-data"
|
||||
|
||||
[dependencies.hammond-downloader]
|
||||
path = "../hammond-downloader"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.5.1"
|
||||
@@ -1,63 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkBox" id="empty_show">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="pixel_size">128</property>
|
||||
<property name="icon_name">application-rss+xml-symbolic</property>
|
||||
<property name="use_fallback">True</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">This show does not have any episodes</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="1.4399999999999999"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">If you think this is an Error, Plese consider opening a bug report.</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,91 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.21.0
|
||||
|
||||
Copyright (C) 2017 - 2018
|
||||
|
||||
This file is part of Hammond.
|
||||
|
||||
Hammond is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Hammond is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Hammond. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Authors:
|
||||
Jordan Petridis
|
||||
Tobias Bernard
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<!-- interface-license-type gplv3 -->
|
||||
<!-- interface-name Hammond -->
|
||||
<!-- interface-description A podcast client for the GNOME Desktop -->
|
||||
<!-- interface-copyright 2017 - 2018 -->
|
||||
<!-- interface-authors Jordan Petridis\nTobias Bernard -->
|
||||
<object class="GtkBox" id="empty_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="pixel_size">128</property>
|
||||
<property name="icon_name">application-rss+xml-symbolic</property>
|
||||
<property name="use_fallback">True</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">No Feed Subscription Found</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="1.4399999999999999"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">You can subscribe to feeds using the "+" button</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,399 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.0
|
||||
|
||||
Copyright (C) 2017 - 2018
|
||||
|
||||
This file is part of Hammond.
|
||||
|
||||
Hammond is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Hammond is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Hammond. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Authors:
|
||||
Jordan Petridis
|
||||
Tobias Bernard
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<!-- interface-license-type gplv3 -->
|
||||
<!-- interface-name Hammond -->
|
||||
<!-- interface-description A podcast client for the GNOME Desktop -->
|
||||
<!-- interface-copyright 2017 - 2018 -->
|
||||
<!-- interface-authors Jordan Petridis\nTobias Bernard -->
|
||||
<object class="GtkBox" id="container">
|
||||
<property name="name">container</property>
|
||||
<property name="width_request">400</property>
|
||||
<property name="height_request">600</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolled_window">
|
||||
<property name="name">scrolled_window</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="frame_parent">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">32</property>
|
||||
<property name="margin_right">32</property>
|
||||
<property name="margin_top">32</property>
|
||||
<property name="margin_bottom">32</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">24</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="today_box">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">Today</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="1.5"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="today_list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="selection_mode">none</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="yday_box">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Yesterday</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="1.5"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="yday_list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="selection_mode">none</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="week_box">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">This Week</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="1.5"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="week_list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="selection_mode">none</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="month_box">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">This Month</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="1.5"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="month_list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="selection_mode">none</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="rest_box">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">Older</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="1.5"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="rest_list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="selection_mode">none</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,300 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.0
|
||||
|
||||
Copyright (C) 2017 - 2018
|
||||
|
||||
This file is part of Hammond.
|
||||
|
||||
Hammond is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Hammond is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Hammond. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Authors:
|
||||
Jordan Petridis
|
||||
Tobias Bernard
|
||||
|
||||
-->
|
||||
<interface domain="">
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<!-- interface-license-type gplv3 -->
|
||||
<!-- interface-name Hammond -->
|
||||
<!-- interface-description A podcast client for the GNOME Desktop -->
|
||||
<!-- interface-copyright 2017 - 2018 -->
|
||||
<!-- interface-authors Jordan Petridis\nTobias Bernard -->
|
||||
<object class="GtkBox" id="container">
|
||||
<property name="width_request">400</property>
|
||||
<property name="height_request">600</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolled_window">
|
||||
<property name="name">scrolled_window</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">32</property>
|
||||
<property name="margin_right">32</property>
|
||||
<property name="margin_top">32</property>
|
||||
<property name="margin_bottom">32</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">24</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="cover">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="pixel_size">256</property>
|
||||
<property name="icon_name">image-x-generic-symbolic</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<property name="min_content_height">80</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="description">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="label">This is embarrasing!
|
||||
Sorry, we could not find a description for this Show.</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">center</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="max_width_chars">70</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="settings_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="icon_name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="link_button">
|
||||
<property name="label" translatable="yes">Website</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="unsub_button">
|
||||
<property name="label" translatable="yes">Unsubscribe</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="destructive-action"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="episodes">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="selection_mode">none</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkPopover" id="show_menu">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="position">bottom</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">6</property>
|
||||
<property name="margin_right">6</property>
|
||||
<property name="margin_top">6</property>
|
||||
<property name="margin_bottom">6</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="mark_all_watched">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="text" translatable="yes">Mark all episodes as listened</property>
|
||||
<property name="centered">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,58 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.0
|
||||
|
||||
Copyright (C) 2017 - 2018
|
||||
|
||||
This file is part of Hammond.
|
||||
|
||||
Hammond is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Hammond is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Hammond. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Authors:
|
||||
Jordan Petridis
|
||||
Tobias Bernard
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<!-- interface-license-type gplv3 -->
|
||||
<!-- interface-name Hammond -->
|
||||
<!-- interface-description A podcast client for the GNOME Desktop -->
|
||||
<!-- interface-copyright 2017 - 2018 -->
|
||||
<!-- interface-authors Jordan Petridis\nTobias Bernard -->
|
||||
<object class="GtkBox" id="fb_child">
|
||||
<property name="width_request">256</property>
|
||||
<property name="height_request">256</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="pd_cover">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="pixel_size">256</property>
|
||||
<property name="icon_name">image-x-generic-symbolic</property>
|
||||
<property name="icon_size">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,72 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.21.0
|
||||
|
||||
Copyright (C) 2017 - 2018
|
||||
|
||||
This file is part of Hammond.
|
||||
|
||||
Hammond is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Hammond is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Hammond. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Authors:
|
||||
Jordan Petridis
|
||||
Tobias Bernard
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<!-- interface-license-type gplv3 -->
|
||||
<!-- interface-name Hammond -->
|
||||
<!-- interface-description A podcast client for the GNOME Desktop -->
|
||||
<!-- interface-copyright 2017 - 2018 -->
|
||||
<!-- interface-authors Jordan Petridis\nTobias Bernard -->
|
||||
<object class="GtkBox" id="fb_parent">
|
||||
<property name="name">fb_parent</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolled_window">
|
||||
<property name="name">scrolled_window</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkFlowBox" id="flowbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="margin_bottom">24</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<property name="max_children_per_line">20</property>
|
||||
<property name="selection_mode">none</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,20 +0,0 @@
|
||||
row {
|
||||
border-bottom: solid 1px rgba(0,0,0, 0.1);
|
||||
}
|
||||
|
||||
row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
list, border {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.player-episode-label {
|
||||
font-weight: bold;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.player-show-label {
|
||||
font-size: smaller;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# subdir('icons')
|
||||
|
||||
install_data('org.gnome.Hammond.desktop', install_dir : datadir + '/applications')
|
||||
install_data('org.gnome.Hammond.appdata.xml', install_dir : datadir + '/appdata')
|
||||
install_data('org.gnome.Hammond.gschema.xml', install_dir: join_paths(datadir, 'glib-2.0', 'schemas'))
|
||||
meson.add_install_script('../../scripts/compile-gschema.py')
|
||||
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop">
|
||||
<id>org.gnome.Hammond</id>
|
||||
<name>Hammond</name>
|
||||
<project_license>GPL-3.0</project_license>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<developer_name>Jordan Petridis</developer_name>
|
||||
<summary>Modern Podcast application for the GNOME desktop</summary>
|
||||
<description xml:lang="en">
|
||||
<p>
|
||||
Hammond is a modern, reliable, and fast Podcast application for the GNOME
|
||||
desktop written in Rust.
|
||||
</p>
|
||||
</description>
|
||||
<url type="homepage">https://gitlab.gnome.org/World/hammond</url>
|
||||
<screenshots>
|
||||
<screenshot>
|
||||
<image>https://gitlab.gnome.org/World/hammond/raw/master/screenshots/episodes_view.png</image>
|
||||
<caption>Page 1</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://gitlab.gnome.org/World/hammond/raw/master/screenshots/shows_view.png</image>
|
||||
<caption>Page 2</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://gitlab.gnome.org/World/hammond/raw/master/screenshots/show_widget.png</image>
|
||||
<caption>Page 3</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="0.4.0" date="2018-07-04"/>
|
||||
</releases>
|
||||
<url type="homepage">https://gitlab.gnome.org/World/hammond</url>
|
||||
<update_contact>jpetridis@gnome.org</update_contact>
|
||||
<developer_name>Jordan Petridis and others</developer_name>
|
||||
</component>
|
||||
@@ -1,11 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Name=Hammond
|
||||
GenericName=Podcast Client
|
||||
Comment=Play, Subscribe and Manage Podcast Feeds.
|
||||
Icon=multimedia-player
|
||||
Exec=hammond
|
||||
Terminal=false
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=AudioVideo;Audio;Video;
|
||||
Keywords=Podcast
|
||||
@@ -1,299 +0,0 @@
|
||||
#![allow(new_without_default)]
|
||||
|
||||
use gio::{
|
||||
self, ActionMapExt, ApplicationExt, ApplicationExtManual, ApplicationFlags, SettingsExt,
|
||||
SimpleAction, SimpleActionExt,
|
||||
};
|
||||
use glib;
|
||||
use gtk;
|
||||
use gtk::prelude::*;
|
||||
use gtk::SettingsExt as GtkSettingsExt;
|
||||
|
||||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||
use hammond_data::Show;
|
||||
|
||||
use headerbar::Header;
|
||||
use settings::{self, WindowGeometry};
|
||||
use stacks::{Content, PopulatedState};
|
||||
use utils;
|
||||
use widgets::appnotif::{InAppNotification, UndoState};
|
||||
use widgets::player;
|
||||
use widgets::{about_dialog, mark_all_notif, remove_show_notif};
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Creates an action named $called in the action map $on with the handler $handle
|
||||
macro_rules! action {
|
||||
($on:expr, $called:expr, $handle:expr) => {{
|
||||
// Create a stateless, parameterless action
|
||||
let act = SimpleAction::new($called, None);
|
||||
// Connect the handler
|
||||
act.connect_activate($handle);
|
||||
// Add it to the map
|
||||
$on.add_action(&act);
|
||||
// Return the action
|
||||
act
|
||||
}};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Action {
|
||||
RefreshAllViews,
|
||||
RefreshEpisodesView,
|
||||
RefreshEpisodesViewBGR,
|
||||
RefreshShowsView,
|
||||
ReplaceWidget(Arc<Show>),
|
||||
RefreshWidgetIfSame(i32),
|
||||
ShowWidgetAnimated,
|
||||
ShowShowsAnimated,
|
||||
HeaderBarShowTile(String),
|
||||
HeaderBarNormal,
|
||||
HeaderBarShowUpdateIndicator,
|
||||
HeaderBarHideUpdateIndicator,
|
||||
MarkAllPlayerNotification(Arc<Show>),
|
||||
RemoveShow(Arc<Show>),
|
||||
ErrorNotification(String),
|
||||
InitEpisode(i32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct App {
|
||||
instance: gtk::Application,
|
||||
window: gtk::ApplicationWindow,
|
||||
overlay: gtk::Overlay,
|
||||
settings: gio::Settings,
|
||||
content: Rc<Content>,
|
||||
headerbar: Rc<Header>,
|
||||
player: Rc<player::PlayerWidget>,
|
||||
sender: Sender<Action>,
|
||||
receiver: Receiver<Action>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new(application: >k::Application) -> Rc<Self> {
|
||||
let settings = gio::Settings::new("org.gnome.Hammond");
|
||||
|
||||
let (sender, receiver) = unbounded();
|
||||
|
||||
let window = gtk::ApplicationWindow::new(application);
|
||||
window.set_title("Hammond");
|
||||
window.connect_delete_event(clone!(application, settings => move |window, _| {
|
||||
WindowGeometry::from_window(&window).write(&settings);
|
||||
application.quit();
|
||||
Inhibit(false)
|
||||
}));
|
||||
|
||||
// Create a content instance
|
||||
let content = Content::new(&sender).expect("Content Initialization failed.");
|
||||
|
||||
// Create the headerbar
|
||||
let header = Header::new(&content, &sender);
|
||||
// Add the Headerbar to the window.
|
||||
window.set_titlebar(&header.container);
|
||||
|
||||
// Add the content main stack to the overlay.
|
||||
let overlay = gtk::Overlay::new();
|
||||
overlay.add(&content.get_stack());
|
||||
|
||||
let wrap = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
||||
// Add the overlay to the main Box
|
||||
wrap.add(&overlay);
|
||||
|
||||
let player = player::PlayerWidget::new(&sender);
|
||||
// Add the player to the main Box
|
||||
wrap.add(&player.action_bar);
|
||||
|
||||
window.add(&wrap);
|
||||
|
||||
let app = App {
|
||||
instance: application.clone(),
|
||||
window,
|
||||
settings,
|
||||
overlay,
|
||||
headerbar: header,
|
||||
content,
|
||||
player,
|
||||
sender,
|
||||
receiver,
|
||||
};
|
||||
|
||||
Rc::new(app)
|
||||
}
|
||||
|
||||
fn init(app: &Rc<Self>) {
|
||||
let cleanup_date = settings::get_cleanup_date(&app.settings);
|
||||
// Garbage collect watched episodes from the disk
|
||||
utils::cleanup(cleanup_date);
|
||||
|
||||
app.setup_gactions();
|
||||
app.setup_timed_callbacks();
|
||||
|
||||
app.instance.connect_activate(move |_| ());
|
||||
|
||||
// Retrieve the previous window position and size.
|
||||
WindowGeometry::from_settings(&app.settings).apply(&app.window);
|
||||
|
||||
// Setup the Action channel
|
||||
gtk::timeout_add(25, clone!(app => move || app.setup_action_channel()));
|
||||
}
|
||||
|
||||
fn setup_timed_callbacks(&self) {
|
||||
self.setup_dark_theme();
|
||||
self.setup_refresh_on_startup();
|
||||
self.setup_auto_refresh();
|
||||
}
|
||||
|
||||
fn setup_dark_theme(&self) {
|
||||
let gtk_settings = gtk::Settings::get_default().unwrap();
|
||||
let enabled = self.settings.get_boolean("dark-theme");
|
||||
|
||||
gtk_settings.set_property_gtk_application_prefer_dark_theme(enabled);
|
||||
}
|
||||
|
||||
fn setup_refresh_on_startup(&self) {
|
||||
// Update the feeds right after the Application is initialized.
|
||||
let sender = self.sender.clone();
|
||||
if self.settings.get_boolean("refresh-on-startup") {
|
||||
info!("Refresh on startup.");
|
||||
// The ui loads async, after initialization
|
||||
// so we need to delay this a bit so it won't block
|
||||
// requests that will come from loading the gui on startup.
|
||||
gtk::timeout_add(1500, move || {
|
||||
let s: Option<Vec<_>> = None;
|
||||
utils::refresh(s, sender.clone());
|
||||
glib::Continue(false)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_auto_refresh(&self) {
|
||||
let refresh_interval = settings::get_refresh_interval(&self.settings).num_seconds() as u32;
|
||||
info!("Auto-refresh every {:?} seconds.", refresh_interval);
|
||||
|
||||
let sender = self.sender.clone();
|
||||
gtk::timeout_add_seconds(refresh_interval, move || {
|
||||
let s: Option<Vec<_>> = None;
|
||||
utils::refresh(s, sender.clone());
|
||||
|
||||
glib::Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
/// Define the `GAction`s.
|
||||
///
|
||||
/// Used in menus and the keyboard shortcuts dialog.
|
||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
fn setup_gactions(&self) {
|
||||
let sender = &self.sender;
|
||||
let win = &self.window;
|
||||
let instance = &self.instance;
|
||||
let header = &self.headerbar;
|
||||
|
||||
// Create the `refresh` action.
|
||||
//
|
||||
// This will trigger a refresh of all the shows in the database.
|
||||
action!(win, "refresh", clone!(sender => move |_, _| {
|
||||
gtk::idle_add(clone!(sender => move || {
|
||||
let s: Option<Vec<_>> = None;
|
||||
utils::refresh(s, sender.clone());
|
||||
glib::Continue(false)
|
||||
}));
|
||||
}));
|
||||
self.instance.set_accels_for_action("win.refresh", &["<primary>r"]);
|
||||
|
||||
// Create the `OPML` import action
|
||||
action!(win, "import", clone!(sender, win => move |_, _| {
|
||||
utils::on_import_clicked(&win, &sender)
|
||||
}));
|
||||
|
||||
// Create the action that shows a `gtk::AboutDialog`
|
||||
action!(win, "about", clone!(win => move |_, _| about_dialog(&win)));
|
||||
|
||||
// Create the quit action
|
||||
action!(win, "quit", clone!(instance => move |_, _| instance.quit()));
|
||||
self.instance.set_accels_for_action("win.quit", &["<primary>q"]);
|
||||
|
||||
// Create the menu action
|
||||
action!(win, "menu",clone!(header => move |_, _| header.open_menu()));
|
||||
// Bind the hamburger menu button to `F10`
|
||||
self.instance.set_accels_for_action("win.menu", &["F10"]);
|
||||
}
|
||||
|
||||
fn setup_action_channel(&self) -> glib::Continue {
|
||||
if let Some(action) = self.receiver.try_recv() {
|
||||
trace!("Incoming channel action: {:?}", action);
|
||||
match action {
|
||||
Action::RefreshAllViews => self.content.update(),
|
||||
Action::RefreshShowsView => self.content.update_shows_view(),
|
||||
Action::RefreshWidgetIfSame(id) => self.content.update_widget_if_same(id),
|
||||
Action::RefreshEpisodesView => self.content.update_home(),
|
||||
Action::RefreshEpisodesViewBGR => self.content.update_home_if_background(),
|
||||
Action::ReplaceWidget(pd) => {
|
||||
let shows = self.content.get_shows();
|
||||
let mut pop = shows.borrow().populated();
|
||||
pop.borrow_mut()
|
||||
.replace_widget(pd.clone())
|
||||
.map_err(|err| error!("Failed to update ShowWidget: {}", err))
|
||||
.map_err(|_| error!("Failed ot update ShowWidget {}", pd.title()))
|
||||
.ok();
|
||||
}
|
||||
Action::ShowWidgetAnimated => {
|
||||
let shows = self.content.get_shows();
|
||||
let mut pop = shows.borrow().populated();
|
||||
pop.borrow_mut().switch_visible(
|
||||
PopulatedState::Widget,
|
||||
gtk::StackTransitionType::SlideLeft,
|
||||
);
|
||||
}
|
||||
Action::ShowShowsAnimated => {
|
||||
let shows = self.content.get_shows();
|
||||
let mut pop = shows.borrow().populated();
|
||||
pop.borrow_mut()
|
||||
.switch_visible(PopulatedState::View, gtk::StackTransitionType::SlideRight);
|
||||
}
|
||||
Action::HeaderBarShowTile(title) => self.headerbar.switch_to_back(&title),
|
||||
Action::HeaderBarNormal => self.headerbar.switch_to_normal(),
|
||||
Action::HeaderBarShowUpdateIndicator => self.headerbar.show_update_notification(),
|
||||
Action::HeaderBarHideUpdateIndicator => self.headerbar.hide_update_notification(),
|
||||
Action::MarkAllPlayerNotification(pd) => {
|
||||
let notif = mark_all_notif(pd, &self.sender);
|
||||
notif.show(&self.overlay);
|
||||
}
|
||||
Action::RemoveShow(pd) => {
|
||||
let notif = remove_show_notif(pd, self.sender.clone());
|
||||
notif.show(&self.overlay);
|
||||
}
|
||||
Action::ErrorNotification(err) => {
|
||||
error!("An error notification was triggered: {}", err);
|
||||
let callback = || glib::Continue(false);
|
||||
let notif = InAppNotification::new(&err, callback, || {}, UndoState::Hidden);
|
||||
notif.show(&self.overlay);
|
||||
}
|
||||
Action::InitEpisode(rowid) => self.player.initialize_episode(rowid).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
glib::Continue(true)
|
||||
}
|
||||
|
||||
pub fn run() {
|
||||
let application = gtk::Application::new("org.gnome.Hammond", ApplicationFlags::empty())
|
||||
.expect("Application Initialization failed...");
|
||||
|
||||
application.connect_startup(clone!(application => move |_| {
|
||||
info!("CONNECT STARTUP RUN");
|
||||
let app = Self::new(&application);
|
||||
Self::init(&app);
|
||||
app.window.show_all();
|
||||
app.window.activate();
|
||||
}));
|
||||
|
||||
// Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
glib::set_application_name("Hammond");
|
||||
glib::set_prgname(Some("Hammond"));
|
||||
// We need out own org.gnome.Hammon icon
|
||||
gtk::Window::set_default_icon_name("multimedia-player");
|
||||
ApplicationExtManual::run(&application, &[]);
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
use gtk;
|
||||
use gtk::prelude::*;
|
||||
use gtk::StackTransitionType;
|
||||
|
||||
use crossbeam_channel::Sender;
|
||||
use failure::Error;
|
||||
use hammond_data::dbqueries::is_episodes_populated;
|
||||
use hammond_data::errors::DataError;
|
||||
|
||||
use app::Action;
|
||||
use widgets::{EmptyView, HomeView};
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum State {
|
||||
Home,
|
||||
Empty,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HomeStack {
|
||||
empty: EmptyView,
|
||||
episodes: Rc<HomeView>,
|
||||
stack: gtk::Stack,
|
||||
state: State,
|
||||
sender: Sender<Action>,
|
||||
}
|
||||
|
||||
impl HomeStack {
|
||||
pub fn new(sender: Sender<Action>) -> Result<HomeStack, Error> {
|
||||
let episodes = HomeView::new(sender.clone())?;
|
||||
let empty = EmptyView::new();
|
||||
let stack = gtk::Stack::new();
|
||||
let state = State::Empty;
|
||||
|
||||
stack.add_named(&episodes.container, "home");
|
||||
stack.add_named(&empty.container, "empty");
|
||||
|
||||
let mut home = HomeStack {
|
||||
empty,
|
||||
episodes,
|
||||
stack,
|
||||
state,
|
||||
sender,
|
||||
};
|
||||
|
||||
home.determine_state()?;
|
||||
Ok(home)
|
||||
}
|
||||
|
||||
pub fn get_stack(&self) -> gtk::Stack {
|
||||
self.stack.clone()
|
||||
}
|
||||
|
||||
pub fn update(&mut self) -> Result<(), Error> {
|
||||
// Copy the vertical scrollbar adjustment from the old view.
|
||||
self.episodes
|
||||
.save_alignment()
|
||||
.map_err(|err| error!("Failed to set episodes_view allignment: {}", err))
|
||||
.ok();
|
||||
|
||||
self.replace_view()?;
|
||||
// Determine the actuall state.
|
||||
self.determine_state().map_err(From::from)
|
||||
}
|
||||
|
||||
fn replace_view(&mut self) -> Result<(), Error> {
|
||||
// Get the container of the view
|
||||
let old = &self.episodes.container.clone();
|
||||
let eps = HomeView::new(self.sender.clone())?;
|
||||
|
||||
// Remove the old widget and add the new one
|
||||
// during this the previous view is removed,
|
||||
// and the visibile child fallsback to empty view.
|
||||
self.stack.remove(old);
|
||||
self.stack.add_named(&eps.container, "home");
|
||||
// Keep the previous state.
|
||||
let s = self.state;
|
||||
// Set the visible child back to the previous one to avoid
|
||||
// the stack transition animation to show the empty view
|
||||
self.switch_visible(s, StackTransitionType::None);
|
||||
|
||||
// replace view in the struct too
|
||||
self.episodes = eps;
|
||||
|
||||
// This might not be needed
|
||||
old.destroy();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn switch_visible(&mut self, s: State, animation: StackTransitionType) {
|
||||
use self::State::*;
|
||||
|
||||
match s {
|
||||
Home => {
|
||||
self.stack.set_visible_child_full("home", animation);
|
||||
self.state = Home;
|
||||
}
|
||||
Empty => {
|
||||
self.stack.set_visible_child_full("empty", animation);
|
||||
self.state = Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn determine_state(&mut self) -> Result<(), DataError> {
|
||||
if is_episodes_populated()? {
|
||||
self.switch_visible(State::Home, StackTransitionType::Crossfade);
|
||||
} else {
|
||||
self.switch_visible(State::Empty, StackTransitionType::Crossfade);
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
mod content;
|
||||
mod home;
|
||||
mod populated;
|
||||
mod show;
|
||||
|
||||
pub use self::content::Content;
|
||||
pub use self::home::HomeStack;
|
||||
pub use self::populated::{PopulatedStack, PopulatedState};
|
||||
pub use self::show::{ShowStack, ShowState};
|
||||
@@ -1,42 +0,0 @@
|
||||
use gtk;
|
||||
use gtk::prelude::*;
|
||||
|
||||
// Totally copied it from fractal.
|
||||
// https://gitlab.gnome.org/danigm/fractal/blob/503e311e22b9d7540089d735b92af8e8f93560c5/fractal-gtk/src/app.rs#L1883-1912
|
||||
/// Given a `window` create and attach an `gtk::AboutDialog` to it.
|
||||
pub fn about_dialog(window: >k::ApplicationWindow) {
|
||||
// Feel free to add yourself if you contribured.
|
||||
let authors = &[
|
||||
"Constantin Nickel",
|
||||
"Gabriele Musco",
|
||||
"James Wykeham-Martin",
|
||||
"Jordan Petridis",
|
||||
"Julian Sparber",
|
||||
"Rowan Lewis",
|
||||
"Zander Brown",
|
||||
];
|
||||
|
||||
let dialog = gtk::AboutDialog::new();
|
||||
// Waiting for a logo.
|
||||
// dialog.set_logo_icon_name("org.gnome.Hammond");
|
||||
dialog.set_logo_icon_name("multimedia-player");
|
||||
dialog.set_comments("Podcast Client for the GNOME Desktop.");
|
||||
dialog.set_copyright("© 2017, 2018 Jordan Petridis");
|
||||
dialog.set_license_type(gtk::License::Gpl30);
|
||||
dialog.set_modal(true);
|
||||
// TODO: make it show it fetches the commit hash from which it was built
|
||||
// and the version number is kept in sync automaticly
|
||||
dialog.set_version("0.4.0");
|
||||
dialog.set_program_name("Hammond");
|
||||
// TODO: Need a wiki page first.
|
||||
// dialog.set_website("https://wiki.gnome.org/Design/Apps/Potential/Podcasts");
|
||||
// dialog.set_website_label("Learn more about Hammond");
|
||||
dialog.set_transient_for(window);
|
||||
|
||||
dialog.set_artists(&["Tobias Bernard"]);
|
||||
dialog.set_authors(authors);
|
||||
|
||||
dialog.connect_response(|dlg, _| dlg.destroy());
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
use glib;
|
||||
use gtk;
|
||||
use gtk::prelude::*;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum UndoState {
|
||||
Shown,
|
||||
Hidden,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InAppNotification {
|
||||
revealer: gtk::Revealer,
|
||||
text: gtk::Label,
|
||||
undo: gtk::Button,
|
||||
close: gtk::Button,
|
||||
}
|
||||
|
||||
impl Default for InAppNotification {
|
||||
fn default() -> Self {
|
||||
let builder = gtk::Builder::new_from_resource("/org/gnome/Hammond/gtk/inapp_notif.ui");
|
||||
|
||||
let revealer: gtk::Revealer = builder.get_object("revealer").unwrap();
|
||||
let text: gtk::Label = builder.get_object("text").unwrap();
|
||||
let undo: gtk::Button = builder.get_object("undo").unwrap();
|
||||
let close: gtk::Button = builder.get_object("close").unwrap();
|
||||
|
||||
InAppNotification {
|
||||
revealer,
|
||||
text,
|
||||
undo,
|
||||
close,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InAppNotification {
|
||||
pub fn new<F, U>(text: &str, mut callback: F, undo_callback: U, show_undo: UndoState) -> Self
|
||||
where
|
||||
F: FnMut() -> glib::Continue + 'static,
|
||||
U: Fn() + 'static,
|
||||
{
|
||||
let notif = InAppNotification::default();
|
||||
notif.text.set_text(&text);
|
||||
|
||||
let revealer = notif.revealer.clone();
|
||||
let id = timeout_add_seconds(6, move || {
|
||||
revealer.set_reveal_child(false);
|
||||
callback()
|
||||
});
|
||||
let id = Rc::new(RefCell::new(Some(id)));
|
||||
|
||||
// Cancel the callback
|
||||
let revealer = notif.revealer.clone();
|
||||
notif.undo.connect_clicked(move |_| {
|
||||
let foo = id.borrow_mut().take();
|
||||
if let Some(id) = foo {
|
||||
glib::source::source_remove(id);
|
||||
}
|
||||
|
||||
undo_callback();
|
||||
|
||||
// Hide the notification
|
||||
revealer.set_reveal_child(false);
|
||||
});
|
||||
|
||||
// Hide the revealer when the close button is clicked
|
||||
let revealer = notif.revealer.clone();
|
||||
notif.close.connect_clicked(move |_| {
|
||||
revealer.set_reveal_child(false);
|
||||
});
|
||||
|
||||
match show_undo {
|
||||
UndoState::Shown => (),
|
||||
UndoState::Hidden => notif.undo.hide(),
|
||||
}
|
||||
|
||||
notif
|
||||
}
|
||||
|
||||
// This is a seperate method cause in order to get a nice animation
|
||||
// the revealer should be attached to something that displays it.
|
||||
// Previously we where doing it in the constructor, which had the result
|
||||
// of the animation being skipped cause there was no parent widget to display it.
|
||||
pub fn show(&self, overlay: >k::Overlay) {
|
||||
overlay.add_overlay(&self.revealer);
|
||||
// We need to display the notification after the widget is added to the overlay
|
||||
// so there will be a nice animation.
|
||||
self.revealer.set_reveal_child(true);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
use gtk;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EmptyView {
|
||||
pub container: gtk::Box,
|
||||
}
|
||||
|
||||
impl Default for EmptyView {
|
||||
fn default() -> Self {
|
||||
let builder = gtk::Builder::new_from_resource("/org/gnome/Hammond/gtk/empty_view.ui");
|
||||
let view: gtk::Box = builder.get_object("empty_view").unwrap();
|
||||
|
||||
EmptyView { container: view }
|
||||
}
|
||||
}
|
||||
|
||||
impl EmptyView {
|
||||
pub fn new() -> EmptyView {
|
||||
EmptyView::default()
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
mod aboutdialog;
|
||||
pub mod appnotif;
|
||||
mod empty;
|
||||
mod episode;
|
||||
mod home_view;
|
||||
pub mod player;
|
||||
mod show;
|
||||
mod shows_view;
|
||||
|
||||
pub use self::aboutdialog::about_dialog;
|
||||
pub use self::empty::EmptyView;
|
||||
pub use self::episode::EpisodeWidget;
|
||||
pub use self::home_view::HomeView;
|
||||
pub use self::show::ShowWidget;
|
||||
pub use self::show::{mark_all_notif, remove_show_notif};
|
||||
pub use self::shows_view::ShowsView;
|
||||
@@ -1,332 +0,0 @@
|
||||
use glib;
|
||||
use gtk;
|
||||
use gtk::prelude::*;
|
||||
|
||||
use crossbeam_channel::Sender;
|
||||
use failure::Error;
|
||||
use html2text;
|
||||
use open;
|
||||
use rayon;
|
||||
use send_cell::SendCell;
|
||||
|
||||
use hammond_data::dbqueries;
|
||||
use hammond_data::utils::delete_show;
|
||||
use hammond_data::Show;
|
||||
|
||||
use app::Action;
|
||||
use utils::{self, lazy_load};
|
||||
use widgets::appnotif::{InAppNotification, UndoState};
|
||||
use widgets::EpisodeWidget;
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
lazy_static! {
|
||||
static ref SHOW_WIDGET_VALIGNMENT: Mutex<Option<(i32, SendCell<gtk::Adjustment>)>> =
|
||||
Mutex::new(None);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ShowWidget {
|
||||
pub container: gtk::Box,
|
||||
scrolled_window: gtk::ScrolledWindow,
|
||||
cover: gtk::Image,
|
||||
description: gtk::Label,
|
||||
link: gtk::Button,
|
||||
settings: gtk::MenuButton,
|
||||
unsub: gtk::Button,
|
||||
episodes: gtk::ListBox,
|
||||
show_id: Option<i32>,
|
||||
}
|
||||
|
||||
impl Default for ShowWidget {
|
||||
fn default() -> Self {
|
||||
let builder = gtk::Builder::new_from_resource("/org/gnome/Hammond/gtk/show_widget.ui");
|
||||
let container: gtk::Box = builder.get_object("container").unwrap();
|
||||
let scrolled_window: gtk::ScrolledWindow = builder.get_object("scrolled_window").unwrap();
|
||||
let episodes = builder.get_object("episodes").unwrap();
|
||||
|
||||
let cover: gtk::Image = builder.get_object("cover").unwrap();
|
||||
let description: gtk::Label = builder.get_object("description").unwrap();
|
||||
let unsub: gtk::Button = builder.get_object("unsub_button").unwrap();
|
||||
let link: gtk::Button = builder.get_object("link_button").unwrap();
|
||||
let settings: gtk::MenuButton = builder.get_object("settings_button").unwrap();
|
||||
|
||||
ShowWidget {
|
||||
container,
|
||||
scrolled_window,
|
||||
cover,
|
||||
description,
|
||||
unsub,
|
||||
link,
|
||||
settings,
|
||||
episodes,
|
||||
show_id: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ShowWidget {
|
||||
pub fn new(pd: Arc<Show>, sender: Sender<Action>) -> Rc<ShowWidget> {
|
||||
let mut pdw = ShowWidget::default();
|
||||
pdw.init(&pd, &sender);
|
||||
let pdw = Rc::new(pdw);
|
||||
populate_listbox(&pdw, pd, sender)
|
||||
.map_err(|err| error!("Failed to populate the listbox: {}", err))
|
||||
.ok();
|
||||
|
||||
pdw
|
||||
}
|
||||
|
||||
pub fn init(&mut self, pd: &Arc<Show>, sender: &Sender<Action>) {
|
||||
let builder = gtk::Builder::new_from_resource("/org/gnome/Hammond/gtk/show_widget.ui");
|
||||
|
||||
self.unsub
|
||||
.connect_clicked(clone!(pd, sender => move |bttn| {
|
||||
on_unsub_button_clicked(pd.clone(), bttn, &sender);
|
||||
}));
|
||||
|
||||
self.set_description(pd.description());
|
||||
self.show_id = Some(pd.id());
|
||||
|
||||
self.set_cover(&pd)
|
||||
.map_err(|err| error!("Failed to set a cover: {}", err))
|
||||
.ok();
|
||||
|
||||
let link = pd.link().to_owned();
|
||||
self.link.set_tooltip_text(Some(link.as_str()));
|
||||
self.link.connect_clicked(move |_| {
|
||||
info!("Opening link: {}", &link);
|
||||
open::that(&link)
|
||||
.map_err(|err| error!("Error: {}", err))
|
||||
.map_err(|_| error!("Failed open link: {}", &link))
|
||||
.ok();
|
||||
});
|
||||
|
||||
let show_menu: gtk::Popover = builder.get_object("show_menu").unwrap();
|
||||
let mark_all: gtk::ModelButton = builder.get_object("mark_all_watched").unwrap();
|
||||
|
||||
let episodes = self.episodes.clone();
|
||||
mark_all.connect_clicked(clone!(pd, sender => move |_| {
|
||||
on_played_button_clicked(
|
||||
pd.clone(),
|
||||
&episodes,
|
||||
&sender
|
||||
)
|
||||
}));
|
||||
self.settings.set_popover(&show_menu);
|
||||
}
|
||||
|
||||
/// Set the show cover.
|
||||
fn set_cover(&self, pd: &Arc<Show>) -> Result<(), Error> {
|
||||
utils::set_image_from_path(&self.cover, pd.id(), 256)
|
||||
}
|
||||
|
||||
/// Set the descripton text.
|
||||
fn set_description(&self, text: &str) {
|
||||
self.description
|
||||
.set_markup(&html2text::from_read(text.as_bytes(), 70));
|
||||
}
|
||||
|
||||
/// Save the scrollabar vajustment to the cache.
|
||||
pub fn save_vadjustment(&self, oldid: i32) -> Result<(), Error> {
|
||||
if let Ok(mut guard) = SHOW_WIDGET_VALIGNMENT.lock() {
|
||||
let adj = self
|
||||
.scrolled_window
|
||||
.get_vadjustment()
|
||||
.ok_or_else(|| format_err!("Could not get the adjustment"))?;
|
||||
*guard = Some((oldid, SendCell::new(adj)));
|
||||
debug!("Widget Alignment was saved with ID: {}.", oldid);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set scrolled window vertical adjustment.
|
||||
fn set_vadjustment(&self, pd: &Arc<Show>) -> Result<(), Error> {
|
||||
let guard = SHOW_WIDGET_VALIGNMENT
|
||||
.lock()
|
||||
.map_err(|err| format_err!("Failed to lock widget align mutex: {}", err))?;
|
||||
|
||||
if let Some((oldid, ref sendcell)) = *guard {
|
||||
// Only copy the old scrollbar if both widget's represent the same podcast.
|
||||
debug!("PID: {}", pd.id());
|
||||
debug!("OLDID: {}", oldid);
|
||||
if pd.id() != oldid {
|
||||
debug!("Early return");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// Copy the vertical scrollbar adjustment from the old view into the new one.
|
||||
sendcell
|
||||
.try_get()
|
||||
.map(|x| utils::smooth_scroll_to(&self.scrolled_window, &x));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn show_id(&self) -> Option<i32> {
|
||||
self.show_id
|
||||
}
|
||||
}
|
||||
|
||||
/// Populate the listbox with the shows episodes.
|
||||
fn populate_listbox(
|
||||
show: &Rc<ShowWidget>,
|
||||
pd: Arc<Show>,
|
||||
sender: Sender<Action>,
|
||||
) -> Result<(), Error> {
|
||||
use crossbeam_channel::bounded;
|
||||
|
||||
let count = dbqueries::get_pd_episodes_count(&pd)?;
|
||||
|
||||
let (sender_, receiver) = bounded(1);
|
||||
rayon::spawn(clone!(pd => move || {
|
||||
let episodes = dbqueries::get_pd_episodeswidgets(&pd).unwrap();
|
||||
// The receiver can be dropped if there's an early return
|
||||
// like on show without episodes for example.
|
||||
sender_.send(episodes);
|
||||
}));
|
||||
|
||||
if count == 0 {
|
||||
let builder = gtk::Builder::new_from_resource("/org/gnome/Hammond/gtk/empty_show.ui");
|
||||
let container: gtk::Box = builder.get_object("empty_show").unwrap();
|
||||
show.episodes.add(&container);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let show_ = show.clone();
|
||||
gtk::idle_add(move || {
|
||||
let episodes = match receiver.try_recv() {
|
||||
Some(e) => e,
|
||||
None => return glib::Continue(true),
|
||||
};
|
||||
|
||||
let list = show_.episodes.clone();
|
||||
|
||||
let constructor = clone!(sender => move |ep| {
|
||||
EpisodeWidget::new(&ep, &sender).container.clone()
|
||||
});
|
||||
|
||||
let callback = clone!(pd, show_ => move || {
|
||||
show_.set_vadjustment(&pd)
|
||||
.map_err(|err| error!("Failed to set ShowWidget Alignment: {}", err))
|
||||
.ok();
|
||||
});
|
||||
|
||||
lazy_load(episodes, list.clone(), constructor, callback);
|
||||
|
||||
glib::Continue(false)
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_unsub_button_clicked(pd: Arc<Show>, unsub_button: >k::Button, sender: &Sender<Action>) {
|
||||
// hack to get away without properly checking for none.
|
||||
// if pressed twice would panic.
|
||||
unsub_button.set_sensitive(false);
|
||||
|
||||
sender.send(Action::RemoveShow(pd));
|
||||
|
||||
sender.send(Action::HeaderBarNormal);
|
||||
sender.send(Action::ShowShowsAnimated);
|
||||
// Queue a refresh after the switch to avoid blocking the db.
|
||||
sender.send(Action::RefreshShowsView);
|
||||
sender.send(Action::RefreshEpisodesView);
|
||||
|
||||
unsub_button.set_sensitive(true);
|
||||
}
|
||||
|
||||
fn on_played_button_clicked(pd: Arc<Show>, episodes: >k::ListBox, sender: &Sender<Action>) {
|
||||
if dim_titles(episodes).is_none() {
|
||||
error!("Something went horribly wrong when dimming the titles.");
|
||||
warn!("RUN WHILE YOU STILL CAN!");
|
||||
}
|
||||
|
||||
sender.send(Action::MarkAllPlayerNotification(pd))
|
||||
}
|
||||
|
||||
fn mark_all_watched(pd: &Show, sender: &Sender<Action>) -> Result<(), Error> {
|
||||
dbqueries::update_none_to_played_now(pd)?;
|
||||
// Not all widgets migth have been loaded when the mark_all is hit
|
||||
// So we will need to refresh again after it's done.
|
||||
sender.send(Action::RefreshWidgetIfSame(pd.id()));
|
||||
sender.send(Action::RefreshEpisodesView);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mark_all_notif(pd: Arc<Show>, sender: &Sender<Action>) -> InAppNotification {
|
||||
let id = pd.id();
|
||||
let callback = clone!(sender => move || {
|
||||
mark_all_watched(&pd, &sender)
|
||||
.map_err(|err| error!("Notif Callback Error: {}", err))
|
||||
.ok();
|
||||
glib::Continue(false)
|
||||
});
|
||||
|
||||
let undo_callback = clone!(sender => move || sender.send(Action::RefreshWidgetIfSame(id)));
|
||||
let text = "Marked all episodes as listened";
|
||||
InAppNotification::new(text, callback, undo_callback, UndoState::Shown)
|
||||
}
|
||||
|
||||
pub fn remove_show_notif(pd: Arc<Show>, sender: Sender<Action>) -> InAppNotification {
|
||||
let text = format!("Unsubscribed from {}", pd.title());
|
||||
|
||||
utils::ignore_show(pd.id())
|
||||
.map_err(|err| error!("Error: {}", err))
|
||||
.map_err(|_| error!("Could not insert {} to the ignore list.", pd.title()))
|
||||
.ok();
|
||||
|
||||
let callback = clone!(pd, sender => move || {
|
||||
utils::uningore_show(pd.id())
|
||||
.map_err(|err| error!("Error: {}", err))
|
||||
.map_err(|_| error!("Could not remove {} from the ignore list.", pd.title()))
|
||||
.ok();
|
||||
|
||||
// Spawn a thread so it won't block the ui.
|
||||
rayon::spawn(clone!(pd, sender => move || {
|
||||
delete_show(&pd)
|
||||
.map_err(|err| error!("Error: {}", err))
|
||||
.map_err(|_| error!("Failed to delete {}", pd.title()))
|
||||
.ok();
|
||||
|
||||
sender.send(Action::RefreshEpisodesView);
|
||||
}));
|
||||
glib::Continue(false)
|
||||
});
|
||||
|
||||
let undo_callback = move || {
|
||||
utils::uningore_show(pd.id())
|
||||
.map_err(|err| error!("{}", err))
|
||||
.ok();
|
||||
sender.send(Action::RefreshShowsView);
|
||||
sender.send(Action::RefreshEpisodesView);
|
||||
};
|
||||
|
||||
InAppNotification::new(&text, callback, undo_callback, UndoState::Shown)
|
||||
}
|
||||
|
||||
// Ideally if we had a custom widget this would have been as simple as:
|
||||
// `for row in listbox { ep = row.get_episode(); ep.dim_title(); }`
|
||||
// But now I can't think of a better way to do it than hardcoding the title
|
||||
// position relative to the EpisodeWidget container gtk::Box.
|
||||
fn dim_titles(episodes: >k::ListBox) -> Option<()> {
|
||||
let children = episodes.get_children();
|
||||
|
||||
for row in children {
|
||||
let row = row.downcast::<gtk::ListBoxRow>().ok()?;
|
||||
let container = row.get_children().remove(0).downcast::<gtk::Box>().ok()?;
|
||||
let foo = container
|
||||
.get_children()
|
||||
.remove(0)
|
||||
.downcast::<gtk::Box>()
|
||||
.ok()?;
|
||||
let bar = foo.get_children().remove(0).downcast::<gtk::Box>().ok()?;
|
||||
let title = bar.get_children().remove(0).downcast::<gtk::Label>().ok()?;
|
||||
|
||||
title.get_style_context().map(|c| c.add_class("dim-label"));
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
use gtk;
|
||||
use gtk::prelude::*;
|
||||
|
||||
use crossbeam_channel::Sender;
|
||||
use failure::Error;
|
||||
use send_cell::SendCell;
|
||||
|
||||
use hammond_data::dbqueries;
|
||||
use hammond_data::Show;
|
||||
|
||||
use app::Action;
|
||||
use utils::{self, get_ignored_shows, lazy_load, set_image_from_path};
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
lazy_static! {
|
||||
static ref SHOWS_VIEW_VALIGNMENT: Mutex<Option<SendCell<gtk::Adjustment>>> = Mutex::new(None);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ShowsView {
|
||||
pub container: gtk::Box,
|
||||
scrolled_window: gtk::ScrolledWindow,
|
||||
flowbox: gtk::FlowBox,
|
||||
}
|
||||
|
||||
impl Default for ShowsView {
|
||||
fn default() -> Self {
|
||||
let builder = gtk::Builder::new_from_resource("/org/gnome/Hammond/gtk/shows_view.ui");
|
||||
let container: gtk::Box = builder.get_object("fb_parent").unwrap();
|
||||
let scrolled_window: gtk::ScrolledWindow = builder.get_object("scrolled_window").unwrap();
|
||||
let flowbox: gtk::FlowBox = builder.get_object("flowbox").unwrap();
|
||||
|
||||
ShowsView {
|
||||
container,
|
||||
scrolled_window,
|
||||
flowbox,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ShowsView {
|
||||
pub fn new(sender: Sender<Action>) -> Result<Rc<Self>, Error> {
|
||||
let pop = Rc::new(ShowsView::default());
|
||||
pop.init(sender);
|
||||
// Populate the flowbox with the Shows.
|
||||
populate_flowbox(&pop)?;
|
||||
Ok(pop)
|
||||
}
|
||||
|
||||
pub fn init(&self, sender: Sender<Action>) {
|
||||
self.flowbox.connect_child_activated(move |_, child| {
|
||||
on_child_activate(child, &sender)
|
||||
.map_err(|err| error!("Error along flowbox child activation: {}", err))
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
|
||||
/// Set scrolled window vertical adjustment.
|
||||
#[allow(unused)]
|
||||
fn set_vadjustment(&self) -> Result<(), Error> {
|
||||
let guard = SHOWS_VIEW_VALIGNMENT
|
||||
.lock()
|
||||
.map_err(|err| format_err!("Failed to lock widget align mutex: {}", err))?;
|
||||
|
||||
if let Some(ref sendcell) = *guard {
|
||||
// Copy the vertical scrollbar adjustment from the old view into the new one.
|
||||
sendcell
|
||||
.try_get()
|
||||
.map(|x| utils::smooth_scroll_to(&self.scrolled_window, &x));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Save the vertical scrollbar position.
|
||||
pub fn save_alignment(&self) -> Result<(), Error> {
|
||||
if let Ok(mut guard) = SHOWS_VIEW_VALIGNMENT.lock() {
|
||||
let adj = self
|
||||
.scrolled_window
|
||||
.get_vadjustment()
|
||||
.ok_or_else(|| format_err!("Could not get the adjustment"))?;
|
||||
*guard = Some(SendCell::new(adj));
|
||||
info!("Saved episodes_view alignment.");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn populate_flowbox(shows: &Rc<ShowsView>) -> Result<(), Error> {
|
||||
let ignore = get_ignored_shows()?;
|
||||
let podcasts = dbqueries::get_podcasts_filter(&ignore)?;
|
||||
|
||||
let constructor = move |parent| ShowsChild::new(&parent).child;
|
||||
let callback = clone!(shows => move || {
|
||||
shows.set_vadjustment()
|
||||
.map_err(|err| error!("Failed to set ShowsView Alignment: {}", err))
|
||||
.ok();
|
||||
});
|
||||
|
||||
let flowbox = shows.flowbox.clone();
|
||||
lazy_load(podcasts, flowbox, constructor, callback);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_child_activate(child: >k::FlowBoxChild, sender: &Sender<Action>) -> Result<(), Error> {
|
||||
use gtk::WidgetExt;
|
||||
|
||||
// This is such an ugly hack...
|
||||
let id = WidgetExt::get_name(child)
|
||||
.ok_or_else(|| format_err!("Faild to get \"episodes\" child from the stack."))?
|
||||
.parse::<i32>()?;
|
||||
let pd = Arc::new(dbqueries::get_podcast_from_id(id)?);
|
||||
|
||||
sender.send(Action::HeaderBarShowTile(pd.title().into()));
|
||||
sender.send(Action::ReplaceWidget(pd));
|
||||
sender.send(Action::ShowWidgetAnimated);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ShowsChild {
|
||||
container: gtk::Box,
|
||||
cover: gtk::Image,
|
||||
child: gtk::FlowBoxChild,
|
||||
}
|
||||
|
||||
impl Default for ShowsChild {
|
||||
fn default() -> Self {
|
||||
let builder = gtk::Builder::new_from_resource("/org/gnome/Hammond/gtk/shows_child.ui");
|
||||
|
||||
let container: gtk::Box = builder.get_object("fb_child").unwrap();
|
||||
let cover: gtk::Image = builder.get_object("pd_cover").unwrap();
|
||||
|
||||
let child = gtk::FlowBoxChild::new();
|
||||
child.add(&container);
|
||||
|
||||
ShowsChild {
|
||||
container,
|
||||
cover,
|
||||
child,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ShowsChild {
|
||||
pub fn new(pd: &Show) -> ShowsChild {
|
||||
let child = ShowsChild::default();
|
||||
child.init(pd);
|
||||
child
|
||||
}
|
||||
|
||||
fn init(&self, pd: &Show) {
|
||||
self.container.set_tooltip_text(pd.title());
|
||||
WidgetExt::set_name(&self.child, &pd.id().to_string());
|
||||
|
||||
self.set_cover(pd.id())
|
||||
.map_err(|err| error!("Failed to set a cover: {}", err))
|
||||
.ok();
|
||||
}
|
||||
|
||||
fn set_cover(&self, show_id: i32) -> Result<(), Error> {
|
||||
set_image_from_path(&self.cover, show_id, 256)
|
||||
}
|
||||
}
|
||||
+47
-17
@@ -2,23 +2,46 @@
|
||||
# https://gitlab.gnome.org/danigm/fractal/blob/6e2911f9d2353c99a18a6c19fab7f903c4bbb431/meson.build
|
||||
|
||||
project(
|
||||
'hammond', 'rust',
|
||||
version: '0.4.0',
|
||||
'gnome-podcasts', 'rust',
|
||||
version: '0.4.6',
|
||||
license: 'GPLv3',
|
||||
)
|
||||
|
||||
hammond_version = meson.project_version()
|
||||
version_array = hammond_version.split('.')
|
||||
hammond_major_version = version_array[0].to_int()
|
||||
hammond_minor_version = version_array[1].to_int()
|
||||
hammond_version_micro = version_array[2].to_int()
|
||||
if get_option('profile') == 'development'
|
||||
profile = 'Devel'
|
||||
vcs_tag = run_command('git', 'rev-parse', '--short', 'HEAD').stdout().strip()
|
||||
if vcs_tag == ''
|
||||
version_suffix = '-devel'
|
||||
else
|
||||
version_suffix = '-@0@'.format (vcs_tag)
|
||||
endif
|
||||
else
|
||||
profile = ''
|
||||
version_suffix = ''
|
||||
endif
|
||||
|
||||
hammond_prefix = get_option('prefix')
|
||||
hammond_bindir = join_paths(hammond_prefix, get_option('bindir'))
|
||||
application_id = 'org.gnome.Podcasts@0@'.format(profile)
|
||||
i18n = import('i18n')
|
||||
|
||||
subdir('podcasts-gtk/po')
|
||||
podir = join_paths (meson.source_root (), 'podcasts-gtk', 'po')
|
||||
|
||||
podcasts_version = meson.project_version()
|
||||
version_array = podcasts_version.split('.')
|
||||
podcasts_major_version = version_array[0].to_int()
|
||||
podcasts_minor_version = version_array[1].to_int()
|
||||
podcasts_version_micro = version_array[2].to_int()
|
||||
|
||||
podcasts_prefix = get_option('prefix')
|
||||
podcasts_bindir = join_paths(podcasts_prefix, get_option('bindir'))
|
||||
podcasts_localedir = join_paths(podcasts_prefix, get_option('localedir'))
|
||||
|
||||
podcasts_conf = configuration_data()
|
||||
podcasts_conf.set('appid', application_id)
|
||||
podcasts_conf.set('bindir', podcasts_bindir)
|
||||
|
||||
datadir = get_option('datadir')
|
||||
icondir = join_paths(datadir, 'icons')
|
||||
subdir('hammond-gtk/resources')
|
||||
subdir('podcasts-gtk/resources')
|
||||
|
||||
cargo = find_program('cargo', required: false)
|
||||
gresource = find_program('glib-compile-resources', required: false)
|
||||
@@ -26,13 +49,20 @@ cargo_vendor = find_program('cargo-vendor', required: false)
|
||||
cargo_script = find_program('scripts/cargo.sh')
|
||||
|
||||
cargo_release = custom_target('cargo-build',
|
||||
build_by_default: true,
|
||||
build_always: true,
|
||||
output: ['hammond'],
|
||||
build_always_stale: true,
|
||||
output: ['gnome-podcasts'],
|
||||
install: true,
|
||||
install_dir: hammond_bindir,
|
||||
command: [cargo_script, '@CURRENT_SOURCE_DIR@', '@OUTPUT@'])
|
||||
install_dir: podcasts_bindir,
|
||||
console: true,
|
||||
command: [cargo_script,
|
||||
'@CURRENT_SOURCE_DIR@',
|
||||
'@OUTPUT@',
|
||||
podcasts_localedir,
|
||||
application_id,
|
||||
podcasts_version + version_suffix,
|
||||
profile
|
||||
])
|
||||
|
||||
run_target('release', command: ['scripts/release.sh',
|
||||
meson.project_name() + '-' + hammond_version
|
||||
meson.project_name() + '-' + podcasts_version
|
||||
])
|
||||
@@ -0,0 +1,9 @@
|
||||
option (
|
||||
'profile',
|
||||
type: 'combo',
|
||||
choices: [
|
||||
'default',
|
||||
'development'
|
||||
],
|
||||
value: 'default'
|
||||
)
|
||||
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"app-id" : "org.gnome.Hammond",
|
||||
"runtime" : "org.gnome.Platform",
|
||||
"runtime-version" : "3.28",
|
||||
"sdk" : "org.gnome.Sdk",
|
||||
"sdk-extensions" : [
|
||||
"org.freedesktop.Sdk.Extension.rust-stable"
|
||||
],
|
||||
"command" : "hammond",
|
||||
"tags" : [
|
||||
"nightly"
|
||||
],
|
||||
"desktop-file-name-prefix" : "(Nightly) ",
|
||||
"finish-args" : [
|
||||
"--filesystem=xdg-run/dconf",
|
||||
"--filesystem=~/.config/dconf:ro",
|
||||
"--talk-name=ca.desrt.dconf",
|
||||
"--env=DCONF_USER_CONFIG_DIR=.config/dconf",
|
||||
"--share=network",
|
||||
"--share=ipc",
|
||||
"--socket=x11",
|
||||
"--socket=wayland",
|
||||
"--socket=pulseaudio",
|
||||
"--talk-name=org.freedesktop.Desktop"
|
||||
],
|
||||
"build-options" : {
|
||||
"append-path" : "/usr/lib/sdk/rust-stable/bin",
|
||||
"build-args" : [
|
||||
"--share=network"
|
||||
],
|
||||
"env" : {
|
||||
"CARGO_HOME" : "/run/build/Hammond/cargo",
|
||||
"RUST_BACKTRACE" : "1",
|
||||
"DEBUG" : "true"
|
||||
}
|
||||
},
|
||||
"modules" : [
|
||||
{
|
||||
"name" : "hammond",
|
||||
"buildsystem" : "meson",
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/World/hammond.git",
|
||||
"branch" : "master"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"app-id" : "org.gnome.PodcastsDevel",
|
||||
"runtime" : "org.gnome.Platform",
|
||||
"runtime-version" : "master",
|
||||
"sdk" : "org.gnome.Sdk",
|
||||
"sdk-extensions" : [
|
||||
"org.freedesktop.Sdk.Extension.rust-stable"
|
||||
],
|
||||
"command" : "gnome-podcasts",
|
||||
"tags" : [
|
||||
"nightly"
|
||||
],
|
||||
"desktop-file-name-prefix" : "(Nightly) ",
|
||||
"finish-args" : [
|
||||
"--filesystem=xdg-run/dconf",
|
||||
"--filesystem=~/.config/dconf:ro",
|
||||
"--talk-name=ca.desrt.dconf",
|
||||
"--env=DCONF_USER_CONFIG_DIR=.config/dconf",
|
||||
"--share=network",
|
||||
"--share=ipc",
|
||||
"--socket=x11",
|
||||
"--socket=wayland",
|
||||
"--socket=pulseaudio",
|
||||
"--device=dri",
|
||||
"--own-name=org.mpris.MediaPlayer2.Podcasts"
|
||||
],
|
||||
"build-options" : {
|
||||
"append-path" : "/usr/lib/sdk/rust-stable/bin",
|
||||
"build-args" : [
|
||||
"--share=network"
|
||||
],
|
||||
"env" : {
|
||||
"CARGO_HOME" : "/run/build/Podcasts/cargo",
|
||||
/* "RUSTFLAGS" : "--error-format=short", */
|
||||
"RUST_BACKTRACE" : "1"
|
||||
}
|
||||
},
|
||||
"modules" : [
|
||||
{
|
||||
"name" : "libhandy",
|
||||
"buildsystem" : "meson",
|
||||
"config-opts" : [
|
||||
"-Dintrospection=true",
|
||||
"-Dgtk-doc=false",
|
||||
"-Dtests=false",
|
||||
"-Dexamples=false",
|
||||
"-Dvapi=false",
|
||||
"-Dglade_catalog=false"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://source.puri.sm/Librem5/libhandy.git"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "gnome-podcasts",
|
||||
"buildsystem" : "meson",
|
||||
"config-opts" : [ "-Dprofile=development" ],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/World/podcasts.git",
|
||||
"branch" : "master"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
[package]
|
||||
authors = ["Jordan Petridis <jordanpetridis@protonmail.com>"]
|
||||
name = "podcasts-data"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
ammonia = "1.2.0"
|
||||
chrono = "0.4.6"
|
||||
derive_builder = "0.6.0"
|
||||
lazy_static = "1.1.0"
|
||||
log = "0.4.5"
|
||||
rayon = "1.0.2"
|
||||
rfc822_sanitizer = "0.3.3"
|
||||
rss = "1.5.0"
|
||||
url = "1.7.1"
|
||||
xdg = "2.1.0"
|
||||
xml-rs = "0.8.0"
|
||||
futures = "0.1.24"
|
||||
hyper = "0.12.11"
|
||||
http = "0.1.13"
|
||||
tokio = "0.1.11"
|
||||
hyper-tls = "0.3.1"
|
||||
native-tls = "0.2.1"
|
||||
num_cpus = "1.8.0"
|
||||
failure = "0.1.2"
|
||||
failure_derive = "0.1.2"
|
||||
|
||||
[dependencies.diesel]
|
||||
features = ["sqlite", "r2d2"]
|
||||
version = "1.3.3"
|
||||
|
||||
[dependencies.diesel_migrations]
|
||||
features = ["sqlite"]
|
||||
version = "1.3.0"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.5.5"
|
||||
tempdir = "0.3.7"
|
||||
pretty_assertions = "0.5.1"
|
||||
maplit = "1.0.1"
|
||||
@@ -24,7 +24,9 @@ lazy_static! {
|
||||
|
||||
#[cfg(not(test))]
|
||||
lazy_static! {
|
||||
static ref DB_PATH: PathBuf = xdg_dirs::HAMMOND_XDG.place_data_file("hammond.db").unwrap();
|
||||
static ref DB_PATH: PathBuf = xdg_dirs::PODCASTS_XDG
|
||||
.place_data_file("podcasts.db")
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -32,8 +34,8 @@ extern crate tempdir;
|
||||
|
||||
#[cfg(test)]
|
||||
lazy_static! {
|
||||
static ref TEMPDIR: tempdir::TempDir = { tempdir::TempDir::new("hammond_unit_test").unwrap() };
|
||||
static ref DB_PATH: PathBuf = TEMPDIR.path().join("hammond.db");
|
||||
static ref TEMPDIR: tempdir::TempDir = { tempdir::TempDir::new("podcasts_unit_test").unwrap() };
|
||||
static ref DB_PATH: PathBuf = TEMPDIR.path().join("podcasts.db");
|
||||
}
|
||||
|
||||
/// Get an r2d2 `SqliteConnection`.
|
||||
@@ -64,7 +66,7 @@ fn run_migration_on(connection: &SqliteConnection) -> Result<(), DataError> {
|
||||
|
||||
/// Reset the database into a clean state.
|
||||
// Test share a Temp file db.
|
||||
#[allow(dead_code)]
|
||||
#[cfg(test)]
|
||||
pub fn truncate_db() -> Result<(), DataError> {
|
||||
let db = connection();
|
||||
let con = db.get()?;
|
||||
@@ -5,7 +5,6 @@ use diesel::prelude::*;
|
||||
|
||||
use diesel;
|
||||
use diesel::dsl::exists;
|
||||
use diesel::query_builder::AsQuery;
|
||||
use diesel::select;
|
||||
|
||||
use database::connection;
|
||||
@@ -111,8 +110,7 @@ pub fn get_episode_widget_from_rowid(ep_id: i32) -> Result<EpisodeWidgetModel, D
|
||||
episodes
|
||||
.select((
|
||||
rowid, title, uri, local_uri, epoch, length, duration, played, show_id,
|
||||
))
|
||||
.filter(rowid.eq(ep_id))
|
||||
)).filter(rowid.eq(ep_id))
|
||||
.get_result::<EpisodeWidgetModel>(&con)
|
||||
.map_err(From::from)
|
||||
}
|
||||
@@ -295,6 +293,23 @@ pub(crate) fn get_episode_minimal_from_pk(
|
||||
.map_err(From::from)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn get_episode_cleaner_from_pk(
|
||||
title_: &str,
|
||||
pid: i32,
|
||||
) -> Result<EpisodeCleanerModel, DataError> {
|
||||
use schema::episodes::dsl::*;
|
||||
let db = connection();
|
||||
let con = db.get()?;
|
||||
|
||||
episodes
|
||||
.select((rowid, local_uri, played))
|
||||
.filter(title.eq(title_))
|
||||
.filter(show_id.eq(pid))
|
||||
.get_result::<EpisodeCleanerModel>(&con)
|
||||
.map_err(From::from)
|
||||
}
|
||||
|
||||
pub(crate) fn remove_feed(pd: &Show) -> Result<(), DataError> {
|
||||
let db = connection();
|
||||
let con = db.get()?;
|
||||
@@ -363,20 +378,20 @@ pub(crate) fn episode_exists(title_: &str, show_id_: i32) -> Result<bool, DataEr
|
||||
/// Check if the `episodes table contains any rows
|
||||
///
|
||||
/// Return true if `episodes` table is populated.
|
||||
pub fn is_episodes_populated() -> Result<bool, DataError> {
|
||||
pub fn is_episodes_populated(filter_show_ids: &[i32]) -> Result<bool, DataError> {
|
||||
use schema::episodes::dsl::*;
|
||||
|
||||
let db = connection();
|
||||
let con = db.get()?;
|
||||
|
||||
select(exists(episodes.as_query()))
|
||||
select(exists(episodes.filter(show_id.ne_all(filter_show_ids))))
|
||||
.get_result(&con)
|
||||
.map_err(From::from)
|
||||
}
|
||||
|
||||
/// Check if the `shows` table contains any rows
|
||||
///
|
||||
/// Return true if `shows table is populated.
|
||||
/// Return true if `shows` table is populated.
|
||||
pub fn is_podcasts_populated(filter_ids: &[i32]) -> Result<bool, DataError> {
|
||||
use schema::shows::dsl::*;
|
||||
|
||||
@@ -388,6 +403,20 @@ pub fn is_podcasts_populated(filter_ids: &[i32]) -> Result<bool, DataError> {
|
||||
.map_err(From::from)
|
||||
}
|
||||
|
||||
/// Check if the `source` table contains any rows
|
||||
///
|
||||
/// Return true if `source` table is populated.
|
||||
pub fn is_source_populated(filter_ids: &[i32]) -> Result<bool, DataError> {
|
||||
use schema::source::dsl::*;
|
||||
|
||||
let db = connection();
|
||||
let con = db.get()?;
|
||||
|
||||
select(exists(source.filter(id.ne_all(filter_ids))))
|
||||
.get_result(&con)
|
||||
.map_err(From::from)
|
||||
}
|
||||
|
||||
pub(crate) fn index_new_episodes(eps: &[NewEpisode]) -> Result<(), DataError> {
|
||||
use schema::episodes::dsl::*;
|
||||
let db = connection();
|
||||
@@ -418,24 +447,26 @@ pub fn update_none_to_played_now(parent: &Show) -> Result<usize, DataError> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use database::*;
|
||||
use failure::Error;
|
||||
use pipeline;
|
||||
|
||||
#[test]
|
||||
fn test_update_none_to_played_now() {
|
||||
truncate_db().unwrap();
|
||||
fn test_update_none_to_played_now() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
|
||||
let url = "https://web.archive.org/web/20180120083840if_/https://feeds.feedburner.\
|
||||
com/InterceptedWithJeremyScahill";
|
||||
let source = Source::from_url(url).unwrap();
|
||||
let source = Source::from_url(url)?;
|
||||
let id = source.id();
|
||||
pipeline::run(vec![source], true).unwrap();
|
||||
let pd = get_podcast_from_source_id(id).unwrap();
|
||||
pipeline::run(vec![source])?;
|
||||
let pd = get_podcast_from_source_id(id)?;
|
||||
|
||||
let eps_num = get_pd_unplayed_episodes(&pd).unwrap().len();
|
||||
let eps_num = get_pd_unplayed_episodes(&pd)?.len();
|
||||
assert_ne!(eps_num, 0);
|
||||
|
||||
update_none_to_played_now(&pd).unwrap();
|
||||
let eps_num2 = get_pd_unplayed_episodes(&pd).unwrap().len();
|
||||
update_none_to_played_now(&pd)?;
|
||||
let eps_num2 = get_pd_unplayed_episodes(&pd)?.len();
|
||||
assert_eq!(eps_num2, 0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use diesel;
|
||||
use diesel::r2d2;
|
||||
use diesel_migrations::RunMigrationsError;
|
||||
use http;
|
||||
use hyper;
|
||||
use native_tls;
|
||||
use rss;
|
||||
@@ -11,7 +12,12 @@ use std::io;
|
||||
|
||||
use models::Source;
|
||||
|
||||
#[fail(display = "Request to {} returned {}. Context: {}", url, status_code, context)]
|
||||
#[fail(
|
||||
display = "Request to {} returned {}. Context: {}",
|
||||
url,
|
||||
status_code,
|
||||
context
|
||||
)]
|
||||
#[derive(Fail, Debug)]
|
||||
pub struct HttpStatusError {
|
||||
url: String,
|
||||
@@ -41,8 +47,9 @@ pub enum DataError {
|
||||
R2D2PoolError(#[cause] r2d2::PoolError),
|
||||
#[fail(display = "Hyper Error: {}", _0)]
|
||||
HyperError(#[cause] hyper::Error),
|
||||
#[fail(display = "ToStr Error: {}", _0)]
|
||||
HttpToStr(#[cause] http::header::ToStrError),
|
||||
#[fail(display = "Failed to parse a url: {}", _0)]
|
||||
// TODO: print the url too
|
||||
UrlError(#[cause] url::ParseError),
|
||||
#[fail(display = "TLS Error: {}", _0)]
|
||||
TLSError(#[cause] native_tls::Error),
|
||||
@@ -56,9 +63,14 @@ pub enum DataError {
|
||||
Bail(String),
|
||||
#[fail(display = "{}", _0)]
|
||||
HttpStatusGeneral(HttpStatusError),
|
||||
#[fail(display = "FIXME: This should be better")]
|
||||
F301(Source),
|
||||
#[fail(display = "Error occured while Parsing an Episode. Reason: {}", reason)]
|
||||
#[fail(display = "Source redirects to a new url")]
|
||||
FeedRedirect(Source),
|
||||
#[fail(display = "Feed is up to date")]
|
||||
FeedNotModified(Source),
|
||||
#[fail(
|
||||
display = "Error occured while Parsing an Episode. Reason: {}",
|
||||
reason
|
||||
)]
|
||||
ParseEpisodeError { reason: String, parent_id: i32 },
|
||||
#[fail(display = "Episode was not changed and thus skipped.")]
|
||||
EpisodeNotChanged,
|
||||
@@ -94,6 +106,12 @@ impl From<hyper::Error> for DataError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<http::header::ToStrError> for DataError {
|
||||
fn from(err: http::header::ToStrError) -> Self {
|
||||
DataError::HttpToStr(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<url::ParseError> for DataError {
|
||||
fn from(err: url::ParseError) -> Self {
|
||||
DataError::UrlError(err)
|
||||
@@ -26,7 +26,7 @@ pub struct Feed {
|
||||
impl Feed {
|
||||
/// Index the contents of the RSS `Feed` into the database.
|
||||
pub fn index(self) -> impl Future<Item = (), Error = DataError> + Send {
|
||||
self.parse_podcast_async()
|
||||
ok(self.parse_podcast())
|
||||
.and_then(|pd| pd.to_podcast())
|
||||
.and_then(move |pd| self.index_channel_items(pd))
|
||||
}
|
||||
@@ -35,16 +35,13 @@ impl Feed {
|
||||
NewShow::new(&self.channel, self.source_id)
|
||||
}
|
||||
|
||||
fn parse_podcast_async(&self) -> impl Future<Item = NewShow, Error = DataError> + Send {
|
||||
ok(self.parse_podcast())
|
||||
}
|
||||
|
||||
fn index_channel_items(self, pd: Show) -> impl Future<Item = (), Error = DataError> + Send {
|
||||
let stream = stream::iter_ok::<_, DataError>(self.channel.into_items());
|
||||
|
||||
// Parse the episodes
|
||||
let episodes = stream.filter_map(move |item| {
|
||||
glue(&item, pd.id())
|
||||
NewEpisodeMinimal::new(&item, pd.id())
|
||||
.and_then(move |ep| determine_ep_state(ep, &item))
|
||||
.map_err(|err| error!("Failed to parse an episode: {}", err))
|
||||
.ok()
|
||||
});
|
||||
@@ -56,10 +53,6 @@ impl Feed {
|
||||
}
|
||||
}
|
||||
|
||||
fn glue(item: &rss::Item, id: i32) -> Result<IndexState<NewEpisode>, DataError> {
|
||||
NewEpisodeMinimal::new(item, id).and_then(move |ep| determine_ep_state(ep, item))
|
||||
}
|
||||
|
||||
fn determine_ep_state(
|
||||
ep: NewEpisodeMinimal,
|
||||
item: &rss::Item,
|
||||
@@ -87,21 +80,22 @@ fn filter_episodes<'a, S>(
|
||||
where
|
||||
S: Stream<Item = IndexState<NewEpisode>, Error = DataError> + Send + 'a,
|
||||
{
|
||||
stream.filter_map(|state| match state {
|
||||
IndexState::NotChanged => None,
|
||||
// Update individual rows, and filter them
|
||||
IndexState::Update((ref ep, rowid)) => {
|
||||
ep.update(rowid)
|
||||
.map_err(|err| error!("{}", err))
|
||||
.map_err(|_| error!("Failed to index episode: {:?}.", ep.title()))
|
||||
.ok();
|
||||
stream
|
||||
.filter_map(|state| match state {
|
||||
IndexState::NotChanged => None,
|
||||
// Update individual rows, and filter them
|
||||
IndexState::Update((ref ep, rowid)) => {
|
||||
ep.update(rowid)
|
||||
.map_err(|err| error!("{}", err))
|
||||
.map_err(|_| error!("Failed to index episode: {:?}.", ep.title()))
|
||||
.ok();
|
||||
|
||||
None
|
||||
},
|
||||
IndexState::Index(s) => Some(s),
|
||||
})
|
||||
// only Index is left, collect them for batch index
|
||||
.collect()
|
||||
None
|
||||
}
|
||||
IndexState::Index(s) => Some(s),
|
||||
})
|
||||
// only Index is left, collect them for batch index
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn batch_insert_episodes(episodes: &[NewEpisode]) {
|
||||
@@ -114,8 +108,7 @@ fn batch_insert_episodes(episodes: &[NewEpisode]) {
|
||||
.map_err(|err| {
|
||||
error!("Failed batch indexng: {}", err);
|
||||
info!("Fallign back to individual indexing.");
|
||||
})
|
||||
.unwrap_or_else(|_| {
|
||||
}).unwrap_or_else(|_| {
|
||||
episodes.iter().for_each(|ep| {
|
||||
ep.index()
|
||||
.map_err(|err| error!("Error: {}.", err))
|
||||
@@ -127,8 +120,9 @@ fn batch_insert_episodes(episodes: &[NewEpisode]) {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use failure::Error;
|
||||
use rss::Channel;
|
||||
use tokio_core::reactor::Core;
|
||||
use tokio::{self, prelude::*};
|
||||
|
||||
use database::truncate_db;
|
||||
use dbqueries;
|
||||
@@ -171,8 +165,8 @@ mod tests {
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_complete_index() {
|
||||
truncate_db().unwrap();
|
||||
fn test_complete_index() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
|
||||
let feeds: Vec<_> = URLS
|
||||
.iter()
|
||||
@@ -180,44 +174,45 @@ mod tests {
|
||||
// Create and insert a Source into db
|
||||
let s = Source::from_url(url).unwrap();
|
||||
get_feed(path, s.id())
|
||||
})
|
||||
.collect();
|
||||
}).collect();
|
||||
|
||||
let mut core = Core::new().unwrap();
|
||||
// Index the channels
|
||||
let list: Vec<_> = feeds.into_iter().map(|x| x.index()).collect();
|
||||
let _foo = core.run(join_all(list));
|
||||
// Index the channes
|
||||
let stream_ = stream::iter_ok(feeds).for_each(|x| x.index());
|
||||
tokio::run(stream_.map_err(|_| ()));
|
||||
|
||||
// Assert the index rows equal the controlled results
|
||||
assert_eq!(dbqueries::get_sources().unwrap().len(), 5);
|
||||
assert_eq!(dbqueries::get_podcasts().unwrap().len(), 5);
|
||||
assert_eq!(dbqueries::get_episodes().unwrap().len(), 354);
|
||||
assert_eq!(dbqueries::get_sources()?.len(), 5);
|
||||
assert_eq!(dbqueries::get_podcasts()?.len(), 5);
|
||||
assert_eq!(dbqueries::get_episodes()?.len(), 354);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_feed_parse_podcast() {
|
||||
truncate_db().unwrap();
|
||||
fn test_feed_parse_podcast() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
|
||||
let path = "tests/feeds/2018-01-20-Intercepted.xml";
|
||||
let feed = get_feed(path, 42);
|
||||
|
||||
let file = fs::File::open(path).unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
let file = fs::File::open(path)?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let pd = NewShow::new(&channel, 42);
|
||||
assert_eq!(feed.parse_podcast(), pd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_feed_index_channel_items() {
|
||||
truncate_db().unwrap();
|
||||
fn test_feed_index_channel_items() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
|
||||
let path = "tests/feeds/2018-01-20-Intercepted.xml";
|
||||
let feed = get_feed(path, 42);
|
||||
let pd = feed.parse_podcast().to_podcast().unwrap();
|
||||
let pd = feed.parse_podcast().to_podcast()?;
|
||||
|
||||
feed.index_channel_items(pd).wait().unwrap();
|
||||
assert_eq!(dbqueries::get_podcasts().unwrap().len(), 1);
|
||||
assert_eq!(dbqueries::get_episodes().unwrap().len(), 43);
|
||||
feed.index_channel_items(pd).wait()?;
|
||||
assert_eq!(dbqueries::get_podcasts()?.len(), 1);
|
||||
assert_eq!(dbqueries::get_episodes()?.len(), 43);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,53 @@
|
||||
#![recursion_limit = "1024"]
|
||||
#![allow(unknown_lints)]
|
||||
#![cfg_attr(all(test, feature = "clippy"), allow(option_unwrap_used, result_unwrap_used))]
|
||||
#![cfg_attr(
|
||||
all(test, feature = "clippy"),
|
||||
allow(option_unwrap_used, result_unwrap_used)
|
||||
)]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(option_map_unit_fn))]
|
||||
#![cfg_attr(
|
||||
feature = "clippy",
|
||||
warn(
|
||||
option_unwrap_used, result_unwrap_used, print_stdout, wrong_pub_self_convention, mut_mut,
|
||||
non_ascii_literal, similar_names, unicode_not_nfc, enum_glob_use, if_not_else,
|
||||
items_after_statements, used_underscore_binding
|
||||
option_unwrap_used,
|
||||
result_unwrap_used,
|
||||
print_stdout,
|
||||
wrong_pub_self_convention,
|
||||
mut_mut,
|
||||
non_ascii_literal,
|
||||
similar_names,
|
||||
unicode_not_nfc,
|
||||
enum_glob_use,
|
||||
if_not_else,
|
||||
items_after_statements,
|
||||
used_underscore_binding
|
||||
)
|
||||
)]
|
||||
// Enable lint group collections
|
||||
#![warn(nonstandard_style, edition_2018, rust_2018_idioms, bad_style, unused)]
|
||||
#![warn(nonstandard_style, bad_style, unused)]
|
||||
#![allow(edition_2018, rust_2018_idioms)]
|
||||
// standalone lints
|
||||
#![warn(
|
||||
const_err, improper_ctypes, non_shorthand_field_patterns, no_mangle_generic_items,
|
||||
overflowing_literals, plugin_as_library, private_no_mangle_fns, private_no_mangle_statics,
|
||||
unconditional_recursion, unions_with_drop_fields, while_true, missing_debug_implementations,
|
||||
missing_docs, trivial_casts, trivial_numeric_casts, elided_lifetime_in_paths,
|
||||
const_err,
|
||||
improper_ctypes,
|
||||
non_shorthand_field_patterns,
|
||||
no_mangle_generic_items,
|
||||
overflowing_literals,
|
||||
plugin_as_library,
|
||||
private_no_mangle_fns,
|
||||
private_no_mangle_statics,
|
||||
unconditional_recursion,
|
||||
unions_with_drop_fields,
|
||||
while_true,
|
||||
missing_debug_implementations,
|
||||
missing_docs,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
elided_lifetime_in_paths,
|
||||
missing_copy_implementations
|
||||
)]
|
||||
#![allow(proc_macro_derive_resolution_fallback)]
|
||||
#![deny(warnings)]
|
||||
|
||||
// warn when code is not using dyn Trait syntax. req rustc 1.27
|
||||
// #![deny(bare_trait_object)]
|
||||
|
||||
//! FIXME: Docs
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -53,15 +76,15 @@ extern crate log;
|
||||
extern crate ammonia;
|
||||
extern crate chrono;
|
||||
extern crate futures;
|
||||
extern crate http;
|
||||
extern crate hyper;
|
||||
extern crate hyper_tls;
|
||||
extern crate native_tls;
|
||||
extern crate num_cpus;
|
||||
extern crate rayon;
|
||||
extern crate rayon_futures;
|
||||
extern crate rfc822_sanitizer;
|
||||
extern crate rss;
|
||||
extern crate tokio_core;
|
||||
extern crate tokio;
|
||||
extern crate url;
|
||||
extern crate xdg;
|
||||
extern crate xml;
|
||||
@@ -96,28 +119,28 @@ pub mod xdg_dirs {
|
||||
use xdg;
|
||||
|
||||
lazy_static!{
|
||||
pub(crate) static ref HAMMOND_XDG: xdg::BaseDirectories = {
|
||||
xdg::BaseDirectories::with_prefix("hammond").unwrap()
|
||||
pub(crate) static ref PODCASTS_XDG: xdg::BaseDirectories = {
|
||||
xdg::BaseDirectories::with_prefix("gnome-podcasts").unwrap()
|
||||
};
|
||||
|
||||
/// XDG_DATA Directory `Pathbuf`.
|
||||
pub static ref HAMMOND_DATA: PathBuf = {
|
||||
HAMMOND_XDG.create_data_directory(HAMMOND_XDG.get_data_home()).unwrap()
|
||||
pub static ref PODCASTS_DATA: PathBuf = {
|
||||
PODCASTS_XDG.create_data_directory(PODCASTS_XDG.get_data_home()).unwrap()
|
||||
};
|
||||
|
||||
/// XDG_CONFIG Directory `Pathbuf`.
|
||||
pub static ref HAMMOND_CONFIG: PathBuf = {
|
||||
HAMMOND_XDG.create_config_directory(HAMMOND_XDG.get_config_home()).unwrap()
|
||||
pub static ref PODCASTS_CONFIG: PathBuf = {
|
||||
PODCASTS_XDG.create_config_directory(PODCASTS_XDG.get_config_home()).unwrap()
|
||||
};
|
||||
|
||||
/// XDG_CACHE Directory `Pathbuf`.
|
||||
pub static ref HAMMOND_CACHE: PathBuf = {
|
||||
HAMMOND_XDG.create_cache_directory(HAMMOND_XDG.get_cache_home()).unwrap()
|
||||
pub static ref PODCASTS_CACHE: PathBuf = {
|
||||
PODCASTS_XDG.create_cache_directory(PODCASTS_XDG.get_cache_home()).unwrap()
|
||||
};
|
||||
|
||||
/// Hammond Download Direcotry `PathBuf`.
|
||||
/// GNOME Podcasts Download Direcotry `PathBuf`.
|
||||
pub static ref DL_DIR: PathBuf = {
|
||||
HAMMOND_XDG.create_data_directory("Downloads").unwrap()
|
||||
PODCASTS_XDG.create_data_directory("Downloads").unwrap()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -53,11 +53,6 @@ impl Episode {
|
||||
&self.title
|
||||
}
|
||||
|
||||
/// Set the `title`.
|
||||
pub fn set_title(&mut self, value: &str) {
|
||||
self.title = value.to_string();
|
||||
}
|
||||
|
||||
/// Get the value of the `uri`.
|
||||
///
|
||||
/// Represents the url(usually) that the media file will be located at.
|
||||
@@ -65,11 +60,6 @@ impl Episode {
|
||||
self.uri.as_ref().map(|s| s.as_str())
|
||||
}
|
||||
|
||||
/// Set the `uri`.
|
||||
pub fn set_uri(&mut self, value: Option<&str>) {
|
||||
self.uri = value.map(|x| x.to_string());
|
||||
}
|
||||
|
||||
/// Get the value of the `local_uri`.
|
||||
///
|
||||
/// Represents the local uri,usually filesystem path,
|
||||
@@ -78,31 +68,16 @@ impl Episode {
|
||||
self.local_uri.as_ref().map(|s| s.as_str())
|
||||
}
|
||||
|
||||
/// Set the `local_uri`.
|
||||
pub fn set_local_uri(&mut self, value: Option<&str>) {
|
||||
self.local_uri = value.map(|x| x.to_string());
|
||||
}
|
||||
|
||||
/// Get the `description`.
|
||||
pub fn description(&self) -> Option<&str> {
|
||||
self.description.as_ref().map(|s| s.as_str())
|
||||
}
|
||||
|
||||
/// Set the `description`.
|
||||
pub fn set_description(&mut self, value: Option<&str>) {
|
||||
self.description = value.map(|x| x.to_string());
|
||||
}
|
||||
|
||||
/// Get the Episode's `guid`.
|
||||
pub fn guid(&self) -> Option<&str> {
|
||||
self.guid.as_ref().map(|s| s.as_str())
|
||||
}
|
||||
|
||||
/// Set the `guid`.
|
||||
pub fn set_guid(&mut self, value: Option<&str>) {
|
||||
self.guid = value.map(|x| x.to_string());
|
||||
}
|
||||
|
||||
/// Get the `epoch` value.
|
||||
///
|
||||
/// Retrieved from the rss Item publish date.
|
||||
@@ -111,11 +86,6 @@ impl Episode {
|
||||
self.epoch
|
||||
}
|
||||
|
||||
/// Set the `epoch`.
|
||||
pub fn set_epoch(&mut self, value: i32) {
|
||||
self.epoch = value;
|
||||
}
|
||||
|
||||
/// Get the `length`.
|
||||
///
|
||||
/// The number represents the size of the file in bytes.
|
||||
@@ -123,11 +93,6 @@ impl Episode {
|
||||
self.length
|
||||
}
|
||||
|
||||
/// Set the `length`.
|
||||
pub fn set_length(&mut self, value: Option<i32>) {
|
||||
self.length = value;
|
||||
}
|
||||
|
||||
/// Get the `duration` value.
|
||||
///
|
||||
/// The number represents the duration of the item/episode in seconds.
|
||||
@@ -135,11 +100,6 @@ impl Episode {
|
||||
self.duration
|
||||
}
|
||||
|
||||
/// Set the `duration`.
|
||||
pub fn set_duration(&mut self, value: Option<i32>) {
|
||||
self.duration = value;
|
||||
}
|
||||
|
||||
/// Epoch representation of the last time the episode was played.
|
||||
///
|
||||
/// None/Null for unplayed.
|
||||
@@ -147,22 +107,10 @@ impl Episode {
|
||||
self.played
|
||||
}
|
||||
|
||||
/// Set the `played` value.
|
||||
pub fn set_played(&mut self, value: Option<i32>) {
|
||||
self.played = value;
|
||||
}
|
||||
|
||||
/// `Show` table foreign key.
|
||||
pub fn show_id(&self) -> i32 {
|
||||
self.show_id
|
||||
}
|
||||
|
||||
/// Sets the `played` value with the current `epoch` timestap and save it.
|
||||
pub fn set_played_now(&mut self) -> Result<(), DataError> {
|
||||
let epoch = Utc::now().timestamp() as i32;
|
||||
self.set_played(Some(epoch));
|
||||
self.save().map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Queryable, AsChangeset, PartialEq)]
|
||||
@@ -275,11 +223,6 @@ impl EpisodeWidgetModel {
|
||||
self.duration
|
||||
}
|
||||
|
||||
/// Set the `duration`.
|
||||
pub fn set_duration(&mut self, value: Option<i32>) {
|
||||
self.duration = value;
|
||||
}
|
||||
|
||||
/// Epoch representation of the last time the episode was played.
|
||||
///
|
||||
/// None/Null for unplayed.
|
||||
@@ -288,7 +231,7 @@ impl EpisodeWidgetModel {
|
||||
}
|
||||
|
||||
/// Set the `played` value.
|
||||
pub fn set_played(&mut self, value: Option<i32>) {
|
||||
fn set_played(&mut self, value: Option<i32>) {
|
||||
self.played = value;
|
||||
}
|
||||
|
||||
@@ -447,11 +390,6 @@ impl EpisodeMinimal {
|
||||
self.length
|
||||
}
|
||||
|
||||
/// Set the `length`.
|
||||
pub fn set_length(&mut self, value: Option<i32>) {
|
||||
self.length = value;
|
||||
}
|
||||
|
||||
/// Get the `duration` value.
|
||||
///
|
||||
/// The number represents the duration of the item/episode in seconds.
|
||||
@@ -217,7 +217,8 @@ impl NewEpisodeMinimal {
|
||||
let enc = item.enclosure();
|
||||
|
||||
// Get the url
|
||||
let uri = enc.map(|s| url_cleaner(s.url().trim()))
|
||||
let uri = enc
|
||||
.map(|s| url_cleaner(s.url().trim()))
|
||||
// Fallback to Rss.Item.link if enclosure is None.
|
||||
.or_else(|| item.link().map(|s| url_cleaner(s.trim())));
|
||||
|
||||
@@ -312,6 +313,7 @@ impl NewEpisodeMinimal {
|
||||
mod tests {
|
||||
use database::truncate_db;
|
||||
use dbqueries;
|
||||
use failure::Error;
|
||||
use models::new_episode::{NewEpisodeMinimal, NewEpisodeMinimalBuilder};
|
||||
use models::*;
|
||||
|
||||
@@ -330,8 +332,7 @@ mod tests {
|
||||
.title("The Super Bowl of Racism")
|
||||
.uri(Some(String::from(
|
||||
"http://traffic.megaphone.fm/PPY6458293736.mp3",
|
||||
)))
|
||||
.guid(Some(String::from("7df4070a-9832-11e7-adac-cb37b05d5e24")))
|
||||
))).guid(Some(String::from("7df4070a-9832-11e7-adac-cb37b05d5e24")))
|
||||
.epoch(1505296800)
|
||||
.length(Some(66738886))
|
||||
.duration(Some(4171))
|
||||
@@ -344,8 +345,7 @@ mod tests {
|
||||
.title("Atlas Golfed — U.S.-Backed Think Tanks Target Latin America")
|
||||
.uri(Some(String::from(
|
||||
"http://traffic.megaphone.fm/FL5331443769.mp3",
|
||||
)))
|
||||
.guid(Some(String::from("7c207a24-e33f-11e6-9438-eb45dcf36a1d")))
|
||||
))).guid(Some(String::from("7c207a24-e33f-11e6-9438-eb45dcf36a1d")))
|
||||
.epoch(1502272800)
|
||||
.length(Some(67527575))
|
||||
.duration(Some(4415))
|
||||
@@ -364,8 +364,7 @@ mod tests {
|
||||
.title("The Super Bowl of Racism")
|
||||
.uri(Some(String::from(
|
||||
"http://traffic.megaphone.fm/PPY6458293736.mp3",
|
||||
)))
|
||||
.description(Some(String::from(descr)))
|
||||
))).description(Some(String::from(descr)))
|
||||
.guid(Some(String::from("7df4070a-9832-11e7-adac-cb37b05d5e24")))
|
||||
.length(Some(66738886))
|
||||
.epoch(1505296800)
|
||||
@@ -388,8 +387,7 @@ mod tests {
|
||||
.title("Atlas Golfed — U.S.-Backed Think Tanks Target Latin America")
|
||||
.uri(Some(String::from(
|
||||
"http://traffic.megaphone.fm/FL5331443769.mp3",
|
||||
)))
|
||||
.description(Some(String::from(descr)))
|
||||
))).description(Some(String::from(descr)))
|
||||
.guid(Some(String::from("7c207a24-e33f-11e6-9438-eb45dcf36a1d")))
|
||||
.length(Some(67527575))
|
||||
.epoch(1502272800)
|
||||
@@ -403,8 +401,7 @@ mod tests {
|
||||
.title("The Super Bowl of Racism")
|
||||
.uri(Some(String::from(
|
||||
"http://traffic.megaphone.fm/PPY6458293736.mp3",
|
||||
)))
|
||||
.description(Some(String::from("New description")))
|
||||
))).description(Some(String::from("New description")))
|
||||
.guid(Some(String::from("7df4070a-9832-11e7-adac-cb37b05d5e24")))
|
||||
.length(Some(66738886))
|
||||
.epoch(1505296800)
|
||||
@@ -418,8 +415,7 @@ mod tests {
|
||||
.title("Hacking Devices with Kali Linux | LUP 214")
|
||||
.uri(Some(String::from(
|
||||
"http://www.podtrac.com/pts/redirect.mp3/traffic.libsyn.com/jnite/lup-0214.mp3",
|
||||
)))
|
||||
.guid(Some(String::from("78A682B4-73E8-47B8-88C0-1BE62DD4EF9D")))
|
||||
))).guid(Some(String::from("78A682B4-73E8-47B8-88C0-1BE62DD4EF9D")))
|
||||
.length(Some(46479789))
|
||||
.epoch(1505280282)
|
||||
.duration(Some(5733))
|
||||
@@ -432,8 +428,7 @@ mod tests {
|
||||
.title("Gnome Does it Again | LUP 213")
|
||||
.uri(Some(String::from(
|
||||
"http://www.podtrac.com/pts/redirect.mp3/traffic.libsyn.com/jnite/lup-0213.mp3",
|
||||
)))
|
||||
.guid(Some(String::from("1CE57548-B36C-4F14-832A-5D5E0A24E35B")))
|
||||
))).guid(Some(String::from("1CE57548-B36C-4F14-832A-5D5E0A24E35B")))
|
||||
.epoch(1504670247)
|
||||
.length(Some(36544272))
|
||||
.duration(Some(4491))
|
||||
@@ -451,8 +446,7 @@ mod tests {
|
||||
.title("Hacking Devices with Kali Linux | LUP 214")
|
||||
.uri(Some(String::from(
|
||||
"http://www.podtrac.com/pts/redirect.mp3/traffic.libsyn.com/jnite/lup-0214.mp3",
|
||||
)))
|
||||
.description(Some(String::from(descr)))
|
||||
))).description(Some(String::from(descr)))
|
||||
.guid(Some(String::from("78A682B4-73E8-47B8-88C0-1BE62DD4EF9D")))
|
||||
.length(Some(46479789))
|
||||
.epoch(1505280282)
|
||||
@@ -473,8 +467,7 @@ mod tests {
|
||||
.title("Gnome Does it Again | LUP 213")
|
||||
.uri(Some(String::from(
|
||||
"http://www.podtrac.com/pts/redirect.mp3/traffic.libsyn.com/jnite/lup-0213.mp3",
|
||||
)))
|
||||
.description(Some(String::from(descr)))
|
||||
))).description(Some(String::from(descr)))
|
||||
.guid(Some(String::from("1CE57548-B36C-4F14-832A-5D5E0A24E35B")))
|
||||
.length(Some(36544272))
|
||||
.epoch(1504670247)
|
||||
@@ -486,68 +479,72 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_episode_minimal_intercepted() {
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_episode_minimal_intercepted() -> Result<(), Error> {
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let episode = channel.items().iter().nth(14).unwrap();
|
||||
let ep = NewEpisodeMinimal::new(&episode, 42).unwrap();
|
||||
let ep = NewEpisodeMinimal::new(&episode, 42)?;
|
||||
assert_eq!(ep, *EXPECTED_MINIMAL_INTERCEPTED_1);
|
||||
|
||||
let episode = channel.items().iter().nth(15).unwrap();
|
||||
let ep = NewEpisodeMinimal::new(&episode, 42).unwrap();
|
||||
let ep = NewEpisodeMinimal::new(&episode, 42)?;
|
||||
assert_eq!(ep, *EXPECTED_MINIMAL_INTERCEPTED_2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_episode_intercepted() {
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_episode_intercepted() -> Result<(), Error> {
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let episode = channel.items().iter().nth(14).unwrap();
|
||||
let ep = NewEpisode::new(&episode, 42).unwrap();
|
||||
let ep = NewEpisode::new(&episode, 42)?;
|
||||
assert_eq!(ep, *EXPECTED_INTERCEPTED_1);
|
||||
|
||||
let episode = channel.items().iter().nth(15).unwrap();
|
||||
let ep = NewEpisode::new(&episode, 42).unwrap();
|
||||
let ep = NewEpisode::new(&episode, 42)?;
|
||||
|
||||
assert_eq!(ep, *EXPECTED_INTERCEPTED_2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_episode_minimal_lup() {
|
||||
let file = File::open("tests/feeds/2018-01-20-LinuxUnplugged.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_episode_minimal_lup() -> Result<(), Error> {
|
||||
let file = File::open("tests/feeds/2018-01-20-LinuxUnplugged.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let episode = channel.items().iter().nth(18).unwrap();
|
||||
let ep = NewEpisodeMinimal::new(&episode, 42).unwrap();
|
||||
let ep = NewEpisodeMinimal::new(&episode, 42)?;
|
||||
assert_eq!(ep, *EXPECTED_MINIMAL_LUP_1);
|
||||
|
||||
let episode = channel.items().iter().nth(19).unwrap();
|
||||
let ep = NewEpisodeMinimal::new(&episode, 42).unwrap();
|
||||
let ep = NewEpisodeMinimal::new(&episode, 42)?;
|
||||
assert_eq!(ep, *EXPECTED_MINIMAL_LUP_2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_episode_lup() {
|
||||
let file = File::open("tests/feeds/2018-01-20-LinuxUnplugged.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_episode_lup() -> Result<(), Error> {
|
||||
let file = File::open("tests/feeds/2018-01-20-LinuxUnplugged.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let episode = channel.items().iter().nth(18).unwrap();
|
||||
let ep = NewEpisode::new(&episode, 42).unwrap();
|
||||
let ep = NewEpisode::new(&episode, 42)?;
|
||||
assert_eq!(ep, *EXPECTED_LUP_1);
|
||||
|
||||
let episode = channel.items().iter().nth(19).unwrap();
|
||||
let ep = NewEpisode::new(&episode, 42).unwrap();
|
||||
let ep = NewEpisode::new(&episode, 42)?;
|
||||
assert_eq!(ep, *EXPECTED_LUP_2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_minimal_into_new_episode() {
|
||||
truncate_db().unwrap();
|
||||
fn test_minimal_into_new_episode() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let item = channel.items().iter().nth(14).unwrap();
|
||||
let ep = EXPECTED_MINIMAL_INTERCEPTED_1
|
||||
@@ -564,42 +561,44 @@ mod tests {
|
||||
.clone()
|
||||
.into_new_episode(&item);
|
||||
assert_eq!(ep, *EXPECTED_INTERCEPTED_2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_episode_insert() {
|
||||
truncate_db().unwrap();
|
||||
fn test_new_episode_insert() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let episode = channel.items().iter().nth(14).unwrap();
|
||||
let new_ep = NewEpisode::new(&episode, 42).unwrap();
|
||||
new_ep.insert().unwrap();
|
||||
let ep = dbqueries::get_episode_from_pk(new_ep.title(), new_ep.show_id()).unwrap();
|
||||
let new_ep = NewEpisode::new(&episode, 42)?;
|
||||
new_ep.insert()?;
|
||||
let ep = dbqueries::get_episode_from_pk(new_ep.title(), new_ep.show_id())?;
|
||||
|
||||
assert_eq!(new_ep, ep);
|
||||
assert_eq!(&new_ep, &*EXPECTED_INTERCEPTED_1);
|
||||
assert_eq!(&*EXPECTED_INTERCEPTED_1, &ep);
|
||||
|
||||
let episode = channel.items().iter().nth(15).unwrap();
|
||||
let new_ep = NewEpisode::new(&episode, 42).unwrap();
|
||||
new_ep.insert().unwrap();
|
||||
let ep = dbqueries::get_episode_from_pk(new_ep.title(), new_ep.show_id()).unwrap();
|
||||
let new_ep = NewEpisode::new(&episode, 42)?;
|
||||
new_ep.insert()?;
|
||||
let ep = dbqueries::get_episode_from_pk(new_ep.title(), new_ep.show_id())?;
|
||||
|
||||
assert_eq!(new_ep, ep);
|
||||
assert_eq!(&new_ep, &*EXPECTED_INTERCEPTED_2);
|
||||
assert_eq!(&*EXPECTED_INTERCEPTED_2, &ep);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_episode_update() {
|
||||
truncate_db().unwrap();
|
||||
let old = EXPECTED_INTERCEPTED_1.clone().to_episode().unwrap();
|
||||
fn test_new_episode_update() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
let old = EXPECTED_INTERCEPTED_1.clone().to_episode()?;
|
||||
|
||||
let updated = &*UPDATED_DURATION_INTERCEPTED_1;
|
||||
updated.update(old.rowid()).unwrap();
|
||||
let new = dbqueries::get_episode_from_pk(old.title(), old.show_id()).unwrap();
|
||||
updated.update(old.rowid())?;
|
||||
let new = dbqueries::get_episode_from_pk(old.title(), old.show_id())?;
|
||||
|
||||
// Assert that updating does not change the rowid and show_id
|
||||
assert_ne!(old, new);
|
||||
@@ -608,11 +607,12 @@ mod tests {
|
||||
|
||||
assert_eq!(updated, &new);
|
||||
assert_ne!(updated, &old);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_episode_index() {
|
||||
truncate_db().unwrap();
|
||||
fn test_new_episode_index() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
let expected = &*EXPECTED_INTERCEPTED_1;
|
||||
|
||||
// First insert
|
||||
@@ -620,7 +620,7 @@ mod tests {
|
||||
// Second identical, This should take the early return path
|
||||
assert!(expected.index().is_ok());
|
||||
// Get the episode
|
||||
let old = dbqueries::get_episode_from_pk(expected.title(), expected.show_id()).unwrap();
|
||||
let old = dbqueries::get_episode_from_pk(expected.title(), expected.show_id())?;
|
||||
// Assert that NewPodcast is equal to the Indexed one
|
||||
assert_eq!(*expected, old);
|
||||
|
||||
@@ -629,31 +629,33 @@ mod tests {
|
||||
// Update the podcast
|
||||
assert!(updated.index().is_ok());
|
||||
// Get the new Podcast
|
||||
let new = dbqueries::get_episode_from_pk(expected.title(), expected.show_id()).unwrap();
|
||||
let new = dbqueries::get_episode_from_pk(expected.title(), expected.show_id())?;
|
||||
// Assert it's diff from the old one.
|
||||
assert_ne!(new, old);
|
||||
assert_eq!(*updated, new);
|
||||
assert_eq!(new.rowid(), old.rowid());
|
||||
assert_eq!(new.show_id(), old.show_id());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_episode_to_episode() {
|
||||
fn test_new_episode_to_episode() -> Result<(), Error> {
|
||||
let expected = &*EXPECTED_INTERCEPTED_1;
|
||||
|
||||
// Assert insert() produces the same result that you would get with to_podcast()
|
||||
truncate_db().unwrap();
|
||||
expected.insert().unwrap();
|
||||
let old = dbqueries::get_episode_from_pk(expected.title(), expected.show_id()).unwrap();
|
||||
let ep = expected.to_episode().unwrap();
|
||||
truncate_db()?;
|
||||
expected.insert()?;
|
||||
let old = dbqueries::get_episode_from_pk(expected.title(), expected.show_id())?;
|
||||
let ep = expected.to_episode()?;
|
||||
assert_eq!(old, ep);
|
||||
|
||||
// Same as above, diff order
|
||||
truncate_db().unwrap();
|
||||
let ep = expected.to_episode().unwrap();
|
||||
truncate_db()?;
|
||||
let ep = expected.to_episode()?;
|
||||
// This should error as a unique constrain violation
|
||||
assert!(expected.insert().is_err());
|
||||
let old = dbqueries::get_episode_from_pk(expected.title(), expected.show_id()).unwrap();
|
||||
let old = dbqueries::get_episode_from_pk(expected.title(), expected.show_id())?;
|
||||
assert_eq!(old, ep);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -157,6 +157,7 @@ mod tests {
|
||||
use super::*;
|
||||
// use tokio_core::reactor::Core;
|
||||
|
||||
use failure::Error;
|
||||
use rss::Channel;
|
||||
|
||||
use database::truncate_db;
|
||||
@@ -199,8 +200,7 @@ mod tests {
|
||||
.description(descr)
|
||||
.image_uri(Some(String::from(
|
||||
"http://www.jupiterbroadcasting.com/images/LASUN-Badge1400.jpg",
|
||||
)))
|
||||
.source_id(42)
|
||||
))).source_id(42)
|
||||
.build()
|
||||
.unwrap()
|
||||
};
|
||||
@@ -222,8 +222,7 @@ mod tests {
|
||||
.image_uri(Some(String::from(
|
||||
"https://imagecdn.acast.com/image?h=1500&w=1500&source=http%3A%2F%2Fi1.sndcdn.\
|
||||
com%2Favatars-000317856075-a2coqz-original.jpg",
|
||||
)))
|
||||
.source_id(42)
|
||||
))).source_id(42)
|
||||
.build()
|
||||
.unwrap()
|
||||
};
|
||||
@@ -257,8 +256,7 @@ mod tests {
|
||||
.description(descr)
|
||||
.image_uri(Some(String::from(
|
||||
"http://www.greaterthancode.com/wp-content/uploads/2016/10/code1400-4.jpg",
|
||||
)))
|
||||
.source_id(42)
|
||||
))).source_id(42)
|
||||
.build()
|
||||
.unwrap()
|
||||
};
|
||||
@@ -289,73 +287,80 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_podcast_intercepted() {
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_podcast_intercepted() -> Result<(), Error> {
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let pd = NewShow::new(&channel, 42);
|
||||
assert_eq!(*EXPECTED_INTERCEPTED, pd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_podcast_lup() {
|
||||
let file = File::open("tests/feeds/2018-01-20-LinuxUnplugged.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_podcast_lup() -> Result<(), Error> {
|
||||
let file = File::open("tests/feeds/2018-01-20-LinuxUnplugged.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let pd = NewShow::new(&channel, 42);
|
||||
assert_eq!(*EXPECTED_LUP, pd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_podcast_thetipoff() {
|
||||
let file = File::open("tests/feeds/2018-01-20-TheTipOff.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_podcast_thetipoff() -> Result<(), Error> {
|
||||
let file = File::open("tests/feeds/2018-01-20-TheTipOff.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let pd = NewShow::new(&channel, 42);
|
||||
assert_eq!(*EXPECTED_TIPOFF, pd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_podcast_steal_the_stars() {
|
||||
let file = File::open("tests/feeds/2018-01-20-StealTheStars.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_podcast_steal_the_stars() -> Result<(), Error> {
|
||||
let file = File::open("tests/feeds/2018-01-20-StealTheStars.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let pd = NewShow::new(&channel, 42);
|
||||
assert_eq!(*EXPECTED_STARS, pd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_podcast_greater_than_code() {
|
||||
let file = File::open("tests/feeds/2018-01-20-GreaterThanCode.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_podcast_greater_than_code() -> Result<(), Error> {
|
||||
let file = File::open("tests/feeds/2018-01-20-GreaterThanCode.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let pd = NewShow::new(&channel, 42);
|
||||
assert_eq!(*EXPECTED_CODE, pd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_podcast_ellinofreneia() {
|
||||
let file = File::open("tests/feeds/2018-03-28-Ellinofreneia.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_podcast_ellinofreneia() -> Result<(), Error> {
|
||||
let file = File::open("tests/feeds/2018-03-28-Ellinofreneia.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let pd = NewShow::new(&channel, 42);
|
||||
assert_eq!(*EXPECTED_ELLINOFRENEIA, pd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
// This maybe could be a doc test on insert.
|
||||
fn test_new_podcast_insert() {
|
||||
truncate_db().unwrap();
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml").unwrap();
|
||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||
fn test_new_podcast_insert() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
let file = File::open("tests/feeds/2018-01-20-Intercepted.xml")?;
|
||||
let channel = Channel::read_from(BufReader::new(file))?;
|
||||
|
||||
let npd = NewShow::new(&channel, 42);
|
||||
npd.insert().unwrap();
|
||||
let pd = dbqueries::get_podcast_from_source_id(42).unwrap();
|
||||
npd.insert()?;
|
||||
let pd = dbqueries::get_podcast_from_source_id(42)?;
|
||||
|
||||
assert_eq!(npd, pd);
|
||||
assert_eq!(*EXPECTED_INTERCEPTED, npd);
|
||||
assert_eq!(&*EXPECTED_INTERCEPTED, &pd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -363,31 +368,32 @@ mod tests {
|
||||
// Currently there's a test that only checks new description or title.
|
||||
// If you have time and want to help, implement the test for the other fields
|
||||
// too.
|
||||
fn test_new_podcast_update() {
|
||||
truncate_db().unwrap();
|
||||
let old = EXPECTED_INTERCEPTED.to_podcast().unwrap();
|
||||
fn test_new_podcast_update() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
let old = EXPECTED_INTERCEPTED.to_podcast()?;
|
||||
|
||||
let updated = &*UPDATED_DESC_INTERCEPTED;
|
||||
updated.update(old.id()).unwrap();
|
||||
let new = dbqueries::get_podcast_from_source_id(42).unwrap();
|
||||
updated.update(old.id())?;
|
||||
let new = dbqueries::get_podcast_from_source_id(42)?;
|
||||
|
||||
assert_ne!(old, new);
|
||||
assert_eq!(old.id(), new.id());
|
||||
assert_eq!(old.source_id(), new.source_id());
|
||||
assert_eq!(updated, &new);
|
||||
assert_ne!(updated, &old);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_podcast_index() {
|
||||
truncate_db().unwrap();
|
||||
fn test_new_podcast_index() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
|
||||
// First insert
|
||||
assert!(EXPECTED_INTERCEPTED.index().is_ok());
|
||||
// Second identical, This should take the early return path
|
||||
assert!(EXPECTED_INTERCEPTED.index().is_ok());
|
||||
// Get the podcast
|
||||
let old = dbqueries::get_podcast_from_source_id(42).unwrap();
|
||||
let old = dbqueries::get_podcast_from_source_id(42)?;
|
||||
// Assert that NewShow is equal to the Indexed one
|
||||
assert_eq!(&*EXPECTED_INTERCEPTED, &old);
|
||||
|
||||
@@ -396,28 +402,30 @@ mod tests {
|
||||
// Update the podcast
|
||||
assert!(updated.index().is_ok());
|
||||
// Get the new Show
|
||||
let new = dbqueries::get_podcast_from_source_id(42).unwrap();
|
||||
let new = dbqueries::get_podcast_from_source_id(42)?;
|
||||
// Assert it's diff from the old one.
|
||||
assert_ne!(new, old);
|
||||
assert_eq!(new.id(), old.id());
|
||||
assert_eq!(new.source_id(), old.source_id());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_podcast() {
|
||||
fn test_to_podcast() -> Result<(), Error> {
|
||||
// Assert insert() produces the same result that you would get with to_podcast()
|
||||
truncate_db().unwrap();
|
||||
EXPECTED_INTERCEPTED.insert().unwrap();
|
||||
let old = dbqueries::get_podcast_from_source_id(42).unwrap();
|
||||
let pd = EXPECTED_INTERCEPTED.to_podcast().unwrap();
|
||||
truncate_db()?;
|
||||
EXPECTED_INTERCEPTED.insert()?;
|
||||
let old = dbqueries::get_podcast_from_source_id(42)?;
|
||||
let pd = EXPECTED_INTERCEPTED.to_podcast()?;
|
||||
assert_eq!(old, pd);
|
||||
|
||||
// Same as above, diff order
|
||||
truncate_db().unwrap();
|
||||
let pd = EXPECTED_INTERCEPTED.to_podcast().unwrap();
|
||||
truncate_db()?;
|
||||
let pd = EXPECTED_INTERCEPTED.to_podcast()?;
|
||||
// This should error as a unique constrain violation
|
||||
assert!(EXPECTED_INTERCEPTED.insert().is_err());
|
||||
let old = dbqueries::get_podcast_from_source_id(42).unwrap();
|
||||
let old = dbqueries::get_podcast_from_source_id(42)?;
|
||||
assert_eq!(old, pd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
use diesel::SaveChangesDsl;
|
||||
|
||||
use database::connection;
|
||||
use errors::DataError;
|
||||
use models::{Save, Source};
|
||||
use models::Source;
|
||||
use schema::shows;
|
||||
|
||||
#[derive(Queryable, Identifiable, AsChangeset, Associations, PartialEq)]
|
||||
@@ -20,19 +16,6 @@ pub struct Show {
|
||||
source_id: i32,
|
||||
}
|
||||
|
||||
impl Save<Show> for Show {
|
||||
type Error = DataError;
|
||||
|
||||
/// Helper method to easily save/"sync" current state of self to the
|
||||
/// Database.
|
||||
fn save(&self) -> Result<Show, Self::Error> {
|
||||
let db = connection();
|
||||
let tempdb = db.get()?;
|
||||
|
||||
self.save_changes::<Show>(&*tempdb).map_err(From::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl Show {
|
||||
/// Get the Feed `id`.
|
||||
pub fn id(&self) -> i32 {
|
||||
@@ -51,21 +34,11 @@ impl Show {
|
||||
&self.link
|
||||
}
|
||||
|
||||
/// Set the Show/Feed `link`.
|
||||
pub fn set_link(&mut self, value: &str) {
|
||||
self.link = value.to_string();
|
||||
}
|
||||
|
||||
/// Get the `description`.
|
||||
pub fn description(&self) -> &str {
|
||||
&self.description
|
||||
}
|
||||
|
||||
/// Set the `description`.
|
||||
pub fn set_description(&mut self, value: &str) {
|
||||
self.description = value.to_string();
|
||||
}
|
||||
|
||||
/// Get the `image_uri`.
|
||||
///
|
||||
/// Represents the uri(url usually) that the Feed cover image is located at.
|
||||
@@ -73,11 +46,6 @@ impl Show {
|
||||
self.image_uri.as_ref().map(|s| s.as_str())
|
||||
}
|
||||
|
||||
/// Set the `image_uri`.
|
||||
pub fn set_image_uri(&mut self, value: Option<&str>) {
|
||||
self.image_uri = value.map(|x| x.to_string());
|
||||
}
|
||||
|
||||
/// `Source` table foreign key.
|
||||
pub fn source_id(&self) -> i32 {
|
||||
self.source_id
|
||||
@@ -4,12 +4,14 @@ use rss::Channel;
|
||||
use url::Url;
|
||||
|
||||
use hyper::client::HttpConnector;
|
||||
use hyper::header::{
|
||||
ETag, EntityTag, HttpDate, IfModifiedSince, IfNoneMatch, LastModified, Location, UserAgent,
|
||||
};
|
||||
use hyper::{Client, Method, Request, Response, StatusCode, Uri};
|
||||
use hyper::{Client, Body};
|
||||
use hyper_tls::HttpsConnector;
|
||||
|
||||
use http::{Request, Response, StatusCode, Uri};
|
||||
use http::header::{
|
||||
ETAG, IF_MODIFIED_SINCE, IF_NONE_MATCH, LAST_MODIFIED, LOCATION, USER_AGENT as USER_AGENT_HEADER,
|
||||
HeaderValue,
|
||||
};
|
||||
// use futures::future::ok;
|
||||
use futures::future::{loop_fn, Future, Loop};
|
||||
use futures::prelude::*;
|
||||
@@ -91,19 +93,28 @@ impl Source {
|
||||
|
||||
/// Extract Etag and LastModifier from res, and update self and the
|
||||
/// corresponding db row.
|
||||
fn update_etag(&mut self, res: &Response) -> Result<(), DataError> {
|
||||
fn update_etag(mut self, res: &Response<Body>) -> Result<Self, DataError> {
|
||||
let headers = res.headers();
|
||||
|
||||
let etag = headers.get::<ETag>().map(|x| x.tag());
|
||||
let lmod = headers.get::<LastModified>().map(|x| format!("{}", x));
|
||||
let etag = headers.get(ETAG).and_then(|h| h.to_str().ok()).map(From::from);
|
||||
let lmod = headers.get(LAST_MODIFIED).and_then(|h| h.to_str().ok()).map(From::from);
|
||||
|
||||
if (self.http_etag() != etag) || (self.last_modified != lmod) {
|
||||
self.set_http_etag(etag);
|
||||
self.set_last_modified(lmod);
|
||||
self.save()?;
|
||||
self = self.save()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Clear the `HTTP` `Etag` and `Last-modified` headers.
|
||||
/// This method does not sync the state of self in the database, call
|
||||
/// .save() method explicitly
|
||||
fn clear_etags(&mut self) {
|
||||
debug!("Source etags before clear: {:#?}", &self);
|
||||
self.http_etag = None;
|
||||
self.last_modified = None;
|
||||
}
|
||||
|
||||
fn make_err(self, context: &str, code: StatusCode) -> DataError {
|
||||
@@ -120,41 +131,68 @@ impl Source {
|
||||
// 408: Timeout
|
||||
// 410: Feed deleted
|
||||
// TODO: Rething this api,
|
||||
fn match_status(mut self, res: Response) -> Result<Response, DataError> {
|
||||
self.update_etag(&res)?;
|
||||
fn match_status(mut self, res: Response<Body>) -> Result<Response<Body>, DataError> {
|
||||
let code = res.status();
|
||||
|
||||
match code {
|
||||
StatusCode::NotModified => return Err(self.make_err("304: skipping..", code)),
|
||||
StatusCode::MovedPermanently => {
|
||||
error!("Feed was moved permanently.");
|
||||
self.handle_301(&res)?;
|
||||
return Err(DataError::F301(self));
|
||||
if code.is_success() {
|
||||
// If request is succesful save the etag
|
||||
self = self.update_etag(&res)?
|
||||
} else {
|
||||
match code.as_u16() {
|
||||
// Save etags if it returns NotModified
|
||||
304 => self = self.update_etag(&res)?,
|
||||
// Clear the Etag/lmod else
|
||||
_ => {
|
||||
self.clear_etags();
|
||||
self = self.save()?;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
match code.as_u16() {
|
||||
304 => {
|
||||
info!("304: Source, (id: {}), is up to date", self.id());
|
||||
return Err(DataError::FeedNotModified(self));
|
||||
}
|
||||
StatusCode::TemporaryRedirect => debug!("307: Temporary Redirect."),
|
||||
StatusCode::PermanentRedirect => warn!("308: Permanent Redirect."),
|
||||
StatusCode::Unauthorized => return Err(self.make_err("401: Unauthorized.", code)),
|
||||
StatusCode::Forbidden => return Err(self.make_err("403: Forbidden.", code)),
|
||||
StatusCode::NotFound => return Err(self.make_err("404: Not found.", code)),
|
||||
StatusCode::RequestTimeout => return Err(self.make_err("408: Request Timeout.", code)),
|
||||
StatusCode::Gone => return Err(self.make_err("410: Feed was deleted..", code)),
|
||||
301 | 302 | 308 => {
|
||||
warn!("Feed was moved permanently.");
|
||||
self = self.update_url(&res)?;
|
||||
return Err(DataError::FeedRedirect(self));
|
||||
}
|
||||
307 => {
|
||||
warn!("307: Temporary Redirect.");
|
||||
// FIXME: How is it actually handling the redirect?
|
||||
return Err(DataError::FeedRedirect(self));
|
||||
}
|
||||
401 => return Err(self.make_err("401: Unauthorized.", code)),
|
||||
403 => return Err(self.make_err("403: Forbidden.", code)),
|
||||
404 => return Err(self.make_err("404: Not found.", code)),
|
||||
408 => return Err(self.make_err("408: Request Timeout.", code)),
|
||||
410 => return Err(self.make_err("410: Feed was deleted..", code)),
|
||||
_ => info!("HTTP StatusCode: {}", code),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn handle_301(&mut self, res: &Response) -> Result<(), DataError> {
|
||||
fn update_url(mut self, res: &Response<Body>) -> Result<Self, DataError> {
|
||||
let code = res.status();
|
||||
let headers = res.headers();
|
||||
info!("HTTP StatusCode: {}", code);
|
||||
debug!("Headers {:#?}", headers);
|
||||
|
||||
if let Some(url) = headers.get::<Location>() {
|
||||
self.set_uri(url.to_string());
|
||||
self.http_etag = None;
|
||||
self.last_modified = None;
|
||||
self.save()?;
|
||||
info!("Feed url was updated succesfully.");
|
||||
if let Some(url) = headers.get(LOCATION) {
|
||||
debug!("Previous Source: {:#?}", &self);
|
||||
|
||||
self.set_uri(url.to_str()?.into());
|
||||
self.clear_etags();
|
||||
self = self.save()?;
|
||||
|
||||
debug!("Updated Source: {:#?}", &self);
|
||||
info!("Feed url of Source {}, was updated succesfully.", self.id());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Construct a new `Source` with the given `uri` and index it.
|
||||
@@ -177,16 +215,15 @@ impl Source {
|
||||
pub fn into_feed(
|
||||
self,
|
||||
client: Client<HttpsConnector<HttpConnector>>,
|
||||
ignore_etags: bool,
|
||||
) -> impl Future<Item = Feed, Error = DataError> {
|
||||
let id = self.id();
|
||||
let response = loop_fn(self, move |source| {
|
||||
source
|
||||
.request_constructor(&client.clone(), ignore_etags)
|
||||
.request_constructor(&client.clone())
|
||||
.then(|res| match res {
|
||||
Ok(response) => Ok(Loop::Break(response)),
|
||||
Err(err) => match err {
|
||||
DataError::F301(s) => {
|
||||
DataError::FeedRedirect(s) => {
|
||||
info!("Following redirect...");
|
||||
Ok(Loop::Continue(s))
|
||||
}
|
||||
@@ -206,31 +243,25 @@ impl Source {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: make ignore_etags an Enum for better ergonomics.
|
||||
// #bools_are_just_2variant_enmus
|
||||
fn request_constructor(
|
||||
self,
|
||||
client: &Client<HttpsConnector<HttpConnector>>,
|
||||
ignore_etags: bool,
|
||||
) -> impl Future<Item = Response, Error = DataError> {
|
||||
) -> impl Future<Item = Response<Body>, Error = DataError> {
|
||||
// FIXME: remove unwrap somehow
|
||||
let uri = Uri::from_str(self.uri()).unwrap();
|
||||
let mut req = Request::new(Method::Get, uri);
|
||||
let mut req = Request::get(uri)
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
|
||||
// Set the UserAgent cause ppl still seem to check it for some reason...
|
||||
req.headers_mut().set(UserAgent::new(USER_AGENT));
|
||||
req.headers_mut().insert(USER_AGENT_HEADER, HeaderValue::from_static(USER_AGENT));
|
||||
|
||||
if !ignore_etags {
|
||||
if let Some(etag) = self.http_etag() {
|
||||
let tag = vec![EntityTag::new(true, etag.to_owned())];
|
||||
req.headers_mut().set(IfNoneMatch::Items(tag));
|
||||
}
|
||||
if let Some(etag) = self.http_etag() {
|
||||
req.headers_mut().insert(IF_NONE_MATCH, HeaderValue::from_str(etag).unwrap());
|
||||
}
|
||||
|
||||
if let Some(lmod) = self.last_modified() {
|
||||
if let Ok(date) = lmod.parse::<HttpDate>() {
|
||||
req.headers_mut().set(IfModifiedSince(date));
|
||||
}
|
||||
}
|
||||
if let Some(lmod) = self.last_modified() {
|
||||
req.headers_mut().insert(IF_MODIFIED_SINCE, HeaderValue::from_str(lmod).unwrap());
|
||||
}
|
||||
|
||||
client
|
||||
@@ -240,9 +271,8 @@ impl Source {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(needless_pass_by_value)]
|
||||
fn response_to_channel(res: Response) -> impl Future<Item = Channel, Error = DataError> + Send {
|
||||
res.body()
|
||||
fn response_to_channel(res: Response<Body>) -> impl Future<Item = Channel, Error = DataError> + Send {
|
||||
res.into_body()
|
||||
.concat2()
|
||||
.map(|x| x.into_iter())
|
||||
.map_err(From::from)
|
||||
@@ -254,29 +284,30 @@ fn response_to_channel(res: Response) -> impl Future<Item = Channel, Error = Dat
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tokio_core::reactor::Core;
|
||||
use failure::Error;
|
||||
use num_cpus;
|
||||
use tokio;
|
||||
|
||||
use database::truncate_db;
|
||||
use utils::get_feed;
|
||||
|
||||
#[test]
|
||||
fn test_into_feed() {
|
||||
truncate_db().unwrap();
|
||||
fn test_into_feed() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
|
||||
let mut core = Core::new().unwrap();
|
||||
let client = Client::configure()
|
||||
.connector(HttpsConnector::new(4, &core.handle()).unwrap())
|
||||
.build(&core.handle());
|
||||
let mut rt = tokio::runtime::Runtime::new()?;
|
||||
let https = HttpsConnector::new(num_cpus::get())?;
|
||||
let client = Client::builder().build::<_, Body>(https);
|
||||
|
||||
let url = "https://web.archive.org/web/20180120083840if_/https://feeds.feedburner.\
|
||||
com/InterceptedWithJeremyScahill";
|
||||
let source = Source::from_url(url).unwrap();
|
||||
let source = Source::from_url(url)?;
|
||||
let id = source.id();
|
||||
|
||||
let feed = source.into_feed(client, true);
|
||||
let feed = core.run(feed).unwrap();
|
||||
let feed = source.into_feed(client);
|
||||
let feed = rt.block_on(feed)?;
|
||||
|
||||
let expected = get_feed("tests/feeds/2018-01-20-Intercepted.xml", id);
|
||||
assert_eq!(expected, feed);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -35,15 +35,14 @@ pub fn import_to_db<R: Read>(reader: R) -> Result<Vec<Source>, reader::Error> {
|
||||
.filter_map(|s| {
|
||||
if let Err(ref err) = s {
|
||||
let txt = "If you think this might be a bug please consider filling a report over \
|
||||
at https://gitlab.gnome.org/World/hammond/issues/new";
|
||||
at https://gitlab.gnome.org/World/podcasts/issues/new";
|
||||
|
||||
error!("Failed to import a Show: {}", err);
|
||||
error!("{}", txt);
|
||||
}
|
||||
|
||||
s.ok()
|
||||
})
|
||||
.collect();
|
||||
}).collect();
|
||||
|
||||
Ok(feeds)
|
||||
}
|
||||
@@ -92,8 +91,7 @@ pub fn extract_sources<R: Read>(reader: R) -> Result<HashSet<Opml>, reader::Erro
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
_ => Ok(()),
|
||||
})
|
||||
.collect::<Result<Vec<_>, reader::Error>>()?;
|
||||
}).collect::<Result<Vec<_>, reader::Error>>()?;
|
||||
|
||||
Ok(list)
|
||||
}
|
||||
@@ -102,9 +100,10 @@ pub fn extract_sources<R: Read>(reader: R) -> Result<HashSet<Opml>, reader::Erro
|
||||
mod tests {
|
||||
use super::*;
|
||||
use chrono::Local;
|
||||
use failure::Error;
|
||||
|
||||
#[test]
|
||||
fn test_extract() {
|
||||
fn test_extract() -> Result<(), Error> {
|
||||
let int_title = String::from("Intercepted with Jeremy Scahill");
|
||||
let int_url = String::from("https://feeds.feedburner.com/InterceptedWithJeremyScahill");
|
||||
let int_desc =
|
||||
@@ -162,6 +161,7 @@ mod tests {
|
||||
url: dec_url
|
||||
},
|
||||
];
|
||||
assert_eq!(extract_sources(sample1.as_bytes()).unwrap(), map);
|
||||
assert_eq!(extract_sources(sample1.as_bytes())?, map);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
// FIXME:
|
||||
//! Docs.
|
||||
|
||||
use futures::{lazy, prelude::*, future::ok, stream::FuturesUnordered};
|
||||
use tokio;
|
||||
|
||||
use hyper::client::HttpConnector;
|
||||
use hyper::{Client, Body};
|
||||
use hyper_tls::HttpsConnector;
|
||||
|
||||
use num_cpus;
|
||||
|
||||
use errors::DataError;
|
||||
use Source;
|
||||
|
||||
use std::iter::FromIterator;
|
||||
|
||||
type HttpsClient = Client<HttpsConnector<HttpConnector>>;
|
||||
|
||||
/// The pipline to be run for indexing and updating a Podcast feed that originates from
|
||||
/// `Source.uri`.
|
||||
///
|
||||
/// Messy temp diagram:
|
||||
/// Source -> GET Request -> Update Etags -> Check Status -> Parse `xml/Rss` ->
|
||||
/// Convert `rss::Channel` into `Feed` -> Index Podcast -> Index Episodes.
|
||||
pub fn pipeline<'a, S>(
|
||||
sources: S,
|
||||
client: HttpsClient,
|
||||
) -> impl Future<Item = (), Error = ()> + 'a
|
||||
where
|
||||
S: Stream<Item = Source, Error = DataError> + Send + 'a,
|
||||
{
|
||||
sources
|
||||
.and_then(move |s| s.into_feed(client.clone()))
|
||||
.map_err(|err| {
|
||||
match err {
|
||||
// Avoid spamming the stderr when its not an eactual error
|
||||
DataError::FeedNotModified(_) => (),
|
||||
_ => error!("Error: {}", err),
|
||||
}
|
||||
})
|
||||
.and_then(move |feed| {
|
||||
let fut = lazy(|| feed.index().map_err(|err| error!("Error: {}", err)));
|
||||
tokio::spawn(fut);
|
||||
Ok(())
|
||||
})
|
||||
// For each terminates the stream at the first error so we make sure
|
||||
// we pass good values regardless
|
||||
.then(move |_| ok(()))
|
||||
// Convert the stream into a Future to later execute as a tokio task
|
||||
.for_each(move |_| ok(()))
|
||||
}
|
||||
|
||||
/// Creates a tokio `reactor::Core`, and a `hyper::Client` and
|
||||
/// runs the pipeline to completion. The `reactor::Core` is dropped afterwards.
|
||||
pub fn run<S>(sources: S) -> Result<(), DataError>
|
||||
where
|
||||
S: IntoIterator<Item = Source>,
|
||||
{
|
||||
let https = HttpsConnector::new(num_cpus::get())?;
|
||||
let client = Client::builder().build::<_, Body>(https);
|
||||
|
||||
let foo = sources.into_iter().map(ok::<_, _>);
|
||||
let stream = FuturesUnordered::from_iter(foo);
|
||||
let p = pipeline(stream, client);
|
||||
tokio::run(p);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use database::truncate_db;
|
||||
use dbqueries;
|
||||
use failure::Error;
|
||||
use Source;
|
||||
|
||||
// (path, url) tuples.
|
||||
const URLS: &[&str] = &[
|
||||
"https://web.archive.org/web/20180120083840if_/https://feeds.feedburner.\
|
||||
com/InterceptedWithJeremyScahill",
|
||||
"https://web.archive.org/web/20180120110314if_/https://feeds.feedburner.com/linuxunplugged",
|
||||
"https://web.archive.org/web/20180120110727if_/https://rss.acast.com/thetipoff",
|
||||
"https://web.archive.org/web/20180120104957if_/https://rss.art19.com/steal-the-stars",
|
||||
"https://web.archive.org/web/20180120104741if_/https://www.greaterthancode.\
|
||||
com/feed/podcast",
|
||||
];
|
||||
|
||||
#[test]
|
||||
/// Insert feeds and update/index them.
|
||||
fn test_pipeline() -> Result<(), Error> {
|
||||
truncate_db()?;
|
||||
let bad_url = "https://gitlab.gnome.org/World/podcasts.atom";
|
||||
// if a stream returns error/None it stops
|
||||
// bad we want to parse all feeds regardless if one fails
|
||||
Source::from_url(bad_url)?;
|
||||
|
||||
URLS.iter().for_each(|url| {
|
||||
// Index the urls into the source table.
|
||||
Source::from_url(url).unwrap();
|
||||
});
|
||||
|
||||
let sources = dbqueries::get_sources()?;
|
||||
run(sources)?;
|
||||
|
||||
let sources = dbqueries::get_sources()?;
|
||||
// Run again to cover Unique constrains erros.
|
||||
run(sources)?;
|
||||
|
||||
// Assert the index rows equal the controlled results
|
||||
assert_eq!(dbqueries::get_sources()?.len(), 6);
|
||||
assert_eq!(dbqueries::get_podcasts()?.len(), 5);
|
||||
assert_eq!(dbqueries::get_episodes()?.len(), 354);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
diff --git a/hammond-data/src/schema.rs b/hammond-data/src/schema.rs
|
||||
diff --git a/podcasts-data/src/schema.rs b/podcasts-data/src/schema.rs
|
||||
index 03cbed0..88f1622 100644
|
||||
--- a/hammond-data/src/schema.rs
|
||||
+++ b/hammond-data/src/schema.rs
|
||||
--- a/podcasts-data/src/schema.rs
|
||||
+++ b/podcasts-data/src/schema.rs
|
||||
@@ -1,8 +1,11 @@
|
||||
+#![allow(warnings)]
|
||||
+
|
||||
@@ -25,8 +25,7 @@ fn download_checker() -> Result<(), DataError> {
|
||||
return Some(ep);
|
||||
}
|
||||
None
|
||||
})
|
||||
.for_each(|ep| {
|
||||
}).for_each(|ep| {
|
||||
ep.set_local_uri(None);
|
||||
ep.save()
|
||||
.map_err(|err| error!("{}", err))
|
||||
@@ -163,6 +162,7 @@ mod tests {
|
||||
use self::tempdir::TempDir;
|
||||
use super::*;
|
||||
use chrono::Duration;
|
||||
use failure::Error;
|
||||
|
||||
use database::truncate_db;
|
||||
use models::NewEpisodeBuilder;
|
||||
@@ -170,15 +170,15 @@ mod tests {
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
fn helper_db() -> TempDir {
|
||||
fn helper_db() -> Result<TempDir, Error> {
|
||||
// Clean the db
|
||||
truncate_db().unwrap();
|
||||
truncate_db()?;
|
||||
// Setup tmp file stuff
|
||||
let tmp_dir = TempDir::new("hammond_test").unwrap();
|
||||
let tmp_dir = TempDir::new("podcasts_test")?;
|
||||
let valid_path = tmp_dir.path().join("virtual_dl.mp3");
|
||||
let bad_path = tmp_dir.path().join("invalid_thing.mp3");
|
||||
let mut tmp_file = File::create(&valid_path).unwrap();
|
||||
writeln!(tmp_file, "Foooo").unwrap();
|
||||
let mut tmp_file = File::create(&valid_path)?;
|
||||
writeln!(tmp_file, "Foooo")?;
|
||||
|
||||
// Setup episodes
|
||||
let n1 = NewEpisodeBuilder::default()
|
||||
@@ -186,33 +186,31 @@ mod tests {
|
||||
.show_id(0)
|
||||
.build()
|
||||
.unwrap()
|
||||
.to_episode()
|
||||
.unwrap();
|
||||
.to_episode()?;
|
||||
|
||||
let n2 = NewEpisodeBuilder::default()
|
||||
.title("bar_baz".to_string())
|
||||
.show_id(1)
|
||||
.build()
|
||||
.unwrap()
|
||||
.to_episode()
|
||||
.unwrap();
|
||||
.to_episode()?;
|
||||
|
||||
let mut ep1 = dbqueries::get_episode_from_pk(n1.title(), n1.show_id()).unwrap();
|
||||
let mut ep2 = dbqueries::get_episode_from_pk(n2.title(), n2.show_id()).unwrap();
|
||||
let mut ep1 = dbqueries::get_episode_cleaner_from_pk(n1.title(), n1.show_id())?;
|
||||
let mut ep2 = dbqueries::get_episode_cleaner_from_pk(n2.title(), n2.show_id())?;
|
||||
ep1.set_local_uri(Some(valid_path.to_str().unwrap()));
|
||||
ep2.set_local_uri(Some(bad_path.to_str().unwrap()));
|
||||
|
||||
ep1.save().unwrap();
|
||||
ep2.save().unwrap();
|
||||
ep1.save()?;
|
||||
ep2.save()?;
|
||||
|
||||
tmp_dir
|
||||
Ok(tmp_dir)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_download_checker() {
|
||||
let tmp_dir = helper_db();
|
||||
download_checker().unwrap();
|
||||
let episodes = dbqueries::get_downloaded_episodes().unwrap();
|
||||
fn test_download_checker() -> Result<(), Error> {
|
||||
let tmp_dir = helper_db()?;
|
||||
download_checker()?;
|
||||
let episodes = dbqueries::get_downloaded_episodes()?;
|
||||
let valid_path = tmp_dir.path().join("virtual_dl.mp3");
|
||||
|
||||
assert_eq!(episodes.len(), 1);
|
||||
@@ -221,69 +219,75 @@ mod tests {
|
||||
episodes.first().unwrap().local_uri()
|
||||
);
|
||||
|
||||
let _tmp_dir = helper_db();
|
||||
download_checker().unwrap();
|
||||
let episode = dbqueries::get_episode_from_pk("bar_baz", 1).unwrap();
|
||||
let _tmp_dir = helper_db()?;
|
||||
download_checker()?;
|
||||
let episode = dbqueries::get_episode_cleaner_from_pk("bar_baz", 1)?;
|
||||
assert!(episode.local_uri().is_none());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_download_cleaner() {
|
||||
let _tmp_dir = helper_db();
|
||||
fn test_download_cleaner() -> Result<(), Error> {
|
||||
let _tmp_dir = helper_db()?;
|
||||
let mut episode: EpisodeCleanerModel =
|
||||
dbqueries::get_episode_from_pk("foo_bar", 0).unwrap().into();
|
||||
dbqueries::get_episode_cleaner_from_pk("foo_bar", 0)?.into();
|
||||
|
||||
let valid_path = episode.local_uri().unwrap().to_owned();
|
||||
delete_local_content(&mut episode).unwrap();
|
||||
delete_local_content(&mut episode)?;
|
||||
assert_eq!(Path::new(&valid_path).exists(), false);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_played_cleaner_expired() {
|
||||
let _tmp_dir = helper_db();
|
||||
let mut episode = dbqueries::get_episode_from_pk("foo_bar", 0).unwrap();
|
||||
fn test_played_cleaner_expired() -> Result<(), Error> {
|
||||
let _tmp_dir = helper_db()?;
|
||||
let mut episode = dbqueries::get_episode_cleaner_from_pk("foo_bar", 0)?;
|
||||
let cleanup_date = Utc::now() - Duration::seconds(1000);
|
||||
let epoch = cleanup_date.timestamp() as i32 - 1;
|
||||
episode.set_played(Some(epoch));
|
||||
episode.save().unwrap();
|
||||
episode.save()?;
|
||||
let valid_path = episode.local_uri().unwrap().to_owned();
|
||||
|
||||
// This should delete the file
|
||||
played_cleaner(cleanup_date).unwrap();
|
||||
played_cleaner(cleanup_date)?;
|
||||
assert_eq!(Path::new(&valid_path).exists(), false);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_played_cleaner_none() {
|
||||
let _tmp_dir = helper_db();
|
||||
let mut episode = dbqueries::get_episode_from_pk("foo_bar", 0).unwrap();
|
||||
fn test_played_cleaner_none() -> Result<(), Error> {
|
||||
let _tmp_dir = helper_db()?;
|
||||
let mut episode = dbqueries::get_episode_cleaner_from_pk("foo_bar", 0)?;
|
||||
let cleanup_date = Utc::now() - Duration::seconds(1000);
|
||||
let epoch = cleanup_date.timestamp() as i32 + 1;
|
||||
episode.set_played(Some(epoch));
|
||||
episode.save().unwrap();
|
||||
episode.save()?;
|
||||
let valid_path = episode.local_uri().unwrap().to_owned();
|
||||
|
||||
// This should not delete the file
|
||||
played_cleaner(cleanup_date).unwrap();
|
||||
played_cleaner(cleanup_date)?;
|
||||
assert_eq!(Path::new(&valid_path).exists(), true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_url_cleaner() {
|
||||
fn test_url_cleaner() -> Result<(), Error> {
|
||||
let good_url = "http://traffic.megaphone.fm/FL8608731318.mp3";
|
||||
let bad_url = "http://traffic.megaphone.fm/FL8608731318.mp3?updated=1484685184";
|
||||
|
||||
assert_eq!(url_cleaner(bad_url), good_url);
|
||||
assert_eq!(url_cleaner(good_url), good_url);
|
||||
assert_eq!(url_cleaner(&format!(" {}\t\n", bad_url)), good_url);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
// This test needs access to local system so we ignore it by default.
|
||||
#[ignore]
|
||||
fn test_get_dl_folder() {
|
||||
fn test_get_dl_folder() -> Result<(), Error> {
|
||||
let foo_ = format!("{}/{}", DL_DIR.to_str().unwrap(), "foo");
|
||||
assert_eq!(get_download_folder("foo").unwrap(), foo_);
|
||||
assert_eq!(get_download_folder("foo")?, foo_);
|
||||
let _ = fs::remove_dir_all(foo_);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
authors = ["Jordan Petridis <jordanpetridis@protonmail.com>"]
|
||||
name = "podcasts-downloader"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
error-chain = "0.12.0"
|
||||
log = "0.4.4"
|
||||
mime_guess = "1.8.6"
|
||||
reqwest = "0.9.2"
|
||||
tempdir = "0.3.7"
|
||||
glob = "0.2.11"
|
||||
failure = "0.1.2"
|
||||
failure_derive = "0.1.2"
|
||||
|
||||
[dependencies.podcasts-data]
|
||||
path = "../podcasts-data"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.5.1"
|
||||
@@ -1,8 +1,8 @@
|
||||
use glob::glob;
|
||||
use hyper::header::*;
|
||||
use mime_guess;
|
||||
use reqwest;
|
||||
use reqwest::RedirectPolicy;
|
||||
use reqwest::header::*;
|
||||
use tempdir::TempDir;
|
||||
|
||||
use std::fs;
|
||||
@@ -11,8 +11,8 @@ use std::io::{BufWriter, Read, Write};
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use hammond_data::xdg_dirs::HAMMOND_CACHE;
|
||||
use hammond_data::{EpisodeWidgetModel, Save, ShowCoverModel};
|
||||
use podcasts_data::xdg_dirs::PODCASTS_CACHE;
|
||||
use podcasts_data::{EpisodeWidgetModel, Save, ShowCoverModel};
|
||||
|
||||
// use failure::Error;
|
||||
use errors::DownloadError;
|
||||
@@ -22,9 +22,12 @@ use errors::DownloadError;
|
||||
// with / or not.
|
||||
|
||||
pub trait DownloadProgress {
|
||||
fn get_downloaded(&self) -> u64;
|
||||
fn set_downloaded(&mut self, downloaded: u64);
|
||||
fn get_size(&self) -> u64;
|
||||
fn set_size(&mut self, bytes: u64);
|
||||
fn should_cancel(&self) -> bool;
|
||||
fn cancel(&mut self);
|
||||
}
|
||||
|
||||
// Adapted from https://github.com/mattgathu/rget .
|
||||
@@ -38,7 +41,7 @@ fn download_into(
|
||||
dir: &str,
|
||||
file_title: &str,
|
||||
url: &str,
|
||||
progress: Option<Arc<Mutex<DownloadProgress>>>,
|
||||
progress: Option<Arc<Mutex<dyn DownloadProgress>>>,
|
||||
) -> Result<String, DownloadError> {
|
||||
info!("GET request to: {}", url);
|
||||
// Haven't included the loop check as
|
||||
@@ -63,28 +66,42 @@ fn download_into(
|
||||
info!("Status Resp: {}", resp.status());
|
||||
|
||||
if !resp.status().is_success() {
|
||||
if let Some(ref prog) = progress {
|
||||
if let Ok(mut m) = prog.lock() {
|
||||
m.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
return Err(DownloadError::UnexpectedResponse(resp.status()));
|
||||
}
|
||||
|
||||
let headers = resp.headers().clone();
|
||||
let ct_len = headers.get::<ContentLength>().map(|ct_len| **ct_len);
|
||||
let ct_type = headers.get::<ContentType>();
|
||||
let ct_len = headers
|
||||
.get(CONTENT_LENGTH)
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.and_then(|len| len.parse().ok());
|
||||
let ct_type = headers
|
||||
.get(CONTENT_TYPE)
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.map(From::from);
|
||||
|
||||
ct_len.map(|x| info!("File Lenght: {}", x));
|
||||
ct_type.map(|x| info!("Content Type: {}", x));
|
||||
|
||||
let ext = get_ext(ct_type.cloned()).unwrap_or_else(|| String::from("unknown"));
|
||||
let ext = get_ext(ct_type).unwrap_or_else(|| String::from("unknown"));
|
||||
info!("Extension: {}", ext);
|
||||
|
||||
// Construct a temp file to save desired content.
|
||||
// It has to be a `new_in` instead of new cause rename can't move cross
|
||||
// filesystems.
|
||||
let tempdir = TempDir::new_in(HAMMOND_CACHE.to_str().unwrap(), "temp_download")?;
|
||||
let tempdir = TempDir::new_in(PODCASTS_CACHE.to_str().unwrap(), "temp_download")?;
|
||||
let out_file = format!("{}/temp.part", tempdir.path().to_str().unwrap(),);
|
||||
|
||||
ct_len.map(|x| {
|
||||
if let Some(p) = progress.clone() {
|
||||
let mut m = p.lock().unwrap();
|
||||
m.set_size(x);
|
||||
if let Some(ref p) = progress {
|
||||
if let Ok(mut m) = p.lock() {
|
||||
m.set_size(x);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -100,17 +117,17 @@ fn download_into(
|
||||
}
|
||||
|
||||
/// Determine the file extension from the http content-type header.
|
||||
fn get_ext(content: Option<ContentType>) -> Option<String> {
|
||||
let cont = content.clone()?;
|
||||
content
|
||||
.and_then(|c| mime_guess::get_extensions(c.type_().as_ref(), c.subtype().as_ref()))
|
||||
.and_then(|c| {
|
||||
if c.contains(&cont.subtype().as_ref()) {
|
||||
Some(cont.subtype().as_ref().to_string())
|
||||
} else {
|
||||
Some(c.first().unwrap().to_string())
|
||||
}
|
||||
})
|
||||
fn get_ext(content: Option<&str>) -> Option<String> {
|
||||
let mut iter = content?.split("/");
|
||||
let type_ = iter.next()?;
|
||||
let subtype = iter.next()?;
|
||||
mime_guess::get_extensions(type_, subtype).and_then(|c| {
|
||||
if c.contains(&&subtype) {
|
||||
Some(subtype.to_string())
|
||||
} else {
|
||||
Some(c.first()?.to_string())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: Write unit-tests.
|
||||
@@ -122,7 +139,7 @@ fn save_io(
|
||||
file: &str,
|
||||
resp: &mut reqwest::Response,
|
||||
content_lenght: Option<u64>,
|
||||
progress: Option<Arc<Mutex<DownloadProgress>>>,
|
||||
progress: Option<Arc<Mutex<dyn DownloadProgress>>>,
|
||||
) -> Result<(), DownloadError> {
|
||||
info!("Downloading into: {}", file);
|
||||
let chunk_size = match content_lenght {
|
||||
@@ -163,7 +180,7 @@ fn save_io(
|
||||
pub fn get_episode(
|
||||
ep: &mut EpisodeWidgetModel,
|
||||
download_folder: &str,
|
||||
progress: Option<Arc<Mutex<DownloadProgress>>>,
|
||||
progress: Option<Arc<Mutex<dyn DownloadProgress>>>,
|
||||
) -> Result<(), DownloadError> {
|
||||
// Check if its alrdy downloaded
|
||||
if ep.local_uri().is_some() {
|
||||
@@ -206,7 +223,7 @@ pub fn cache_image(pd: &ShowCoverModel) -> Result<String, DownloadError> {
|
||||
return Err(DownloadError::NoImageLocation);
|
||||
}
|
||||
|
||||
let cache_path = HAMMOND_CACHE
|
||||
let cache_path = PODCASTS_CACHE
|
||||
.to_str()
|
||||
.ok_or_else(|| DownloadError::InvalidCacheLocation)?;
|
||||
let cache_download_fold = format!("{}{}", cache_path, pd.title().to_owned());
|
||||
@@ -236,35 +253,37 @@ pub fn cache_image(pd: &ShowCoverModel) -> Result<String, DownloadError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use hammond_data::dbqueries;
|
||||
use hammond_data::pipeline;
|
||||
use hammond_data::Source;
|
||||
use failure::Error;
|
||||
use podcasts_data::dbqueries;
|
||||
use podcasts_data::pipeline;
|
||||
use podcasts_data::Source;
|
||||
|
||||
use std::fs;
|
||||
|
||||
#[test]
|
||||
// This test inserts an rss feed to your `XDG_DATA/hammond/hammond.db` so we make it explicit
|
||||
// This test inserts an rss feed to your `XDG_DATA/podcasts/podcasts.db` so we make it explicit
|
||||
// to run it.
|
||||
#[ignore]
|
||||
fn test_cache_image() {
|
||||
fn test_cache_image() -> Result<(), Error> {
|
||||
let url = "https://web.archive.org/web/20180120110727if_/https://rss.acast.com/thetipoff";
|
||||
// Create and index a source
|
||||
let source = Source::from_url(url).unwrap();
|
||||
let source = Source::from_url(url)?;
|
||||
// Copy it's id
|
||||
let sid = source.id();
|
||||
// Convert Source it into a future Feed and index it
|
||||
pipeline::run(vec![source], true).unwrap();
|
||||
pipeline::run(vec![source])?;
|
||||
|
||||
// Get the Podcast
|
||||
let pd = dbqueries::get_podcast_from_source_id(sid).unwrap().into();
|
||||
let pd = dbqueries::get_podcast_from_source_id(sid)?.into();
|
||||
|
||||
let img_path = cache_image(&pd);
|
||||
let foo_ = format!(
|
||||
"{}{}/cover.jpeg",
|
||||
HAMMOND_CACHE.to_str().unwrap(),
|
||||
PODCASTS_CACHE.to_str().unwrap(),
|
||||
pd.title()
|
||||
);
|
||||
assert_eq!(img_path.unwrap(), foo_);
|
||||
fs::remove_file(foo_).unwrap();
|
||||
assert_eq!(img_path?, foo_);
|
||||
fs::remove_file(foo_)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
use hammond_data::errors::DataError;
|
||||
#![allow(bare_trait_objects)]
|
||||
|
||||
use podcasts_data::errors::DataError;
|
||||
use reqwest;
|
||||
use std::io;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#![recursion_limit = "1024"]
|
||||
#![allow(unknown_lints)]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(blacklisted_name, option_map_unit_fn)
|
||||
)]
|
||||
// Enable lint group collections
|
||||
#![warn(
|
||||
nonstandard_style,
|
||||
edition_2018,
|
||||
rust_2018_idioms,
|
||||
bad_style,
|
||||
unused
|
||||
)]
|
||||
// standalone lints
|
||||
#![warn(
|
||||
const_err,
|
||||
improper_ctypes,
|
||||
non_shorthand_field_patterns,
|
||||
no_mangle_generic_items,
|
||||
overflowing_literals,
|
||||
plugin_as_library,
|
||||
private_no_mangle_fns,
|
||||
private_no_mangle_statics,
|
||||
unconditional_recursion,
|
||||
unions_with_drop_fields,
|
||||
while_true,
|
||||
missing_debug_implementations,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
elided_lifetime_in_paths,
|
||||
missing_copy_implementations
|
||||
)]
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
extern crate failure_derive;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate pretty_assertions;
|
||||
|
||||
extern crate glob;
|
||||
extern crate mime_guess;
|
||||
extern crate podcasts_data;
|
||||
extern crate reqwest;
|
||||
extern crate tempdir;
|
||||
|
||||
pub mod downloader;
|
||||
pub mod errors;
|
||||
@@ -0,0 +1,51 @@
|
||||
[package]
|
||||
authors = ["Jordan Petridis <jordanpetridis@protonmail.com>"]
|
||||
build = "build.rs"
|
||||
name = "podcasts-gtk"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.6"
|
||||
crossbeam-channel = "0.2.6"
|
||||
gdk = "0.9.0"
|
||||
gdk-pixbuf = "0.5.0"
|
||||
glib = "0.6.0"
|
||||
gstreamer = "0.12.0"
|
||||
gstreamer-player = "0.12.0"
|
||||
humansize = "1.1.0"
|
||||
lazy_static = "1.1.0"
|
||||
log = "0.4.4"
|
||||
loggerv = "0.7.1"
|
||||
open = "1.2.2"
|
||||
rayon = "1.0.2"
|
||||
url = "1.7.1"
|
||||
failure = "0.1.2"
|
||||
failure_derive = "0.1.2"
|
||||
fragile = "0.3.0"
|
||||
regex = "1.0.4"
|
||||
reqwest = "0.9.2"
|
||||
serde_json = "1.0.31"
|
||||
# html2text = "0.1.8"
|
||||
html2text = { git = "https://github.com/alatiera/rust-html2text" }
|
||||
gettext-rs = { git = "https://github.com/danigm/gettext-rs", branch = "no-gettext", features = ["gettext-system"] }
|
||||
mpris-player = "0.1.0"
|
||||
|
||||
[dependencies.gtk]
|
||||
features = ["v3_22"]
|
||||
version = "0.5.0"
|
||||
|
||||
[dependencies.gio]
|
||||
features = ["v2_50"]
|
||||
version = "0.5.0"
|
||||
|
||||
[dependencies.libhandy]
|
||||
git = "https://gitlab.gnome.org/jsparber/libhandy-rs"
|
||||
|
||||
[dependencies.podcasts-data]
|
||||
path = "../podcasts-data"
|
||||
|
||||
[dependencies.podcasts-downloader]
|
||||
path = "../podcasts-downloader"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.5.1"
|
||||
@@ -5,9 +5,10 @@ fn main() {
|
||||
println!("cargo:rerun-if-changed=resources");
|
||||
println!("cargo:rerun-if-changed=resources/*");
|
||||
|
||||
Command::new("glib-compile-resources")
|
||||
let out = Command::new("glib-compile-resources")
|
||||
.args(&["--generate", "resources.xml"])
|
||||
.current_dir("resources")
|
||||
.status()
|
||||
.unwrap();
|
||||
.expect("failed to generate resources");
|
||||
assert!(out.success());
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# please keep this list sorted alphabetically
|
||||
#
|
||||
ca
|
||||
cs
|
||||
de
|
||||
es
|
||||
fi
|
||||
fur
|
||||
gl
|
||||
hr
|
||||
hu
|
||||
id
|
||||
it
|
||||
ko
|
||||
lv
|
||||
pl
|
||||
pt_BR
|
||||
sv
|
||||
tr
|
||||
@@ -0,0 +1,46 @@
|
||||
# List of source files containing translatable strings.
|
||||
# Please keep this file sorted alphabetically.
|
||||
podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml
|
||||
podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in
|
||||
podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in
|
||||
|
||||
# ui files
|
||||
podcasts-gtk/resources/gtk/empty_view.ui
|
||||
podcasts-gtk/resources/gtk/episode_widget.ui
|
||||
podcasts-gtk/resources/gtk/hamburger.ui
|
||||
podcasts-gtk/resources/gtk/headerbar.ui
|
||||
podcasts-gtk/resources/gtk/help-overlay.ui
|
||||
podcasts-gtk/resources/gtk/home_episode.ui
|
||||
podcasts-gtk/resources/gtk/home_view.ui
|
||||
podcasts-gtk/resources/gtk/inapp_notif.ui
|
||||
podcasts-gtk/resources/gtk/player_toolbar.ui
|
||||
podcasts-gtk/resources/gtk/prefs.ui
|
||||
podcasts-gtk/resources/gtk/secondary_menu.ui
|
||||
podcasts-gtk/resources/gtk/show_menu.ui
|
||||
podcasts-gtk/resources/gtk/show_widget.ui
|
||||
|
||||
# rust files
|
||||
podcasts-gtk/src/app.rs
|
||||
podcasts-gtk/src/headerbar.rs
|
||||
podcasts-gtk/src/main.rs
|
||||
podcasts-gtk/src/manager.rs
|
||||
podcasts-gtk/src/prefs.rs
|
||||
podcasts-gtk/src/settings.rs
|
||||
podcasts-gtk/src/stacks/content.rs
|
||||
podcasts-gtk/src/stacks/home.rs
|
||||
podcasts-gtk/src/stacks/mod.rs
|
||||
podcasts-gtk/src/stacks/populated.rs
|
||||
podcasts-gtk/src/stacks/show.rs
|
||||
podcasts-gtk/src/static_resource.rs
|
||||
podcasts-gtk/src/utils.rs
|
||||
podcasts-gtk/src/widgets/aboutdialog.rs
|
||||
podcasts-gtk/src/widgets/appnotif.rs
|
||||
podcasts-gtk/src/widgets/base_view.rs
|
||||
podcasts-gtk/src/widgets/empty.rs
|
||||
podcasts-gtk/src/widgets/episode.rs
|
||||
podcasts-gtk/src/widgets/home_view.rs
|
||||
podcasts-gtk/src/widgets/mod.rs
|
||||
podcasts-gtk/src/widgets/player.rs
|
||||
podcasts-gtk/src/widgets/show_menu.rs
|
||||
podcasts-gtk/src/widgets/show.rs
|
||||
podcasts-gtk/src/widgets/shows_view.rs
|
||||
@@ -0,0 +1,404 @@
|
||||
# Catalan translation for podcasts.
|
||||
# Copyright (C) 2018 podcasts's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the podcasts package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: podcasts master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-09-23 15:55+0000\n"
|
||||
"PO-Revision-Date: 2018-09-23 23:03-0500\n"
|
||||
"Language-Team: Catalan <gnome@llistes.softcatala.org>\n"
|
||||
"Language: ca\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Last-Translator: Adolfo Jayme Barrientos <fitojb@ubuntu.com>\n"
|
||||
"X-Generator: Poedit 2.1.1\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "Posició superior de l'última finestra principal oberta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "Posició esquerra de l'última finestra principal oberta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "Alçada de l'última finestra principal oberta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "Amplada de l'última finestra principal oberta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "Estat de maximització de l'ultima finestra principal oberta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Habilita o inhabilita el tema fosc"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "Si s'ha d'actualitzar periòdicament el contingut"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr "Quants períodes de temps esperar entre les actualitzacions automàtiques"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr "Quin període de temps esperar entre les actualitzacions automàtiques"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Si s'ha d'actualitzar el contingut després d'iniciar"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr "Quants períodes de temps esperar entre les neteges automàtiques"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "Quin període de temps esperar entre les neteges automàtiques"
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcasts"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "Escolteu els vostres podcasts predilectes, sense sortir del vostre escriptori."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;RSS;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Aplicació de podcasts per al GNOME"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:51
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Aquest programa no té cap episodi encara"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr "Si sospiteu que això és un error, considereu crear un informe."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "Cerqueu-vos alguns programes"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Afegeix programes nous mitjançant l'URL del canal"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Importa programes des d'un altre dispositiu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:180
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "S'està calculant la mida de l'episodi…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:220
|
||||
msgid "Play this episode"
|
||||
msgstr "Reprodueix aquest episodi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:241
|
||||
msgid "Cancel the download proccess"
|
||||
msgstr "Cancel·la el procés de baixada"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:264
|
||||
msgid "Download this episode"
|
||||
msgstr "Baixa aquest episodi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "_Comprova si hi ha episodis nous"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "_Importa programes"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "_Preferències"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:29
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "_Dreceres de teclat"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:37
|
||||
msgid "_About"
|
||||
msgstr "_Quant a"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Afegeix un canal nou"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Introduïu l'adreça del canal que s'ha d'afegir"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Afegeix"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "Ja us heu subscrit a aquest canal."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Títol del programa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Enrere"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "General"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Comprova si hi ha episodis nous"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Preferències"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Surt de l'aplicació"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Avui"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Ahir"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Aquesta setmana"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Aquest mes"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Més antics"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Una notificació d'acció dins l'aplicació"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Desfés"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "Rebobina 10 segons"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Reprodueix"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Posa en pausa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "Avança 10 segons"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Canvia la velocitat de la reproducció"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1,00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1,50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "Velocitat d'1,5"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1,25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "Velocitat d'1,25"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Velocitat normal"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Preferències"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Aparença"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Tema fosc"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Suprimeix els episodis reproduïts"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Després"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "_Marca tots els episodis com a reproduïts"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "_Lloc web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "_Cancel·la la subscripció"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Obre el lloc web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Marca'ls tots com a reproduïts"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Cancel·la la subscripció"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "S'estan recuperant els episodis nous"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Ja us heu subscrit a aquest programa"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "L'URL no és vàlid"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "Segons"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "Minuts"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "Hores"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "Dies"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "Setmanes"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Nous"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Programes"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:357
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Seleccioneu el fitxer des del qual voleu importar els programes."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:360
|
||||
msgid "_Import"
|
||||
msgstr "_Importa"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:369
|
||||
msgid "OPML file"
|
||||
msgstr "Fitxer OPML"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:386
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "No s'ha pogut analitzar el fitxer importat"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:391
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "No s'ha pogut accedir al fitxer seleccionat."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Client de podcasts per a l'escriptori GNOME."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "Més informació sobre el GNOME Podcasts"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr "Adolfo Jayme Barrientos <fitojb@ubuntu.com>, 2018"
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:130
|
||||
msgid "{} min"
|
||||
msgstr "{} m"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "El reproductor multimèdia ha sigut incapaç d'executar cap acció."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "S'han marcat tots els episodis com a escoltats"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Heu cancel·lat la subscripció a {}"
|
||||
@@ -0,0 +1,405 @@
|
||||
# Czech translation for podcasts.
|
||||
# Copyright (C) 2018 podcasts's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the podcasts package.
|
||||
# Marek Černocký <marek@manet.cz>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: podcasts master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-09-28 23:51+0000\n"
|
||||
"PO-Revision-Date: 2018-09-29 21:28+0200\n"
|
||||
"Last-Translator: Marek Černocký <marek@manet.cz>\n"
|
||||
"Language-Team: čeština <gnome-cs-list@gnome.org>\n"
|
||||
"Language: cs\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
"X-Generator: Gtranslator 2.91.7\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "Horní souřadnice naposledy otevřeného hlavního okna"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "Levá souřadnice naposledy otevřeného hlavního okna"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "Výška naposledy otevřeného hlavního okna"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "Šířka naposledy otevřeného hlavního okna"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "Stav maximalizace naposledy otevřeného hlavního okna"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Vypnutý nebo zapnutý tmavý motiv"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "Zda pravidelně aktualizovat obsah"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr "Kolik časových jednotek čekat mezi automatickými aktualizacemi"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr "Jaká je časová jednotka pro čekání mezi automatickými aktualizacemi"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Zda aktualizovat obsah po spuštění"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr "Kolik časových jednotek čekat mezi automatickými vymazáními"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "Jaká je časová jednotka pro čekání mezi automatickými vymazáními"
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcasty"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "Poslouchejte své oblíbené podcasty přímo z počítače"
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "podcast;RSS;pořad;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Podcastová aplikace pro GNOME"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:51
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Pořad zatím nemá žádné epizody"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr "Pokud si myslíte, že se jedná o chybu, zvažte její nahlášení."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "Doplňte si pořady"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Přidat nové pořady pomocí URL kanálu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Naimportovat pořady z jiného zařízení"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:180
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "Počítá se velikost epizody…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:220
|
||||
msgid "Play this episode"
|
||||
msgstr "Přehrát tuto epizodu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:241
|
||||
msgid "Cancel the download proccess"
|
||||
msgstr "Zrušit probíhající stahování"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:264
|
||||
msgid "Download this episode"
|
||||
msgstr "Stáhnout tuto epizodu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "Vy_hledat nové epizody"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "Na_importovat pořady"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "_Předvolby"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:27
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "_Klávesové zkratky"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:35
|
||||
msgid "_About Podcasts"
|
||||
msgstr "O _aplikaci Podcasty"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Přidat nový kanál"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Zadejte adresu kanálu, který chcete přidat"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Přidat"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "Z tohoto kanálu již odebíráte!"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Název pořadu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Zpět"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "Obecné"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Vyhledat nové epizody"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Předvolby"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Ukončit aplikaci"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Dnes"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Včera"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Tento týden"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Tento měsíc"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Starší"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Oznámení o činnosti v aplikaci"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Zpět"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "Převinout zpět o 10 sekund"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Přehrát"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Pozastavit"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "Posunou rychle vpřed o 10 sekund"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Změnit rychlost přehrávání"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1,00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1,50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "1,5 násobek rychlosti"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1,25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "1,25 násobek rychlosti"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Normální rychlost"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Předvolby"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Vzhled"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Tmavý motiv"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Smazat přehrané epizody"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Po uplynutí"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "Oz_načit všechny epizody jako přehrané"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "_Webové stránky"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "O_dhlásit odběr"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Otevřít webové stránky"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Označit vše jako přehrané"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Odhlásit odběr"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "Stahují se nové epizody"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Již jste přihlášeni k odběru tohoto pořadu"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "Neplatná adresa URL"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "sekund"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "minut"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "hodin"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "dnů"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "týdnů"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Nový"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Pořady"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:357
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Výběr soubor pro import pořadu"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:360
|
||||
msgid "_Import"
|
||||
msgstr "Na_importovat"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:369
|
||||
msgid "OPML file"
|
||||
msgstr "Soubor OPML"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:386
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "Selhalo zpracování naimportovaného souboru"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:391
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "K vybranému souboru není přístup"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Podcastový klient pro uživatelské prostředí GNOME"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "Dozvědět se více o Podcastech GNOME"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr "Marek Černocký <marek@manet.cz>"
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:130
|
||||
msgid "{} min"
|
||||
msgstr "{} min"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "Multimediální přehrávač nebyl schopen provést žádnou činnost."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "Všechny epizody byly označené jak přehrané"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Byl odhlášen odběr z {}"
|
||||
@@ -0,0 +1,417 @@
|
||||
# German translation for podcasts.
|
||||
# Copyright (C) 2018 podcasts's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the podcasts package.
|
||||
# Mario Blättermann <mario.blaettermann@gmail.com>, 2018.
|
||||
# Tim Sabsch <tim@sabsch.com>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: podcasts master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-09-28 23:51+0000\n"
|
||||
"PO-Revision-Date: 2018-10-04 21:57-0400\n"
|
||||
"Last-Translator: Florian Heiser <gnu.l10n.de@gmail.com>\n"
|
||||
"Language-Team: Deutsch <gnome-de@gnome.org>\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 2.1.1\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "Obere Position des zuletzt geöffneten Hauptfensters"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "Linke Position des zuletzt geöffneten Hauptfensters"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "Höhe des zuletzt geöffneten Hauptfensters"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "Breite des zuletzt geöffneten Hauptfensters"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "Maximierungsstatus des zuletzt geöffneten Hauptfensters"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Dunkles Thema aktivieren oder deaktivieren"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr ""
|
||||
"Legt fest, ob Inhalte in regelmäßigen Abständen aktualisiert werden sollen"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr "Zeitintervall zwischen automatischen Aktualisierungsvorgängen"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr "Zeitintervall zwischen automatischen Aktualisierungsvorgängen"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Legt fest, ob Inhalte beim Programmstart aktualisiert werden sollen"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr "Zeitintervall zwischen automatischen Löschvorgängen"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "Zeitintervall zwischen automatischen Löschvorgängen"
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcasts"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "Hören Sie Ihre Lieblings-Podcasts direkt in Ihrer Arbeitsumgebung."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;RSS;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Podcast-Anwendung für GNOME"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:51
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Dieser Podcast hat noch keine Folgen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr ""
|
||||
"Falls Sie meinen, dass es sich um einen Fehler handeln könnte, schreiben Sie "
|
||||
"bitte einen Fehlerbericht."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "Podcasts abonnieren"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Neue Podcasts mittels Quellen-Adresse hinzufügen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Podcasts von einem anderen Gerät importieren"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:180
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "Größe der Folge wird ermittelt …"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:220
|
||||
msgid "Play this episode"
|
||||
msgstr "Diese Folge abspielen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:241
|
||||
msgid "Cancel the download proccess"
|
||||
msgstr "Herunterladen abbrechen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:264
|
||||
msgid "Download this episode"
|
||||
msgstr "Diese Folge herunterladen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "Auf neue Folgen _prüfen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "Podcasts _importieren"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "_Einstellungen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:27
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "Tasten_kürzel"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:35
|
||||
msgid "_About Podcasts"
|
||||
msgstr "Info zu _Podcasts"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Neue Quelle hinzufügen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Hinzuzufügende Quellen-Adresse eingeben"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Hinzufügen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "Sie haben diese Quelle bereits abonniert!"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Titel anzeigen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Zurück"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "Allgemein"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Auf neue Folgen prüfen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Die Anwendung beenden"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Heute"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Gestern"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Diese Woche"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Diesen Monat"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Älter"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Eine anwendungsinterne Aktionsmeldung"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Rückgängig"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "10 Sekunden zurückspulen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Wiedergeben"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "10 Sekunden vorspulen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Die Wiedergabegeschwindigkeit ändern"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1,00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1,50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "1,5-fache Geschwindigkeit"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1,25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "1,25-fache Geschwindigkeit"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Normale Geschwidigkeit"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Erscheinungsbild"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Dunkles Thema"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Angehörte Folgen löschen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Nach"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "Alle Folgen als angehört _markieren"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "_Internetseite"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "Ab_bestellen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Internetseite öffnen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Alle als angehört markieren"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Abbestellen"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "Neue Folgen werden abgerufen"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Sie haben diese Show nun abonniert"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "Ungültige Adresse"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "Sekunden"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "Minuten"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "Stunden"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "Tage"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "Wochen"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Neu"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Podcasts"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:357
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Wählen Sie die Datei aus, aus der Sie Shows importieren wollen."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:360
|
||||
msgid "_Import"
|
||||
msgstr "_Importieren"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:369
|
||||
msgid "OPML file"
|
||||
msgstr "OPML-Datei"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:386
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "Die importierte Datei konnte nicht ausgewertet werden"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:391
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "Auf die gewählte Datei konnte nicht zugegriffen werden."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Podcast-Client für die GNOME-Arbeitsumgebung."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "Erfahren Sie mehr über GNOME Podcasts"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr ""
|
||||
"Mario Blättermann <mario.blaettermann@gmail.com>\n"
|
||||
"Tim Sabsch <tim@sabsch.com>"
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:130
|
||||
msgid "{} min"
|
||||
msgstr "{} min"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "Die Medienwiedergabe konnte eine Aktion nicht ausführen."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "Alle Folgen als angehört markieren"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Abonnement von {} gekündigt"
|
||||
|
||||
#~ msgid "_About"
|
||||
#~ msgstr "I_nfo"
|
||||
|
||||
#~ msgid "Cancel"
|
||||
#~ msgstr "Abbrechen"
|
||||
@@ -0,0 +1,442 @@
|
||||
# Spanish translations for gnome-podcasts package.
|
||||
# Copyright (C) 2018 THE gnome-podcasts'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-podcasts package.
|
||||
# Automatically generated, 2018.
|
||||
# Daniel Garcia Moreno <danigm@wadobo.com>, 2018.
|
||||
# Daniel Mustieles <daniel.mustieles@gmail.com>, 2018.
|
||||
# Rodrigo <rodhos92@gmail.com>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-podcasts\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-09-08 17:18+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 19:03+0200\n"
|
||||
"Last-Translator: Rodrigo <rodhos92@gmail.com>\n"
|
||||
"Language-Team: Español <gnome-es-list@gnome.org>\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Gtranslator 2.91.7\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "Posición superior de la última ventana abierta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "Posición izquierda de la última ventana abierta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "Altura de la última ventana abierta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "Anchura de la última ventana abierta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "Estado de maximizado de la última ventana abierta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Activar o desactivar el tema oscuro"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "Indica si se debe actualizar el contenido periódicamente"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr ""
|
||||
"Cuántos periodos de tiempo hay que esperar entre actualizaciones automáticas"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr ""
|
||||
"Qué periodo de tiempo hay que esperar entre actualizaciones automáticas"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Indica si se debe actualizar el contenido al iniciar"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr "Cuántos periodos de tiempo hay que esperar entre limpiezas automáticas"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "Cuántos periodos de tiempo hay que esperar entre limpiezas automáticas"
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcasts"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "Escuche sus podcasts favoritos, directamente desde su escritorio."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;RSS;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Aplicación de Podcast para GNOME"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:51
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Este programa no tiene episodios todavía"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr "Si cree que esto es un error considere abrir un informe de error."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "Consiga algún programa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Añadir un programa nuevo a través de canal URL"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Importar programas de otro dispositivo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:180
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "Calculando tamaño del episodio…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:220
|
||||
msgid "Play this episode"
|
||||
msgstr "Reproducir este episodio"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:241
|
||||
msgid "Cancel the download proccess"
|
||||
msgstr "Cancelar el proceso de descarga"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:264
|
||||
msgid "Download this episode"
|
||||
msgstr "Descargar este episodio"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "Comprobar si hay nuevos episodios"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "_Importar programas"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "_Preferencias"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:29
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "Atajos de _teclado"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:37
|
||||
msgid "_About"
|
||||
msgstr "_Acerca de"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Añadir un canal nuevo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Introduzca la dirección del canal que añadir"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Añadir"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "¡Ya está suscrito a este canal!"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Título del programa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Atrás"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "General"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Comprobar si hay episodios nuevos"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Preferencias"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Salir de la aplicación"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Hoy"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Ayer"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Esta semana"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Este mes"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Antiguo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Una notificación de acción dentro de la aplicación"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Deshacer"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "Retroceder 10 segundos"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Reproducir"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Pausa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "Avanzar 10 segundos"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Cambiar velocidad de reproducción"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1.00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1.50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "velocidad 1.5"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1.25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "velocidad 1.25"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Velocidad normal"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Preferencias"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Aspecto"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Tema oscuro"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Eliminar episodios reproducidos"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Después"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "_Marcar todos los episodios como reproducidos"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "Página _Web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "_Cancelar suscripción"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Abrir Web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Marcar todo como reproducido"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Cancelar suscripción"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "Obteniendo nuevos episodios"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Ya está suscrito a este programa"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "URL no válido"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "Segundos"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "Minutos"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "Horas"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "Días"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "Semanas"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Nuevo"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Programas"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:357
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Selecciona el fichero desde el que quiere importar programas."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:360
|
||||
msgid "_Import"
|
||||
msgstr "_Importar"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:369
|
||||
msgid "OPML file"
|
||||
msgstr "fichero OPML"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:386
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "Fallo al analizar el fichero importado"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:391
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "No se ha podido acceder al archivo seleccionado."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Aplicación de Podcast para el escritorio GNOME."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "Aprenda más sobre GNOME Podcasts"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr ""
|
||||
"Daniel Mustieles <daniel.musiteles@gmail.com>, 2018\n"
|
||||
"Daniel García Moreno <danigm@wadobo.com>"
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:130
|
||||
msgid "{} min"
|
||||
msgstr "{} min"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "El reproductor no ha podido reproducir una acción."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "Marcar todos los episodios como escuchados"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Suscripción cancelada para {}"
|
||||
|
||||
#~ msgid "Cancel"
|
||||
#~ msgstr "Cancelar"
|
||||
|
||||
#~ msgid "org.gnome.Podcasts"
|
||||
#~ msgstr "org.gnome.Podcasts"
|
||||
|
||||
#~ msgid "Mark all episodes as listened"
|
||||
#~ msgstr "Marcar todos los episodios como escuchados"
|
||||
|
||||
#~ msgid "Episode Title"
|
||||
#~ msgstr "Título del episodio"
|
||||
|
||||
#~ msgid "3 Jan"
|
||||
#~ msgstr "3 Jan"
|
||||
|
||||
#~ msgid "·"
|
||||
#~ msgstr "·"
|
||||
|
||||
#~ msgid "42 min"
|
||||
#~ msgstr "42 min"
|
||||
|
||||
#~ msgid "0 MB"
|
||||
#~ msgstr "0 MB"
|
||||
|
||||
#~ msgid "/"
|
||||
#~ msgstr "/"
|
||||
|
||||
#~ msgid "© 2017, 2018 Jordan Petridis"
|
||||
#~ msgstr "© 2017, 2018 Jordan Petridis"
|
||||
@@ -0,0 +1,411 @@
|
||||
# Finnish translation for podcasts.
|
||||
# Copyright (C) 2018 podcasts's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the podcasts package.
|
||||
# Jiri Grönroos <jiri.gronroos@iki.fi>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: podcasts master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-08-28 20:54+0000\n"
|
||||
"PO-Revision-Date: 2018-09-01 19:58+0300\n"
|
||||
"Last-Translator: Jiri Grönroos <jiri.gronroos+l10n@iki.fi>\n"
|
||||
"Language-Team: Finnish <lokalisointi-lista@googlegroups.com>\n"
|
||||
"Language: fi\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 2.0.6\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr ""
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr ""
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr ""
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr ""
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr ""
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Ota käyttöön tai poista käytöstä tumma teema"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "Päivitetäänkö sisältö säännöllisesti"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr ""
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr ""
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Päivitetäänkö sisältö sovelluksen käynnistyttyä"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr ""
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr ""
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcastit"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "Kuuntele suosikkipodcastejasi suoraan työpöydältäsi."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;RSS;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Podcast-sovellus Gnomelle"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:31
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Tässä ohjelmassa ei ole vielä yhtäkään jaksoa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr "Jos tämä on mielestäsi virhe, teethän bugiraportin."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "Hanki ohjelmia"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Lisää uusia ohjelmia syötteen osoitteen avulla"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Tuo ohjelmia toiselta laitteelta"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:177
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "Lasketaan jakson kokoa…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:212
|
||||
msgid "Cancel"
|
||||
msgstr "Peru"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:230
|
||||
msgid "Download this episode"
|
||||
msgstr "Lataa tämä jakso"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:254
|
||||
msgid "Play this episode"
|
||||
msgstr "Toista tämä jakso"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "Ta_rkista uudet jaksot"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "Tu_o jaksoja"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "_Asetukset"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:29
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "_Pikanäppäimet"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:37
|
||||
msgid "_About"
|
||||
msgstr "_Tietoja"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Lisää uusi syöte"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Anna lisättävän syötteen osoite"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Lisää"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "Olet jo tilannut kyseisen syötteen!"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Ohjelman nimi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Takaisin"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "Yleiset"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Tarkista uudet jaksot"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Asetukset"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Lopeta sovellus"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Tänään"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Eilen"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Tällä viikolla"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Tässä kuussa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Vanhemmat"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Sovelluksen sisäinen ilmoitus"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Kumoa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "Siirry taakse 10 sekuntia"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Toista"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Keskeytä"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "Siirry eteen 10 sekuntia"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Vaihda toistonopeutta"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1.00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1.50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "1,5-kertainen nopeus"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1.25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "1,25-kertainen nopeus"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Tavallinen nopeus"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Asetukset"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Ulkoasu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Tumma teema"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Poista toistetut jaksot"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Viive"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "_Merkitse kaikki jaksot toistetuiksi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "_Verkkosivusto"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "_Lopeta tilaus"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Avaa verkkosivusto"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Merkitse kaikki toistetuiksi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Lopeta tilaus"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "Noudetaan uusia jaksoja"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Olet jo tilannut tämän ohjelman"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "Virheellinen osoite"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "sekuntia"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "minuuttia"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "tuntia"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "päivää"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "viikkoa"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Uudet"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Ohjelmat"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:350
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Valitse tiedosto, josta haluat tuoda ohjelmia."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:353
|
||||
msgid "_Import"
|
||||
msgstr "_Tuo"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:362
|
||||
msgid "OPML file"
|
||||
msgstr "OPML-tiedosto"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:379
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "Tuotua tiedostoa ei voitu jäsentää"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:384
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "Valittua tiedostoa ei voitu käyttää."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Podcast-sovellus Gnome-työpöydlle."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr ""
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr "Jiri Grönroos"
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:129
|
||||
msgid "{} min"
|
||||
msgstr "{} min"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "Mediasoitin ei kyennyt suorittamaan toimintoa."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "Merkitse kaikki jaksot toistetuiksi"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Lopeta syötteen {} tilaus"
|
||||
|
||||
#~ msgid "org.gnome.Podcasts"
|
||||
#~ msgstr "org.gnome.Podcasts"
|
||||
|
||||
#~ msgid "Episode Title"
|
||||
#~ msgstr "Jakson nimi"
|
||||
@@ -0,0 +1,404 @@
|
||||
# Friulian translation for podcasts.
|
||||
# Copyright (C) 2018 podcasts's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the podcasts package.
|
||||
# Fabio Tomat <f.t.public@gmail.com>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: podcasts master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-09-03 13:42+0000\n"
|
||||
"PO-Revision-Date: 2018-09-04 20:17+0200\n"
|
||||
"Language-Team: Friulian <fur@li.org>\n"
|
||||
"Language: fur\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Last-Translator: \n"
|
||||
"X-Generator: Poedit 2.0.7\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "Posizion superiôr dal ultin barcon principâl viert"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "Posizion de çampe dal ultin barcon principâl viert"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "Altece dal ultin barcon principâl viert"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "Largjece dal ultin barcon principâl viert"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "Stât slargjât dal ultin barcon principâl viert"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Abilite o disabilite il teme scûr"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "Indiche se inzornâ in maniere periodiche il contignût"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr "Trops periodis di timp di spietâ tra i inzornaments automatics"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr "Ce periodi di timp di spietâ tra i inzornaments automatics"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Indiche se inzornâ il contignût dopo dal inviament"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr "Trops periodis di timp di spietâ tra lis netisiis automatichis"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "Ce periodi di timp di spietâ tra lis netisiis automatichis"
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcasts"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "Scolte i tiei podcast preferîts, daurman dal to scritori."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;RSS;Regjistrazion;Trasmission;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Aplicazion podcast par GNOME"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:51
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Chest spetacul nol à ancjemò episodis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr "Se tu pensis che chest al sedi un erôr, considere di scrivi une segnalazion di erôr."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "Oten cualchi spetacul"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Zonte gnûfs spetacui vie URL di feed"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Impuarte i spetacui di un altri dispositîf"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:178
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "Calcul de dimension dal episodi…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:214
|
||||
msgid "Cancel"
|
||||
msgstr "Anule"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:232
|
||||
msgid "Download this episode"
|
||||
msgstr "Discjarie chest episodi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:256
|
||||
msgid "Play this episode"
|
||||
msgstr "Viôt chest episodi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "_Controle par gnûfs episodis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "_Impuarte spetacui"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "_Preferencis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:29
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "_Scurtis tastiere"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:37
|
||||
msgid "_About"
|
||||
msgstr "_Informazions"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Zonte un gnûf feed"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Inserìs la direzion dal feed di zontâ"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Zonte"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "Tu sês za sotscrit a chest feed!"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Titul dal spetacul"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Indaûr"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "Gjenerâl"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Controle se a son gnûfs episodis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Preferencis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Jes de aplicazion"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Vuê"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Îr"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Cheste setemane"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Chest mês"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Plui vecjo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Une notifiche di aplicazion in-app"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Disfe"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "Torne indaûr di 10 seconts"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Riprodûs"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "Va indenant di 10 minûts"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Cambie la velocitât di riproduzion"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1.00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1.50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "rapuart di velocitât 1.5"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1.25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "rapuart di velocitât 1.25"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Velocitât normâl"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Preferencis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Aspiet"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Teme scûr"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Elimine i episodis viodûts"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Dopo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "_Segne ducj i episodis come viodûts"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "Sît _web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "_Anule sotscrizion"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Vierç sît web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Segne dut come viodût"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Anule sotscrizion"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "Daûr a recuperâ i gnûfs episodis"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Tu sês za sotscrit a chest spetacul"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "URL no valit"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "Seconts"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "Minûts"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "Oris"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "Diis"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "Setemanis"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Gnûf"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Spetacui"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:357
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Selezione il file che di chei si desidere impuartâ i spetacui."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:360
|
||||
msgid "_Import"
|
||||
msgstr "_Impuarte"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:369
|
||||
msgid "OPML file"
|
||||
msgstr "File OPML"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:386
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "No si è rivâts a analizâ il file impuartât"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:391
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "Il file selezionât nol pues jessi doprât."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Client podcast pal scritori GNOME."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "Plui informazions su GNOME Podcasts"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr "Fabio Tomat <f.t.public@gmail.com>"
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:129
|
||||
msgid "{} min"
|
||||
msgstr "{} min"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "Il riprodutôr multimediâl nol è stât bon di eseguî une azion."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "Segnât ducj i episodis come scoltâts"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Sotscrizion anulade di {}"
|
||||
@@ -0,0 +1,407 @@
|
||||
# Spanish translations for gnome-podcasts package.
|
||||
# Copyright (C) 2018 THE gnome-podcasts'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-podcasts package.
|
||||
# Automatically generated, 2018.
|
||||
# Fran Dieguez <frandieguez@gnome.org>, 2018.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-podcasts\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-08-22 06:50+0300\n"
|
||||
"PO-Revision-Date: 2018-08-30 10:39+0200\n"
|
||||
"Last-Translator: Fran Dieguez <frandieguez@gnome.org>\n"
|
||||
"Language-Team: Galician\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Virtaal 0.7.1\n"
|
||||
"X-Project-Style: gnome\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "Posición superior da última xanela aberta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "Posición esquerda da última xanela aberta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "Alto da última xanela aberta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "Anchura da última xanela aberta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "Estado de maximizado da última xanela aberta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Activar o desactivar el tema oscuro"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "Se refrescar o contido periodicamente"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr "Cantos periodos de tempo a esperar entre refrescos automáticos"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr "Qué periodo de tempo hai que esperar entre refrescos automáticos"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Se refrescar o contido ao iniciar"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr "Cantos periodos de tempo hai que esperar entre limpados automáticos"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "Cantos periodos de tiempo hai que esperar entre limpiados automáticos"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml:4
|
||||
#: podcasts-gtk/src/app.rs:92 podcasts-gtk/src/app.rs:406
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcasts"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr ""
|
||||
"Escoita os teus podcasts favoritos, directamente desde o teu escritorio."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop:6
|
||||
msgid "org.gnome.Podcasts"
|
||||
msgstr "org.gnome.Podcasts"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;RSS;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Aplicativo de Podcast para GNOME"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml:31
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Este programa aínda non ten episodios"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr ""
|
||||
"Se cres que isto é un erro, por favor, considera abrir un informe de erro."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:107
|
||||
msgid "Get some shows"
|
||||
msgstr "Obter algúns programas"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:144
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Engadir novo programa a través do URL da canle"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:173
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Importar programas desde outro dispositivo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:177
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "Calculando tamaño do episodio…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:212
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:230
|
||||
msgid "Download this episode"
|
||||
msgstr "Descargar este episodio"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:254
|
||||
msgid "Play this episode"
|
||||
msgstr "Reproducir este episodio"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "_Comprobar se hai novos episodios"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "_Importar programas"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "_Preferencias"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:29
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "Atallos de _teclado"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:37
|
||||
msgid "_About"
|
||||
msgstr "_Sobre"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Engadir unha nova canle"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Escriba o enderezo da canle a engadir"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Engadir"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "Xa estás suscrito a esta canle!"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Título do Programa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Atrás"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "Xeral"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Comprobar se hai novos episodios"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Preferencias"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Saír do aplicativo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Hoxe"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Onte"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Esta semana"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Este mes"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Antigo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Unha notificación de acción en aplicativo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Desfacer"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "Atrás 10 segundos"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Reproducir"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Pausa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "Adiante 10 segundos"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Cambiar velocidade de reprodución"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1.00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1.50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "velocidade 1.5"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1.25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "velocidade 1.25"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Velocidade normal"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Preferencias"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Aspecto"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Tema escuro"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Eliminar episodios reproducidos"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Despois"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "_Marcar todos os episodios como reproducidos"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "Páxina _Web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "_Cancelar subscrición"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Abrir sitio web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Marcar todo como reproducido"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Cancelar subscrición"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:331
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "Obtendo novos episodios"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Xa estás subscrito a este programa"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "URL non válida"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "Segundos"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "Minutos"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "Horas"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "Días"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "Semanas"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Novo"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Programas"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:350
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Seleccione o fichero desde o cal queres importar programas."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:353
|
||||
msgid "_Import"
|
||||
msgstr "_Importar"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:362
|
||||
msgid "OPML file"
|
||||
msgstr "Fichero OPML"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:379
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "Produciuse un fallo ao leer o fichero importado"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:384
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "O fichero seleccionado non é accesíbel."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Aplicativo de Podcast para o ambiente GNOME."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:35
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "Saber máis sobre Podcasts de GNOME"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:40
|
||||
msgid "translator-credits"
|
||||
msgstr "Fran Dieguez <frandieguez@gnome.org>, 2018"
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:129
|
||||
msgid "{} min"
|
||||
msgstr "{} min"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "O reprodutor non puido reproducir unha acción."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "Marcar todos os episodios como escoitados"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Subscrición cancelada para {}"
|
||||
@@ -0,0 +1,414 @@
|
||||
# Croatian translation for podcasts.
|
||||
# Copyright (C) 2018 podcasts's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the podcasts package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: podcasts master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-09-08 17:18+0000\n"
|
||||
"PO-Revision-Date: 2018-09-19 14:24+0200\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Croatian <hr@li.org>\n"
|
||||
"Language: hr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
||||
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"X-Generator: Poedit 2.1.1\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "Gornji položaj posljednjeg otvorenog prozora"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "Lijevi položaj posljednjeg otvorenog prozora"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "Visina posljednjeg otvorenog prozora"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "Širina posljednjeg otvorenog prozora"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "Stanje uvećanja posljednjeg otvorenog prozora"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Omogući ili onemogući tamnu temu"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "Treba li povremeno osvježiti sadržaj"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr ""
|
||||
"Koliko vremenskih razdoblja treba pričekati između automatskih osvježavanja"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr ""
|
||||
"Koliko vremensko razdoblje treba pričekati između automatskih osvježavanja"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Treba li osvježiti sadržaj nakon pokretanja"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr ""
|
||||
"Koliko vremenskih razdoblja treba pričekati između automatskih čišćenja"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "Koliko vremensko razdoblje treba pričekati između automatskih čišćenja"
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcasti"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "Slušajte svoje omiljene podcaste."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;RSS;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Podcast aplikacija za GNOME"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:51
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Ova emisjia još nema epizoda"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr "Ako mislite da je ovo greška, prijavite izvještaj greške."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "Nabavite nove emisije"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Dodaj novu emisiju putem kanala ili URL-a"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Uvezi emisije iz drugog uređaja"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:180
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "Izračunavanje veličine emisjie…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:220
|
||||
msgid "Play this episode"
|
||||
msgstr "Slušaj ovu epizodu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:241
|
||||
msgid "Cancel the download proccess"
|
||||
msgstr "Prekini preuzimanja"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:264
|
||||
msgid "Download this episode"
|
||||
msgstr "Preuzmi ovu epizodu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "_Provjeri ima li novih epizoda"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "_Uvezi emisije"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "_Osobitosti"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:29
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "_Prečaci tipkovnice"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:37
|
||||
msgid "_About"
|
||||
msgstr "_O programu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Dodaj novi kanal"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Upišite adresu kanala za dodavanje"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Dodaj"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "Već ste pretplaćeni na ovaj kanal!"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Prikaži naslov"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Natrag"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "Općenito"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Provjeri ima li novih epizoda"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Osobitosti"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Zatvori aplikaciju"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Danas"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Jučer"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Ovaj tjedan"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Ovaj mjesec"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Starije"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Obavijesti radnja iz aplikacije"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Vrati"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "Premotaj 10 sekundi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Reproduciraj"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Pauziraj"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "Brzo premotaj 10 sekundi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Promijeni brzinu reprodukcije"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1.00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1.50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "1.5 brže"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1.25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "1.25 brže"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Normalna brzina"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Osobitosti"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Izgled"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Tamna tema"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Obriši poslušane epizode"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Poslije"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "_Označi se epizode kao odslušane"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "_Web stranica"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "_Ukini pretplatu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Otvori web stranicu"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Označi sve kao odslušano"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Ukini pretplatu"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "Preuzimanje novi epizoda"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Već ste pretplaćeni na ovu emisiju"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "Nevažeći URL"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "Sekunda"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "Minuta"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "Sata"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "Dana"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "Tjedana"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Novo"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Emisije"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:357
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Odaberite datoteku iz koje želite uvesti emisije."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:360
|
||||
msgid "_Import"
|
||||
msgstr "_Uvoz"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:369
|
||||
msgid "OPML file"
|
||||
msgstr "OPML datoteka"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:386
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "Neuspjela obrada uvezene datoteke"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:391
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "Nemoguć pristup dabranoj datoteci."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Podcast klijent za GNOME radnu površinu."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "Saznajte više o GNOME Podcasti"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr ""
|
||||
"Launchpad Contributions:\n"
|
||||
" gogo https://launchpad.net/~trebelnik-stefina"
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:130
|
||||
msgid "{} min"
|
||||
msgstr "{} min"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "Medijski reproduktor nije uspio izvršiti radnju."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "Označi sve epizodae kao odslušane"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Ukini pretplatu za {}"
|
||||
|
||||
#~ msgid "Cancel"
|
||||
#~ msgstr "Odustani"
|
||||
@@ -0,0 +1,407 @@
|
||||
# Hungarian translation for podcasts.
|
||||
# Copyright (C) 2018. Free Software Foundation, Inc.
|
||||
# This file is distributed under the same license as the podcasts package.
|
||||
#
|
||||
# Meskó Balázs <mesko.balazs@fsf.hu>, 2018.
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: podcasts master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-09-03 11:31+0000\n"
|
||||
"PO-Revision-Date: 2018-09-06 00:08+0100\n"
|
||||
"Last-Translator: Meskó Balázs <mesko.balazs@fsf.hu>\n"
|
||||
"Language-Team: Hungarian <openscope at googlegroups dot com>\n"
|
||||
"Language: hu\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Lokalize 2.0\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "A legutóbbi nyitott főablak fenti pozíciója"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "A legutóbbi nyitott főablak bal oldali pozíciója"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "A legutóbbi nyitott főablak magassága"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "A legutóbbi nyitott főablak szélessége"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "A legutóbbi nyitott főablak maximalizálási állapota"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Sötét téma engedélyezése vagy letiltása"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "Időközönként frissüljön-e a tartalom"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr "Mennyi időközt várjon az automatikus frissítések között"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr "Milyen időközöket várjon az automatikus frissítések között"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Indításkor frissüljön-e a tartalom"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr "Mennyi időközt várjon az automatikus tisztítások között"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "Milyen időközöket várjon az automatikus tisztítások között"
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcastok"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "Hallgassa kedvenc podcastjait, közvetlenül az asztalán."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;RSS;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Podcast alkalmazás a GNOME-hoz"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:51
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Ennek a műsornak még nincsenek epizódjai"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr "Ha úgy gondolja hogy ez hiba, akkor írjon egy hibajelentést."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "Szerezzen be néhány műsort"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Új műsorok hozzáadása csatorna URL-ből"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Műsorok importálása egy másik eszközről"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:178
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "Epizódméret kiszámítása…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:214
|
||||
msgid "Cancel"
|
||||
msgstr "Mégse"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:232
|
||||
msgid "Download this episode"
|
||||
msgstr "Ezen epizód letöltése"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:256
|
||||
msgid "Play this episode"
|
||||
msgstr "Ezen epizód lejátszása"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "Új epizódok _keresése"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "Műsorok _importálása"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "_Beállítások"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:29
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "Gyorsbille_ntyűk"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:37
|
||||
msgid "_About"
|
||||
msgstr "_Névjegy"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Új csatorna hozzáadása"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Adja meg a hozzáadandó csatorna címét"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Hozzáadás"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "Már feliratkozott erre a csatornára."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Műsor címe"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Vissza"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "Általános"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Új epizódok keresése"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Beállítások"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Kilépés az alkalmazásból"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Ma"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Tegnap"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Ezen a héten"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Ebben a hónapban"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Régebbi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Alkalmazáson belüli műveletértesítések"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Visszavonás"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "Visszatekerés 10 másodperccel"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Lejátszás"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Szünet"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "Előretekerés 10 másodperccel"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Lejátszási sebesség módosítása"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1,00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1,50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "1,5-szeres sebesség"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1,25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "1,25-szörös sebesség"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Normál sebesség"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Beállítások"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Megjelenés"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Sötét téma"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Lejátszott epizódok törlése"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Később"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "Összes epizód meg_jelölése lejátszottként"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "_Webhely"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "_Leiratkozás"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Webhely megnyitása"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Összes megjelölése lejátszottként"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Leiratkozás"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "Új epizódok lekérése"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Már feliratkozott erre a műsorra"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "Érvénytelen URL"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "Másodperc"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "Perc"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "Óra"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "Nap"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "Hét"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Új"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Műsorok"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:357
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Válasszon egy fájlt, amelyből műsorokat akar importálni."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:360
|
||||
msgid "_Import"
|
||||
msgstr "_Importálás"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:369
|
||||
msgid "OPML file"
|
||||
msgstr "OPML fájl"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:386
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "Az importált fájl feldolgozása meghiúsult"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:391
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "A kiválasztott fájlok nem érhetőek el."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Podcast-kliens a GNOME asztali környezethez."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "További tudnivalók a GNOME Podcastokról"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr "Meskó Balázs <mesko dot balazs at fsf dot hu>"
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:129
|
||||
msgid "{} min"
|
||||
msgstr "{} perc"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "A médialejátszó nem tudott végrehajtani egy műveletet."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "Összes epizód megjelölve meghallgatottként"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Leiratkozott innen: {}"
|
||||
|
||||
@@ -0,0 +1,412 @@
|
||||
# Indonesian translation for podcasts.
|
||||
# Copyright (C) 2018 podcasts's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the podcasts package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: podcasts master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-09-28 23:51+0000\n"
|
||||
"PO-Revision-Date: 2018-10-02 20:34+0700\n"
|
||||
"Last-Translator: Kukuh Syafaat <kukuhsyafaat@gnome.org>\n"
|
||||
"Language-Team: Indonesian <gnome-l10n-id@googlegroups.com>\n"
|
||||
"Language: id\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 2.0.6\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "Posisi atas dari jendela utama terbuka terakhir"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "Posisi kiri dari jendela utama terbuka terakhir"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "Tinggi dari jendela utama terbuka terakhir"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "Lebar dari jendela utama terbuka terakhir"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "Keadaan dimaksimalkan dari jendela utama terbuka terakhir"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Aktifkan atau nonaktifkan tema gelap"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "Apakah akan menyegarkan konten secara berkala"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr "Berapa banyak periode waktu untuk menunggu antara penyegaran otomatis"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr "Berapa lama waktu untuk menunggu antara penyegaran otomatis"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Apakah akan menyegarkan konten setelah awal mula"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr "Berapa lama waktu menunggu antara pembersihan otomatis"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "Berapa lama waktu untuk menunggu di antara pembersihan otomatis"
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcast"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "Dengarkan podcast favorit Anda, langsung dari destop Anda."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;RSS;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Aplikasi Podcast untuk GNOME"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:51
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Acara ini belum memiliki episode"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr ""
|
||||
"Jika Anda pikir ini adalah kesalahan, silakan mempertimbangkan untuk menulis "
|
||||
"laporan kutu."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "Dapatkan beberapa acara"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Tambahkan acara baru melalui URL feed"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Impor acara dari perangkat lain"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:180
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "Menghitung ukuran episode…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:220
|
||||
msgid "Play this episode"
|
||||
msgstr "Putar episode ini"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:241
|
||||
msgid "Cancel the download proccess"
|
||||
msgstr "Batalkan proses pengunduhan"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:264
|
||||
msgid "Download this episode"
|
||||
msgstr "Unduh episode ini"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "Periksa Episode _Baru"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "_Impor Acara"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "_Preferensi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:27
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "Pintasan Papan _Ketik"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:35
|
||||
msgid "_About Podcasts"
|
||||
msgstr "Tent_ang Podcast"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Tambahkan feed baru"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Masukkan alamat feed untuk ditambahkan"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Tambah"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "Anda sudah berlangganan feed itu!"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Tampilkan Judul"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Kembali"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "Umum"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Periksa episode baru"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Preferensi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Keluar dari aplikasi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Hari ini"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Kemarin"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Minggu Ini"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Bulan ini"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Lebih lama"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Notifikasi aksi dalam aplikasi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Tak Jadi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "Putar mundur 10 detik"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Putar"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Jeda"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "Maju cepat 10 detik"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Ubah kecepatan pemutaran"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "Ubah kecepatan pemutaran"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1.50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "tingkat kecepatan 1.5"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1.25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "tingkat kecepatan 1.25"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Kecepatan normal"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Preferensi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Penampilan"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Tema Gelap"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Hapus episode yang diputar"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Sesudah"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "Tandai Se_mua Episode sebagai Sudah Diputar"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "Situs _Web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "_Berhenti Berlangganan"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Buka Situs Web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Tandai Semua sebagai Sudah Diputar"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Berhenti Berlangganan"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "Mengambil episode baru"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Anda sudah berlangganan ke acara ini"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "URL tak valid"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "Detik"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "Menit"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "Jam"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "Hari"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "Minggu"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Baru"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Acara"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:357
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Pilih berkas dari mana Anda ingin mengimpor acara."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:360
|
||||
msgid "_Import"
|
||||
msgstr "_Impor"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:369
|
||||
msgid "OPML file"
|
||||
msgstr "Berkas OPML"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:386
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "Gagal mengurai berkas yang diimpor"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:391
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "Berkas yang dipilih tidak dapat diakses."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Klien Podcast untuk Destop GNOME."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "Pelajari lebih lanjut tentang GNOME Podcast"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr "Kukuh Syafaat <kukuhsyafaat@gnome.org>, 2018."
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:130
|
||||
msgid "{} min"
|
||||
msgstr "{} mnt"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "Pemutar media tidak dapat melakukan aksi."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "Tandai semua episode sebagai sudah didengarkan"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Berhenti berlangganan dari {}"
|
||||
|
||||
#~ msgid "_About"
|
||||
#~ msgstr "Tent_ang"
|
||||
|
||||
#~ msgid "Cancel"
|
||||
#~ msgstr "Batal"
|
||||
@@ -0,0 +1,405 @@
|
||||
# Italian translation for podcasts.
|
||||
# Copyright (C) 2018 podcasts's Free Software Foundation, Inc.
|
||||
# This file is distributed under the same license as the podcasts package.
|
||||
# Milo Casagrande <milo@milo.name>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: podcasts master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-09-03 11:31+0000\n"
|
||||
"PO-Revision-Date: 2018-09-03 15:41+0200\n"
|
||||
"Language-Team: Italian <gnome-it-list@gnome.org>\n"
|
||||
"Language: it\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Last-Translator: Milo Casagrande <milo@milo.name>\n"
|
||||
"X-Generator: Poedit 2.1.1\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "Posizione superiore dell'ultima finestra principale aperta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "Posizione sinistra dell'ultima finestra principale aperta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "Altezza dell'ultima finestra principale aperta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "Larghezza dell'ultima finestra principale aperta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "Stato di massimizzazione dell'ultima finestra principale aperta"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "Abilita/Disabilita il tema scuro"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "Indica se aggiornare i contenuti periodicamente"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr "Quanto tempo aspettare tra gli aggiornamenti automatici"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr "Che periodo di tempo aspettare tra gli aggiornamenti automatici"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "Indica se aggiornare i contenuti dopo l'avvio"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr "Quanto tempo aspettare tra la pulizia automatica"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "Che periodi di tempo aspettare tra la pulizia automatica"
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "Podcast"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "Ascoltare i propri podcast preferiti, direttamente proprio computer."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;RSS;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "Applicazione per podcast per GNOME"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:51
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "Questo show non ha ancora episodi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr "Se considerate questo evento un errore, inviare una segnalazione."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "Ottieni show"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "Aggiungi nuovi show via URL"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "Importa show da un altro dispositivo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:178
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "Calcolo dimensione episodio…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:214
|
||||
msgid "Cancel"
|
||||
msgstr "Annulla"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:232
|
||||
msgid "Download this episode"
|
||||
msgstr "Scarica questo episodio"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:256
|
||||
msgid "Play this episode"
|
||||
msgstr "Riproduci questo episodio"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "Controlla per _nuovi episodi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "_Importa show"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "Preferen_ze"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:29
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "_Scorciatoie da tastiera"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:37
|
||||
msgid "_About"
|
||||
msgstr "I_nformazioni"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "Aggiungi nuovo feed"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "Inserire un indirizzo da aggiungere"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "Aggiungi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "Si è già abbonati a questo feed."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "Titolo show"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "Indietro"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "Generale"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "Controlla presenza nuovi episodi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "Preferenze"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "Esce dall'applicazione"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "Oggi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "Ieri"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "Questa settimana"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "Questo mese"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "Più vecchi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "Una notifica"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "Annulla"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "Indietro 10 secondi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "Riproduci"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "Pausa"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "Avanti veloce 10 secondi"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "Modifica la velocità di riproduzione"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1,00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1,50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "1,5 volte la velocità"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1,25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "1,25 volte la velocità"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "Velocità normale"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "Preferenze"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "Aspetto"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "Tema scuro"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "Eliminare episodi ascoltati"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "Dopo"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "_Segna tutti gli episodi come ascoltati"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "Sito _web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "_Annulla abbonamento"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "Apri sito web"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "Segna tutti ascoltati"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "Annulla abbonamento"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "Scaricamento nuovi episodi"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "Si è già abbonati a questo show"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "URL non valido"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "secondi"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "Minuti"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "Ore"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "Giorni"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "Settimane"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "Nuovo"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "Show"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:357
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "Selezionare il file da cui importare gli show."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:360
|
||||
msgid "_Import"
|
||||
msgstr "_Importa"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:369
|
||||
msgid "OPML file"
|
||||
msgstr "File OPML"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:386
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "Analisi del file importato non riuscita"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:391
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "Impossibile accedere al file selezionato."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "Client podcast per l'ambiente grafico GNOME."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "Maggiori informazioni su Podcast GNOME"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr "Milo Casagrande <milo@milo.name>"
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:129
|
||||
msgid "{} min"
|
||||
msgstr "{} min"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "Il riproduttore multimediale non può eseguire un'azione."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "Episodi segnati come letti"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "Abbonamento a {} annullato"
|
||||
@@ -0,0 +1,405 @@
|
||||
# Korean translation for podcasts.
|
||||
# Copyright (C) 2018 podcasts's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the podcasts package.
|
||||
# Seong-ho Cho <shcho@gnome.org>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: podcasts master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/podcasts/issues\n"
|
||||
"POT-Creation-Date: 2018-08-30 10:43+0000\n"
|
||||
"PO-Revision-Date: 2018-08-30 21:26+0900\n"
|
||||
"Language-Team: Korean <gnome-kr@googlegroups.com>\n"
|
||||
"Language: ko\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"Last-Translator: Seong-ho Cho <shcho@gnome.org>\n"
|
||||
"X-Generator: Poedit 2.0.6\n"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:15
|
||||
msgid "Top position of the last open main window"
|
||||
msgstr "최근 연 메인 창 상단 위치"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:19
|
||||
msgid "Left position of the last open main window"
|
||||
msgstr "최근 연 메인 창 좌측 위치"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:23
|
||||
msgid "Height of the last open main window"
|
||||
msgstr "최근 연 메인 창 높이"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:27
|
||||
msgid "Width of the last open main window"
|
||||
msgstr "최근 연 메인 창 너비"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:31
|
||||
msgid "Maximized state of the last open main window"
|
||||
msgstr "최근 연 메인 창 최대화 상태"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:36
|
||||
msgid "Enable or disable dark theme"
|
||||
msgstr "어두움 테마 사용 함/안함"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:41
|
||||
msgid "Whether to periodically refresh content"
|
||||
msgstr "주기적으로 내용 새로 고침 여부"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:46
|
||||
msgid "How many periods of time to wait between automatic refreshes"
|
||||
msgstr "자동 새로 고침 기다림 주기 시간 간격"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:50
|
||||
msgid "What period of time to wait between automatic refreshes"
|
||||
msgstr "자동 새로 고침 기다림 주기 시간"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:54
|
||||
msgid "Whether to refresh content after startup"
|
||||
msgstr "시작 후 내용 새로 고침 여부"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:60
|
||||
msgid "How many periods of time to wait between automatic cleanups"
|
||||
msgstr "자동 정리 기다림 주기 시간 간격"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.gschema.xml:64
|
||||
msgid "What period of time to wait between automatic cleanups"
|
||||
msgstr "자동 정리 기다림 주기 시간"
|
||||
|
||||
#. Weird magic I copy-pasted that sets the Application Name in the Shell.
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:3
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:4
|
||||
#: podcasts-gtk/src/app.rs:91 podcasts-gtk/src/app.rs:414
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:31
|
||||
msgid "Podcasts"
|
||||
msgstr "팟캐스트"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:4
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:10
|
||||
msgid "Listen to your favorite podcasts, right from your desktop."
|
||||
msgstr "데스크톱에서 바로 원하는 팟캐스트를 듣습니다."
|
||||
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:6
|
||||
msgid "@icon@"
|
||||
msgstr "@icon@"
|
||||
|
||||
#. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.desktop.in.in:13
|
||||
msgid "Podcast;RSS;"
|
||||
msgstr "Podcast;팟캐스트;RSS;"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:8
|
||||
msgid "Podcast app for GNOME"
|
||||
msgstr "그놈용 팟캐스트 앱"
|
||||
|
||||
#: podcasts-gtk/resources/org.gnome.Podcasts.appdata.xml.in.in:31
|
||||
msgid "Jordan Petridis"
|
||||
msgstr "Jordan Petridis"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:46
|
||||
msgid "This show does not have episodes yet"
|
||||
msgstr "아직 보여줄 에피소드가 없습니다"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:62
|
||||
msgid "If you think this is an error, please consider writing a bug report."
|
||||
msgstr "오류인 것 같다면 오류 보고서 작성을 고려하십시오."
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:106
|
||||
msgid "Get some shows"
|
||||
msgstr "일부 쇼 가져오기"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:143
|
||||
msgid "Add new shows via feed URL"
|
||||
msgstr "피드 URL 주소로 새 쇼 추가"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/empty_view.ui:172
|
||||
msgid "Import shows from another device"
|
||||
msgstr "다른 장치에서 쇼 가져오기"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:177
|
||||
msgid "Calculating episode size…"
|
||||
msgstr "에피소드 용량 계산 중…"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:212
|
||||
msgid "Cancel"
|
||||
msgstr "취소"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:230
|
||||
msgid "Download this episode"
|
||||
msgstr "이 에피소드 다운로드"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/episode_widget.ui:254
|
||||
msgid "Play this episode"
|
||||
msgstr "이 에피소드 재생"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:7
|
||||
msgid "_Check for New Episodes"
|
||||
msgstr "새 에피소드 확인(_C)"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:12
|
||||
msgid "_Import Shows"
|
||||
msgstr "쇼 가져오기(_I)"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:22
|
||||
msgid "_Preferences"
|
||||
msgstr "기본 설정(_P)"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:29
|
||||
msgid "_Keyboard Shortcuts"
|
||||
msgstr "키보드 바로 가기 키(_K)"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/hamburger.ui:37
|
||||
msgid "_About"
|
||||
msgstr "정보(_A)"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:35
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:189
|
||||
msgid "Add a new feed"
|
||||
msgstr "새 피드 추가"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:53
|
||||
msgid "Enter feed address to add"
|
||||
msgstr "추가할 피드 주소를 입력하십시오"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:89
|
||||
msgid "Add"
|
||||
msgstr "추가"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:133
|
||||
msgid "You are already subscribed to that feed!"
|
||||
msgstr "해당 피드에 이미 가입했습니다!"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:169
|
||||
msgid "Show Title"
|
||||
msgstr "제목 표시"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/headerbar.ui:210
|
||||
msgid "Back"
|
||||
msgstr "뒤로"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:12
|
||||
msgid "General"
|
||||
msgstr "일반"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:18
|
||||
msgctxt "shortcut window"
|
||||
msgid "Check for new episodes"
|
||||
msgstr "새 에피소드 확인"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:25
|
||||
msgctxt "shortcut window"
|
||||
msgid "Preferences"
|
||||
msgstr "기본 설정"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/help-overlay.ui:32
|
||||
msgctxt "shortcut window"
|
||||
msgid "Quit the application"
|
||||
msgstr "프로그램 끝내기"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:56
|
||||
msgid "Today"
|
||||
msgstr "오늘"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:112
|
||||
msgid "Yesterday"
|
||||
msgstr "어제"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:168
|
||||
msgid "This Week"
|
||||
msgstr "금주"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:224
|
||||
msgid "This Month"
|
||||
msgstr "이번 달"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/home_view.ui:281
|
||||
msgid "Older"
|
||||
msgstr "이전"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:101
|
||||
msgid "An in-app action notification"
|
||||
msgstr "앱 동작 알림"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/inapp_notif.ui:112
|
||||
msgid "Undo"
|
||||
msgstr "실행 취소"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:72
|
||||
msgid "Rewind 10 seconds"
|
||||
msgstr "10초 되감기"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:87
|
||||
msgid "Play"
|
||||
msgstr "재생"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:103
|
||||
msgid "Pause"
|
||||
msgstr "일시 정지"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:119
|
||||
msgid "Fast forward 10 seconds"
|
||||
msgstr "10초 빨리감기"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:285
|
||||
msgid "Change the playback speed"
|
||||
msgstr "재생 속도 조절"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:300
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:380
|
||||
msgid "1.00×"
|
||||
msgstr "1.00×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:344
|
||||
msgid "1.50×"
|
||||
msgstr "1.50×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:348
|
||||
msgid "1.5 speed rate"
|
||||
msgstr "1.5배 속도"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:362
|
||||
msgid "1.25×"
|
||||
msgstr "1.25×"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:366
|
||||
msgid "1.25 speed rate"
|
||||
msgstr "1.25배 속도"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/player_toolbar.ui:384
|
||||
msgid "Normal speed"
|
||||
msgstr "일반 속도"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:42
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:295
|
||||
msgid "Preferences"
|
||||
msgstr "기본 설정"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:76
|
||||
msgid "Appearance"
|
||||
msgstr "모양새"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:120
|
||||
msgid "Dark Theme"
|
||||
msgstr "어두움 테마"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:166
|
||||
msgid "Delete played episodes"
|
||||
msgstr "재생한 에피소드 삭제"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/prefs.ui:211
|
||||
msgid "After"
|
||||
msgstr "다음"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:7
|
||||
msgid "_Mark All Episodes as Played"
|
||||
msgstr "모든 에피소드를 재생 상태로 표시(_M)"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:11
|
||||
msgid "_Website"
|
||||
msgstr "웹사이트(_W)"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/secondary_menu.ui:15
|
||||
msgid "_Unsubscribe"
|
||||
msgstr "가입 취소(_U)"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:51
|
||||
msgid "Open Website"
|
||||
msgstr "웹사이트 열기"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:64
|
||||
msgid "Mark All as Played"
|
||||
msgstr "모두 재생한 항목으로 표시"
|
||||
|
||||
#: podcasts-gtk/resources/gtk/show_menu.ui:89
|
||||
msgid "Unsubscribe"
|
||||
msgstr "가입 취소"
|
||||
|
||||
#: podcasts-gtk/src/app.rs:332
|
||||
msgid "Fetching new episodes"
|
||||
msgstr "새 에피소드 가져오는 중"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:98
|
||||
msgid "You are already subscribed to this show"
|
||||
msgstr "이미 이 쇼에 가입했습니다"
|
||||
|
||||
#: podcasts-gtk/src/headerbar.rs:106
|
||||
msgid "Invalid URL"
|
||||
msgstr "잘못된 URL 주소"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:59
|
||||
msgid "Seconds"
|
||||
msgstr "초"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:60
|
||||
msgid "Minutes"
|
||||
msgstr "분"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:61
|
||||
msgid "Hours"
|
||||
msgstr "시간"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:62
|
||||
msgid "Days"
|
||||
msgstr "일"
|
||||
|
||||
#: podcasts-gtk/src/prefs.rs:63
|
||||
msgid "Weeks"
|
||||
msgstr "주"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:35
|
||||
msgid "New"
|
||||
msgstr "새 항목"
|
||||
|
||||
#: podcasts-gtk/src/stacks/content.rs:36
|
||||
msgid "Shows"
|
||||
msgstr "쇼"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:357
|
||||
msgid "Select the file from which to you want to import shows."
|
||||
msgstr "가져올 쇼의 파일을 선택하십시오."
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:360
|
||||
msgid "_Import"
|
||||
msgstr "가져오기(_I)"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:369
|
||||
msgid "OPML file"
|
||||
msgstr "OPML 파일"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:386
|
||||
msgid "Failed to parse the imported file"
|
||||
msgstr "가져온 파일 해석에 실패했습니다"
|
||||
|
||||
#: podcasts-gtk/src/utils.rs:391
|
||||
msgid "Selected file could not be accessed."
|
||||
msgstr "선택한 파일에 접근할 수 없습니다."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:26
|
||||
msgid "Podcast Client for the GNOME Desktop."
|
||||
msgstr "그놈 데스크톱용 팟캐스트 클라이언트."
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:33
|
||||
msgid "Learn more about GNOME Podcasts"
|
||||
msgstr "그놈 팟캐스트에 대해 더 알아보세요"
|
||||
|
||||
#: podcasts-gtk/src/widgets/aboutdialog.rs:38
|
||||
msgid "translator-credits"
|
||||
msgstr "조성호 <shcho@gnome.org>, 2018."
|
||||
|
||||
#: podcasts-gtk/src/widgets/episode.rs:129
|
||||
msgid "{} min"
|
||||
msgstr "{}분"
|
||||
|
||||
#. sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
|
||||
#: podcasts-gtk/src/widgets/player.rs:301
|
||||
msgid "The media player was unable to execute an action."
|
||||
msgstr "미디어 재생기에서 이 동작을 수행할 수 없습니다."
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:150
|
||||
msgid "Marked all episodes as listened"
|
||||
msgstr "모든 에피소드를 감청 상태로 표시했습니다"
|
||||
|
||||
#: podcasts-gtk/src/widgets/show_menu.rs:155
|
||||
msgid "Unsubscribed from {}"
|
||||
msgstr "{}에서 가입 취소했습니다"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user