Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0631ba268a | ||
|
|
ab4055bede | ||
|
|
28f821e482 | ||
|
|
832674b5b3 | ||
|
|
28ff9be4ac | ||
|
|
89255083b9 | ||
|
|
3a8788896f | ||
|
|
22d5667995 | ||
|
|
bdfb92a736 | ||
|
|
4e3da60708 | ||
|
|
f7d5d31108 | ||
|
|
1d11e11ee6 | ||
|
|
d14e1189f2 | ||
|
|
378abb7d4b | ||
|
|
51d330e6f3 | ||
|
|
3963eb41ce | ||
|
|
af12a936d6 | ||
|
|
cc6661321d | ||
|
|
e70a8689bb | ||
|
|
6511812f2e | ||
|
|
668642d893 | ||
|
|
151281f58c | ||
|
|
f01057a244 | ||
|
|
e494a6f1a6 | ||
|
|
b43d967f69 | ||
|
|
6b94a459de | ||
|
|
1109b81870 | ||
|
|
9f404d37f6 | ||
|
|
32be492e82 | ||
|
|
c4de93e4d1 | ||
|
|
e5c817b955 | ||
|
|
cc2dcd1abb | ||
|
|
4b343157a2 | ||
|
|
52f330d6be | ||
|
|
435d530b14 | ||
|
|
a2d1288e06 | ||
|
|
72500ef1a8 | ||
|
|
6e67e63c32 | ||
|
|
634ccf7835 | ||
|
|
da6363d6cc | ||
|
|
0447eb3ca2 | ||
|
|
d49addb1ae | ||
|
|
bade37f9f2 | ||
|
|
5581c9f8e9 | ||
|
|
342984283c | ||
|
|
d313c4b79b | ||
|
|
eb3bb80669 | ||
|
|
c56bbb68f6 | ||
|
|
f5a54fc7e7 | ||
|
|
f2f653815b | ||
|
|
4edfc8db71 | ||
|
|
f368c8fd8c | ||
|
|
a0f7854c52 | ||
|
|
fb9e17621f | ||
|
|
d5b2c2c45c | ||
|
|
0e6abff8ff | ||
|
|
a762edafc7 | ||
|
|
d1bf0c711c | ||
|
|
996322c335 | ||
|
|
54d7c276bf | ||
|
|
234f364b33 | ||
|
|
0d019b9499 | ||
|
|
f4d144d53e | ||
|
|
49bff407ad | ||
|
|
1e2df2d6d8 | ||
|
|
7c3d83704b | ||
|
|
2796d9be83 | ||
|
|
4233a323b7 | ||
|
|
cf5d8df35d | ||
|
|
86f16fc7af | ||
|
|
7024e1526f | ||
|
|
d2b256f943 | ||
|
|
dcf1b9df98 | ||
|
|
0f0e8a5974 | ||
|
|
f703f1e357 | ||
|
|
3815759cd3 | ||
|
|
72242e328c | ||
|
|
c38805fa92 | ||
|
|
1ae12c868e | ||
|
|
9f3789eac5 | ||
|
|
a956177d6a | ||
|
|
b900c44188 | ||
|
|
e521c07102 | ||
|
|
e696298bc9 | ||
|
|
b65fbe83f4 | ||
|
|
ce6782a131 | ||
|
|
a37746440a | ||
|
|
eaf62c2770 | ||
|
|
147392f317 | ||
|
|
63d56acd88 | ||
|
|
28d07b370f | ||
|
|
d648ba9c93 | ||
|
|
a82dae6251 | ||
|
|
f99a17339b | ||
|
|
198266c081 | ||
|
|
756c2f8b56 | ||
|
|
abdba9922a | ||
|
|
7ca4095571 | ||
|
|
c3128c9855 | ||
|
|
20ae6c37cb | ||
|
|
3c2fdca5fc | ||
|
|
395c7ad140 | ||
|
|
630b54933d | ||
|
|
2293280316 | ||
|
|
14116b9cd2 | ||
|
|
4c7db5d5c9 | ||
|
|
f26bc80421 | ||
|
|
f934e99254 | ||
|
|
b6cd3c4a2b | ||
|
|
76763b9be1 | ||
|
|
1606f91124 | ||
|
|
cf8c982228 | ||
|
|
e94362854d | ||
|
|
40f3d5eab1 | ||
|
|
dc3b35bffa | ||
|
|
52c654179f | ||
|
|
a07a3c162f | ||
|
|
e4f8f96517 | ||
|
|
6fdb0321d6 | ||
|
|
be9b0d57e9 | ||
|
|
b4c6749a76 | ||
|
|
a98e3c7b92 | ||
|
|
26e7bbbdb8 | ||
|
|
efa7dd674a | ||
|
|
ef59e9d418 | ||
|
|
e1678a76ba | ||
|
|
56ffb52ce5 | ||
|
|
f0a2d2e79a | ||
|
|
182e77a68d | ||
|
|
98ccbfe99d | ||
|
|
53bfc641b4 | ||
|
|
1aabf2eefc | ||
|
|
0d54dfb660 | ||
|
|
8093f16f16 | ||
|
|
bac6ac3362 | ||
|
|
2f914d9f60 | ||
|
|
d3293d22ab | ||
|
|
4de3fdae81 | ||
|
|
9518c73415 | ||
|
|
05be539411 | ||
|
|
f12c4e3109 | ||
|
|
004ef28a15 | ||
|
|
afa9b25aff | ||
|
|
303ce7c816 | ||
|
|
e7cbd07b80 | ||
|
|
923ae5fc96 | ||
|
|
51a3b3c68e | ||
|
|
ef1582c67c | ||
|
|
2091e39b90 | ||
|
|
ab02e72f1f | ||
|
|
d498d6a407 | ||
|
|
6dc6e9538c | ||
|
|
3b0cbefe85 | ||
|
|
38e152fc52 | ||
|
|
0f111b43be | ||
|
|
ffbeab0b14 | ||
|
|
8860b62eec | ||
|
|
93433d8714 | ||
|
|
211a0c6f93 | ||
|
|
aadfc71200 | ||
|
|
1532adedb1 | ||
|
|
16ce656201 | ||
|
|
a398723bdb | ||
|
|
f7a4788e73 | ||
|
|
15425c7b01 | ||
|
|
96c2a505a7 | ||
|
|
b58e3fc2d4 | ||
|
|
4b1cbf11ad | ||
|
|
1037ac8c02 | ||
|
|
572f3c4c94 | ||
|
|
e48d6c8bb6 | ||
|
|
d717e7dff9 | ||
|
|
cb16ebb812 | ||
|
|
2c1df5e9e4 | ||
|
|
c3873d05ac | ||
|
|
4fca0ca0c5 | ||
|
|
c02f369a0f | ||
|
|
2e68ec0880 | ||
|
|
c7b22b348e | ||
|
|
f4c8172201 | ||
|
|
9fa7757efd | ||
|
|
fc2c359bd7 | ||
|
|
f17987b3e7 | ||
|
|
7c2bbf3a98 | ||
|
|
4320921a96 | ||
|
|
306a4c866c | ||
|
|
2bfd142300 | ||
|
|
bec70c37db | ||
|
|
a7e9588a90 | ||
|
|
463bdde0a0 | ||
|
|
c83d7f582b | ||
|
|
62385df312 | ||
|
|
dad015195b | ||
|
|
b89fed88ee | ||
|
|
613dd1eb51 | ||
|
|
b7754e7d60 | ||
|
|
644c343e95 | ||
|
|
c9d530be76 | ||
|
|
aa0268694f | ||
|
|
8e873e726d | ||
|
|
dca3373056 | ||
|
|
6d57cad22c | ||
|
|
b67fdc384f | ||
|
|
32f98a7c9b | ||
|
|
2b8ac69916 | ||
|
|
ad6fe5e633 | ||
|
|
1ad6586a07 | ||
|
|
0249604199 | ||
|
|
1a93e0d944 | ||
|
|
347613a7f2 | ||
|
|
424c67a268 | ||
|
|
64d7a911fa | ||
|
|
961dca328d | ||
|
|
433d95969c | ||
|
|
15f439c38e | ||
|
|
ca4d5d8b77 | ||
|
|
06338900dc | ||
|
|
8ec674fbef | ||
|
|
58eefc29eb | ||
|
|
9312331755 | ||
|
|
1d25f46f52 | ||
|
|
a775cd58be | ||
|
|
ae5ed3b10b | ||
|
|
8aab91568e | ||
|
|
6647346314 | ||
|
|
bfb41310ad | ||
|
|
c3371adda4 | ||
|
|
9bcf017c8d | ||
|
|
2c0b13ff9f | ||
|
|
abfd901a82 | ||
|
|
135b8859d6 | ||
|
|
f8637b686c | ||
|
|
53f466c976 | ||
|
|
762976159e | ||
|
|
de1a872f74 | ||
|
|
3f39fc9e90 | ||
|
|
e8e6a5f1e2 | ||
|
|
51a9799281 | ||
|
|
73078eb5e7 | ||
|
|
d138b5c67b | ||
|
|
ef3846df6b | ||
|
|
a31494d83f | ||
|
|
b131fcc7d9 | ||
|
|
e6379db384 | ||
|
|
f50cf92e9a | ||
|
|
e9e0e4f143 | ||
|
|
dfc0b8cbcd | ||
|
|
473b4ee83e | ||
|
|
f40c9fd497 | ||
|
|
0ca21344f8 | ||
|
|
d4d85a8b58 | ||
|
|
cfd4b3de53 | ||
|
|
96c5f344cc | ||
|
|
d6e8ddca11 | ||
|
|
db63766cc7 | ||
|
|
048e876710 | ||
|
|
d7e74e2a5f | ||
|
|
722b78e49b | ||
|
|
734caa0280 |
No files matched your search
Symlink
+1
@@ -0,0 +1 @@
|
||||
org.kde.audiotube.json
|
||||
@@ -6,3 +6,4 @@
|
||||
*.kdev4
|
||||
CMakeLists.txt.user
|
||||
flatpak/flatpak-builder-tools/
|
||||
build/
|
||||
+4
-1
@@ -3,4 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
include:
|
||||
- 'https://invent.kde.org/sysadmin/ci-tooling/raw/master/invent/ci-reuse.yml'
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/reuse-lint.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/flatpak.yml
|
||||
+21
@@ -2,3 +2,24 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: AudioTube
|
||||
Upstream-Contact: Jonah Brüchert <[email protected]>
|
||||
Source: https://invent.kde.org/plasma-mobile/audiotube
|
||||
|
||||
# Sample paragraph, commented out:
|
||||
#
|
||||
# Files: ...
|
||||
# Copyright: $YEAR $NAME <$CONTACT>
|
||||
# License: ...
|
||||
# Comment: ...
|
||||
|
||||
Files: README.md
|
||||
Copyright: 2021 Jonah Brüchert <[email protected]>
|
||||
License: CC0-1.0
|
||||
|
||||
Files: org.kde.audiotube.desktop
|
||||
org.kde.audiotube.json
|
||||
Copyright: 2021 Jonah Brüchert <[email protected]>
|
||||
License: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
Files: logo.png
|
||||
org.kde.audiotube.svg
|
||||
Copyright: 2021 Mathis Brüchert <[email protected]>
|
||||
License: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
+7
-5
@@ -8,11 +8,11 @@ project(audiotube)
|
||||
|
||||
include(FeatureSummary)
|
||||
|
||||
set(PROJECT_VERSION "21.08")
|
||||
set(PROJECT_VERSION "22.11")
|
||||
set(QT5_MIN_VERSION 5.15)
|
||||
set(KF5_MIN_VERSION 5.81)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
@@ -33,11 +33,13 @@ ecm_setup_version(${PROJECT_VERSION}
|
||||
|
||||
kde_enable_exceptions()
|
||||
|
||||
find_package(Qt5 ${QT5_MIN_VERSION} REQUIRED COMPONENTS Core Gui Qml QuickControls2 Svg)
|
||||
find_package(Qt${QT_MAJOR_VERSION} ${QT5_MIN_VERSION} REQUIRED COMPONENTS Core Gui Qml QuickControls2 Svg Sql Widgets)
|
||||
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Kirigami2 I18n CoreAddons Crash)
|
||||
find_package(pybind11 REQUIRED)
|
||||
find_package(YoutubeDL REQUIRED RUNTIME)
|
||||
find_package(YTMusicAPI REQUIRED RUNTIME)
|
||||
find_package(Ytdlp REQUIRED RUNTIME)
|
||||
find_package(YTMusicAPI 0.24.0 REQUIRED RUNTIME)
|
||||
|
||||
ki18n_install(po)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
|
||||
AudioTube is a client for YouTube Music.
|
||||
|
||||
<a href='https://flathub.org/apps/details/org.kde.audiotube'><img width='190px' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-i-en.png'/></a>
|
||||
|
||||
## Links
|
||||
* Project page: https://invent.kde.org/plasma-mobile/audiotube
|
||||
* File issues: https://bugs.kde.org/describecomponents.cgi?product=audiotube
|
||||
|
||||
# Dependencies
|
||||
|
||||
It depends on Qt, Kirigami, KI18n, KCoreAddons and KCrash in addition to a few python packages:
|
||||
* ytmusicapi
|
||||
* youtube_dl
|
||||
* yt_dlp
|
||||
|
||||
YouTube uses webp images for the cover art, so you will need to install qtimageformats.
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
SPDX-FileCopyrightText: 2021 Jonah Brüchert <[email protected]>
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
@@ -4,8 +4,20 @@
|
||||
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
|
||||
execute_process(COMMAND ${Python3_EXECUTABLE} -c "import ytmusicapi" RESULT_VARIABLE YTMUSICAPI_CHECK_RESULT)
|
||||
execute_process(COMMAND ${Python3_EXECUTABLE} -c "import ytmusicapi; print(ytmusicapi.version('ytmusicapi'))" RESULT_VARIABLE YTMUSICAPI_CHECK_RESULT OUTPUT_VARIABLE YTMusicAPI_VERSION)
|
||||
|
||||
string(STRIP ${YTMusicAPI_VERSION} YTMusicAPI_VERSION)
|
||||
|
||||
if (${YTMUSICAPI_CHECK_RESULT} EQUAL 0)
|
||||
set(YTMusicAPI_FOUND TRUE)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(YTMusicAPI
|
||||
FOUND_VAR
|
||||
YTMusicAPI_FOUND
|
||||
REQUIRED_VARS
|
||||
Python3_EXECUTABLE
|
||||
VERSION_VAR
|
||||
YTMusicAPI_VERSION
|
||||
)
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
|
||||
execute_process(COMMAND ${Python3_EXECUTABLE} -c "import youtube_dl" RESULT_VARIABLE YTDL_CHECK_RESULT)
|
||||
execute_process(COMMAND ${Python3_EXECUTABLE} -c "import yt_dlp" RESULT_VARIABLE YTDLP_CHECK_RESULT)
|
||||
|
||||
if (${YTDL_CHECK_RESULT} EQUAL 0)
|
||||
set(YoutubeDL_FOUND TRUE)
|
||||
if (${YTDLP_CHECK_RESULT} EQUAL 0)
|
||||
set(Ytdlp_FOUND TRUE)
|
||||
endif()
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"name": "python3-youtube_dl",
|
||||
"buildsystem": "simple",
|
||||
"build-commands": [
|
||||
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"youtube_dl\" --no-build-isolation"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/c6/75/05979677d9abc76851d13d8db3951e39017ac223545adab6e8576fa0cbe7/youtube_dl-2021.6.6.tar.gz",
|
||||
"sha256": "cb2d3ee002158ede783e97a82c95f3817594df54367ea6a77ce5ceea4772f0ab"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "python3-yt-dlp",
|
||||
"buildsystem": "simple",
|
||||
"build-commands": [
|
||||
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"yt-dlp\" --no-build-isolation"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/2a/18/70c32fe9357f3eea18598b23aa9ed29b1711c3001835f7cf99a9818985d0/Brotli-1.0.9.zip",
|
||||
"sha256": "4d1b810aa0ed773f81dceda2cc7b403d01057458730e309856356d4ef4188438"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/1d/38/fa96a426e0c0e68aabc68e896584b83ad1eec779265a028e156ce509630e/certifi-2022.9.24-py3-none-any.whl",
|
||||
"sha256": "90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/03/ee/114d7016d2e34f341e212fefb5e7bd87785077ebcfff0ad23a497c70eea1/mutagen-1.46.0-py3-none-any.whl",
|
||||
"sha256": "8af0728aa2d5c3ee5a727e28d0627966641fddfe804c23eabb5926a4d770aed5"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/52/0d/6cc95a83f6961a1ca041798d222240890af79b381e97eda3b9b538dba16f/pycryptodomex-3.15.0.tar.gz",
|
||||
"sha256": "7341f1bb2dadb0d1a0047f34c3a58208a92423cdbd3244d998e4b28df5eac0ed"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz",
|
||||
"sha256": "eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/2b/8c/6382d335662361fe06bea1ca96a189982cc050c2f9946dcd320b8c26a833/yt_dlp-2022.10.4-py2.py3-none-any.whl",
|
||||
"sha256": "cc21d91048b275bda7018bdc3103374882261ccf29720206d61b10e168c8b719"
|
||||
}
|
||||
]
|
||||
}
|
||||
File renamed without changes.
@@ -7,33 +7,33 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/4f/5a/597ef5911cb8919efe4d86206aa8b2658616d676a7088f0825ca08bd7cb8/urllib3-1.26.6.tar.gz",
|
||||
"sha256": "f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"
|
||||
"url": "https://files.pythonhosted.org/packages/1d/38/fa96a426e0c0e68aabc68e896584b83ad1eec779265a028e156ce509630e/certifi-2022.9.24-py3-none-any.whl",
|
||||
"sha256": "90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/ea/b7/e0e3c1c467636186c39925827be42f16fee389dc404ac29e930e9136be70/idna-2.10.tar.gz",
|
||||
"sha256": "b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"
|
||||
"url": "https://files.pythonhosted.org/packages/db/51/a507c856293ab05cdc1db77ff4bc1268ddd39f29e7dc4919aa497f0adbec/charset_normalizer-2.1.1-py3-none-any.whl",
|
||||
"sha256": "83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/ee/2d/9cdc2b527e127b4c9db64b86647d567985940ac3698eeabc7ffaccb4ea61/chardet-4.0.0.tar.gz",
|
||||
"sha256": "0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"
|
||||
"url": "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl",
|
||||
"sha256": "90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/6d/78/f8db8d57f520a54f0b8a438319c342c61c22759d8f9a1cd2e2180b5e5ea9/certifi-2021.5.30.tar.gz",
|
||||
"sha256": "2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"
|
||||
"url": "https://files.pythonhosted.org/packages/ca/91/6d9b8ccacd0412c08820f72cebaa4f0c0441b5cda699c90f618b6f8a1b42/requests-2.28.1-py3-none-any.whl",
|
||||
"sha256": "8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/6b/47/c14abc08432ab22dc18b9892252efaf005ab44066de871e72a38d6af464b/requests-2.25.1.tar.gz",
|
||||
"sha256": "27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"
|
||||
"url": "https://files.pythonhosted.org/packages/6f/de/5be2e3eed8426f871b170663333a0f627fc2924cc386cd41be065e7ea870/urllib3-1.26.12-py2.py3-none-any.whl",
|
||||
"sha256": "b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://files.pythonhosted.org/packages/83/aa/3e2c231fbef90d5bd75614e3739bb27e7e33e28c9891d6ee0561fe52a9df/ytmusicapi-0.18.0.tar.gz",
|
||||
"sha256": "447d1b6a594f49942f7ac75412cba59c191b6f3540d98ac65a1333445beec16d"
|
||||
"url": "https://files.pythonhosted.org/packages/74/5f/929784007a6777272b3bd51dc7a13e39d5192d64b3831535e83776cd825d/ytmusicapi-0.24.0-py3-none-any.whl",
|
||||
"sha256": "ac25baec1314274030e422c841932d94119394f54c7e70c64a2be1f26be69c2b"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -16,5 +16,5 @@ else
|
||||
git -C flatpak-builder-tools pull
|
||||
fi
|
||||
|
||||
./flatpak-builder-tools/pip/flatpak-pip-generator youtube_dl
|
||||
./flatpak-builder-tools/pip/flatpak-pip-generator yt-dlp
|
||||
./flatpak-builder-tools/pip/flatpak-pip-generator ytmusicapi
|
||||
@@ -1,3 +0,0 @@
|
||||
SPDX-FileCopyrightText: 2021 Mathis Brüchert <[email protected]>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
@@ -7,6 +7,8 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<component type="desktop-application">
|
||||
<id>org.kde.audiotube</id>
|
||||
<name>AudioTube</name>
|
||||
<name xml:lang="ar">تيوب الصوتي</name>
|
||||
<name xml:lang="az">AudioTube</name>
|
||||
<name xml:lang="ca">AudioTube</name>
|
||||
<name xml:lang="ca-valencia">AudioTube</name>
|
||||
<name xml:lang="cs">AudioTube</name>
|
||||
@@ -17,21 +19,30 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<name xml:lang="fi">AudioTube</name>
|
||||
<name xml:lang="fr">AudioTube</name>
|
||||
<name xml:lang="hi">ओडियो-ट्यूब</name>
|
||||
<name xml:lang="id">AudioTube</name>
|
||||
<name xml:lang="it">AudioTube</name>
|
||||
<name xml:lang="ka">AudioTube</name>
|
||||
<name xml:lang="ko">AudioTube</name>
|
||||
<name xml:lang="nl">AudioTube</name>
|
||||
<name xml:lang="nn">AudioTube</name>
|
||||
<name xml:lang="pa">ਆਡੀਓ-ਟਿਊਬ</name>
|
||||
<name xml:lang="pl">AudioTube</name>
|
||||
<name xml:lang="pt">AudioTube</name>
|
||||
<name xml:lang="pt-BR">AudioTube</name>
|
||||
<name xml:lang="ro">AudioTube</name>
|
||||
<name xml:lang="ru">AudioTube</name>
|
||||
<name xml:lang="sk">AudioTube</name>
|
||||
<name xml:lang="sl">AudioTube</name>
|
||||
<name xml:lang="sv">AudioTube</name>
|
||||
<name xml:lang="tr">AudioTube</name>
|
||||
<name xml:lang="uk">AudioTube</name>
|
||||
<name xml:lang="x-test">xxAudioTubexx</name>
|
||||
<name xml:lang="zh-CN">AudioTube</name>
|
||||
<summary>Convergent YouTube Music client</summary>
|
||||
<summary xml:lang="ca">Client convergent per a la música de YouTube</summary>
|
||||
<summary xml:lang="ca-valencia">Client convergent per a la música de YouTube</summary>
|
||||
<summary xml:lang="ar">عميل موسيقى يوتيوب متعدد المنصات</summary>
|
||||
<summary xml:lang="az">Birləşmiş YouTube Musiqi müştərisi</summary>
|
||||
<summary xml:lang="ca">Client convergent de música de YouTube</summary>
|
||||
<summary xml:lang="ca-valencia">Client convergent de música de YouTube</summary>
|
||||
<summary xml:lang="de">Konvergentes YouTube-Musikprogramm</summary>
|
||||
<summary xml:lang="en-GB">Convergent YouTube Music client</summary>
|
||||
<summary xml:lang="es">Cliente de música de YouTube convergente</summary>
|
||||
@@ -39,19 +50,28 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<summary xml:lang="fi">Mukautuva YouTube Music -asiakas</summary>
|
||||
<summary xml:lang="fr">Client convergent pour musique sur YouTube</summary>
|
||||
<summary xml:lang="hi">अभिसृत यूट्यूब संगीत क्लाएंट</summary>
|
||||
<summary xml:lang="id">Klien YouTube Music konvergen</summary>
|
||||
<summary xml:lang="it">Client YouTube Music convergente</summary>
|
||||
<summary xml:lang="ka">YouTube Music -ის კონვერგენტული კლიენტი</summary>
|
||||
<summary xml:lang="ko">올인원 YouTube Music 클라이언트</summary>
|
||||
<summary xml:lang="nl">Convergente muziekclient van YouTube</summary>
|
||||
<summary xml:lang="nn">YouTube Music-klient, tilpassa ulike brukarflater</summary>
|
||||
<summary xml:lang="pl">Adaptacyjny program do YouTube Music</summary>
|
||||
<summary xml:lang="pt">Cliente de música do YouTube convergente</summary>
|
||||
<summary xml:lang="pt-BR">Um cliente convergente para o YouTube Music</summary>
|
||||
<summary xml:lang="ro">Client convergent de muzică pentru YouTube</summary>
|
||||
<summary xml:lang="ru">Клиент для YouTube Music</summary>
|
||||
<summary xml:lang="sl">Konvergentni odjemalec glasbe YouTube</summary>
|
||||
<summary xml:lang="sv">Konvergent YouTube-musikprogram</summary>
|
||||
<summary xml:lang="tr">Yakınsak YouTube Müzik İstemcisi</summary>
|
||||
<summary xml:lang="uk">Зручний музичний клієнт YouTube</summary>
|
||||
<summary xml:lang="x-test">xxConvergent YouTube Music clientxx</summary>
|
||||
<summary xml:lang="zh-CN">桌面和移动设备通用 YouTube Music 客户端</summary>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-2.0+</project_license>
|
||||
<developer_name>KDE Community</developer_name>
|
||||
<developer_name xml:lang="ar">مجتمع كدي</developer_name>
|
||||
<developer_name xml:lang="az">KDE İcması</developer_name>
|
||||
<developer_name xml:lang="ca">La comunitat KDE</developer_name>
|
||||
<developer_name xml:lang="ca-valencia">La comunitat KDE</developer_name>
|
||||
<developer_name xml:lang="cs">Komunita KDE</developer_name>
|
||||
@@ -62,30 +82,82 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<developer_name xml:lang="fi">KDE-yhteisö</developer_name>
|
||||
<developer_name xml:lang="fr">Communauté de KDE</developer_name>
|
||||
<developer_name xml:lang="hi">केडीई समुदाय</developer_name>
|
||||
<developer_name xml:lang="id">Komunitas KDE</developer_name>
|
||||
<developer_name xml:lang="it">Comunità KDE</developer_name>
|
||||
<developer_name xml:lang="ka">KDE-ის საზოგადოება</developer_name>
|
||||
<developer_name xml:lang="ko">KDE 커뮤니티</developer_name>
|
||||
<developer_name xml:lang="nl">KDE-gemeenschap</developer_name>
|
||||
<developer_name xml:lang="nn">KDE-fellesskapet</developer_name>
|
||||
<developer_name xml:lang="pa">ਕੇਡੀਈ ਕਮਿਊਨਟੀ</developer_name>
|
||||
<developer_name xml:lang="pl">Społeczność KDE</developer_name>
|
||||
<developer_name xml:lang="pt">Comunidade do KDE</developer_name>
|
||||
<developer_name xml:lang="pt-BR">A Comunidade KDE</developer_name>
|
||||
<developer_name xml:lang="ro">Comunitatea KDE</developer_name>
|
||||
<developer_name xml:lang="ru">Сообщество KDE</developer_name>
|
||||
<developer_name xml:lang="sk">KDE komunita</developer_name>
|
||||
<developer_name xml:lang="sl">Skupnost KDE</developer_name>
|
||||
<developer_name xml:lang="sv">KDE-gemenskapen</developer_name>
|
||||
<developer_name xml:lang="tr">KDE Topluluğu</developer_name>
|
||||
<developer_name xml:lang="uk">Спільнота KDE</developer_name>
|
||||
<developer_name xml:lang="x-test">xxKDE Communityxx</developer_name>
|
||||
<developer_name xml:lang="zh-CN">KDE 社区</developer_name>
|
||||
<content_rating type="oars-1.0"/>
|
||||
<url type="homepage">https://apps.kde.org/en/audiotube</url>
|
||||
<releases>
|
||||
<release version="22.11" date="2022-11-30">
|
||||
<url>https://plasma-mobile.org/2022/11/30/plasma-mobile-gear-22-11/</url>
|
||||
</release>
|
||||
<release version="22.09" date="2022-09-27">
|
||||
<url>https://www.plasma-mobile.org/2022/09/27/plasma-mobile-gear-22-09/</url>
|
||||
</release>
|
||||
<release version="22.06" date="2022-06-24">
|
||||
<url>https://www.plasma-mobile.org/2022/06/28/plasma-mobile-gear-22-06/</url>
|
||||
<description>
|
||||
<ul>
|
||||
<li>Add library page which shows favourites and most played songs</li>
|
||||
<li>Improve layout of the search popup</li>
|
||||
<li>General performance improvements including startup</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="22.04" date="2022-04-26">
|
||||
<url>https://www.plasma-mobile.org/2022/04/26/plasma-mobile-gear-22-04/</url>
|
||||
<description>
|
||||
<ul>
|
||||
<li>Update the version of ytmusicapi</li>
|
||||
<li>General code-refactoring and translation updates</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="22.02" date="2022-02-09">
|
||||
<url>https://www.plasma-mobile.org/2022/02/09/plasma-mobile-gear-22-02/</url>
|
||||
<description>
|
||||
<ul>
|
||||
<li>Update the version of ytmusicapi</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="21.12" date="2021-12-07">
|
||||
<url>https://www.plasma-mobile.org/2021/12/07/plasma-mobile-gear-21-12/</url>
|
||||
</release>
|
||||
<release version="21.08" date="2021-08-31">
|
||||
<url>https://www.plasma-mobile.org/2021/08/31/plasma-mobile-gear-21-08/</url>
|
||||
</release>
|
||||
</releases>
|
||||
<launchable type="desktop-id">org.kde.audiotube.desktop</launchable>
|
||||
<screenshots>
|
||||
<screenshot>
|
||||
<image>https://cdn.kde.org/screenshots/audiotube/library.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://cdn.kde.org/screenshots/audiotube/player.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://cdn.kde.org/screenshots/audiotube/desktop.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://cdn.kde.org/screenshots/audiotube/mobile_album.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://cdn.kde.org/screenshots/audiotube/mobile_playlist.png</image>
|
||||
</screenshot>
|
||||
@@ -97,8 +169,10 @@ SPDX-License-Identifier: CC0-1.0
|
||||
</recommends>
|
||||
<description>
|
||||
<p>AudioTube can search YouTube Music, list albums and artists, play automatically generated playlists, albums and allows to put your own playlist together.</p>
|
||||
<p xml:lang="ar">يمكن لتيوب الصوتي البحث في موسيقى يوتيوب، وعرض الألبومات والفنانين، وتشغيل القوائم والألبومات المولدة تلقائيًا، ويسمح لك بوضع قائمة التشغيل الخاصة بك معًا.</p>
|
||||
<p xml:lang="az">AudioTube YouTube Musiqi, albomların və ifaçıların siyahısı üzrə axtarış etməyə, yaradılmış mahnı siyahısı və albomları avtomatik oxutmağa və öz mahnı siyahınızı yaratmağa imkan verir.</p>
|
||||
<p xml:lang="ca">L'AudioTube pot cercar música a YouTube, llistar àlbums i artistes, reproduir llistes de reproducció generades automàticament, àlbums i permet crear la vostra pròpia llista de reproducció.</p>
|
||||
<p xml:lang="ca-valencia">L'AudioTube pot cercar música a YouTube, llistar àlbums i artistes, reproduir llistes de reproducció generades automàticament, àlbums i permet crear la vostra pròpia llista de reproducció.</p>
|
||||
<p xml:lang="ca-valencia">L'AudioTube pot buscar música a YouTube, llistar àlbums i artistes, reproduir llistes de reproducció generades automàticament, àlbums i permet crear la vostra pròpia llista de reproducció.</p>
|
||||
<p xml:lang="de">AudioTube kann Musik auf YouTube durchsuchen, Alben und Interpreten auflisten, automatisch generierte Wiedergabelisten und Alben abspielen und erlaubt es, eine eigene Wiedergabeliste zusammenzustellen.</p>
|
||||
<p xml:lang="en-GB">AudioTube can search YouTube Music, list albums and artists, play automatically generated playlists, albums and allows to put your own playlist together.</p>
|
||||
<p xml:lang="es">AudioTube puede buscar música de YouTube, listar álbumes y artistas, reproducir las listas de reproducción generadas, álbumes y le permite crear su propia lista de reproducción.</p>
|
||||
@@ -106,15 +180,21 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<p xml:lang="fi">AudioTube osaa etsiä YouTube Music -haun, albumien ja artistien luettelun, luotujen soittolistojen automaattisen toiston ja omien soittolistojen kokoamisen.</p>
|
||||
<p xml:lang="fr">AudioTube peut effectuer des recherches de musiques sur YouTube Music, établir une liste d'albums et d'artistes, lire des listes de lecture générées automatiquement, des albums et permet de composer sa propre liste de lecture.</p>
|
||||
<p xml:lang="hi">ऑडियोट्यूब यूट्यूब संगीत खोज सकता है, एल्बम और कलाकारों की सूची बना सकता है, स्वचालित रूप से उत्पन्न की गई गीतसूची, एल्बम बजा सकता है और आपकी अपनी खुद की प्लेलिस्ट को एक साथ रखने में मदद करता है।</p>
|
||||
<p xml:lang="id">AudioTube dapat menelusuri YouTube Music, daftarkan album dan artis, putar daftar putar dan yang dibuat secara otomatis dan album, dan memungkinkan Anda untuk membuat daftar putar Anda sendiri.</p>
|
||||
<p xml:lang="it">AudioTube può eseguire ricerche su YouTube Music, elencare album e artisti, riprodurre scalette e album generati automaticamente e ti consente di creare la tua scaletta.</p>
|
||||
<p xml:lang="ka">AudioTube -ს შეუძლია მოძებნოს მუსიკა YouTube-ზე, გაჩვენოთ ალბომებისა და შემსრულებლების სია, დაუკრას დაგენერირებული დასაკრავი სიები, ალბომები და საშუალებას გაძლევთ, თქვენი დასაკრავი სია შექმნათ.</p>
|
||||
<p xml:lang="ko">AudioTube는 YouTube Music을 검색하고, 앨범과 아티스트를 표시하고, 자동 생성된 재생 목록, 앨범을 재생하고, 사용자 정의 재생 목록을 만들 수 있습니다.</p>
|
||||
<p xml:lang="nl">AudioTube kan in YouTube Music zoeken, een lijst maken van albums en artiesten, automatically gegenereerde afspeellijsten, albums afspelen en biedt u het samenstellen van uw eigen afspeellijst.</p>
|
||||
<p xml:lang="nn">Med AudioTube kan du søkja på YouTube Music, visa album og artistar, spela automatiske genererte spelelister og album samt laga eigne spelelister.</p>
|
||||
<p xml:lang="pl">AudioTube może przeszukiwać serwis YouTube Music, wypisać albumy i wykonawców, odtwarzać samoczynnie utworzone listy odtwarzania, albumy oraz umożliwia tworzenie własnych list odtwarzania.</p>
|
||||
<p xml:lang="pt">O AudioTube consegue pesquisar no YouTube Music, enumerar os álbuns e artistas, reproduzir listas geradas automaticamente, álbuns e permite-lhe reproduzir as suas próprias listas de reprodução.</p>
|
||||
<p xml:lang="pt-BR">O AudioTube pode pesquisar no YouTube Music, listar álbuns e artistas, rodar listas de reprodução geradas automaticamente, álbuns inteiros, e criar a sua própria lista de reprodução.</p>
|
||||
<p xml:lang="ru">AudioTube позволяет выполнять поиск в сервисе YouTube Music, просматривать списки найденных альбомов и исполнителей, проигрывать автоматически созданные списки воспроизведения и альбомы, а также использовать свои собственные списки воспроизведения.</p>
|
||||
<p xml:lang="sl">AudioTube lahko išče po YouTube Music, izdela sezname albumov in avtorjev, samodejno predvaja generirane sezname, albume in sestavlja vaše sezname predvajanja.</p>
|
||||
<p xml:lang="sv">AudioTube kan söka på YouTube Music, lista album och artister, spela upp automatiskt genererade spellistor, albums och låter dig sammanställa egna spellistor.</p>
|
||||
<p xml:lang="tr">AudioTube, YouTube Müzik'te arama yapabilir; albümleri, sanatçıları listeler; kendiliğinden oluşturulmuş çalma listelerini, albümleri çalar ve kendi çalma listenizi oluşturmanıza izin verir.</p>
|
||||
<p xml:lang="uk">AudioTube може виконувати пошук на YouTube Music, показувати списки альбомів та виконавців, відтворювати створені автоматично списки відтворення, альбоми та надає вам змогу створювати власні списки відворення.</p>
|
||||
<p xml:lang="x-test">xxAudioTube can search YouTube Music, list albums and artists, play automatically generated playlists, albums and allows to put your own playlist together.xx</p>
|
||||
<p xml:lang="zh-CN">AudioTube 可以搜索 YouTube Music 的内容,列出专辑和艺人,播放自动生成的播放列表,还可以自行制作播放列表。</p>
|
||||
</description>
|
||||
</component>
|
||||
@@ -1,5 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Name=AudioTube
|
||||
Name[ar]=تيوب الصوتي
|
||||
Name[az]=AudioTube
|
||||
Name[ca]=AudioTube
|
||||
Name[ca@valencia]=AudioTube
|
||||
Name[cs]=AudioTube
|
||||
@@ -10,20 +12,28 @@ Name[eu]=AudioTube
|
||||
Name[fi]=AudioTube
|
||||
Name[fr]=AudioTube
|
||||
Name[hi]=ओडियो-ट्यूब
|
||||
Name[id]=AudioTube
|
||||
Name[it]=AudioTube
|
||||
Name[ka]=AudioTube
|
||||
Name[ko]=AudioTube
|
||||
Name[nl]=AudioTube
|
||||
Name[nn]=AudioTube
|
||||
Name[pa]=ਆਡੀਓ-ਟਿਊਬ
|
||||
Name[pl]=AudioTube
|
||||
Name[pt]=AudioTube
|
||||
Name[pt_BR]=AudioTube
|
||||
Name[ro]=AudioTube
|
||||
Name[ru]=AudioTube
|
||||
Name[sk]=AudioTube
|
||||
Name[sl]=AudioTube
|
||||
Name[sv]=AudioTube
|
||||
Name[tr]=AudioTube
|
||||
Name[uk]=AudioTube
|
||||
Name[x-test]=xxAudioTubexx
|
||||
Name[zh_CN]=AudioTube
|
||||
Comment=YouTube Music client
|
||||
Comment[ar]=عميل يوتيوب ميوزيك
|
||||
Comment[az]=YouTube Musiqi müştərisi
|
||||
Comment[ca]=Client de música de YouTube
|
||||
Comment[ca@valencia]=Client de música de YouTube
|
||||
Comment[cs]=Hudební klient YouTube
|
||||
@@ -34,19 +44,25 @@ Comment[eu]=YouTube Music bezeroa
|
||||
Comment[fi]=YouTube Music -asiakas
|
||||
Comment[fr]=Client de musique sur Youtube
|
||||
Comment[hi]=यूट्यूब संगीत क्लाएंट
|
||||
Comment[id]=Klien YouTube Music
|
||||
Comment[it]=Client YouTube Music
|
||||
Comment[ka]=YouTube Music -ის კლიენტი
|
||||
Comment[ko]=YouTube Music 클라이언트
|
||||
Comment[nl]=Muziekclient van YouTube
|
||||
Comment[nn]=YouTube Music-klient
|
||||
Comment[pa]=ਯੂਟਿਊਬ ਸੰਗੀਤ ਕਲਾਈਂਟ
|
||||
Comment[pl]=Program do YouTube Music
|
||||
Comment[pt]=Cliente do YouTube Music
|
||||
Comment[pt_BR]=Cliente YouTube Music
|
||||
Comment[ro]=Client de muzică pentru YouTube
|
||||
Comment[ru]=Клиент для YouTube Music
|
||||
Comment[sk]=Hudobný klient YouTube
|
||||
Comment[sl]=Glasbeni odjemalec Youtube
|
||||
Comment[sv]=YouTube-musikprogram
|
||||
Comment[tr]=YouTube Müzik istemcisi
|
||||
Comment[uk]=Музичний клієнт YouTube
|
||||
Comment[x-test]=xxYouTube Music clientxx
|
||||
Comment[zh_CN]=YouTube Music 客户端
|
||||
Version=1.0
|
||||
Exec=audiotube
|
||||
Icon=org.kde.audiotube
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
SPDX-FileCopyrightText: 2021 Jonah Brüchert <[email protected]>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "org.kde.audiotube",
|
||||
"runtime": "org.kde.Platform",
|
||||
"runtime-version": "5.15",
|
||||
"runtime-version": "5.15-21.08",
|
||||
"sdk": "org.kde.Sdk",
|
||||
"command": "audiotube",
|
||||
"tags": ["nightly"],
|
||||
@@ -21,14 +21,14 @@
|
||||
],
|
||||
|
||||
"modules": [
|
||||
"flatpak/python3-youtube_dl.json",
|
||||
"flatpak/python3-yt-dlp.json",
|
||||
"flatpak/python3-ytmusicapi.json",
|
||||
{
|
||||
"name": "pybind11",
|
||||
"config-opts": ["-DPYBIND11_FINDPYTHON=ON", "-DPYBIND11_TEST=OFF"],
|
||||
"buildsystem": "cmake-ninja",
|
||||
"builddir": true,
|
||||
"sources": [ { "type": "git", "url": "https://github.com/pybind/pybind11", "tag": "v2.6.2" } ]
|
||||
"sources": [ { "type": "git", "url": "https://github.com/pybind/pybind11", "tag": "v2.9.1" } ]
|
||||
},
|
||||
{
|
||||
"name": "org.kde.audiotube",
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
SPDX-FileCopyrightText: 2021 Jonah Brüchert <[email protected]>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
@@ -1,3 +0,0 @@
|
||||
SPDX-FileCopyrightText: 2021 Mathis Brüchert <[email protected]>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
@@ -0,0 +1,240 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Zayed Al-Saidi <[email protected]>, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-12-22 16:43+0400\n"
|
||||
"Last-Translator: Zayed Al-Saidi <[email protected]>\n"
|
||||
"Language-Team: ar\n"
|
||||
"Language: ar\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
|
||||
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
||||
"X-Generator: Lokalize 21.12.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "زايد السعيدي"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "شغّل"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "اخلط"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "افتح في المتصفّح"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "الألبوم • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "المزيد"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "راديو"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "الفنّانون"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr "تشغيل الفيديو غير مدعوم حتى الآن. هل تريد تشغيل صوت فقط من \"%1\"؟"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "الألبومات"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "فردي"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "أغاني"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "الفيديوهات"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "حسنًا"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "ألغِ"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "المفضلة"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "أظهر الكلّ"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "الأغاني المفضّلة"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "الأكثر تشغيلا"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "الأغاني المشغلة"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "عُد"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "ابحث"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "تيوب الصوتي"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "المشغل الآن"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "صُفّ"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "الكلمات"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "أزل المسار"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "لا يوجد وسائط تعمل"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "قائمة غير معروفة من الأغاني"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "لا يوجد أي أغنية بعد"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "قائمة التشغيل"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "الفنّانون"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "قوائم التّشغيل"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "مجهول"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "اعثر على موسيقى على موسيقى يوتيوب"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "شغل التالي"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "أضف للطابور"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "أزل المفضلة"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "أضف للمفضلة"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "أضف إلى قائمة التّشغيل"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "شغل التالي"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "امسح"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "ألبث"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "وسع"
|
||||
@@ -0,0 +1,245 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Kheyyam Gojayev <[email protected]>, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-06-19 12:16+0400\n"
|
||||
"Last-Translator: Kheyyam <[email protected]>\n"
|
||||
"Language-Team: Azerbaijani <[email protected]>\n"
|
||||
"Language: az\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 22.04.2\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Xəyyam Qocayev"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Başladın"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Qarışıq"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "İfaçılar"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Video göstərilməsi hələlik dəstəklənmir. Siz yalnız \"%1\" videosunun səsini "
|
||||
"oynatmaq istəyirsiniz?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albomlar"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Musiqilər"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Mahnılar"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videolar"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OLDU"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "İmtina"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Süçilmişlər"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Hamısı göstərilsin"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Seçilmiş mahnılar"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Daha çox dinlənilən"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Oxudulan mahnılar"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Geriyə"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Axtarın"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "İndi səslənir"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Növbə"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Mahnını silin"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Media faylı oynadılmır"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Naməlum mahnı siyahısı"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Hələlik burada mahnılar yoxdur"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "Mahnı siyahıları"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "İfaçılar"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Mahnı siyahıları"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Bilinməyən"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Musiqini YouTube Musiqi-də tapın"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Sonrakını oxudun"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Süçilmişlər"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Add Favourite"
|
||||
msgstr "Süçilmişlər"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Mahnı siyahısına əlavə edin"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Sonrakını başladın"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Təmizləyin"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Fasilə"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Açmaq"
|
||||
@@ -0,0 +1,229 @@
|
||||
# Translation of audiotube.po to Catalan
|
||||
# Copyright (C) 2021-2022 This_file_is_part_of_KDE
|
||||
# This file is distributed under the license LGPL version 2.1 or
|
||||
# version 3 or later versions approved by the membership of KDE e.V.
|
||||
#
|
||||
# Antoni Bella Pérez <[email protected]>, 2021.
|
||||
# Josep M. Ferrer <[email protected]>, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-28 08:58+0100\n"
|
||||
"Last-Translator: Josep M. Ferrer <[email protected]>\n"
|
||||
"Language-Team: Catalan <[email protected]>\n"
|
||||
"Language: ca\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 20.12.0\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Antoni Bella"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Reprodueix"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Barreja"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Obre en el navegador"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Àlbum • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Més"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Ràdio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artista"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Encara no s'admet la reproducció de vídeo. Voleu reproduir només l'àudio de "
|
||||
"«%1»?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Àlbums"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Individuals"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Cançons"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Vídeos"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "D'acord"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Cancel·la"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Preferides"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Mostra-ho tot"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Cançons preferides"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Les més reproduïdes"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Cançons reproduïdes"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Enrere"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Cerca"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Ara s'està reproduint"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Cua"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Lletra"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Elimina la pista"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "No s'està reproduint cap suport"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Llista desconeguda de cançons"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Encara no hi ha cap cançó"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Llista de reproducció"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artistes"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Llistes de reproducció"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Desconeguda"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Cerca a la Música de Youtube"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Reprodueix el següent"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Afegeix a la cua"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Elimina de les preferides"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Afegeix a les preferides"
|
||||
@@ -0,0 +1,229 @@
|
||||
# Translation of audiotube.po to Catalan (Valencian)
|
||||
# Copyright (C) 2021-2022 This_file_is_part_of_KDE
|
||||
# This file is distributed under the license LGPL version 2.1 or
|
||||
# version 3 or later versions approved by the membership of KDE e.V.
|
||||
#
|
||||
# Antoni Bella Pérez <[email protected]>, 2021.
|
||||
# Josep M. Ferrer <[email protected]>, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-28 08:58+0100\n"
|
||||
"Last-Translator: Josep M. Ferrer <[email protected]>\n"
|
||||
"Language-Team: Catalan <[email protected]>\n"
|
||||
"Language: ca@valencia\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 20.12.0\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Antoni Bella"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Reproduïx"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Barreja"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Obri en el navegador"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Àlbum • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Més"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Ràdio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artista"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Encara no s'admet la reproducció de vídeo. Voleu reproduir només l'àudio de "
|
||||
"«%1»?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Àlbums"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Individuals"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Cançons"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Vídeos"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "D'acord"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Cancel·la"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Preferides"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Mostra-ho tot"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Cançons preferides"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Les més reproduïdes"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Cançons reproduïdes"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Arrere"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Busca"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Ara s'està reproduint"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Cua"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Lletra"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Elimina la pista"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "No s'està reproduint cap suport"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Llista desconeguda de cançons"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Encara no hi ha cap cançó"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Llista de reproducció"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artistes"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Llistes de reproducció"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Desconeguda"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Busca en la Música de Youtube"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Reproduïx el següent"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Afig a la cua"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Elimina de les preferides"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Afig a les preferides"
|
||||
@@ -0,0 +1,236 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# Vit Pelcak <[email protected]>, 2021, 2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-06-28 13:58+0200\n"
|
||||
"Last-Translator: Vit Pelcak <[email protected]>\n"
|
||||
"Language-Team: Czech <[email protected]>\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: Lokalize 22.04.2\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Vít Pelčák"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Přehrát"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Zamíchat"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Otevřít v prohlížeči"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Rádio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "Umělci"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Přehrávání videa ještě není podporováno. Chcete z \"%1\" přehrávat pouze "
|
||||
"zvuk?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Alba"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Samotné"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Písně"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videa"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Zrušit"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Oblíbené"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Zobrazit vše"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Oblíbené skladby"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Nejčastěji hrané"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Přehrané skladby"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Zpět"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Hledat"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Nyní přehrávám"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Fronta"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Odstranit skladbu"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Nepřehrává se žádné médium"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Neznámý seznam skladeb"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Zatím zde nejsou žádné skladby"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "Seznamy skladeb"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Umělci"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Seznamy skladeb"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Neznámý"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Najít hudbu na Hudba YouTube"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Přehrát následující"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Oblíbené"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Add Favourite"
|
||||
msgstr "Oblíbené"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Přidat do seznamu skladeb"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Přehrát následující"
|
||||
@@ -0,0 +1,250 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# Burkhard Lück <[email protected]>, 2021.
|
||||
# Frederik Schwarzer <[email protected]>, 2021, 2022.
|
||||
# Frank Steinmetzger <[email protected]>, 2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-10 20:16+0100\n"
|
||||
"Last-Translator: Frank Steinmetzger <[email protected]>\n"
|
||||
"Language-Team: German <[email protected]>\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: Lokalize 22.08.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Deutsches KDE-Übersetzerteam"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Wiedergabe"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Zufällig"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "In Browser öffnen"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "Interpreten"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Die Video-Wiedergabe wird noch nicht unterstützt. Möchten Sie nur die "
|
||||
"Audiospur von „%1“ abspielen?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Alben"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Singles"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Songs"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videos"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Abbrechen"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Favoriten"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Alle anzeigen"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Lieblingsstücke"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Am meisten abgespielt"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Abgespielte Stücke"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Zurück"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Suchen"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Aktueller Titel"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Warteschlange"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Stück entfernen"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Es werden keine Medien wiedergegeben"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Unbekannte Liste von Liedern"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Bisher keine Lieder hier"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "Wiedergabelisten"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Interpreten"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Wiedergabelisten"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Unbekannt"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Musik auf YouTube suchen"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Nächste Wiedergabe"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Favoriten"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Add Favourite"
|
||||
msgstr "Favoriten"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Zur Wiedergabeliste hinzufügen"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Nächste Wiedergabe"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Löschen"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Pause"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Erweitern"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Nur Audio abspielen"
|
||||
@@ -0,0 +1,248 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Steve Allewell <[email protected]>, 2021, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-26 12:33+0000\n"
|
||||
"Last-Translator: Steve Allewell <[email protected]>\n"
|
||||
"Language-Team: British English <[email protected]>\n"
|
||||
"Language: en_GB\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 21.12.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Steve Allewell"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Play"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Shuffle"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Open in Browser"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "Artists"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albums"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Singles"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Songs"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videos"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Cancel"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Favourites"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Show All"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Favourite Songs"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Most played"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Played Songs"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Back"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Search"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Now Playing"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Queue"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Lyrics"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Remove Track"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "No media playing"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Unknown list of songs"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "No songs here yet"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "Playlists"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artists"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Playlists"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Unknown"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Find music on YouTube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Play Next"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Favourites"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Add Favourite"
|
||||
msgstr "Favourites"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Add to Playlist"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Play next"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Clear"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Pause"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Expand"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Play only Audio"
|
||||
@@ -0,0 +1,246 @@
|
||||
# Spanish translations for audiotube.po package.
|
||||
# Copyright (C) 2021 This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Automatically generated, 2021.
|
||||
# Eloy Cuadra <[email protected]>, 2021, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-28 05:14+0100\n"
|
||||
"Last-Translator: Eloy Cuadra <[email protected]>\n"
|
||||
"Language-Team: Spanish <[email protected]>\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: Lokalize 22.11.80\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Eloy Cuadra"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Reproducir"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Desordenar"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Abrir en el navegador"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Álbum • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Más"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artista"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"La reproducción de vídeo aún no está permitida. ¿Desea reproducir solo el "
|
||||
"sonido de «%1»?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Álbumes"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Sencillos"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Canciones"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Vídeos"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "Aceptar"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Favoritas"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Mostrar todas"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Canciones favoritas"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Más reproducidas"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Canciones reproducidas"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Volver"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Reproduciendo"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Cola"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Letra"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Eliminar pista"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Ningún medio en reproducción"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Lista de canciones desconocida"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Todavía no contiene canciones"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Lista de reproducción"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artistas"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Listas de reproducción"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Desconocido"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Encuentre música en YouTube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Reproducir siguiente"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Añadir a la cola"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Eliminar favorita"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Añadir favorita"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Añadir a la lista de reproducción"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Reproducir siguiente"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Borrar todo"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Pausar"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Expandir"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Reproducir solo el sonido"
|
||||
@@ -0,0 +1,247 @@
|
||||
# Translation for audiotube.po to Euskara/Basque (eu).
|
||||
# Copyright (C) 2021-2022 This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# KDE euskaratzeko proiektuko arduraduna <[email protected]>.
|
||||
#
|
||||
# Translators:
|
||||
# Iñigo Salvador Azurmendi <[email protected]>, 2021, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-29 05:34+0100\n"
|
||||
"Last-Translator: Iñigo Salvador Azurmendi <[email protected]>\n"
|
||||
"Language-Team: Basque <[email protected]>\n"
|
||||
"Language: eu\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 22.08.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Iñigo Salvador Azurmendi"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Jo"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Nahastu"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Ireki arakatzailean"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Albuma • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Gehiago"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Irratia"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artista"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Oraindik ez dago bideoa atzera jotzeko euskarririk. «%1»(r)en audioa "
|
||||
"bakarrik jo nahi duzu?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albumak"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Banakoa"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Abestiak"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Bideoak"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "Ados"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Utzi"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Gogokoak"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Erakutsi denak"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Gogoko abestiak"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Gehien jotakoa"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Jotako abestiak"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Atzera"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Bilatu"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Orain jotzen"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Ilara"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Hitzak"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Kendu pista"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Ez da euskarririk jotzen ari"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Abesti zerrenda ezezaguna"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Hemen oraindik ez dago abestirik"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Jotze-zerrenda"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artistak"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Jotze-zerrendak"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Ezezaguna"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Aurkitu musika «Youtube Music»en"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Jo hurrengoa"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Gehitu ilaran"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Kendu gogokoa"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Gehitu gogokoa"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Gehitu jotze-zerrendara"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Jo hurrengoa"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Garbitu"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Eten"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Zabaldu"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Audio bakarrik jo"
|
||||
@@ -0,0 +1,247 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# Tommi Nieminen <[email protected]>, 2021, 2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-10-24 07:57+0300\n"
|
||||
"Last-Translator: Tommi Nieminen <[email protected]>\n"
|
||||
"Language-Team: Finnish <[email protected]>\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: Lokalize 20.12.0\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Tommi Nieminen"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Toista"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Sekoita"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Avaa selaimeen"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "Artistit"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Videotoistoa ei vielä tueta. Haluatko toistaa videosta ”%1” vain äänen?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albumit"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Singlet"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Kappaleet"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videot"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Peru"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Suosikit"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Näytä kaikki"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Suosikkikappaleet"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Soitetuimmat"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Soitetut kappaleet"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Takaisin"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Etsi"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Nyt soi"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Jono"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Poista raita"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Mitään ei toisteta"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Tuntematon kappaleluettelo"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Ei vielä kappaleita"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "Soittolistat"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artistit"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Soittolistat"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Tuntematon"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Etsi musiikkia Youtube Musicista"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Toista seuraava"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Suosikit"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Add Favourite"
|
||||
msgstr "Suosikit"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Lisää soittolistaan"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Toista seuraava"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Tyhjennä"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Tauko"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Laajenna"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Toista vain ääni"
|
||||
@@ -0,0 +1,241 @@
|
||||
# Xavier Besnard <[email protected]>, 2021, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-12-04 08:33+0100\n"
|
||||
"Last-Translator: Xavier Besnard <[email protected]>\n"
|
||||
"Language-Team: French <[email protected]>\n"
|
||||
"Language: fr\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 22.11.90\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Xavier Besnard"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Lire"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Mélanger"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Ouvrir dans un navigateur"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Album • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Et plus encore"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artiste"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"La lecture de vidéos n'est pas encore prise en charge. Voulez-vous vraiment "
|
||||
"lire uniquement l'audio de « %1 » ?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albums"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Titres uniques"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Chansons"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Vidéos"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "Ok"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Favoris"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Tout afficher"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Titres favoris"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Les plus lus"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Titres lus"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "En arrière"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Rechercher"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "En cours de lecture"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Mettre en file d'attente"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Paroles"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Supprimer une piste"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Aucun média en lecture"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Liste inconnue de titres"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Aucun titre ici encore"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Liste de lecture"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artistes"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Listes de lecture"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Inconnu"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Rechercher de la musique sur « YouTube Music »"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Lire le suivant"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Ajouter à la file de lecture"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Supprimer un favori"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Ajouter un favori"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Ajouter à la liste de lecture"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Lire le suivant"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Effacer"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Pause"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Développer"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Ne lire que l'audio"
|
||||
@@ -0,0 +1,246 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Raghavendra Kamath <[email protected]>, 2021.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2021-09-17 20:09+0530\n"
|
||||
"Last-Translator: Raghavendra Kamath <[email protected]>\n"
|
||||
"Language-Team: kde-hindi\n"
|
||||
"Language: hi\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 21.08.1\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "राघवेंद्र कामत"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "बजाएँ"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "फेंटें"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "रेडियो"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "कलाकार"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"वीडियो चलाना अभी तक समर्थित नहीं है। क्या आप केवल \"%1\" का ध्वनी चलाना चाहते हैं?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "एल्बम्स"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "एक गीत"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "गीत"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "वीडियो"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "खोजें"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "ओडियो-ट्यूब"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "No media playing"
|
||||
msgid "Now Playing"
|
||||
msgstr "कोई मीडिया नहीं बजा रहा है"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "गाना हटाएँ"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "कोई मीडिया नहीं बजा रहा है"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "गीत-सूचीयाँ"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "कलाकार"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "गीत-सूचीयाँ"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "अज्ञात"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "यूट्यूब संगीत पर संगीत ढूंढें"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "अगला बजाएँ"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "गीत-सूची में जोड़ें"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "अगला बजाएँ"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "साफ करें"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "रोकें"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "विस्तृत करें"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "केवल ध्वनी चलाएँ"
|
||||
@@ -0,0 +1,232 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# Linerly <[email protected]>, 2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-12-21 11:44+0700\n"
|
||||
"Last-Translator: Linerly <[email protected]>\n"
|
||||
"Language-Team: Indonesian <[email protected]>\n"
|
||||
"Language: id\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 22.08.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Linerly"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Putar"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Acak"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Buka di Peramban"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Album • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Lainnya"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artis"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Pemutaran video belum didukung. Apakah Anda ingin memutar audionya dari "
|
||||
"\"%1\" saja?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Album"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Single"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Lagu"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Video"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "Oke"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Batalkan"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Favorit"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Tampilkan Semua"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Lagu Favorit"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Paling banyak diputar"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Lagu yang telah diputar"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Kembali"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Cari"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Sekarang Diputarkan"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Antrean"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Lirik"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Hapus Trek"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Tidak ada media yang diputarkan"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Daftar lagu yang tidak diketahui"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Belum ada lagu di sini"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Daftar Putar"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artis"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Daftar Putar"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Tidak diketahui"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Cari musik di YouTube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Putar Berikutnya"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Tambahkan ke antrean"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Hapus Favorit"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Tambahkan Favorit"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Tambahkan ke Daftar Putar"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Putar berikutnya"
|
||||
@@ -0,0 +1,244 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# Vincenzo Reale <[email protected]>, 2021, 2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-28 14:06+0100\n"
|
||||
"Last-Translator: Vincenzo Reale <[email protected]>\n"
|
||||
"Language-Team: Italian <[email protected]>\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"
|
||||
"X-Generator: Lokalize 22.08.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Vincenzo Reale"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Riproduci"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Mescola"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Apri nel browser"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Album • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Altro"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artista"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"La riproduzione dei video non è ancora supportata. Vuoi riprodurre solo "
|
||||
"l'audio di «%1»?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Album"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Singoli"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Brani"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Video"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Annulla"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Preferiti"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Mostra tutto"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Brani preferiti"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Più riprodotti"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Brani riprodotti"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Indietro"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Cerca"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "In riproduzione"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Coda"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Testi"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Rimuovi traccia"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Nessun supporto in riproduzione"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Elenco di brani sconosciuto"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Non c'è ancora alcun brano"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Scaletta"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artisti"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Scalette"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Sconosciuto"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Trova musica su Youtube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Riproduci successivo"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Aggiungi alla coda"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Rimuovi preferito"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Aggiungi preferito"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Aggiungi alla scaletta"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Riproduci successivo"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Pulisci"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Pausa"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Espandi"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Riproduci solo l'audio"
|
||||
@@ -0,0 +1,221 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2021-05-29 19:15-0700\n"
|
||||
"Last-Translator: Japanese KDE translation team <[email protected]>\n"
|
||||
"Language-Team: Japanese <[email protected]>\n"
|
||||
"Language: ja\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-Accelerator-Marker: &\n"
|
||||
"X-Text-Markup: kde4\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr ""
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,232 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-29 06:58+0100\n"
|
||||
"Last-Translator: Temuri Doghonadze <[email protected]>\n"
|
||||
"Language-Team: Georgian <[email protected]>\n"
|
||||
"Language: ka\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 3.2\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Temuri Doghonadze"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "დაკვრა"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "შემთხვევით"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "ბრაუზერში გახსნა"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "ალბომი • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "მეტი"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "რადიო"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "შემსრულებელი"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"ვიდეოს დაკვრა ჯერ მხარდაჭერილი არაა. გნებავთ \"%1\"-ის მხოლოდ ხმა დავუკრა?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "ალბომები"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "სინგლები"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "სიმღერები"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "ვიდეო"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "კარგი"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "გაუქმენა"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "რჩეულები"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "ყველას ჩვენება"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "რჩეული სიმღერები"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "ხშირად დაკრულები"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "დაკრული სიმღერები"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "უკან"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "ძებნა"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "მიმდინარეობს დაკვრა"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "რიგი"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "ლირიკა"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "აუდიობილიკის წაშლა"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "არაფერს ვუკრავ"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "უცნობი სიმღერების სია"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "აქ ჯერ სიმღერები არაა"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "დასაკრავი სია"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "შემსრულებლები"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "დასაკრავი სიები"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "უცნობი"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "იპოვეთ მუსიკა YouTube Music-ზე"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "შემდეგის დაკვრა"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "რიგში ჩამატება"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "რჩეულის წაშლა"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "რჩეულის დამატება"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "დასაკრავი სიაში დამატება"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "შემდეგის დაკვრა"
|
||||
@@ -0,0 +1,246 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# Shinjo Park <[email protected]>, 2021, 2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-10-03 14:20+0200\n"
|
||||
"Last-Translator: Shinjo Park <[email protected]>\n"
|
||||
"Language-Team: Korean <[email protected]>\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"
|
||||
"X-Generator: Lokalize 21.12.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "박신조"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "재생"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "무순서 재생"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "브라우저로 열기"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "라디오"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "아티스트"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr "비디오 재생은 지원하지 않습니다. \"%1\"의 오디오만 재생하시겠습니까?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "앨범"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "싱글"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "곡"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "비디오"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "확인"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "취소"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "책갈피"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "모두 표시"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "책갈피에 등록된 노래"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "가장 많이 재생됨"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "재생한 노래"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "뒤로"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "검색"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "지금 재생 중"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "대기열에 추가"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "트랙 삭제"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "재생 중인 미디어 없음"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "알 수 없는 노래 목록"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "목록에 등록된 곡 없음"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "재생 목록"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "아티스트"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "재생 목록"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "알 수 없음"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "YouTube Music에서 음악 찾기"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "다음 재생"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Remove Favourite"
|
||||
msgstr "책갈피"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Add Favourite"
|
||||
msgstr "책갈피"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "재생 목록에 추가"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "다음 재생"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "지우기"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "일시 정지"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "확장"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "오디오만 재생"
|
||||
@@ -0,0 +1,244 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Freek de Kruijf <[email protected]>, 2021, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-28 11:10+0100\n"
|
||||
"Last-Translator: Freek de Kruijf <[email protected]>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: nl\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 22.08.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Freek de Kruijf - 2021 t/m 2022"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Afspelen"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Willekeurig afspelen"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "In browser openen"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Album • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Meer"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artiest"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Afspelen van video wordt nog niet ondersteund. Wilt u alleen het geluid van "
|
||||
"\"%1\" afspelen?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albums"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Enkelvoudige"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Songs"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Video's"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Annuleren"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Favorieten"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Alles tonen"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Favoriete songs"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Meest afgespeeld"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Afgespeelde songs"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Terug"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Zoeken"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Speelt nu"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Wachtrij"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Liedteksten"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Track verwijderen"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Er speelt geen medium"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Onbekende lijst met songs"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Er zijn hier nog geen songs"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Afspeellijst"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artiesten"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Afspeellijsten"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Onbekend"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Muziek zoeken op YouTube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Volgende afspelen"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Aan wachtrij toevoegen"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Favoriet verwijderen"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Favoriet toevoegen"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Aan afspeellijst toevoegen"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Volgende afspelen"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Wissen"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Pauzeren"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Uitbreiden"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Alleen geluid afspelen"
|
||||
@@ -0,0 +1,227 @@
|
||||
# Translation of audiotube to Norwegian Nynorsk
|
||||
#
|
||||
# Øystein Steffensen-Alværvik <[email protected]>, 2022.
|
||||
# Karl Ove Hufthammer <[email protected]>, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-12 00:49+0000\n"
|
||||
"PO-Revision-Date: 2022-09-11 19:45+0200\n"
|
||||
"Last-Translator: Karl Ove Hufthammer <[email protected]>\n"
|
||||
"Language-Team: Norwegian Nynorsk <[email protected]>\n"
|
||||
"Language: nn\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 22.08.1\n"
|
||||
"X-Environment: kde\n"
|
||||
"X-Accelerator-Marker: &\n"
|
||||
"X-Text-Markup: kde4\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Øystein Steffensen-Alværvik"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Spel av"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Stokk om"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Opna i nettlesar"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr "Videoavspeling er endå ikkje støtta. Vil du spela av lyden til «%1»?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Album"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Singelplater"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Songar"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videoar"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Avbryt"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Favorittar"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:181
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Vis alle"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Favorittsongar"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:171
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Oftast avspela"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:186
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Avspela songar"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Tilbake"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Søk"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Spelar no"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Kø"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Fjern spor"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Inkje medium vert spela"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Ukjend songliste"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Ingen songar enno"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artistar"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Spelelister"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Ukjend"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Søk etter musikk på YouTube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:26
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Spel som neste"
|
||||
|
||||
#: contents/ui/SongMenu.qml:32
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:39
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:39
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,245 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# A S Alam <[email protected]>, 2021, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-01-01 09:11-0800\n"
|
||||
"Last-Translator: A S Alam <[email protected]>\n"
|
||||
"Language-Team: Punjabi <[email protected]>\n"
|
||||
"Language: pa\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 21.04.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "ਅਮਨਪਰੀਤ ਸਿੰਘ ਆਲਮ ੨੦੨੧"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "alam yellow @ gmail.com"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "ਚਲਾਓ"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "ਰਲਵੇਂ"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "ਰੇਡੀਓ"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "ਕਲਾਕਾਰ"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr "ਵਿਡੀਓ ਪਲੇਅਬੈਕ ਹਾਲੇ ਸਹਾਇਕ ਨਹੀਂ ਹੈ। ਕੀ ਤੁਸੀਂ \"%1\" ਦਾ ਆਡੀਓ ਹੀ ਚਲਾਉਣਾ ਚਾਹੋਗੇ?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "ਐਲਬਮਾਂ"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "ਇਕੱਲੇ"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "ਗੀਤ"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "ਵਿਡੀਓ"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "ਠੀਕ ਹੈ"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "ਰੱਦ ਕਰੋ"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "ਖੋਜੋ"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "ਆਡੀਓ-ਟਿਊਬ"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "No media playing"
|
||||
msgid "Now Playing"
|
||||
msgstr "ਕੋਈ ਮੀਡੀਆ ਨਹੀਂ ਚੱਲਦਾ"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "ਟਰੈਕ ਨੂੰ ਹਟਾਓ"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "ਕੋਈ ਮੀਡੀਆ ਨਹੀਂ ਚੱਲਦਾ"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "ਪਲੇਅਲਿਸਟਾਂ"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "ਕਲਾਕਾਰ"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "ਪਲੇਅਲਿਸਟਾਂ"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "ਅਣਪਛਾਤਾ"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "ਯੂਟਿਊਬ ਸੰਗੀਤ ਉੱਤੇ ਸੰਗੀਤ ਲੱਭੋ"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "ਅਗਲਾ ਚਲਾਓ"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "ਪਲੇਅਲਿਸਟ ਵਿੱਚ ਜੋੜੋ"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "ਅਗਲਾ ਚਲਾਓ"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "ਮਿਟਾਓ"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "ਵਿਰਾਮ"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "ਫੈਲਾਓ"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "ਸਿਰਫ਼ ਆਡੀਓ ਹੀ ਚਲਾਓ"
|
||||
@@ -0,0 +1,250 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Łukasz Wojniłowicz <[email protected]>, 2021, 2022.
|
||||
# Ignacy Kajdan <[email protected]>, 2021.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-10-18 18:06+0200\n"
|
||||
"Last-Translator: Łukasz Wojniłowicz <[email protected]>\n"
|
||||
"Language-Team: Polish <[email protected]>\n"
|
||||
"Language: pl\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%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2);\n"
|
||||
"X-Generator: Lokalize 22.08.1\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Łukasz Wojniłowicz, Ignacy Kajdan"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected], [email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Odtwórz"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Wymieszaj"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Otwórz w przeglądarce"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "Wykonawcy"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Odtwarzanie wideo nie jest jeszcze obsługiwane. Czy odtworzyć tylko dźwięk z "
|
||||
"„%1”?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albumy"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Single"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Piosenki"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Filmy"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Anuluj"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Ulubione"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Pokaż wszystkie"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Ulubione utwory"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Najczęściej odtwarzane"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Odtwarzane utwory"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Wstecz"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Szukaj"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Teraz odtwarzany"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Kolejka"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Usuń utwór"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Nic nie jest odtwarzane"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Nieznana lista utworów"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Jeszcze nie ma tutaj utworów"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "Listy odtwarzania"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Wykonawcy"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Listy odtwarzania"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Nieznany"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Znajdź muzykę w serwisie YouTube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Odtwórz następny"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Ulubione"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Add Favourite"
|
||||
msgstr "Ulubione"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Dodaj do listy odtwarzania"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Odtwórz następny"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Wyczyść"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Wstrzymaj"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Rozwiń"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Odtwórz tylko dźwięk"
|
||||
@@ -0,0 +1,228 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-28 18:35+0000\n"
|
||||
"Last-Translator: José Nuno Coelho Pires <[email protected]>\n"
|
||||
"Language-Team: Portuguese <[email protected]>\n"
|
||||
"Language: pt\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-POFile-SpellExtra: Singles AudioTube YouTube Music\n"
|
||||
"X-POFile-IgnoreConsistency: Singles\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "José Nuno Pires"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Reproduzir"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Baralhar"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Abrir no Navegador"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Álbum • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Mais"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Rádio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artista"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"A reprodução de vídeos ainda não é suportada. Deseja reproduzir apenas o "
|
||||
"áudio de \"%1\"?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Álbuns"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "'Singles'"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Músicas"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Vídeos"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Favoritos"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Mostrar Tudo"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Músicas Favoritas"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Mais Tocadas"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Músicas Tocadas"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Recuar"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Procurar"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Agora a Ouvir"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Fila"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Letras Musicais"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Remover a Faixa"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Nada em reprodução"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Lista de músicas desconhecida"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Ainda sem músicas aqui"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Lista de Reprodução"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artistas"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Listas de Reprodução"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Desconhecido"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Procurar música no YouTube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Reproduzir o Seguinte"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Adicionar à fila"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Remover o Favorito"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Adicionar aos Favoritos"
|
||||
@@ -0,0 +1,245 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Luiz Fernando Ranghetti <[email protected]>, 2021, 2022.
|
||||
# Thiago Masato Costa Sueto <[email protected]>, 2021.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-12-20 10:48-0300\n"
|
||||
"Last-Translator: Luiz Fernando Ranghetti <[email protected]>\n"
|
||||
"Language-Team: Portuguese <[email protected]>\n"
|
||||
"Language: pt_BR\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 21.12.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Luiz Fernando Ranghetti"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Reproduzir"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Embaralhar"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Abrir no navegador"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Álbum • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Mais"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Rádio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artista"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"A reprodução de vídeos ainda não é suportada. Deseja reproduzir apenas o "
|
||||
"áudio de \"%1\"?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Álbuns"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Singles"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Músicas"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Vídeos"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Favoritas"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Mostrar tudo"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Músicas favoritas"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Mais reproduzidas"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Músicas reproduzidas"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Voltar"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Pesquisar"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Reproduzindo agora"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Fila"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Letras"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Remover faixa"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Nenhuma mídia em reprodução"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Lista de músicas desconhecida"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Nenhuma música ainda"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Lista de músicas"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artistas"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Listas de músicas"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Desconhecido"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Encontre músicas no YouTube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Reproduzir próxima"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Adicionar à fila"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Remover das favoritas"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Adicionar favorita"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Adicionar à lista de reprodução"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Reproduzir próxima"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Limpar"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Pausar"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Expandir"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Reproduzir apenas áudio"
|
||||
@@ -0,0 +1,232 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Alexander Yavorsky <[email protected]>, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-12-27 10:21+0300\n"
|
||||
"Last-Translator: Alexander Yavorsky <[email protected]>\n"
|
||||
"Language-Team: Russian <[email protected]>\n"
|
||||
"Language: ru\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n"
|
||||
"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Lokalize 21.08.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Александр Яворский, Павел Чернышов"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected], [email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Воспроизвести"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Перемешать"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Открыть в браузере"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Альбом • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Дополнительно"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Радио"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Исполнитель"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Воспроизведение видео пока не поддерживается. Воспроизвести звук трека «%1»?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Альбомы"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Синглы"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Треки"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Видеозаписи"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "ОК"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Отмена"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Избранное"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Показать все"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Избранные треки"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Часто воспроизводимые"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Воспроизведённые треки"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Назад"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Поиск"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Текущий трек"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Очередь воспроизведения"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Текст песни"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Удалить дорожку"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Ничего не воспроизводится"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Неизвестный список треков"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Пока нет ни одного трека"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Список воспроизведения"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Исполнители"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Списки воспроизведения"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Неизвестный тип"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Найти музыку в YouTube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Воспроизвести следующим"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Добавить в очередь воспроизведения"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Убрать из избранного"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Добавить в избранное"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Очистить"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Приостановить"
|
||||
@@ -0,0 +1,238 @@
|
||||
# translation of audiotube.po Slovak
|
||||
# Roman Paholik <[email protected]>, 2021, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-04-07 18:01+0200\n"
|
||||
"Last-Translator: Roman Paholik <[email protected]>\n"
|
||||
"Language-Team: Slovak <[email protected]>\n"
|
||||
"Language: sk\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Lokalize 21.12.3\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Roman Paholík"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Prehrať"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Zamiešať"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Rádio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "Interpreti"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albumy"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Samotné"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videá"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Zrušiť"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Hľadať"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "No media playing"
|
||||
msgid "Now Playing"
|
||||
msgstr "Neprehráva sa žiadne médium"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Neprehráva sa žiadne médium"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "Zoznamy skladieb"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Interpreti"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Zoznamy skladieb"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Neznáme"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Play"
|
||||
msgid "Play Next"
|
||||
msgstr "Prehrať"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Pridať do zoznamu skladieb"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Vyčistiť"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Pozastaviť"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Rozvinúť"
|
||||
@@ -0,0 +1,243 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Matjaž Jeran <[email protected]>, 2021, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-29 07:45+0100\n"
|
||||
"Last-Translator: Matjaž Jeran <[email protected]>\n"
|
||||
"Language-Team: Slovenian <[email protected]>\n"
|
||||
"Language: sl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Lokalize 22.08.3\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n"
|
||||
"%100==4 ? 3 : 0);\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Matjaž Jeran"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Predvajaj"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Premešaj"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Odpri v brskalniku"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Album • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Več"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Avtor"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr "Video playback še ni podprt. Ali želite predvajati samo zvok \"%1\"?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albumi"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Singli"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Glasba"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videposnetki"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "V redu"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Prekliči"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Priljubljene"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Prikaži vse"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Priljubljene pesmi"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Največkrat predvajane"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Predvajane pesmi"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Nazaj"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Išči"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Pravkar predvajano"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Čakalna vrsta"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Besedilo"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Odstrani sled"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Niče se ne predvaja"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Neznan seznam pesmi"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Tu še ni nobene pesmi"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Seznam predvajanja"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Avtorji"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Seznami predvajanja"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Neznano"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Najdi glasbo na Youtube Music"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Predvajaj naslednjo"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Dodaj v v čakalno vrsto"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Odstrani priljubljenega"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Dodaj priljubljenega"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Dodaj v seznam predvajanja"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Predvajaj naslednjo"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Očisti"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Premor"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Razširi"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Predvajaj samo zvok"
|
||||
@@ -0,0 +1,246 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Stefan Asserhäll <[email protected]>, 2021, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-09-24 14:57+0200\n"
|
||||
"Last-Translator: Stefan Asserhäll <[email protected]>\n"
|
||||
"Language-Team: Swedish <[email protected]>\n"
|
||||
"Language: sv\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 20.08.1\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Stefan Asserhäll"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Spela"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Blanda"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Öppna i webbläsare"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Artists"
|
||||
msgid "Artist"
|
||||
msgstr "Artister"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr "Videouppspelning stöds inte ännu. Vill du bara spela ljudet på \"%1\"?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Album"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Singlar"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Låtar"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videor"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "Ok"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Avbryt"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Favoriter"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Visa alla"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Favoritlåtar"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Mest spelade"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Spelade låtar"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Bakåt"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Sök"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Spelar nu"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Köa"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Ta bort spår"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Inga media spelar"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Okänd låtlista"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Inga låtar här ännu"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Playlists"
|
||||
msgid "Playlist"
|
||||
msgstr "Spellistor"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artister"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Spellistor"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Okänd"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Sök efter musik på YouTube musik"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Spela nästa"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Favoriter"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, fuzzy, kde-format
|
||||
#| msgid "Favourites"
|
||||
msgid "Add Favourite"
|
||||
msgstr "Favoriter"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Lägg till i spellista"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Spela nästa"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Rensa"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Paus"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Expandera"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Spela bara ljud"
|
||||
@@ -0,0 +1,241 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
#
|
||||
# Emir SARI <[email protected]>, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-28 18:46+0300\n"
|
||||
"Last-Translator: Emir SARI <[email protected]>\n"
|
||||
"Language-Team: Turkish <[email protected]>\n"
|
||||
"Language: tr\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 22.08.3\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Emir SARI"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Çal"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Karıştır"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Tarayıcıda Aç"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Albüm • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Daha Fazla"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radyo"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Sanatçı"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Video oynatımı henüz desteklenmiyor. \"%1\" videosunun yalnızca sesinin "
|
||||
"çalınmasını ister misiniz?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albümler"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Tekliler"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Şarkılar"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videolar"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "Tamam"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "İptal"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Beğeniler"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Tümünü Göster"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Beğenilen Şarkılar"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "En Çok Çalınanlar"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Çalınan Şarkılar"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Geri"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Ara"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Şimdi Çalınıyor"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Kuyruk"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Şarkı Sözleri"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Parçayı Kaldır"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Ortam çalmıyor"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Bilinmeyen şarkılar listesi"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Burada henüz şarkı yok"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Çalma Listesi"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Sanatçılar"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Çalma Listeleri"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Bilinmiyor"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "YouTube Müzik'te müzik bul"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Sonrakini Çal"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Kuyruğa ekle"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Beğenilerden Kaldır"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Beğenilere Ekle"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Çalma Listesine Ekle"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Sonrakini çal"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Temizle"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Duraklat"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Genişlet"
|
||||
@@ -0,0 +1,245 @@
|
||||
# Copyright (C) YEAR This file is copyright:
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
#
|
||||
# Yuri Chornoivan <[email protected]>, 2021, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-11-28 20:43+0200\n"
|
||||
"Last-Translator: Fracture dept <[email protected]>\n"
|
||||
"Language-Team: Ukrainian <[email protected]>\n"
|
||||
"Language: uk\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n"
|
||||
"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Lokalize 20.12.0\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Юрій Чорноіван"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Відтворити"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Перемішати"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Відкрити у переглядачі"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Альбом • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Більше"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Радіо"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Виконавець"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Підтримки відтворення відео ще не передбачено. Хочете, щоб було відтворено "
|
||||
"лише звукову частину «%1»?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Альбоми"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Одинарні"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Пісні"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Відео"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "Гаразд"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Скасувати"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Улюблені"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Показати всі"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "Улюблені композиції"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Часто слухали"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Відтворені композиції"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "Назад"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Пошук"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "Зараз відтворюємо"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "Додати до черги"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr "Текст"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Вилучити композицію"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Відтворення не відбувається"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Невідомий список композицій"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Тут ще немає композицій"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Список відтворення"
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Виконавці"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Списки відтворення"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Невідомий"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "Шукати музику на сайті «Музика Youtube»"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Відтворити наступну"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Додати до черги"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Вилучити з улюблених"
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Додати до улюблених"
|
||||
|
||||
#~ msgid "Add to Playlist"
|
||||
#~ msgstr "Додати до списку відтворення"
|
||||
|
||||
#~ msgid "Play next"
|
||||
#~ msgstr "Відтворити наступну"
|
||||
|
||||
#~ msgid "Clear"
|
||||
#~ msgstr "Спорожнити"
|
||||
|
||||
#~ msgid "Pause"
|
||||
#~ msgstr "Призупинити"
|
||||
|
||||
#~ msgid "Expand"
|
||||
#~ msgstr "Розгорнути"
|
||||
|
||||
#~ msgid "Play only Audio"
|
||||
#~ msgstr "Відтворити лише звук"
|
||||
@@ -0,0 +1,224 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: kdeorg\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-12-24 11:42\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Chinese Simplified\n"
|
||||
"Language: zh_CN\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"
|
||||
"X-Crowdin-Project: kdeorg\n"
|
||||
"X-Crowdin-Project-ID: 269464\n"
|
||||
"X-Crowdin-Language: zh-CN\n"
|
||||
"X-Crowdin-File: /kf5-trunk/messages/audiotube/audiotube.pot\n"
|
||||
"X-Crowdin-File-ID: 25474\n"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Qi Binye, Tyson Tan"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected], [email protected]"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "播放"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "随机播放"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "在浏览器中打开"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "电台"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr "视频播放尚未被支持。您想要只播放“%1”中的音频吗?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "专辑"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "单曲"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "曲目"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "视频"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "确定"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "取消"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "收藏夹"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "显示全部"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr "收藏的歌曲"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "最常播放"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "已播放歌曲"
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr "返回"
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "搜索"
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr "正在播放"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr "播放队列"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "移除曲目"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "没有正在播放的媒体"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "未知歌曲列表"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "此处无歌曲"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "艺人"
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "播放列表"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr "查找 YouTube Music 中的音乐"
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "播放下一首"
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,225 @@
|
||||
# Chinese translations for audiotube package
|
||||
# audiotube 套件的正體中文翻譯.
|
||||
# Copyright (C) 2022 This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# Automatically generated, 2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2022-12-24 00:52+0000\n"
|
||||
"PO-Revision-Date: 2022-05-30 00:47+0000\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: zh_TW\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"
|
||||
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr ""
|
||||
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:22 contents/ui/PlaylistPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:29 contents/ui/ArtistPage.qml:32
|
||||
#: contents/ui/PlaylistPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:37 contents/ui/ArtistPage.qml:39
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:44
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/AlbumPage.qml:87 contents/ui/ArtistPage.qml:125
|
||||
#: contents/ui/PlaybackHistory.qml:72 contents/ui/PlaylistPage.qml:89
|
||||
#: contents/ui/SearchPage.qml:128
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:46
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:68 contents/ui/SearchPage.qml:69
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:85 contents/ui/SearchPage.qml:25
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:89 contents/ui/SearchPage.qml:31
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ArtistPage.qml:91 contents/ui/SearchPage.qml:33
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:21
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:206
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Favourite Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:196
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/LibraryPage.qml:211
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:49
|
||||
#, kde-format
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:83 contents/ui/SearchPage.qml:149
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/main.qml:95
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Now Playing"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:132
|
||||
#, kde-format
|
||||
msgid "Queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:157
|
||||
#, kde-format
|
||||
msgid "Lyrics"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:273
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:315
|
||||
#: contents/ui/MinimizedPlayerControls.qml:91
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:15
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:27
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:42
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SearchPage.qml:27
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SearchPage.qml:29
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "Find music on YouTube Music"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:50 contents/ui/SongMenu.qml:97
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:59 contents/ui/SongMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr ""
|
||||
|
||||
#: contents/ui/SongMenu.qml:69 contents/ui/SongMenu.qml:110
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr ""
|
||||
+2
-2
@@ -3,5 +3,5 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
ytmusicapi==0.18.0
|
||||
youtube_dl
|
||||
ytmusicapi==0.24.0
|
||||
yt-dlp
|
||||
+18
-6
@@ -10,6 +10,14 @@ target_link_libraries(ytm PUBLIC pybind11::embed)
|
||||
target_include_directories(ytm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_definitions(ytm PRIVATE -DRANDALL_WAS_HERE)
|
||||
|
||||
add_library(asyncdatabase STATIC
|
||||
asyncdatabase.cpp
|
||||
asyncdatabase_p.h
|
||||
)
|
||||
|
||||
target_include_directories(asyncdatabase PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(asyncdatabase PUBLIC Qt::Sql)
|
||||
|
||||
add_subdirectory(example)
|
||||
|
||||
add_executable(audiotube
|
||||
@@ -26,21 +34,25 @@ add_executable(audiotube
|
||||
playerutils.cpp
|
||||
abstractytmusicmodel.cpp
|
||||
multiiterableview.h
|
||||
library.cpp
|
||||
resources.qrc
|
||||
)
|
||||
|
||||
target_link_libraries(audiotube
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Qml
|
||||
Qt5::Quick
|
||||
Qt5::QuickControls2
|
||||
Qt5::Svg
|
||||
Qt::Core
|
||||
Qt::Gui
|
||||
Qt::Qml
|
||||
Qt::Quick
|
||||
Qt::QuickControls2
|
||||
Qt::Svg
|
||||
Qt::Widgets
|
||||
KF5::I18n
|
||||
KF5::CoreAddons
|
||||
KF5::Crash
|
||||
ytm
|
||||
asyncdatabase
|
||||
)
|
||||
|
||||
target_compile_definitions(audiotube PRIVATE -DQT_NO_KEYWORDS -DQT_NO_URL_CAST_FROM_STRING)
|
||||
|
||||
install(TARGETS audiotube ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
+41
-22
@@ -3,29 +3,32 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "albummodel.h"
|
||||
#include "playlistutils.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringBuilder>
|
||||
|
||||
AlbumModel::AlbumModel(QObject *parent)
|
||||
: AbstractYTMusicModel(parent)
|
||||
{
|
||||
connect(this, &AlbumModel::browseIdChanged, this, [=] {
|
||||
connect(this, &AlbumModel::browseIdChanged, this, [this] {
|
||||
setLoading(true);
|
||||
YTMusicThread::instance()->fetchAlbum(m_browseId);
|
||||
});
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchAlbumFinished, this, [=](const album::Album &album) {
|
||||
setLoading(false);
|
||||
auto future = YTMusicThread::instance()->fetchAlbum(m_browseId);
|
||||
connectFuture(future, this, [=, this](const album::Album &album) {
|
||||
setLoading(false);
|
||||
|
||||
beginResetModel();
|
||||
m_album = album;
|
||||
endResetModel();
|
||||
std::sort(m_album.thumbnails.begin(), m_album.thumbnails.end());
|
||||
beginResetModel();
|
||||
m_album = album;
|
||||
endResetModel();
|
||||
std::sort(m_album.thumbnails.begin(), m_album.thumbnails.end());
|
||||
|
||||
Q_EMIT titleChanged();
|
||||
Q_EMIT thumbnailUrlChanged();
|
||||
Q_EMIT playlistIdChanged();
|
||||
Q_EMIT titleChanged();
|
||||
Q_EMIT artistsChanged();
|
||||
Q_EMIT thumbnailUrlChanged();
|
||||
Q_EMIT playlistIdChanged();
|
||||
});
|
||||
});
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [=] {
|
||||
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [=, this] {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
@@ -43,12 +46,15 @@ QVariant AlbumModel::data(const QModelIndex &index, int role) const
|
||||
case VideoId:
|
||||
return QString::fromStdString(m_album.tracks[index.row()].video_id.value_or(std::string()));
|
||||
case Artists:
|
||||
return QVariant::fromValue(std::vector<meta::Artist> {
|
||||
{
|
||||
m_album.tracks[index.row()].artists,
|
||||
std::nullopt
|
||||
}
|
||||
});
|
||||
return QVariant::fromValue(m_album.tracks[index.row()].artists);
|
||||
case ThumbnailUrl:
|
||||
if (!m_album.thumbnails.empty()) {
|
||||
return QString::fromStdString(m_album.thumbnails.front().url);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
case ArtistsDisplayString:
|
||||
return PlaylistUtils::artistsToString(m_album.tracks[index.row()].artists);
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
@@ -61,7 +67,9 @@ QHash<int, QByteArray> AlbumModel::roleNames() const
|
||||
return {
|
||||
{Title, "title"},
|
||||
{VideoId, "videoId"},
|
||||
{Artists, "artists"}
|
||||
{Artists, "artists"},
|
||||
{ThumbnailUrl, "thumbnailUrl"},
|
||||
{ArtistsDisplayString, "artistsDisplayString"}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -81,6 +89,12 @@ QString AlbumModel::title() const
|
||||
return QString::fromStdString(m_album.title);
|
||||
}
|
||||
|
||||
QString AlbumModel::artists() const
|
||||
{
|
||||
return PlaylistUtils::artistsToString(m_album.artists);
|
||||
}
|
||||
|
||||
|
||||
QUrl AlbumModel::thumbnailUrl() const
|
||||
{
|
||||
if (m_album.thumbnails.empty()) {
|
||||
@@ -92,5 +106,10 @@ QUrl AlbumModel::thumbnailUrl() const
|
||||
|
||||
QString AlbumModel::playlistId() const
|
||||
{
|
||||
return QString::fromStdString(m_album.playlist_id);
|
||||
return QString::fromStdString(m_album.audio_playlist_id);
|
||||
}
|
||||
|
||||
QUrl AlbumModel::webUrl() const
|
||||
{
|
||||
return QUrl(YTMUSIC_WEB_BASE_URL % "/playlist?list=" % QString::fromStdString(m_album.audio_playlist_id));
|
||||
}
|
||||
+10
-1
@@ -16,14 +16,18 @@ class AlbumModel : public AbstractYTMusicModel
|
||||
Q_PROPERTY(QString browseId READ browseId WRITE setBrowseId NOTIFY browseIdChanged REQUIRED)
|
||||
|
||||
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
|
||||
Q_PROPERTY(QString artists READ artists NOTIFY artistsChanged)
|
||||
Q_PROPERTY(QUrl thumbnailUrl READ thumbnailUrl NOTIFY thumbnailUrlChanged)
|
||||
Q_PROPERTY(QString playlistId READ playlistId NOTIFY playlistIdChanged)
|
||||
Q_PROPERTY(QUrl webUrl READ webUrl NOTIFY webUrlChanged)
|
||||
|
||||
public:
|
||||
enum Role {
|
||||
Title = Qt::UserRole + 1,
|
||||
VideoId,
|
||||
Artists
|
||||
Artists,
|
||||
ThumbnailUrl,
|
||||
ArtistsDisplayString
|
||||
};
|
||||
|
||||
explicit AlbumModel(QObject *parent = nullptr);
|
||||
@@ -39,12 +43,17 @@ public:
|
||||
QString title() const;
|
||||
Q_SIGNAL void titleChanged();
|
||||
|
||||
QString artists() const;
|
||||
Q_SIGNAL void artistsChanged();
|
||||
QUrl thumbnailUrl() const;
|
||||
Q_SIGNAL void thumbnailUrlChanged();
|
||||
|
||||
QString playlistId() const;
|
||||
Q_SIGNAL void playlistIdChanged();
|
||||
|
||||
QUrl webUrl() const;
|
||||
Q_SIGNAL void webUrlChanged();
|
||||
|
||||
private:
|
||||
QString m_browseId;
|
||||
|
||||
|
||||
+69
-50
@@ -4,58 +4,66 @@
|
||||
|
||||
#include "artistmodel.h"
|
||||
|
||||
#include <QStringBuilder>
|
||||
|
||||
#include <asyncytmusic.h>
|
||||
|
||||
ArtistModel::ArtistModel(QObject *parent)
|
||||
: AbstractYTMusicModel(parent)
|
||||
, m_view(albums, singles, songs, videos)
|
||||
{
|
||||
connect(this, &ArtistModel::channelIdChanged, this, [=] {
|
||||
connect(this, &ArtistModel::channelIdChanged, this, [this] {
|
||||
if (m_channelId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
YTMusicThread::instance()->fetchArtist(m_channelId);
|
||||
auto future = YTMusicThread::instance()->fetchArtist(m_channelId);
|
||||
connectFuture(future, this, [=, this](const artist::Artist &artist) {
|
||||
setLoading(false);
|
||||
|
||||
beginResetModel();
|
||||
m_artist = artist;
|
||||
std::sort(m_artist.thumbnails.begin(), m_artist.thumbnails.end());
|
||||
|
||||
albums = m_artist.albums ? m_artist.albums->results : std::vector<artist::Artist::Album>();
|
||||
for (auto &album : albums) {
|
||||
std::sort(album.thumbnails.begin(), album.thumbnails.end());
|
||||
}
|
||||
singles = m_artist.singles ? m_artist.singles->results : std::vector<artist::Artist::Single>();
|
||||
for (auto &single : singles) {
|
||||
std::sort(single.thumbnails.begin(), single.thumbnails.end());
|
||||
}
|
||||
songs = m_artist.songs ? m_artist.songs->results : std::vector<artist::Artist::Song>();
|
||||
for (auto &song : songs) {
|
||||
std::sort(song.thumbnails.begin(), song.thumbnails.end());
|
||||
}
|
||||
videos = m_artist.videos ? m_artist.videos->results : std::vector<artist::Artist::Video>();
|
||||
for (auto &video : videos) {
|
||||
std::sort(video.thumbnails.begin(), video.thumbnails.end());
|
||||
}
|
||||
|
||||
// std::span can't know if the data pointer underneath it was changed, so re-create
|
||||
m_view = MultiIterableView(albums, singles, songs, videos);
|
||||
endResetModel();
|
||||
|
||||
Q_EMIT titleChanged();
|
||||
Q_EMIT thumbnailUrlChanged();
|
||||
});
|
||||
});
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchArtistFinished, this, [=](const artist::Artist &artist) {
|
||||
setLoading(false);
|
||||
|
||||
beginResetModel();
|
||||
m_artist = artist;
|
||||
std::sort(m_artist.thumbnails.begin(), m_artist.thumbnails.end());
|
||||
|
||||
auto albums = m_artist.albums ? m_artist.albums->results : std::vector<artist::Artist::Album>();
|
||||
auto singles = m_artist.singles ? m_artist.singles->results : std::vector<artist::Artist::Single>();
|
||||
auto songs = m_artist.songs ? m_artist.songs->results : std::vector<artist::Artist::Song>();
|
||||
auto videos = m_artist.videos ? m_artist.videos->results : std::vector<artist::Artist::Video>();
|
||||
|
||||
m_view = std::optional(MultiIterableView(std::move(albums),
|
||||
std::move(singles),
|
||||
std::move(songs),
|
||||
std::move(videos)));
|
||||
endResetModel();
|
||||
|
||||
|
||||
Q_EMIT titleChanged();
|
||||
Q_EMIT thumbnailUrlChanged();
|
||||
});
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [=] {
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [this] {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
|
||||
int ArtistModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : m_view ? int(m_view->size()) : 0;
|
||||
return parent.isValid() ? 0 : m_view.size();
|
||||
}
|
||||
|
||||
QVariant ArtistModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!m_view) {
|
||||
return {};
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case Title:
|
||||
return QString::fromStdString(std::visit([&](auto&& item) {
|
||||
@@ -71,7 +79,7 @@ QVariant ArtistModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}, m_view.value()[index.row()]));
|
||||
}, m_view[index.row()]));
|
||||
case Type:
|
||||
return std::visit([&](auto&& item) {
|
||||
using T = std::decay_t<decltype(item)>;
|
||||
@@ -86,7 +94,7 @@ QVariant ArtistModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}, m_view.value()[index.row()]);
|
||||
}, m_view[index.row()]);
|
||||
case Artists:
|
||||
return QVariant::fromValue(std::vector<meta::Artist> {
|
||||
{
|
||||
@@ -108,7 +116,14 @@ QVariant ArtistModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}, m_view.value()[index.row()]);
|
||||
}, m_view[index.row()]);
|
||||
case ThumbnailUrl:
|
||||
return std::visit([&](auto&& item) {
|
||||
if (!item.thumbnails.empty()) {
|
||||
return QString::fromStdString(item.thumbnails.front().url);
|
||||
}
|
||||
return QString();
|
||||
}, m_view[index.row()]);
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
@@ -122,7 +137,8 @@ QHash<int, QByteArray> ArtistModel::roleNames() const
|
||||
{Title, "title"},
|
||||
{Type, "type"},
|
||||
{Artists, "artists"},
|
||||
{VideoId, "videoId"}
|
||||
{VideoId, "videoId"},
|
||||
{ThumbnailUrl, "thumbnailUrl"}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -151,22 +167,25 @@ QUrl ArtistModel::thumbnailUrl() const
|
||||
return QUrl(QString::fromStdString(m_artist.thumbnails.back().url));
|
||||
}
|
||||
|
||||
QUrl ArtistModel::webUrl() const
|
||||
{
|
||||
return QUrl(YTMUSIC_WEB_BASE_URL % u"channel/" % QString::fromStdString(m_artist.channel_id));
|
||||
}
|
||||
|
||||
void ArtistModel::triggerItem(int row)
|
||||
{
|
||||
if (m_view) {
|
||||
std::visit([&](auto&& item) {
|
||||
using T = std::decay_t<decltype(item)>;
|
||||
if constexpr(std::is_same_v<T, artist::Artist::Album>) {
|
||||
Q_EMIT openAlbum(QString::fromStdString(item.browse_id));
|
||||
} else if constexpr(std::is_same_v<T, artist::Artist::Single>) {
|
||||
Q_EMIT openAlbum(QString::fromStdString(item.browse_id));
|
||||
} else if constexpr(std::is_same_v<T, artist::Artist::Song>) {
|
||||
Q_EMIT openSong(QString::fromStdString(item.video_id));
|
||||
} else if constexpr(std::is_same_v<T, artist::Artist::Video>) {
|
||||
Q_EMIT openVideo(QString::fromStdString(item.video_id), QString::fromStdString(item.title));
|
||||
} else {
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}, m_view.value()[row]);
|
||||
}
|
||||
std::visit([&](auto&& item) {
|
||||
using T = std::decay_t<decltype(item)>;
|
||||
if constexpr(std::is_same_v<T, artist::Artist::Album>) {
|
||||
Q_EMIT openAlbum(QString::fromStdString(item.browse_id));
|
||||
} else if constexpr(std::is_same_v<T, artist::Artist::Single>) {
|
||||
Q_EMIT openAlbum(QString::fromStdString(item.browse_id));
|
||||
} else if constexpr(std::is_same_v<T, artist::Artist::Song>) {
|
||||
Q_EMIT openSong(QString::fromStdString(item.video_id));
|
||||
} else if constexpr(std::is_same_v<T, artist::Artist::Video>) {
|
||||
Q_EMIT openVideo(QString::fromStdString(item.video_id), QString::fromStdString(item.title));
|
||||
} else {
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}, m_view[row]);
|
||||
}
|
||||
+14
-3
@@ -23,6 +23,7 @@ class ArtistModel : public AbstractYTMusicModel
|
||||
|
||||
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
|
||||
Q_PROPERTY(QUrl thumbnailUrl READ thumbnailUrl NOTIFY thumbnailUrlChanged)
|
||||
Q_PROPERTY(QUrl webUrl READ webUrl NOTIFY webUrlChanged)
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
@@ -37,7 +38,8 @@ public:
|
||||
Title,
|
||||
Type,
|
||||
Artists,
|
||||
VideoId
|
||||
VideoId,
|
||||
ThumbnailUrl
|
||||
};
|
||||
|
||||
explicit ArtistModel(QObject *parent = nullptr);
|
||||
@@ -56,6 +58,9 @@ public:
|
||||
QUrl thumbnailUrl() const;
|
||||
Q_SIGNAL void thumbnailUrlChanged();
|
||||
|
||||
QUrl webUrl() const;
|
||||
Q_SIGNAL void webUrlChanged();
|
||||
|
||||
Q_INVOKABLE void triggerItem(int row);
|
||||
|
||||
Q_SIGNAL void openAlbum(const QString &browseId);
|
||||
@@ -66,7 +71,13 @@ private:
|
||||
QString m_channelId;
|
||||
|
||||
artist::Artist m_artist;
|
||||
std::optional<MultiIterableView<
|
||||
|
||||
std::vector<artist::Artist::Album> albums;
|
||||
std::vector<artist::Artist::Single> singles;
|
||||
std::vector<artist::Artist::Song> songs;
|
||||
std::vector<artist::Artist::Video> videos;
|
||||
|
||||
MultiIterableView<
|
||||
artist::Artist::Album, artist::Artist::Single, artist::Artist::Song, artist::Artist::Video
|
||||
>> m_view;
|
||||
> m_view;
|
||||
};
|
||||
@@ -0,0 +1,309 @@
|
||||
// SPDX-FileCopyrightText: 2022 Jonah Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "asyncdatabase.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QUrl>
|
||||
#include <QStringBuilder>
|
||||
#include <QVariant>
|
||||
#include <QSqlResult>
|
||||
#include <QSqlError>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#define SCHAMA_MIGRATIONS_TABLE "__qt_schema_migrations"
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(asyncdatabase)
|
||||
Q_LOGGING_CATEGORY(asyncdatabase, "asyncdatabase")
|
||||
|
||||
namespace asyncdatabase_private {
|
||||
|
||||
// migrations
|
||||
void createInternalTable(QSqlDatabase &database) {
|
||||
QSqlQuery query(QStringLiteral("create table if not exists " SCHAMA_MIGRATIONS_TABLE " ("
|
||||
"version Text primary key not null, "
|
||||
"run_on timestamp not null default current_timestamp)"), database);
|
||||
if (!query.exec()) {
|
||||
printSqlError(query);
|
||||
}
|
||||
}
|
||||
|
||||
void markMigrationRun(QSqlDatabase &database, const QString &name) {
|
||||
qCDebug(asyncdatabase) << "Marking migration" << name << "as done.";
|
||||
|
||||
QSqlQuery query(database);
|
||||
if (!query.prepare(QStringLiteral("insert into " SCHAMA_MIGRATIONS_TABLE " (version) values (:name)"))) {
|
||||
printSqlError(query);
|
||||
}
|
||||
query.bindValue(QStringLiteral(":name"), QVariant(name));
|
||||
if (!query.exec()) {
|
||||
printSqlError(query);
|
||||
}
|
||||
}
|
||||
|
||||
bool checkMigrationAlreadyRun(QSqlDatabase &database, const QString &name) {
|
||||
qCDebug(asyncdatabase) << "Checking whether migration" << name << "is already applied";
|
||||
QSqlQuery query(database);
|
||||
query.prepare(QStringLiteral("select count(*) from " SCHAMA_MIGRATIONS_TABLE " where version = :name"));
|
||||
query.bindValue(QStringLiteral(":name"), QVariant(name));
|
||||
query.exec();
|
||||
|
||||
query.next();
|
||||
int count = query.value(0).toInt();
|
||||
bool isApplied = count > 0;
|
||||
if (isApplied) {
|
||||
qCDebug(asyncdatabase) << "… yes";
|
||||
} else {
|
||||
qDebug(asyncdatabase) << "… no";
|
||||
}
|
||||
return isApplied;
|
||||
}
|
||||
|
||||
void runDatabaseMigrations(QSqlDatabase &database, const QString &migrationDirectory)
|
||||
{
|
||||
createInternalTable(database);
|
||||
|
||||
QDir dir(migrationDirectory);
|
||||
auto entries = dir.entryList(QDir::Filter::Dirs | QDir::Filter::NoDotAndDotDot, QDir::SortFlag::Name);
|
||||
|
||||
for (const auto &entry : entries) {
|
||||
QDir subdir(entry);
|
||||
if (!checkMigrationAlreadyRun(database, subdir.dirName())) {
|
||||
QFile file(migrationDirectory % QDir::separator() % entry % QDir::separator() % "up.sql");
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
qCDebug(asyncdatabase) << "Failed to open migration file" << file.fileName();
|
||||
}
|
||||
qCDebug(asyncdatabase) << "Running migration" << subdir.dirName();
|
||||
|
||||
database.transaction();
|
||||
|
||||
// Hackish
|
||||
const auto statements = file.readAll().split(';');
|
||||
|
||||
bool migrationSuccessful = true;
|
||||
for (const QByteArray &statement : statements) {
|
||||
const auto trimmedStatement = statement.trimmed();
|
||||
QSqlQuery query(database);
|
||||
|
||||
if (!trimmedStatement.isEmpty()) {
|
||||
qCDebug(asyncdatabase) << "Running" << trimmedStatement;
|
||||
if (!query.prepare(trimmedStatement)) {
|
||||
printSqlError(query);
|
||||
} else {
|
||||
bool success = query.exec();
|
||||
migrationSuccessful &= success;
|
||||
if (!success) {
|
||||
printSqlError(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (migrationSuccessful) {
|
||||
database.commit();
|
||||
markMigrationRun(database, subdir.dirName());
|
||||
} else {
|
||||
database.rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
qCDebug(asyncdatabase) << "Migrations finished";
|
||||
}
|
||||
|
||||
struct AsyncSqlDatabasePrivate {
|
||||
QSqlDatabase database;
|
||||
};
|
||||
|
||||
// Internal asynchronous database class
|
||||
QFuture<void> AsyncSqlDatabase::establishConnection(const DatabaseConfiguration &configuration)
|
||||
{
|
||||
return runAsync([=, this] {
|
||||
d->database = QSqlDatabase::addDatabase(configuration.type());
|
||||
if (configuration.databaseName()) {
|
||||
d->database.setDatabaseName(*configuration.databaseName());
|
||||
}
|
||||
if (configuration.hostName()) {
|
||||
d->database.setHostName(*configuration.hostName());
|
||||
}
|
||||
if (configuration.userName()) {
|
||||
d->database.setUserName(*configuration.userName());
|
||||
}
|
||||
if (configuration.password()) {
|
||||
d->database.setPassword(*configuration.password());
|
||||
}
|
||||
|
||||
if (!d->database.open()) {
|
||||
qCDebug(asyncdatabase) << "Failed to open database" << d->database.lastError().text();
|
||||
if (configuration.databaseName()) {
|
||||
qCDebug(asyncdatabase) << "Tried to use database" << *configuration.databaseName();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AsyncSqlDatabase::AsyncSqlDatabase()
|
||||
: QObject()
|
||||
, d(std::make_unique<AsyncSqlDatabasePrivate>())
|
||||
{
|
||||
}
|
||||
|
||||
Row AsyncSqlDatabase::retrieveRow(const QSqlQuery &query) {
|
||||
Row row;
|
||||
int i = 0;
|
||||
|
||||
while (true) {
|
||||
if (query.isValid()) {
|
||||
QVariant value = query.value(i);
|
||||
if (value.isValid()) {
|
||||
row.push_back(std::move(value));
|
||||
i++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
Rows AsyncSqlDatabase::retrieveRows(QSqlQuery &query)
|
||||
{
|
||||
Rows rows;
|
||||
while (query.next()) {
|
||||
rows.push_back(retrieveRow(query));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
std::optional<Row> AsyncSqlDatabase::retrieveOptionalRow(QSqlQuery &query)
|
||||
{
|
||||
query.next();
|
||||
|
||||
if (query.isValid()) {
|
||||
return retrieveRow(query);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
QSqlDatabase &AsyncSqlDatabase::db()
|
||||
{
|
||||
return d->database;
|
||||
}
|
||||
|
||||
AsyncSqlDatabase::~AsyncSqlDatabase() = default;
|
||||
|
||||
void printSqlError(const QSqlQuery &query)
|
||||
{
|
||||
qCDebug(asyncdatabase) << "SQL error:" << query.lastError().text();
|
||||
}
|
||||
|
||||
QSqlQuery prepareQuery(const QSqlDatabase &database, const QString &sqlQuery)
|
||||
{
|
||||
qCDebug(asyncdatabase) << "Running" << sqlQuery;
|
||||
QSqlQuery query(database);
|
||||
if (!query.prepare(sqlQuery)) {
|
||||
printSqlError(query);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
QSqlQuery runQuery(QSqlQuery &query)
|
||||
{
|
||||
if (!query.exec()) {
|
||||
printSqlError(query);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct DatabaseConfigurationPrivate : public QSharedData {
|
||||
QString type;
|
||||
std::optional<QString> hostName;
|
||||
std::optional<QString> databaseName;
|
||||
std::optional<QString> userName;
|
||||
std::optional<QString> password;
|
||||
};
|
||||
|
||||
DatabaseConfiguration::DatabaseConfiguration() : d(new DatabaseConfigurationPrivate)
|
||||
{}
|
||||
|
||||
DatabaseConfiguration::~DatabaseConfiguration() = default;
|
||||
DatabaseConfiguration::DatabaseConfiguration(const DatabaseConfiguration &) = default;
|
||||
|
||||
void DatabaseConfiguration::setType(const QString &type) {
|
||||
d->type = type;
|
||||
}
|
||||
|
||||
const QString &DatabaseConfiguration::type() const {
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void DatabaseConfiguration::setHostName(const QString &hostName) {
|
||||
d->hostName = hostName;
|
||||
}
|
||||
|
||||
const std::optional<QString> &DatabaseConfiguration::hostName() const {
|
||||
return d->hostName;
|
||||
}
|
||||
|
||||
void DatabaseConfiguration::setDatabaseName(const QString &databaseName) {
|
||||
d->databaseName = databaseName;
|
||||
}
|
||||
|
||||
const std::optional<QString> &DatabaseConfiguration::databaseName() const {
|
||||
return d->databaseName;
|
||||
}
|
||||
|
||||
void DatabaseConfiguration::setUserName(const QString &userName) {
|
||||
d->userName = userName;
|
||||
}
|
||||
|
||||
const std::optional<QString> &DatabaseConfiguration::userName() const {
|
||||
return d->userName;
|
||||
}
|
||||
|
||||
void DatabaseConfiguration::setPassword(const QString &password) {
|
||||
d->password = password;
|
||||
}
|
||||
|
||||
const std::optional<QString> &DatabaseConfiguration::password() const {
|
||||
return d->password;
|
||||
}
|
||||
|
||||
|
||||
struct ThreadedDatabasePrivate {
|
||||
asyncdatabase_private::AsyncSqlDatabase db;
|
||||
};
|
||||
|
||||
std::unique_ptr<ThreadedDatabase> ThreadedDatabase::establishConnection(DatabaseConfiguration config) {
|
||||
auto threadedDb = std::make_unique<ThreadedDatabase>();
|
||||
threadedDb->setObjectName(QStringLiteral("database thread"));
|
||||
threadedDb->d->db.moveToThread(&*threadedDb);
|
||||
threadedDb->start();
|
||||
threadedDb->d->db.establishConnection(config);
|
||||
return threadedDb;
|
||||
}
|
||||
|
||||
ThreadedDatabase::ThreadedDatabase()
|
||||
: QThread()
|
||||
, d(std::make_unique<ThreadedDatabasePrivate>())
|
||||
{
|
||||
}
|
||||
|
||||
ThreadedDatabase::~ThreadedDatabase()
|
||||
{
|
||||
quit();
|
||||
wait();
|
||||
}
|
||||
|
||||
asyncdatabase_private::AsyncSqlDatabase &ThreadedDatabase::db()
|
||||
{
|
||||
return d->db;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
// SPDX-FileCopyrightText: 2022 Jonah Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
class QUrl;
|
||||
class QSqlDatabase;
|
||||
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
#include <QSharedDataPointer>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "asyncdatabase_p.h"
|
||||
|
||||
struct DatabaseConfigurationPrivate;
|
||||
|
||||
///
|
||||
/// Options for connecting to a database
|
||||
///
|
||||
class DatabaseConfiguration {
|
||||
public:
|
||||
DatabaseConfiguration();
|
||||
DatabaseConfiguration(const DatabaseConfiguration &);
|
||||
~DatabaseConfiguration();
|
||||
|
||||
/// Set the name of the database driver, for example DATABASE_TYPE_SQLITE or a custom string.
|
||||
void setType(const QString &type);
|
||||
const QString &type() const;
|
||||
|
||||
/// Set the hostname
|
||||
void setHostName(const QString &hostName);
|
||||
const std::optional<QString> &hostName() const;
|
||||
|
||||
/// Set the name of the database (path of the file for SQLite)
|
||||
void setDatabaseName(const QString &databaseName);
|
||||
const std::optional<QString> &databaseName() const;
|
||||
|
||||
/// Set user name
|
||||
void setUserName(const QString &userName);
|
||||
const std::optional<QString> &userName() const;
|
||||
|
||||
/// Set password
|
||||
void setPassword(const QString &password);
|
||||
const std::optional<QString> &password() const;
|
||||
|
||||
private:
|
||||
QSharedDataPointer<DatabaseConfigurationPrivate> d;
|
||||
};
|
||||
|
||||
///
|
||||
/// The SQLite database driver
|
||||
///
|
||||
const QString DATABASE_TYPE_SQLITE = QStringLiteral("QSQLITE");
|
||||
|
||||
template <typename T>
|
||||
concept FromSql = requires(T v, typename T::ColumnTypes row)
|
||||
{
|
||||
typename T::ColumnTypes;
|
||||
{ std::tuple(row) } -> std::same_as<typename T::ColumnTypes>;
|
||||
{ T::fromSql(row) } -> std::same_as<T>;
|
||||
};
|
||||
|
||||
struct ThreadedDatabasePrivate;
|
||||
|
||||
class ThreadedDatabase : public QThread {
|
||||
public:
|
||||
///
|
||||
/// \brief Connect to a database
|
||||
/// \param configuration of the database connection
|
||||
/// \return
|
||||
///
|
||||
static std::unique_ptr<ThreadedDatabase> establishConnection(DatabaseConfiguration config);
|
||||
|
||||
///
|
||||
/// \brief Execute an SQL query on the database, ignoring the result.
|
||||
/// \param SQL query string to execute
|
||||
/// \param Parameters to bind to the placeholders in the SQL Query
|
||||
/// \return
|
||||
///
|
||||
template <typename ...Args>
|
||||
requires std::conjunction_v<std::is_convertible<Args, QVariant>...>
|
||||
auto execute(const QString &sqlQuery, Args... args) -> QFuture<void> {
|
||||
return db().execute(sqlQuery, args...);
|
||||
}
|
||||
|
||||
///
|
||||
/// Run database migrations in the given directory.
|
||||
/// The directory needs to contain a subdirectory for each migration.
|
||||
/// The subdirectories need to be named so that when sorted alphabetically the migrations will be run in the correct order.
|
||||
/// Each subdirectory needs to contain a file named up.sql.
|
||||
///
|
||||
/// \param Directory which contains the migrations.
|
||||
/// \return
|
||||
///
|
||||
auto runMigrations(const QString &migrationDirectory) -> QFuture<void> {
|
||||
return db().runMigrations(migrationDirectory);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Execute an SQL query on the database, retrieving the result.
|
||||
/// \param SQL Query to execute
|
||||
/// \param parameters to bind to the placeholders in the SQL query.
|
||||
/// \return Future of a list of lists of variants.
|
||||
///
|
||||
/// T must provide a tuple of the column types as `using ColumnTypes = std::tuple<...>`
|
||||
/// and a `static T fromSql(ColumnTypes tuple)` deserialization method.
|
||||
///
|
||||
template <typename T, typename ...Args>
|
||||
requires FromSql<T> && std::conjunction_v<std::is_convertible<Args, QVariant>...>
|
||||
auto getResults(const QString &sqlQuery, Args... args) -> QFuture<std::vector<T>> {
|
||||
return db().getResults<T, Args...>(sqlQuery, args...);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Like getResults, but for retrieving just one row.
|
||||
///
|
||||
template <typename T, typename ...Args>
|
||||
requires FromSql<T> && std::conjunction_v<std::is_convertible<Args, QVariant>...>
|
||||
auto getResult(const QString &sqlQuery, Args... args) -> QFuture<std::optional<T>> {
|
||||
return db().getResult<T, Args...>(sqlQuery, args...);
|
||||
}
|
||||
|
||||
ThreadedDatabase();
|
||||
~ThreadedDatabase();
|
||||
|
||||
private:
|
||||
asyncdatabase_private::AsyncSqlDatabase &db();
|
||||
|
||||
std::unique_ptr<ThreadedDatabasePrivate> d;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Deserialize just a single value from a query result.
|
||||
///
|
||||
template <typename T>
|
||||
struct SingleValue {
|
||||
using ColumnTypes = std::tuple<T>;
|
||||
|
||||
static SingleValue fromSql(ColumnTypes tuple) {
|
||||
auto [value] = tuple;
|
||||
return SingleValue { value };
|
||||
}
|
||||
|
||||
T value;
|
||||
};
|
||||
@@ -0,0 +1,179 @@
|
||||
// SPDX-FileCopyrightText: 2022 Jonah Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <optional>
|
||||
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlDatabase>
|
||||
#include <QThread>
|
||||
|
||||
class DatabaseConfiguration;
|
||||
|
||||
namespace asyncdatabase_private {
|
||||
|
||||
// Helpers
|
||||
template <typename Tuple, typename Func, std::size_t i>
|
||||
inline constexpr void iterate_impl(Tuple &tup, Func fun)
|
||||
{
|
||||
if constexpr(i >= std::tuple_size_v<std::decay_t<decltype(tup)>>) {
|
||||
return;
|
||||
} else {
|
||||
fun(std::get<i>(tup));
|
||||
return asyncdatabase_private::iterate_impl<Tuple, Func, i + 1>(tup, fun);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tuple, typename Func>
|
||||
inline constexpr void iterate_tuple(Tuple &tup, Func fun)
|
||||
{
|
||||
asyncdatabase_private::iterate_impl<Tuple, Func, 0>(tup, fun);
|
||||
}
|
||||
|
||||
template <typename T, typename QObjectDerivedType, typename Function>
|
||||
void connectFuture(const QFuture<T> &future, QObjectDerivedType *self, const Function &fun) {
|
||||
auto watcher = std::make_shared<QFutureWatcher<T>>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher.get(), &QFutureWatcherBase::finished, self, [self, watcher, fun, future] {
|
||||
if constexpr (std::is_same_v<void, T>) {
|
||||
if constexpr (std::is_member_function_pointer_v<Function>) {
|
||||
fun->*(self);
|
||||
} else {
|
||||
fun();
|
||||
}
|
||||
} else if (future.resultCount() > 0) {
|
||||
if constexpr (std::is_member_function_pointer_v<Function>) {
|
||||
(self->*fun)(watcher->result());
|
||||
} else {
|
||||
fun(watcher->result());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
using Row = std::vector<QVariant>;
|
||||
using Rows = std::vector<Row>;
|
||||
|
||||
template <typename RowTypesTuple>
|
||||
auto parseRow(const Row &row) -> RowTypesTuple
|
||||
{
|
||||
auto tuple = RowTypesTuple();
|
||||
int i = 0;
|
||||
asyncdatabase_private::iterate_tuple(tuple, [&](auto &elem) {
|
||||
elem = row.at(i).value<std::decay_t<decltype(elem)>>();
|
||||
i++;
|
||||
});
|
||||
return tuple;
|
||||
}
|
||||
|
||||
template <typename RowTypesTuple>
|
||||
auto parseRows(const Rows &rows) -> std::vector<RowTypesTuple> {
|
||||
std::vector<RowTypesTuple> parsedRows;
|
||||
parsedRows.reserve(rows.size());
|
||||
std::ranges::transform(rows, std::back_inserter(parsedRows), parseRow<RowTypesTuple>);
|
||||
return parsedRows;
|
||||
}
|
||||
|
||||
void runDatabaseMigrations(QSqlDatabase &database, const QString &migrationDirectory);
|
||||
|
||||
void printSqlError(const QSqlQuery &query);
|
||||
|
||||
// non-template helper functions to allow patching a much as possible in the shared library
|
||||
QSqlQuery prepareQuery(const QSqlDatabase &database, const QString &sqlQuery);
|
||||
QSqlQuery runQuery(QSqlQuery &query);
|
||||
|
||||
struct AsyncSqlDatabasePrivate;
|
||||
|
||||
class AsyncSqlDatabase : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QFuture<void> establishConnection(const DatabaseConfiguration &configuration);
|
||||
|
||||
template <typename T, typename ...Args>
|
||||
auto getResults(const QString &sqlQuery, Args... args) -> QFuture<std::vector<T>> {
|
||||
return runAsync([=, this] {
|
||||
auto query = executeQuery(sqlQuery, args...);
|
||||
const auto rows = parseRows<typename T::ColumnTypes>(retrieveRows(query));
|
||||
|
||||
std::vector<T> deserializedRows;
|
||||
std::ranges::transform(rows, std::back_inserter(deserializedRows), T::fromSql);
|
||||
return deserializedRows;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T, typename ...Args>
|
||||
auto getResult(const QString &sqlQuery, Args... args) -> QFuture<std::optional<T>> {
|
||||
return runAsync([=, this]() -> std::optional<T> {
|
||||
auto query = executeQuery(sqlQuery, args...);
|
||||
if (const auto row = retrieveOptionalRow(query)) {
|
||||
return T::fromSql(parseRow<typename T::ColumnTypes>(*row));
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename ...Args>
|
||||
auto execute(const QString &sqlQuery, Args... args) -> QFuture<void> {
|
||||
return runAsync([=, this] {
|
||||
executeQuery(sqlQuery, args...);
|
||||
});
|
||||
}
|
||||
|
||||
auto runMigrations(const QString &migrationDirectory) -> QFuture<void> {
|
||||
return runAsync([=, this] {
|
||||
runDatabaseMigrations(db(), migrationDirectory);
|
||||
});
|
||||
}
|
||||
|
||||
AsyncSqlDatabase();
|
||||
~AsyncSqlDatabase();
|
||||
|
||||
private:
|
||||
template <typename ...Args>
|
||||
QSqlQuery executeQuery(const QString &sqlQuery, Args... args) {
|
||||
auto query = prepareQuery(db(), sqlQuery);
|
||||
auto argsTuple = std::make_tuple<Args...>(std::move(args)...);
|
||||
int i = 0;
|
||||
asyncdatabase_private::iterate_tuple(argsTuple, [&](auto &arg) {
|
||||
query.bindValue(i, arg);
|
||||
i++;
|
||||
});
|
||||
return runQuery(query);
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
QFuture<std::invoke_result_t<Functor>> runAsync(Functor func) {
|
||||
using ReturnType = std::invoke_result_t<Functor>;
|
||||
auto interface = std::make_shared<QFutureInterface<ReturnType>>();
|
||||
QMetaObject::invokeMethod(this, [interface, func] {
|
||||
if constexpr (!std::is_same_v<ReturnType, void>) {
|
||||
auto result = func();
|
||||
interface->reportResult(result);
|
||||
} else {
|
||||
func();
|
||||
}
|
||||
|
||||
interface->reportFinished();
|
||||
});
|
||||
|
||||
return interface->future();
|
||||
}
|
||||
|
||||
Row retrieveRow(const QSqlQuery &query);
|
||||
Rows retrieveRows(QSqlQuery &query);
|
||||
std::optional<Row> retrieveOptionalRow(QSqlQuery &query);
|
||||
|
||||
QSqlDatabase &db();
|
||||
|
||||
std::unique_ptr<AsyncSqlDatabasePrivate> d;
|
||||
};
|
||||
|
||||
}
|
||||
+64
-103
@@ -6,6 +6,10 @@
|
||||
|
||||
#include <QThread>
|
||||
#include <QDebug>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QFutureInterface>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <pybind11/embed.h>
|
||||
|
||||
@@ -13,10 +17,21 @@
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
template <typename R, typename T, typename OP>
|
||||
std::optional<R> map_optional(const std::optional<T> &optional, OP op) {
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
|
||||
template <typename T, typename OP>
|
||||
std::optional<std::invoke_result_t<OP, T>> mapOptional(const std::optional<T> &optional, OP op) {
|
||||
if (optional.has_value()) {
|
||||
return op(optional.value());
|
||||
if constexpr (std::is_member_function_pointer<OP>::value) {
|
||||
return (&optional.value()->*op)();
|
||||
} else {
|
||||
return op(optional.value());
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
@@ -37,15 +52,6 @@ AsyncYTMusic::AsyncYTMusic(QObject *parent)
|
||||
qRegisterMetaType<std::vector<meta::Artist>>();
|
||||
qRegisterMetaType<meta::Artist>();
|
||||
|
||||
connect(this, &AsyncYTMusic::startSearch, this, &AsyncYTMusic::internalSearch);
|
||||
connect(this, &AsyncYTMusic::startFetchArtist, this, &AsyncYTMusic::internalFetchArtist);
|
||||
connect(this, &AsyncYTMusic::startFetchAlbum, this, &AsyncYTMusic::internalFetchAlbum);
|
||||
connect(this, &AsyncYTMusic::startFetchSong, this, &AsyncYTMusic::internalFetchSong);
|
||||
connect(this, &AsyncYTMusic::startFetchPlaylist, this, &AsyncYTMusic::internalFetchPlaylist);
|
||||
connect(this, &AsyncYTMusic::startFetchArtistAlbums, this, &AsyncYTMusic::internalFetchArtistAlbums);
|
||||
connect(this, &AsyncYTMusic::startExtractVideoInfo, this, &AsyncYTMusic::internalExtractVideoInfo);
|
||||
connect(this, &AsyncYTMusic::startFetchWatchPlaylist, this, &AsyncYTMusic::internalFetchWatchPlaylist);
|
||||
|
||||
connect(this, &AsyncYTMusic::errorOccurred, this, [](const QString &err) {
|
||||
std::cerr << qPrintable(err);
|
||||
});
|
||||
@@ -54,139 +60,92 @@ AsyncYTMusic::AsyncYTMusic(QObject *parent)
|
||||
//
|
||||
// search
|
||||
//
|
||||
void AsyncYTMusic::search(const QString &query)
|
||||
QFuture<std::vector<search::SearchResultItem>> AsyncYTMusic::search(const QString &query)
|
||||
{
|
||||
Q_EMIT startSearch(query);
|
||||
}
|
||||
|
||||
void AsyncYTMusic::internalSearch(const QString &query)
|
||||
{
|
||||
try {
|
||||
Q_EMIT searchFinished(m_ytm->search(query.toStdString()));
|
||||
} catch (const py::error_already_set &err) {
|
||||
Q_EMIT errorOccurred(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
return invokeAndCatchOnThread([=, this]() {
|
||||
return m_ytm->search(query.toStdString());
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// fetchArtist
|
||||
//
|
||||
void AsyncYTMusic::fetchArtist(const QString &channelId)
|
||||
QFuture<artist::Artist> AsyncYTMusic::fetchArtist(const QString &channelId)
|
||||
{
|
||||
Q_EMIT startFetchArtist(channelId);
|
||||
}
|
||||
|
||||
void AsyncYTMusic::internalFetchArtist(const QString &channelId)
|
||||
{
|
||||
try {
|
||||
Q_EMIT fetchArtistFinished(m_ytm->get_artist(channelId.toStdString()));
|
||||
} catch (const py::error_already_set &err) {
|
||||
Q_EMIT errorOccurred(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
return invokeAndCatchOnThread([=, this]() {
|
||||
return m_ytm->get_artist(channelId.toStdString());
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// fetchAlbum
|
||||
//
|
||||
void AsyncYTMusic::fetchAlbum(const QString &browseId)
|
||||
QFuture<album::Album> AsyncYTMusic::fetchAlbum(const QString &browseId)
|
||||
{
|
||||
Q_EMIT startFetchAlbum(browseId);
|
||||
}
|
||||
|
||||
void AsyncYTMusic::internalFetchAlbum(const QString &browseId)
|
||||
{
|
||||
try {
|
||||
Q_EMIT fetchAlbumFinished(m_ytm->get_album(browseId.toStdString()));
|
||||
} catch (const py::error_already_set &err) {
|
||||
Q_EMIT errorOccurred(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
return invokeAndCatchOnThread([=, this]() {
|
||||
return m_ytm->get_album(browseId.toStdString());
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// fetchSong
|
||||
//
|
||||
void AsyncYTMusic::fetchSong(const QString &videoId)
|
||||
QFuture<std::optional<song::Song>> AsyncYTMusic::fetchSong(const QString &videoId)
|
||||
{
|
||||
Q_EMIT startFetchSong(videoId);
|
||||
}
|
||||
|
||||
void AsyncYTMusic::internalFetchSong(const QString &videoId)
|
||||
{
|
||||
try {
|
||||
Q_EMIT fetchSongFinished(m_ytm->get_song(videoId.toStdString()));
|
||||
} catch (const py::error_already_set &err) {
|
||||
Q_EMIT errorOccurred(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
return invokeAndCatchOnThread([=, this]() {
|
||||
return m_ytm->get_song(videoId.toStdString());
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// fetchPlaylist
|
||||
//
|
||||
void AsyncYTMusic::fetchPlaylist(const QString &playlistId) {
|
||||
Q_EMIT startFetchPlaylist(playlistId);
|
||||
}
|
||||
|
||||
void AsyncYTMusic::internalFetchPlaylist(const QString &playlistId)
|
||||
{
|
||||
try {
|
||||
Q_EMIT fetchPlaylistFinished(m_ytm->get_playlist(playlistId.toStdString()));
|
||||
} catch (const py::error_already_set &err) {
|
||||
Q_EMIT errorOccurred(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
QFuture<playlist::Playlist> AsyncYTMusic::fetchPlaylist(const QString &playlistId) {
|
||||
return invokeAndCatchOnThread([=, this]() {
|
||||
return m_ytm->get_playlist(playlistId.toStdString());
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// fetchArtistAlbum
|
||||
//
|
||||
void AsyncYTMusic::fetchArtistAlbums(const QString &channelId, const QString ¶ms)
|
||||
QFuture<std::vector<artist::Artist::Album>> AsyncYTMusic::fetchArtistAlbums(const QString &channelId, const QString ¶ms)
|
||||
{
|
||||
Q_EMIT startFetchArtistAlbums(channelId, params);
|
||||
}
|
||||
|
||||
void AsyncYTMusic::internalFetchArtistAlbums(const QString &channelid, const QString ¶ms)
|
||||
{
|
||||
try {
|
||||
Q_EMIT fetchArtistAlbumsFinished(m_ytm->get_artist_albums(channelid.toStdString(), params.toStdString()));
|
||||
} catch (const py::error_already_set &err) {
|
||||
Q_EMIT errorOccurred(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
return invokeAndCatchOnThread([=, this]() {
|
||||
return m_ytm->get_artist_albums(channelId.toStdString(), params.toStdString());
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// extractVideoInfo
|
||||
//
|
||||
void AsyncYTMusic::extractVideoInfo(const QString &videoId)
|
||||
QFuture<video_info::VideoInfo> AsyncYTMusic::extractVideoInfo(const QString &videoId)
|
||||
{
|
||||
Q_EMIT startExtractVideoInfo(videoId);
|
||||
}
|
||||
|
||||
void AsyncYTMusic::internalExtractVideoInfo(const QString &videoId)
|
||||
{
|
||||
try {
|
||||
Q_EMIT extractVideoInfoFinished(m_ytm->extract_video_info(videoId.toStdString()));
|
||||
} catch (const py::error_already_set &err) {
|
||||
Q_EMIT errorOccurred(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
return invokeAndCatchOnThread([=, this]() {
|
||||
return m_ytm->extract_video_info(videoId.toStdString());
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// fetchWatchPlaylist
|
||||
//
|
||||
void AsyncYTMusic::fetchWatchPlaylist(const std::optional<QString> &videoId, const std::optional<QString> &playlistId)
|
||||
QFuture<watch::Playlist> AsyncYTMusic::fetchWatchPlaylist(const std::optional<QString> &videoId, const std::optional<QString> &playlistId)
|
||||
{
|
||||
Q_EMIT startFetchWatchPlaylist(videoId, playlistId);
|
||||
return invokeAndCatchOnThread([=, this]() {
|
||||
return m_ytm->get_watch_playlist(
|
||||
mapOptional(videoId, &QString::toStdString),
|
||||
mapOptional(playlistId, &QString::toStdString)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void AsyncYTMusic::internalFetchWatchPlaylist(const std::optional<QString> &videoId, const std::optional<QString> &playlistId)
|
||||
QFuture<Lyrics> AsyncYTMusic::fetchLyrics(const QString &browseId)
|
||||
{
|
||||
try {
|
||||
Q_EMIT fetchWatchPlaylistFinished(m_ytm->get_watch_playlist(
|
||||
map_optional<std::string>(videoId, [](const QString &value) { return value.toStdString(); }),
|
||||
map_optional<std::string>(playlistId, [](const QString &value) { return value.toStdString(); })
|
||||
));
|
||||
} catch (const py::error_already_set &err) {
|
||||
Q_EMIT errorOccurred(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
return invokeAndCatchOnThread([=, this]() {
|
||||
return m_ytm->get_lyrics(
|
||||
browseId.toStdString()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
YTMusicThread &YTMusicThread::instance()
|
||||
@@ -203,17 +162,19 @@ YTMusicThread::~YTMusicThread()
|
||||
|
||||
AsyncYTMusic *YTMusicThread::operator->()
|
||||
{
|
||||
return &m_ytm;
|
||||
return m_ytm;
|
||||
}
|
||||
|
||||
AsyncYTMusic &YTMusicThread::get()
|
||||
{
|
||||
return m_ytm;
|
||||
return *m_ytm;
|
||||
}
|
||||
|
||||
YTMusicThread::YTMusicThread()
|
||||
: m_ytm(new AsyncYTMusic())
|
||||
{
|
||||
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, m_ytm, &QObject::deleteLater);
|
||||
setObjectName(QStringLiteral("YTMusicAPI"));
|
||||
m_ytm.moveToThread(this);
|
||||
m_ytm->moveToThread(this);
|
||||
start();
|
||||
}
|
||||
+79
-40
@@ -6,11 +6,15 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <ytmusic.h>
|
||||
|
||||
constexpr QStringView YTMUSIC_WEB_BASE_URL = u"https://music.youtube.com/";
|
||||
|
||||
Q_DECLARE_METATYPE(std::vector<artist::Artist::Album>);
|
||||
Q_DECLARE_METATYPE(std::vector<search::SearchResultItem>)
|
||||
Q_DECLARE_METATYPE(artist::Artist)
|
||||
@@ -45,6 +49,53 @@ private:
|
||||
std::unique_ptr<T> m_item = nullptr;
|
||||
};
|
||||
|
||||
///
|
||||
/// Similar to QObject::connect, except that the first two arguments are replaced with a QFuture.
|
||||
///
|
||||
template <typename T, typename QObjectDerivedType, typename Function>
|
||||
void connectFuture(const QFuture<T> &future, QObjectDerivedType *self, const Function &fun) {
|
||||
auto watcher = std::make_shared<QFutureWatcher<T>>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher.get(), &QFutureWatcherBase::finished, self, [self, watcher, fun, future]() {
|
||||
if constexpr (std::is_same_v<void, T>) {
|
||||
if constexpr (std::is_member_function_pointer_v<Function>) {
|
||||
(self->*fun)();
|
||||
} else {
|
||||
Q_UNUSED(self);
|
||||
fun();
|
||||
}
|
||||
} else if (future.resultCount() > 0) {
|
||||
if constexpr (std::is_member_function_pointer_v<Function>) {
|
||||
(self->*fun)(watcher->result());
|
||||
} else {
|
||||
Q_UNUSED(self);
|
||||
fun(watcher->result());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
///
|
||||
/// Applies a function to a the contained value of a QFuture once it finishes.
|
||||
/// @returns a QFuture that finishes once the future given as first argument finished
|
||||
///
|
||||
template <typename T, typename Func>
|
||||
QFuture<std::invoke_result_t<Func, T>> mapFuture(const QFuture<T> &future, Func mapFunction) {
|
||||
using ReturnType = std::invoke_result_t<Func, T>;
|
||||
auto watcher = std::make_shared<QFutureWatcher<T>>();
|
||||
watcher->setFuture(future);
|
||||
|
||||
auto interface = std::make_shared<QFutureInterface<ReturnType>>();
|
||||
QObject::connect(watcher.get(), &QFutureWatcherBase::finished, watcher.get(), [interface, watcher, mapFunction] {
|
||||
auto result = watcher->result();
|
||||
auto mapped = mapFunction(std::move(result));
|
||||
interface->reportResult(mapped);
|
||||
interface->reportFinished();
|
||||
});
|
||||
|
||||
return interface->future();
|
||||
}
|
||||
|
||||
class AsyncYTMusic : public QObject
|
||||
{
|
||||
friend class YTMusicThread;
|
||||
@@ -53,30 +104,24 @@ class AsyncYTMusic : public QObject
|
||||
|
||||
public:
|
||||
// public functions need to be thread safe
|
||||
void search(const QString &query);
|
||||
Q_SIGNAL void searchFinished(std::vector<search::SearchResultItem>);
|
||||
QFuture<std::vector<search::SearchResultItem>> search(const QString &query);
|
||||
|
||||
void fetchArtist(const QString &channelId);
|
||||
Q_SIGNAL void fetchArtistFinished(artist::Artist);
|
||||
QFuture<artist::Artist> fetchArtist(const QString &channelId);
|
||||
|
||||
void fetchAlbum(const QString &browseId);
|
||||
Q_SIGNAL void fetchAlbumFinished(album::Album);
|
||||
QFuture<album::Album> fetchAlbum(const QString &browseId);
|
||||
|
||||
void fetchSong(const QString &videoId);
|
||||
Q_SIGNAL void fetchSongFinished(song::Song);
|
||||
QFuture<std::optional<song::Song> > fetchSong(const QString &videoId);
|
||||
|
||||
void fetchPlaylist(const QString &playlistId);
|
||||
Q_SIGNAL void fetchPlaylistFinished(playlist::Playlist);
|
||||
QFuture<playlist::Playlist> fetchPlaylist(const QString &playlistId);
|
||||
|
||||
void fetchArtistAlbums(const QString &channelId, const QString ¶ms);
|
||||
Q_SIGNAL void fetchArtistAlbumsFinished(std::vector<artist::Artist::Album>);
|
||||
QFuture<std::vector<artist::Artist::Album>> fetchArtistAlbums(const QString &channelId, const QString ¶ms);
|
||||
|
||||
void extractVideoInfo(const QString &videoId);
|
||||
Q_SIGNAL void extractVideoInfoFinished(video_info::VideoInfo);
|
||||
QFuture<video_info::VideoInfo> extractVideoInfo(const QString &videoId);
|
||||
|
||||
void fetchWatchPlaylist(const std::optional<QString> &videoId = std::nullopt ,
|
||||
QFuture<watch::Playlist> fetchWatchPlaylist(const std::optional<QString> &videoId = std::nullopt ,
|
||||
const std::optional<QString> &playlistId = std::nullopt);
|
||||
Q_SIGNAL void fetchWatchPlaylistFinished(watch::Playlist);
|
||||
|
||||
QFuture<Lyrics> fetchLyrics(const QString &browseId);
|
||||
|
||||
Q_SIGNAL void errorOccurred(const QString &error);
|
||||
|
||||
@@ -84,29 +129,23 @@ protected:
|
||||
explicit AsyncYTMusic(QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
Q_SIGNAL void startSearch(const QString &query);
|
||||
Q_SLOT void internalSearch(const QString &query);
|
||||
|
||||
Q_SIGNAL void startFetchArtist(const QString &channelId);
|
||||
Q_SLOT void internalFetchArtist(const QString &channelId);
|
||||
|
||||
Q_SIGNAL void startFetchAlbum(const QString &browseId);
|
||||
Q_SLOT void internalFetchAlbum(const QString &browseId);
|
||||
|
||||
Q_SIGNAL void startFetchSong(const QString &videoId);
|
||||
Q_SLOT void internalFetchSong(const QString &videoId);
|
||||
|
||||
Q_SIGNAL void startFetchPlaylist(const QString &playlistId);
|
||||
Q_SLOT void internalFetchPlaylist(const QString &playlistId);
|
||||
|
||||
Q_SIGNAL void startFetchArtistAlbums(const QString &channelid, const QString ¶ms);
|
||||
Q_SLOT void internalFetchArtistAlbums(const QString &channelid, const QString ¶ms);
|
||||
|
||||
Q_SIGNAL void startExtractVideoInfo(const QString &videoId);
|
||||
Q_SLOT void internalExtractVideoInfo(const QString &videoId);
|
||||
|
||||
Q_SIGNAL void startFetchWatchPlaylist(const std::optional<QString> &videoId, const std::optional<QString> &playlistId);
|
||||
Q_SLOT void internalFetchWatchPlaylist(const std::optional<QString> &videoId, const std::optional<QString> &playlistId);
|
||||
/// Invokes the given function on the thread of the YTMusic object, and handles exceptions that occur while invoking it.
|
||||
template <typename Func>
|
||||
QFuture<std::invoke_result_t<Func>> invokeAndCatchOnThread(Func fun) {
|
||||
using ReturnType = std::invoke_result_t<Func>;
|
||||
auto interface = std::make_shared<QFutureInterface<ReturnType>>();
|
||||
QMetaObject::invokeMethod(this, [=, this]() {
|
||||
try {
|
||||
ReturnType val = fun();
|
||||
interface->reportResult(val);
|
||||
interface->reportFinished();
|
||||
} catch (const std::exception &err) {
|
||||
interface->reportFinished();
|
||||
Q_EMIT errorOccurred(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
});
|
||||
return interface->future();
|
||||
}
|
||||
|
||||
// Python interpreter will be initialized from the thread calling the methods
|
||||
Lazy<YTMusic> m_ytm;
|
||||
@@ -123,5 +162,5 @@ public:
|
||||
private:
|
||||
YTMusicThread();
|
||||
|
||||
AsyncYTMusic m_ytm;
|
||||
AsyncYTMusic *m_ytm;
|
||||
};
|
||||
@@ -13,39 +13,65 @@ Kirigami.ScrollablePage {
|
||||
property alias browseId: albumModel.browseId
|
||||
title: albumModel.title
|
||||
|
||||
actions {
|
||||
main: Kirigami.Action {
|
||||
icon.name: "media-playback-start"
|
||||
text: i18n("Play")
|
||||
onTriggered: {
|
||||
applicationWindow().playPlaylist(albumModel.playlistId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
header: Kirigami.ItemViewHeader {
|
||||
backgroundImage.source: albumModel.thumbnailUrl
|
||||
id: songList
|
||||
header: ListHeader {
|
||||
visibleActions: [
|
||||
Kirigami.Action {
|
||||
icon.name: "media-playback-start"
|
||||
text: i18n("Play")
|
||||
onTriggered: {
|
||||
applicationWindow().playPlaylist(albumModel.playlistId)
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "media-playlist-shuffle"
|
||||
text: i18n("Shuffle")
|
||||
onTriggered: {
|
||||
applicationWindow().playShufflePlaylist(albumModel.playlistId)
|
||||
}
|
||||
}
|
||||
]
|
||||
overflowActions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Open in Browser")
|
||||
icon.name: "internet-services"
|
||||
onTriggered: Qt.openUrlExternally(albumModel.webUrl)
|
||||
}
|
||||
]
|
||||
title: albumModel.title
|
||||
imageSourceURL: albumModel.thumbnailUrl
|
||||
subtitle: i18n("Album • %1" , albumModel.artists)
|
||||
width: songList.width
|
||||
}
|
||||
|
||||
|
||||
reuseItems: true
|
||||
|
||||
model: AlbumModel {
|
||||
id: albumModel
|
||||
}
|
||||
SongMenu {
|
||||
id: menu
|
||||
}
|
||||
delegate: Kirigami.SwipeListItem {
|
||||
id: delegateItem
|
||||
|
||||
required property string title
|
||||
required property string videoId
|
||||
required property var artists
|
||||
required property string thumbnailUrl
|
||||
required property string artistsDisplayString
|
||||
required property int index
|
||||
|
||||
RowLayout {
|
||||
Layout.fillHeight: true
|
||||
Kirigami.Icon {
|
||||
Layout.fillHeight: true
|
||||
source: "emblem-music-symbolic"
|
||||
Controls.Label {
|
||||
text: (index + 1)
|
||||
font.bold: true
|
||||
leftPadding: 5
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
Layout.preferredWidth: 30
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
@@ -57,18 +83,13 @@ Kirigami.ScrollablePage {
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
icon.name: "go-next"
|
||||
text: i18n("Play Next")
|
||||
onTriggered: UserPlaylistModel.playNext(delegateItem.videoId, delegateItem.title, delegateItem.artists)
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "media-playlist-append"
|
||||
text: i18n("Add to Playlist")
|
||||
onTriggered: UserPlaylistModel.append(delegateItem.videoId, delegateItem.title, delegateItem.artists)
|
||||
icon.name: "view-more-horizontal-symbolic"
|
||||
text: i18n("More")
|
||||
onTriggered: menu.openForSong(delegateItem.videoId, delegateItem.title, delegateItem.artists, delegateItem.artistsDisplayString)
|
||||
}
|
||||
]
|
||||
|
||||
onClicked: play(videoId)
|
||||
onClicked: play(delegateItem.videoId)
|
||||
}
|
||||
|
||||
Controls.BusyIndicator {
|
||||
|
||||
@@ -11,13 +11,42 @@ import org.kde.ytmusic 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
property alias channelId: artistModel.channelId
|
||||
|
||||
property string radioId
|
||||
property string shuffleId
|
||||
title: artistModel.title
|
||||
|
||||
SongMenu {
|
||||
id: menu
|
||||
}
|
||||
ListView {
|
||||
header: Kirigami.ItemViewHeader {
|
||||
backgroundImage.source: artistModel.thumbnailUrl
|
||||
id: songList
|
||||
|
||||
header: ListHeader {
|
||||
visibleActions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Radio")
|
||||
icon.name: "radio"
|
||||
onTriggered: playPlaylist(radioId)
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Shuffle")
|
||||
icon.name: "media-playlist-shuffle"
|
||||
onTriggered: playPlaylist(shuffleId)
|
||||
}
|
||||
]
|
||||
overflowActions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Open in Browser")
|
||||
icon.name: "internet-services"
|
||||
onTriggered: Qt.openUrlExternally(artistModel.webUrl)
|
||||
}
|
||||
]
|
||||
title: artistModel.title
|
||||
imageSourceURL: artistModel.thumbnailUrl
|
||||
subtitle: i18n("Artist")
|
||||
rounded: true
|
||||
width: songList.width
|
||||
|
||||
}
|
||||
|
||||
reuseItems: true
|
||||
@@ -36,9 +65,18 @@ Kirigami.ScrollablePage {
|
||||
}
|
||||
|
||||
onOpenVideo: (videoId, title) => {
|
||||
askPlayVideoAudio(videoId, title)
|
||||
videoPlayMessage.text = i18n("Video playback is not supported yet. Do you want to play only the audio of \"%1\"?", title)
|
||||
videoPlayMessage.visible = true
|
||||
videoPlayMessage.okAction = () => {
|
||||
play(videoId)
|
||||
videoPlayMessage.visible = false
|
||||
}
|
||||
videoPlayMessage.cancelAction = () => {
|
||||
videoPlayMessage.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section.property: "type"
|
||||
section.delegate: Kirigami.ListSectionHeader {
|
||||
text: {
|
||||
@@ -54,6 +92,7 @@ Kirigami.ScrollablePage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Kirigami.SwipeListItem {
|
||||
id: delegateItem
|
||||
|
||||
@@ -62,22 +101,15 @@ Kirigami.ScrollablePage {
|
||||
required property int index
|
||||
required property var artists
|
||||
required property string videoId
|
||||
required property string thumbnailUrl
|
||||
|
||||
RowLayout {
|
||||
Layout.fillHeight: true
|
||||
Kirigami.Icon {
|
||||
Layout.fillHeight: true
|
||||
source: {
|
||||
switch (type) {
|
||||
case ArtistModel.Album:
|
||||
return "media-album-cover"
|
||||
case ArtistModel.Single:
|
||||
case ArtistModel.Song:
|
||||
return "emblem-music-symbolic"
|
||||
case ArtistModel.Video:
|
||||
return "emblem-videos-symbolic"
|
||||
}
|
||||
}
|
||||
RoundedImage {
|
||||
source: delegateItem.thumbnailUrl
|
||||
height: 35
|
||||
width: height
|
||||
radius:5
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
@@ -89,16 +121,10 @@ Kirigami.ScrollablePage {
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
icon.name: "go-next"
|
||||
text: i18n("Play Next")
|
||||
icon.name: "view-more-horizontal-symbolic"
|
||||
text: i18n("More")
|
||||
visible: type === ArtistModel.Song
|
||||
onTriggered: UserPlaylistModel.playNext(delegateItem.videoId, delegateItem.title, delegateItem.artists)
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "media-playlist-append"
|
||||
text: i18n("Add to Playlist")
|
||||
visible: type === ArtistModel.Song
|
||||
onTriggered: UserPlaylistModel.append(delegateItem.videoId, delegateItem.title, delegateItem.artists)
|
||||
onTriggered: menu.openForSong(delegateItem.videoId, delegateItem.title, delegateItem.artists, artistModel.title)
|
||||
}
|
||||
]
|
||||
|
||||
@@ -110,4 +136,8 @@ Kirigami.ScrollablePage {
|
||||
visible: artistModel.loading
|
||||
}
|
||||
}
|
||||
|
||||
footer: ConfirmationMessage {
|
||||
id: videoPlayMessage
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// SPDX-FileCopyrightText: 2021 Dimitris Kardarakos <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
import org.kde.kirigami 2.14 as Kirigami
|
||||
|
||||
Kirigami.InlineMessage {
|
||||
|
||||
property var okAction
|
||||
property var cancelAction
|
||||
|
||||
visible: false
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("OK")
|
||||
|
||||
onTriggered: okAction()
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Cancel")
|
||||
|
||||
onTriggered: cancelAction()
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
// SPDX-FileCopyrightText: 2022 Jonah Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.1
|
||||
import QtQuick.Controls 2.12 as Controls
|
||||
import QtQuick.Layouts 1.3
|
||||
import org.kde.kirigami 2.14 as Kirigami
|
||||
|
||||
import org.kde.ytmusic 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
objectName: "libraryPage"
|
||||
|
||||
globalToolBarStyle: Kirigami.ApplicationHeaderStyle.None
|
||||
|
||||
ColumnLayout {
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Kirigami.Heading {
|
||||
text: i18n("Favourites")
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
}
|
||||
|
||||
// Spacer
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.ToolButton {
|
||||
text: i18n("Show All")
|
||||
Layout.alignment: Qt.AlignRight
|
||||
icon.name: "arrow-right"
|
||||
onClicked: pageStack.layers.push("qrc:/PlaybackHistory.qml", {
|
||||
"dataModel": Library.favourites,
|
||||
"title": i18n("Favourite Songs")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Controls.ScrollView {
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
Repeater {
|
||||
Layout.fillWidth: true
|
||||
model: Library.favourites
|
||||
delegate: ColumnLayout {
|
||||
id: delegateItem
|
||||
required property string title
|
||||
required property var artists
|
||||
required property string artistsDisplayString
|
||||
required property string videoId
|
||||
|
||||
Layout.fillWidth: false
|
||||
Layout.maximumWidth: 200
|
||||
|
||||
Kirigami.ShadowedRectangle {
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
id: favCover
|
||||
MouseArea {
|
||||
id: favArea
|
||||
anchors.fill: parent
|
||||
onClicked: play(delegateItem.videoId)
|
||||
hoverEnabled: !Kirigami.Settings.hasTransientTouchInput
|
||||
onEntered: {
|
||||
if (!Kirigami.Settings.hasTransientTouchInput){
|
||||
favSelected.visible = true
|
||||
playAnimationPosition.running = true
|
||||
playAnimationOpacity.running = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onExited: favSelected.visible = false
|
||||
|
||||
}
|
||||
Layout.margins: 5
|
||||
|
||||
width: 200
|
||||
height: 200
|
||||
radius: 10
|
||||
shadow.size: 15
|
||||
shadow.xOffset: 5
|
||||
shadow.yOffset: 5
|
||||
shadow.color: Qt.rgba(0, 0, 0, 0.2)
|
||||
ThumbnailSource {
|
||||
id: thumbnailSource
|
||||
videoId: delegateItem.videoId
|
||||
}
|
||||
RoundedImage {
|
||||
source: thumbnailSource.cachedPath
|
||||
height: 200
|
||||
width: height
|
||||
radius: 10
|
||||
}
|
||||
Rectangle {
|
||||
id: favSelected
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Kirigami.Theme.hoverColor
|
||||
radius: 10
|
||||
opacity: 0.2
|
||||
}
|
||||
Item{
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
NumberAnimation on opacity{
|
||||
id: playAnimationOpacity
|
||||
easing.type: Easing.OutCubic
|
||||
running: false
|
||||
from: 0; to: 1
|
||||
}
|
||||
NumberAnimation on y {
|
||||
id: playAnimationPosition
|
||||
easing.type: Easing.OutCubic
|
||||
running: false
|
||||
from: 20; to: 0
|
||||
duration: 100
|
||||
}
|
||||
Rectangle {
|
||||
height: 45
|
||||
width: 45
|
||||
radius: 50
|
||||
color: Kirigami.Theme.hoverColor
|
||||
opacity: 0.8
|
||||
anchors.centerIn: parent
|
||||
|
||||
|
||||
}
|
||||
Kirigami.Icon {
|
||||
x: 100 - 0.43 * height
|
||||
y: 100 - 0.5 * height
|
||||
color: "white"
|
||||
source: "media-playback-start"
|
||||
}
|
||||
}
|
||||
visible: false
|
||||
anchors.fill: parent
|
||||
|
||||
radius: 9
|
||||
|
||||
border.color: Kirigami.Theme.hoverColor
|
||||
border.width: 2
|
||||
color: "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
ColumnLayout {
|
||||
Controls.Label {
|
||||
text: delegateItem.title
|
||||
Layout.maximumWidth: 200
|
||||
Layout.fillWidth: true
|
||||
leftPadding: 5
|
||||
elide: Text.ElideRight
|
||||
|
||||
}
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: 200
|
||||
leftPadding: 5
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
text: delegateItem.artistsDisplayString
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
Controls.ToolButton {
|
||||
Layout.fillHeight: true
|
||||
icon.name: "view-more-horizontal-symbolic"
|
||||
onPressed: favMenu.openForSong(delegateItem.videoId,
|
||||
delegateItem.title,
|
||||
delegateItem.artists,
|
||||
delegateItem.artistsDisplayString)
|
||||
SongMenu {
|
||||
id:favMenu
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Item {
|
||||
height: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
height: 20
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Kirigami.Heading {
|
||||
text: i18n("Most played")
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
}
|
||||
|
||||
// Spacer
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.ToolButton {
|
||||
text: i18n("Show All")
|
||||
Layout.alignment: Qt.AlignRight
|
||||
icon.name: "arrow-right"
|
||||
onClicked: pageStack.layers.push("qrc:/PlaybackHistory.qml", {
|
||||
"dataModel": Library.playbackHistory,
|
||||
"title": i18n("Played Songs")
|
||||
})
|
||||
}
|
||||
}
|
||||
Controls.ScrollView {
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
Repeater {
|
||||
Layout.fillWidth: true
|
||||
model: Library.mostPlayed
|
||||
delegate: ColumnLayout {
|
||||
id: mpdelegateItem
|
||||
required property string title
|
||||
required property var artists
|
||||
required property string artistsDisplayString
|
||||
required property string videoId
|
||||
|
||||
Layout.fillWidth: false
|
||||
Layout.maximumWidth: 200
|
||||
|
||||
Kirigami.ShadowedRectangle {
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
id: recCover
|
||||
MouseArea {
|
||||
id: recArea
|
||||
anchors.fill: parent
|
||||
onClicked: play(mpdelegateItem.videoId)
|
||||
hoverEnabled: !Kirigami.Settings.hasTransientTouchInput
|
||||
onEntered: {
|
||||
if (!Kirigami.Settings.hasTransientTouchInput)
|
||||
recSelected.visible = true
|
||||
playAnimationPositionRec.running = true
|
||||
playAnimationOpacityRec.running = true
|
||||
}
|
||||
onExited: recSelected.visible = false
|
||||
|
||||
}
|
||||
Layout.margins: 5
|
||||
|
||||
width: 200
|
||||
height: 200
|
||||
radius: 10
|
||||
shadow.size: 15
|
||||
shadow.xOffset: 5
|
||||
shadow.yOffset: 5
|
||||
shadow.color: Qt.rgba(0, 0, 0, 0.2)
|
||||
ThumbnailSource {
|
||||
id: mpthumbnailSource
|
||||
videoId: mpdelegateItem.videoId
|
||||
}
|
||||
RoundedImage {
|
||||
source: mpthumbnailSource.cachedPath
|
||||
height: 200
|
||||
width: height
|
||||
radius: 10
|
||||
}
|
||||
Rectangle {
|
||||
id: recSelected
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Kirigami.Theme.hoverColor
|
||||
radius: 10
|
||||
opacity: 0.2
|
||||
}
|
||||
Item{
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
NumberAnimation on opacity{
|
||||
id: playAnimationOpacityRec
|
||||
easing.type: Easing.OutCubic
|
||||
running: false
|
||||
from: 0; to: 1
|
||||
}
|
||||
NumberAnimation on y {
|
||||
id: playAnimationPositionRec
|
||||
easing.type: Easing.OutCubic
|
||||
running: false
|
||||
from: 20; to: 0
|
||||
duration: 100
|
||||
}
|
||||
Rectangle {
|
||||
height: 45
|
||||
width: 45
|
||||
radius: 50
|
||||
color: Kirigami.Theme.hoverColor
|
||||
opacity: 0.8
|
||||
anchors.centerIn: parent
|
||||
|
||||
|
||||
}
|
||||
Kirigami.Icon {
|
||||
x: 100 - 0.43 * height
|
||||
y: 100 - 0.5 * height
|
||||
color: "white"
|
||||
source: "media-playback-start"
|
||||
}
|
||||
}
|
||||
|
||||
visible: false
|
||||
anchors.fill: parent
|
||||
|
||||
radius: 9
|
||||
|
||||
border.color: Kirigami.Theme.hoverColor
|
||||
border.width: 2
|
||||
color: "transparent"
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
ColumnLayout {
|
||||
Controls.Label {
|
||||
text: mpdelegateItem.title
|
||||
Layout.maximumWidth: 200
|
||||
Layout.fillWidth: true
|
||||
leftPadding: 5
|
||||
elide: Text.ElideRight
|
||||
|
||||
}
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: 200
|
||||
leftPadding: 5
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
text: mpdelegateItem.artistsDisplayString
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
Controls.ToolButton {
|
||||
Layout.fillHeight: true
|
||||
icon.name: "view-more-horizontal-symbolic"
|
||||
onPressed: mpMenu.openForSong(mpdelegateItem.videoId,
|
||||
mpdelegateItem.title,
|
||||
mpdelegateItem.artists,
|
||||
mpdelegateItem.artistsDisplayString)
|
||||
SongMenu{
|
||||
id:mpMenu
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Item {
|
||||
height: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
// SPDX-FileCopyrightText: 2022 Mathis Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
import org.kde.kirigami 2.14 as Kirigami
|
||||
import QtQuick.Controls 2.14 as Controls
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import org.kde.ytmusic 1.0
|
||||
|
||||
|
||||
Item {
|
||||
id:root
|
||||
|
||||
required property string imageSourceURL
|
||||
property bool rounded : false
|
||||
required property string title
|
||||
property string subtitle
|
||||
property list<Kirigami.Action> visibleActions
|
||||
property list<Kirigami.Action> overflowActions
|
||||
|
||||
height: root.width > 500 ? 200 : 400
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
|
||||
Image {
|
||||
scale: 1.8
|
||||
anchors.fill: parent
|
||||
asynchronous: true
|
||||
|
||||
source: imageSourceURL
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
sourceSize.width: 512
|
||||
sourceSize.height: 512
|
||||
}
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: HueSaturation {
|
||||
cached: true
|
||||
|
||||
saturation: 1.9
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: FastBlur {
|
||||
cached: true
|
||||
radius: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
gradient: Gradient{
|
||||
GradientStop { position: -1.0; color: "transparent" }
|
||||
GradientStop { position: 1.0; color: Kirigami.Theme.backgroundColor }
|
||||
|
||||
}
|
||||
}
|
||||
GridLayout {
|
||||
width: parent.width
|
||||
|
||||
flow: root.width > 500?GridLayout.LeftToRight:GridLayout.TopToBottom
|
||||
Kirigami.ShadowedRectangle {
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
Layout.margins: 30
|
||||
width: 150
|
||||
height: width
|
||||
radius: rounded ? 100 : 10
|
||||
shadow.size: 15
|
||||
shadow.xOffset: 5
|
||||
shadow.yOffset: 5
|
||||
shadow.color: Qt.rgba(0, 0, 0, 0.2)
|
||||
|
||||
RoundedImage {
|
||||
source: imageSourceURL
|
||||
height: parent.height
|
||||
width: height
|
||||
radius: rounded ? 100 : 10
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.leftMargin: 30
|
||||
Layout.fillWidth: true
|
||||
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: title
|
||||
font.bold: true
|
||||
font.pixelSize: 22
|
||||
elide: Qt.ElideRight
|
||||
|
||||
}
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: subtitle
|
||||
elide: Qt.ElideRight
|
||||
|
||||
}
|
||||
RowLayout {
|
||||
visible: root.visibleActions.length>0
|
||||
Layout.topMargin: 30
|
||||
Layout.rightMargin: 30
|
||||
|
||||
Repeater {
|
||||
model: root.visibleActions
|
||||
delegate: Controls.RoundButton{
|
||||
required property var modelData
|
||||
Layout.fillWidth: root.width <= 500
|
||||
leftPadding: 20
|
||||
rightPadding: 20
|
||||
icon.name: modelData.icon.name
|
||||
text:modelData.text
|
||||
onClicked: modelData.triggered()
|
||||
}
|
||||
}
|
||||
Controls.Menu {
|
||||
id: overflowMenu
|
||||
Instantiator {
|
||||
model: root.overflowActions
|
||||
onObjectAdded: overflowMenu.insertItem(index, object)
|
||||
onObjectRemoved: overflowMenu.removeItem(object)
|
||||
delegate: Controls.MenuItem {
|
||||
required property var modelData
|
||||
icon.name: modelData.icon.name
|
||||
text:modelData.text
|
||||
onTriggered: modelData.triggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
Controls.RoundButton {
|
||||
onClicked: overflowMenu.popup()
|
||||
visible: root.overflowActions.length > 0
|
||||
icon.name: "overflow-menu"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,509 @@
|
||||
// SPDX-FileCopyrightText: 2020-2022 Devin Lin <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtMultimedia 5.12
|
||||
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
import org.kde.ytmusic 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var info // VideoInfoExtractor object
|
||||
required property var audio // Audio object
|
||||
|
||||
signal requestClose()
|
||||
|
||||
// background image
|
||||
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(25, 25, 30, 1)
|
||||
}
|
||||
|
||||
Image {
|
||||
scale: 1.8
|
||||
anchors.fill: parent
|
||||
asynchronous: true
|
||||
|
||||
source: info.thumbnail
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
sourceSize.width: 512
|
||||
sourceSize.height: 512
|
||||
}
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: HueSaturation {
|
||||
cached: true
|
||||
|
||||
lightness: -0.5
|
||||
saturation: 1.9
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: FastBlur {
|
||||
cached: true
|
||||
radius: 100
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
gradient: Gradient{
|
||||
GradientStop { position: 0.0; color: "transparent" }
|
||||
GradientStop { position: 1.1; color: "black" }
|
||||
}
|
||||
}
|
||||
|
||||
// content
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// hide arrow button
|
||||
ToolButton {
|
||||
id: closeButton
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
||||
Layout.maximumHeight: parent.height
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
Layout.maximumWidth: parent.height
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
icon.name: "arrow-down"
|
||||
icon.color: "white"
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
onClicked: root.requestClose()
|
||||
}
|
||||
|
||||
// top tab bar
|
||||
ScrollView {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.maximumWidth: parent.width
|
||||
RowLayout {
|
||||
id: tabBar
|
||||
|
||||
ToolButton {
|
||||
id: nowPlayingTab
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
onClicked: swipeView.setCurrentIndex(0)
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 9
|
||||
|
||||
contentItem: Label {
|
||||
text: i18n("Now Playing")
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
color: "white" // we need to ensure the label is white
|
||||
}
|
||||
|
||||
// selection indicator
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: Kirigami.Theme.highlightColor
|
||||
height: 1
|
||||
visible: swipeView.currentIndex == 0
|
||||
}
|
||||
}
|
||||
ToolButton {
|
||||
id: queueTab
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
onClicked: swipeView.setCurrentIndex(1)
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 9
|
||||
|
||||
contentItem: Label {
|
||||
text: i18n("Queue")
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
color: "white"
|
||||
}
|
||||
|
||||
// selection indicator
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: Kirigami.Theme.highlightColor
|
||||
height: 1
|
||||
visible: swipeView.currentIndex == 1
|
||||
}
|
||||
}
|
||||
ToolButton {
|
||||
id: lyricsTab
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
onClicked: swipeView.setCurrentIndex(2)
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 9
|
||||
|
||||
contentItem: Label {
|
||||
text: i18n("Lyrics")
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
color: "white"
|
||||
}
|
||||
|
||||
// selection indicator
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: Kirigami.Theme.highlightColor
|
||||
height: 1
|
||||
visible: swipeView.currentIndex == 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tabs
|
||||
Item {
|
||||
height: 30
|
||||
}
|
||||
SwipeView {
|
||||
id: swipeView
|
||||
property double specWidth: {
|
||||
let allowedWidth = root.width - Kirigami.Units.largeSpacing * 4;
|
||||
let allowedHeight = root.height - Kirigami.Units.largeSpacing * 8 - (closeButton.height + tabBar.height + bottomPlayerControls.height);
|
||||
if (allowedWidth > allowedHeight) {
|
||||
return allowedHeight;
|
||||
} else {
|
||||
return allowedWidth;
|
||||
}
|
||||
}
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: specWidth
|
||||
|
||||
// music art
|
||||
Item {
|
||||
|
||||
height: swipeView.width
|
||||
width: swipeView.height
|
||||
Kirigami.ShadowedRectangle {
|
||||
anchors.centerIn: parent
|
||||
width: swipeView.specWidth
|
||||
height: swipeView.specWidth
|
||||
|
||||
|
||||
color: "transparent"
|
||||
radius: 10
|
||||
shadow.size: 15
|
||||
shadow.xOffset: 5
|
||||
shadow.yOffset: 5
|
||||
shadow.color: Qt.rgba(0, 0, 0, 0.2)
|
||||
RoundedImage {
|
||||
source: info.thumbnail
|
||||
height: parent.height
|
||||
width: height
|
||||
radius: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
// playlist
|
||||
ColumnLayout{
|
||||
width: swipeView.width
|
||||
height: swipeView.height
|
||||
ScrollView {
|
||||
Layout.maximumWidth: 900
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
ListView {
|
||||
clip: true
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
visible: UserPlaylistModel.loading || UserPlaylistModel.loading
|
||||
}
|
||||
|
||||
model: UserPlaylistModel
|
||||
|
||||
delegate: Kirigami.SwipeListItem {
|
||||
id: delegateItem
|
||||
required property string title
|
||||
required property string videoId
|
||||
required property string artists
|
||||
required property bool isCurrent
|
||||
|
||||
backgroundColor: 'transparent'
|
||||
highlighted: isCurrent
|
||||
onClicked: UserPlaylistModel.skipTo(videoId)
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Kirigami.Heading {
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
level: 2
|
||||
text: title
|
||||
}
|
||||
|
||||
Label {
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
text: artists
|
||||
}
|
||||
}
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Remove Track")
|
||||
icon.name: "list-remove"
|
||||
icon.color: "white"
|
||||
onTriggered: UserPlaylistModel.remove(delegateItem.videoId)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout{
|
||||
width: swipeView.width
|
||||
height: swipeView.height
|
||||
ScrollView {
|
||||
Layout.maximumWidth: 900
|
||||
contentWidth: -1
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
clip: true
|
||||
|
||||
//contentY: audio.position / audio.duration
|
||||
|
||||
Label {
|
||||
padding: 20
|
||||
text: UserPlaylistModel.lyrics
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: bottomPlayerControls
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
Layout.leftMargin: Kirigami.Units.gridUnit * 2
|
||||
Layout.rightMargin: Kirigami.Units.gridUnit * 2
|
||||
Layout.bottomMargin: Kirigami.Units.gridUnit * 2
|
||||
|
||||
// song name
|
||||
Label {
|
||||
id: mainLabel
|
||||
text: info.title ? info.title : i18n("No media playing")
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
// Hardcoded because the footerbar blur always makes a dark-ish
|
||||
// background, so we don't want to use a color scheme color that
|
||||
// might also be dark
|
||||
color: "white"
|
||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 1.5
|
||||
font.weight: Font.Bold
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
// song artist
|
||||
Kirigami.Heading {
|
||||
id: authorLabel
|
||||
text: info.artist ? info.artist : info.channel
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
// Hardcoded because the footerbar blur always makes a dark-ish
|
||||
// background, so we don't want to use a color scheme color that
|
||||
// might also be dark
|
||||
color: "white"
|
||||
opacity: 0.9
|
||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 1.3
|
||||
font.weight: Font.Bold
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
// slider row
|
||||
RowLayout {
|
||||
Layout.topMargin: Kirigami.Units.gridUnit * 2
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: "white"
|
||||
visible: info.title
|
||||
text: PlayerUtils.formatTimestamp(audio.position)
|
||||
}
|
||||
|
||||
Slider {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
to: audio.duration
|
||||
value: audio.position
|
||||
enabled: audio.seekable
|
||||
onMoved: {
|
||||
console.log("Value:", value);
|
||||
audio.seek(Math.floor(value));
|
||||
}
|
||||
|
||||
Behavior on value {
|
||||
NumberAnimation {
|
||||
duration: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: "white"
|
||||
visible: info.title
|
||||
text: PlayerUtils.formatTimestamp(audio.duration)
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
// ensure white icons
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
|
||||
ToolButton {
|
||||
id: favouriteButton
|
||||
readonly property QtObject favouriteWatcher: Library.favouriteWatcher(info.videoId)
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2.5
|
||||
Layout.maximumWidth: height
|
||||
Layout.preferredWidth: height
|
||||
|
||||
onClicked: {
|
||||
if (favouriteWatcher) {
|
||||
if (favouriteWatcher.isFavourite) {
|
||||
Library.removeFavourite(info.videoId)
|
||||
// This would insert slightly ugly data into the database, but let's hope the song is already saved
|
||||
} else {
|
||||
let index = UserPlaylistModel.index(UserPlaylistModel.currentIndex, 0)
|
||||
let videoId = UserPlaylistModel.data(index, UserPlaylistModel.VideoId)
|
||||
let title = UserPlaylistModel.data(index, UserPlaylistModel.Title)
|
||||
let artist = UserPlaylistModel.data(index, UserPlaylistModel.Artists)
|
||||
let album = UserPlaylistModel.data(index, UserPlaylistModel.Album)
|
||||
Library.addFavourite(videoId, title, artist, album)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
icon.name: favouriteWatcher ? (favouriteWatcher.isFavourite ? "starred-symbolic" : "non-starred-symbolic") : ""
|
||||
icon.width: Kirigami.Units.gridUnit * 1.5
|
||||
icon.height: Kirigami.Units.gridUnit * 1.5
|
||||
icon.color: "white"
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
id: skipBackwardButton
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2.5
|
||||
Layout.maximumWidth: height
|
||||
Layout.preferredWidth: height
|
||||
|
||||
enabled: false
|
||||
|
||||
icon.name: "media-skip-backward"
|
||||
icon.width: Kirigami.Units.gridUnit * 1.5
|
||||
icon.height: Kirigami.Units.gridUnit * 1.5
|
||||
icon.color: "white"
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
id: playPauseButton
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 4
|
||||
Layout.maximumWidth: height
|
||||
Layout.preferredWidth: height
|
||||
|
||||
enabled: info.audioUrl != ""
|
||||
onClicked: audio.playbackState === Audio.PlayingState ? audio.pause() : audio.play()
|
||||
|
||||
icon.name: audio.playbackState === Audio.PlayingState ? "media-playback-pause" : "media-playback-start"
|
||||
icon.width: Kirigami.Units.gridUnit * 3
|
||||
icon.height: Kirigami.Units.gridUnit * 3
|
||||
icon.color: "white"
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
id: skipForwardButton
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2.5
|
||||
Layout.maximumWidth: height
|
||||
Layout.preferredWidth: height
|
||||
|
||||
enabled: UserPlaylistModel.canSkip
|
||||
onClicked: UserPlaylistModel.next()
|
||||
|
||||
icon.name: "media-skip-forward"
|
||||
icon.width: Kirigami.Units.gridUnit * 1.5
|
||||
icon.height: Kirigami.Units.gridUnit * 1.5
|
||||
icon.color: "white"
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
id: shuffleButton
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2.5
|
||||
Layout.maximumWidth: height
|
||||
Layout.preferredWidth: height
|
||||
|
||||
onClicked: UserPlaylistModel.shufflePlaylist()
|
||||
|
||||
icon.name: "media-playlist-shuffle"
|
||||
icon.width: Kirigami.Units.gridUnit * 1.5
|
||||
icon.height: Kirigami.Units.gridUnit * 1.5
|
||||
icon.color: "white"
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
// SPDX-FileCopyrightText: 2020-2022 Devin Lin <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtMultimedia 5.12
|
||||
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
import org.kde.ytmusic 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
z: 2000
|
||||
|
||||
required property int progressBarHeight
|
||||
required property int minimizedPlayerContentHeight
|
||||
|
||||
required property var info // VideoInfoExtractor object
|
||||
required property var audio // Audio object
|
||||
|
||||
readonly property bool isWidescreen: width >= Kirigami.Units.gridUnit * 40
|
||||
|
||||
signal requestOpen()
|
||||
|
||||
Rectangle {
|
||||
id: miniProgressBar
|
||||
z: 1
|
||||
visible: !root.isWidescreen
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
height: root.progressBarHeight
|
||||
color: Kirigami.Theme.highlightColor
|
||||
width: parent.width * (audio.position / audio.duration)
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: Kirigami.Units.gridUnit * 20
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 20
|
||||
color: Qt.rgba(0, 0, 0, trackClick.containsMouse ? 0.1 : trackClick.pressed ? 0.3 : 0)
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Kirigami.Units.largeSpacing
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
// track image
|
||||
Item {
|
||||
property double imageSize: root.height - Kirigami.Units.largeSpacing * 2
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.maximumWidth: imageSize
|
||||
Layout.preferredWidth: imageSize
|
||||
Layout.maximumHeight: imageSize
|
||||
Layout.minimumHeight: imageSize
|
||||
|
||||
RoundedImage {
|
||||
id: mainIcon
|
||||
anchors.fill: parent
|
||||
visible: !loadingIndicator.visible
|
||||
source: info.thumbnail
|
||||
radius: 5
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
id: loadingIndicator
|
||||
anchors.centerIn: parent
|
||||
visible: UserPlaylistModel.loading
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
}
|
||||
|
||||
// track information
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Label {
|
||||
id: mainLabel
|
||||
text: info.title ? info.title : i18n("No media playing")
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.Wrap
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
// Hardcoded because the footerbar blur always makes a dark-ish
|
||||
// background, so we don't want to use a color scheme color that
|
||||
// might also be dark
|
||||
color: "white"
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
|
||||
Label {
|
||||
id: authorLabel
|
||||
text: info.artist ? info.artist : info.channel
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.Wrap
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
// Hardcoded because the footerbar blur always makes a dark-ish
|
||||
// background, so we don't want to use a color scheme color that
|
||||
// might also be dark
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: trackClick
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: root.requestOpen()
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: root.isWidescreen
|
||||
Layout.preferredWidth: 0
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: "white"
|
||||
visible: info.title
|
||||
text: PlayerUtils.formatTimestamp(audio.position)
|
||||
}
|
||||
|
||||
Slider {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
to: audio.duration
|
||||
value: audio.position
|
||||
enabled: audio.seekable
|
||||
onMoved: {
|
||||
console.log("Value:", value);
|
||||
audio.seek(Math.floor(value));
|
||||
}
|
||||
|
||||
Behavior on value {
|
||||
NumberAnimation {
|
||||
duration: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: "white"
|
||||
visible: info.title
|
||||
text: PlayerUtils.formatTimestamp(audio.duration)
|
||||
}
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
id: playPauseButton
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
Layout.maximumWidth: height
|
||||
Layout.preferredWidth: height
|
||||
|
||||
enabled: info.audioUrl != ""
|
||||
onClicked: audio.playbackState === Audio.PlayingState ? audio.pause() : audio.play()
|
||||
|
||||
icon.name: audio.playbackState === Audio.PlayingState ? "media-playback-pause" : "media-playback-start"
|
||||
icon.width: Kirigami.Units.gridUnit
|
||||
icon.height: Kirigami.Units.gridUnit
|
||||
icon.color: "white"
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
id: skipForwardButton
|
||||
Layout.rightMargin: Math.floor(Kirigami.Units.smallSpacing / 2)
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
Layout.maximumWidth: height
|
||||
Layout.preferredWidth: height
|
||||
|
||||
enabled: UserPlaylistModel.canSkip
|
||||
onClicked: UserPlaylistModel.next()
|
||||
|
||||
icon.name: "media-skip-forward"
|
||||
icon.width: Kirigami.Units.gridUnit
|
||||
icon.height: Kirigami.Units.gridUnit
|
||||
icon.color: "white"
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// SPDX-FileCopyrightText: 2022 Jonah Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15 as Controls
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
|
||||
import org.kde.ytmusic 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
id: playbackHistoryPage
|
||||
title: i18n("Unknown list of songs")
|
||||
|
||||
property QtObject dataModel
|
||||
SongMenu {
|
||||
id:menu
|
||||
}
|
||||
ListView {
|
||||
id: listView
|
||||
reuseItems: true
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
visible: listView.count < 1
|
||||
text: i18n("No songs here yet")
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
model: playbackHistoryPage.dataModel
|
||||
|
||||
delegate: Kirigami.SwipeListItem {
|
||||
id: delegateItem
|
||||
required property string title
|
||||
required property string videoId
|
||||
required property string artists
|
||||
|
||||
onClicked: {
|
||||
play(videoId)
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
ThumbnailSource {
|
||||
id: thumbnailSource
|
||||
|
||||
videoId: delegateItem.videoId
|
||||
}
|
||||
|
||||
RoundedImage {
|
||||
source: thumbnailSource.cachedPath
|
||||
height: 35
|
||||
width: height
|
||||
radius: 5
|
||||
}
|
||||
ColumnLayout {
|
||||
Controls.Label {
|
||||
text: delegateItem.title
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
text: delegateItem.artists
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
icon.name: "view-more-horizontal-symbolic"
|
||||
text: i18n("More")
|
||||
onTriggered: menu.openForSong(delegateItem.videoId, delegateItem.title, delegateItem.artists, delegateItem.artists)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+372
-203
@@ -1,260 +1,429 @@
|
||||
// SPDX-FileCopyrightText: 2021 Jonah Brüchert <[email protected]>
|
||||
// SPDX-FileCopyrightText: 2021 Bart De Vries <[email protected]>
|
||||
// SPDX-FileCopyrightText: 2020-2022 Devin Lin <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.12 as Controls
|
||||
|
||||
import QtMultimedia 5.12
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import org.kde.kirigami 2.12 as Kirigami
|
||||
import org.kde.ytmusic 1.0
|
||||
import QtMultimedia 5.12
|
||||
|
||||
Item {
|
||||
Flickable {
|
||||
id: footerItem
|
||||
|
||||
property bool maximized: false
|
||||
|
||||
readonly property int progressBarHeight: Kirigami.Units.gridUnit / 6
|
||||
readonly property int minimizedPlayerContentHeight: Math.round(Kirigami.Units.gridUnit * 3.5)
|
||||
readonly property int minimizedPlayerHeight: minimizedPlayerContentHeight + progressBarHeight
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: maximized ? applicationWindow().height : 75
|
||||
|
||||
Rectangle {
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||
anchors.fill: footerLayout
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
function close() {
|
||||
toClose.restart();
|
||||
}
|
||||
|
||||
function resetToBoundsOnFlick() {
|
||||
if (!atYBeginning || !atYEnd) {
|
||||
if (footerItem.verticalVelocity > 0) {
|
||||
toOpen.restart();
|
||||
} else if (footerItem.verticalVelocity < 0) {
|
||||
toClose.restart();
|
||||
} else { // i.e. when verticalVelocity === 0
|
||||
if (contentY > contentHeight / 4) {
|
||||
toOpen.restart();
|
||||
} else {
|
||||
toClose.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetToBoundsOnResize() {
|
||||
if (contentY > contentHeight / 4) {
|
||||
contentY = contentHeight / 2;
|
||||
} else {
|
||||
contentY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NumberAnimation on contentY {
|
||||
id: toOpen
|
||||
from: contentY
|
||||
to: contentHeight / 2
|
||||
duration: Kirigami.Units.longDuration * 2
|
||||
easing.type: Easing.OutCubic
|
||||
running: false
|
||||
}
|
||||
|
||||
NumberAnimation on contentY {
|
||||
id: toClose
|
||||
from: contentY
|
||||
to: 0
|
||||
duration: Kirigami.Units.longDuration * 2
|
||||
easing.type: Easing.OutCubic
|
||||
running: false
|
||||
}
|
||||
|
||||
// snap to end
|
||||
MouseArea {
|
||||
anchors.fill: footerLayout
|
||||
propagateComposedEvents: true
|
||||
onPressed: {
|
||||
toOpen.stop();
|
||||
toClose.stop();
|
||||
propagateComposedEvents = true;
|
||||
}
|
||||
onReleased: footerItem.resetToBoundsOnFlick()
|
||||
}
|
||||
|
||||
onMovementStarted: {
|
||||
toOpen.stop();
|
||||
toClose.stop();
|
||||
}
|
||||
onFlickStarted: resetToBoundsOnFlick()
|
||||
onMovementEnded: resetToBoundsOnFlick()
|
||||
onHeightChanged: resetToBoundsOnResize()
|
||||
|
||||
property var videoInfoExtractor: VideoInfoExtractor {
|
||||
id: info
|
||||
|
||||
onSongChanged: audio.play()
|
||||
videoId: UserPlaylistModel.currentVideoId
|
||||
onTitleChanged: {
|
||||
let index = UserPlaylistModel.index(UserPlaylistModel.currentIndex, 0)
|
||||
let videoId = UserPlaylistModel.data(index, UserPlaylistModel.VideoId)
|
||||
let title = UserPlaylistModel.data(index, UserPlaylistModel.Title)
|
||||
let artist = UserPlaylistModel.data(index, UserPlaylistModel.Artists)
|
||||
let album = UserPlaylistModel.data(index, UserPlaylistModel.Album)
|
||||
Library.addPlaybackHistoryItem(videoId, title, artist, album)
|
||||
}
|
||||
}
|
||||
|
||||
property var audioPlayer: Audio {
|
||||
id: audio
|
||||
|
||||
source: info.audioUrl
|
||||
onStatusChanged: {
|
||||
if (status === Audio.EndOfMedia) {
|
||||
console.log("Song ended");
|
||||
UserPlaylistModel.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentHeight: height * 2
|
||||
|
||||
ColumnLayout {
|
||||
id: footerLayout
|
||||
height: parent.height
|
||||
anchors.fill: parent
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
GridLayout {
|
||||
id: playerLayout
|
||||
|
||||
readonly property bool mobile: width > height
|
||||
|
||||
Layout.fillHeight: footerItem.maximized
|
||||
// margin from top
|
||||
Item {
|
||||
Layout.minimumHeight: footerItem.height - footerItem.minimizedPlayerHeight
|
||||
}
|
||||
|
||||
Controls.Control {
|
||||
Layout.fillWidth: true
|
||||
flow: width > height ? GridLayout.LeftToRight : GridLayout.TopToBottom
|
||||
visible: footerItem.maximized
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: info.thumbnail
|
||||
Layout.fillHeight: info.thumbnail
|
||||
padding: 0
|
||||
implicitHeight: footerItem.minimizedPlayerHeight
|
||||
|
||||
// minimized player background
|
||||
background: Item {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(25, 25, 30, 1)
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: 0.2
|
||||
source: info.thumbnail
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Controls.ScrollView {
|
||||
asynchronous: true
|
||||
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
}
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: HueSaturation {
|
||||
cached: true
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
id: playlistView
|
||||
lightness: -0.5
|
||||
saturation: 1.9
|
||||
|
||||
clip: true
|
||||
|
||||
Controls.BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
visible: UserPlaylistModel.loading || UserPlaylistModel.loading
|
||||
}
|
||||
|
||||
onCountChanged: {
|
||||
if (count < 1) {
|
||||
footerItem.maximized = false
|
||||
}
|
||||
}
|
||||
|
||||
model: UserPlaylistModel
|
||||
|
||||
delegate: Kirigami.SwipeListItem {
|
||||
id: delegateItem
|
||||
required property string title
|
||||
required property string videoId
|
||||
required property string artists
|
||||
required property bool isCurrent
|
||||
|
||||
highlighted: isCurrent
|
||||
onClicked: UserPlaylistModel.skipTo(videoId)
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Kirigami.Heading {
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
level: 2
|
||||
text: title
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
text: artists
|
||||
}
|
||||
}
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Remove Track")
|
||||
icon.name: "list-remove"
|
||||
onTriggered: UserPlaylistModel.remove(delegateItem.videoId)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
header: Controls.ToolBar {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.ToolButton {
|
||||
text: i18n("Clear")
|
||||
icon.name: "edit-clear-all"
|
||||
onClicked: UserPlaylistModel.clear()
|
||||
}
|
||||
Controls.ToolButton {
|
||||
text: i18n("Shuffle")
|
||||
icon.name: "media-playlist-shuffle"
|
||||
onClicked: UserPlaylistModel.shufflePlaylist()
|
||||
}
|
||||
}
|
||||
}
|
||||
layer.enabled: true
|
||||
layer.effect: FastBlur {
|
||||
cached: true
|
||||
radius: 64
|
||||
transparentBorder: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MinimizedPlayerControls {
|
||||
progressBarHeight: footerItem.progressBarHeight
|
||||
minimizedPlayerContentHeight: footerItem.minimizedPlayerContentHeight
|
||||
height: minimizedPlayerHeight
|
||||
|
||||
focus: true
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
|
||||
info: footerItem.videoInfoExtractor
|
||||
audio: footerItem.audioPlayer
|
||||
|
||||
onRequestOpen: toOpen.start();
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
|
||||
MaximizedPlayerPage {
|
||||
id: maximizedPlayerPage
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitHeight: footerItem.height
|
||||
|
||||
info: footerItem.videoInfoExtractor
|
||||
audio: footerItem.audioPlayer
|
||||
|
||||
onRequestClose: toClose.start();
|
||||
}
|
||||
|
||||
//GridLayout {
|
||||
//id: playerLayout
|
||||
|
||||
RowLayout {
|
||||
id: player
|
||||
//readonly property bool mobile: width > height
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: !footer.maximized
|
||||
//Layout.fillHeight: footerItem.maximized
|
||||
//Layout.fillWidth: true
|
||||
//flow: width > height ? GridLayout.LeftToRight : GridLayout.TopToBottom
|
||||
//visible: footerItem.maximized
|
||||
|
||||
VideoInfoExtractor {
|
||||
id: info
|
||||
//ColumnLayout {
|
||||
//Layout.preferredWidth: footerLayout.width * (playerLayout.mobile ? 1 : 0.5)
|
||||
//Layout.preferredHeight: footerLayout.height * (playerLayout.mobile ? 0.5 : 1)
|
||||
|
||||
onSongChanged: audio.play()
|
||||
videoId: UserPlaylistModel.currentVideoId
|
||||
}
|
||||
//Item {
|
||||
//Layout.fillWidth: true
|
||||
//Layout.fillHeight: true
|
||||
|
||||
Audio {
|
||||
id: audio
|
||||
//Image {
|
||||
//anchors.fill: parent
|
||||
//source: info.thumbnail
|
||||
//fillMode: Image.PreserveAspectFit
|
||||
//}
|
||||
//}
|
||||
//Controls.RoundButton {
|
||||
//readonly property QtObject favouriteWatcher: Library.favouriteWatcher(info.videoId)
|
||||
|
||||
source: info.audioUrl
|
||||
onStatusChanged: {
|
||||
if (status === Audio.EndOfMedia) {
|
||||
console.log("Song ended");
|
||||
UserPlaylistModel.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
//Layout.alignment: Qt.AlignHCenter
|
||||
//icon.name: favouriteWatcher ? (favouriteWatcher.isFavourite ? "starred-symbolic" : "non-starred-symbolic") : ""
|
||||
//onClicked: if (favouriteWatcher)
|
||||
//favouriteWatcher.isFavourite
|
||||
//? Library.removeFavourite(info.videoId)
|
||||
//: Library.addFavourite(info.videoId, info.title)
|
||||
//}
|
||||
//}
|
||||
|
||||
Controls.ToolButton {
|
||||
display: Controls.AbstractButton.IconOnly
|
||||
Layout.preferredWidth: parent.height
|
||||
Layout.fillHeight: true
|
||||
enabled: info.audioUrl != ""
|
||||
text: audio.playbackState === Audio.PlayingState ? i18n("Pause") : i18n("Play")
|
||||
visible: !info.loading
|
||||
icon.name: audio.playbackState === Audio.PlayingState ? "media-playback-pause" : "media-playback-start"
|
||||
onClicked: audio.playbackState === Audio.PlayingState ? audio.pause() : audio.play()
|
||||
}
|
||||
//Item {
|
||||
//Layout.fillWidth: true
|
||||
//Layout.fillHeight: true
|
||||
//Layout.preferredWidth: footerLayout.width * (playerLayout.mobile ? 1 : 0.5)
|
||||
//Layout.preferredHeight: footerLayout.height * (playerLayout.mobile ? 0.5 : 1)
|
||||
|
||||
Controls.ToolButton {
|
||||
display: Controls.AbstractButton.IconOnly
|
||||
Layout.preferredWidth: parent.height
|
||||
Layout.fillHeight: true
|
||||
enabled: UserPlaylistModel.canSkip
|
||||
visible: !info.loading
|
||||
icon.name: "media-skip-forward"
|
||||
onClicked: UserPlaylistModel.next()
|
||||
}
|
||||
//Controls.ScrollView {
|
||||
//anchors.fill: parent
|
||||
|
||||
Controls.BusyIndicator {
|
||||
Layout.fillHeight: true
|
||||
visible: info.loading
|
||||
}
|
||||
//ListView {
|
||||
//anchors.fill: parent
|
||||
//id: playlistView
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
||||
//clip: true
|
||||
|
||||
Kirigami.Heading {
|
||||
level: 3
|
||||
Layout.fillWidth: true
|
||||
elide: Qt.ElideRight
|
||||
text: info.title ? info.title : i18n("No media playing")
|
||||
}
|
||||
//Controls.BusyIndicator {
|
||||
//anchors.centerIn: parent
|
||||
//visible: UserPlaylistModel.loading || UserPlaylistModel.loading
|
||||
//}
|
||||
|
||||
RowLayout{
|
||||
//onCountChanged: {
|
||||
//if (count < 1) {
|
||||
//footerItem.maximized = false
|
||||
//}
|
||||
//}
|
||||
|
||||
Controls.Label{
|
||||
visible: info.title
|
||||
text: PlayerUtils.formatTimestamp(audio.position)
|
||||
}
|
||||
//model: UserPlaylistModel
|
||||
|
||||
Controls.Slider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
to: audio.duration
|
||||
value: audio.position
|
||||
enabled: audio.seekable
|
||||
onMoved: {
|
||||
console.log("Value:", value);
|
||||
audio.seek(Math.floor(value));
|
||||
}
|
||||
//delegate: Kirigami.SwipeListItem {
|
||||
//id: delegateItem
|
||||
//required property string title
|
||||
//required property string videoId
|
||||
//required property string artists
|
||||
//required property bool isCurrent
|
||||
|
||||
Behavior on value {
|
||||
NumberAnimation {
|
||||
}
|
||||
//highlighted: isCurrent
|
||||
//onClicked: UserPlaylistModel.skipTo(videoId)
|
||||
|
||||
}
|
||||
//ColumnLayout {
|
||||
//Layout.fillWidth: true
|
||||
//Kirigami.Heading {
|
||||
//elide: Text.ElideRight
|
||||
//Layout.fillWidth: true
|
||||
//level: 2
|
||||
//text: title
|
||||
//}
|
||||
|
||||
}
|
||||
//Controls.Label {
|
||||
//elide: Text.ElideRight
|
||||
//Layout.fillWidth: true
|
||||
//text: artists
|
||||
//}
|
||||
//}
|
||||
|
||||
Controls.Label{
|
||||
visible: info.title
|
||||
text: PlayerUtils.formatTimestamp(audio.duration)
|
||||
}
|
||||
//actions: [
|
||||
//Kirigami.Action {
|
||||
//text: i18n("Remove Track")
|
||||
//icon.name: "list-remove"
|
||||
//onTriggered: UserPlaylistModel.remove(delegateItem.videoId)
|
||||
//}
|
||||
//]
|
||||
//}
|
||||
|
||||
}
|
||||
//header: Controls.ToolBar {
|
||||
//anchors.left: parent.left
|
||||
//anchors.right: parent.right
|
||||
//RowLayout {
|
||||
//anchors.fill: parent
|
||||
//Item {
|
||||
//Layout.fillWidth: true
|
||||
//}
|
||||
|
||||
//Controls.ToolButton {
|
||||
//text: i18n("Clear")
|
||||
//icon.name: "edit-clear-all"
|
||||
//onClicked: UserPlaylistModel.clear()
|
||||
//}
|
||||
//Controls.ToolButton {
|
||||
//text: i18n("Shuffle")
|
||||
//icon.name: "media-playlist-shuffle"
|
||||
//onClicked: UserPlaylistModel.shufflePlaylist()
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
//Kirigami.Separator {
|
||||
//Layout.fillWidth: true
|
||||
//}
|
||||
|
||||
//RowLayout {
|
||||
//id: player
|
||||
|
||||
//Layout.fillWidth: true
|
||||
//Layout.fillHeight: !footer.maximized
|
||||
|
||||
//Controls.ToolButton {
|
||||
//display: Controls.AbstractButton.IconOnly
|
||||
//Layout.preferredWidth: parent.height
|
||||
//Layout.fillHeight: true
|
||||
//enabled: info.audioUrl != ""
|
||||
//text: audio.playbackState === Audio.PlayingState ? i18n("Pause") : i18n("Play")
|
||||
//visible: !info.loading
|
||||
//icon.name: audio.playbackState === Audio.PlayingState ? "media-playback-pause" : "media-playback-start"
|
||||
//onClicked: audio.playbackState === Audio.PlayingState ? audio.pause() : audio.play()
|
||||
//}
|
||||
|
||||
//Controls.ToolButton {
|
||||
//display: Controls.AbstractButton.IconOnly
|
||||
//Layout.preferredWidth: parent.height
|
||||
//Layout.fillHeight: true
|
||||
//enabled: UserPlaylistModel.canSkip
|
||||
//visible: !info.loading
|
||||
//icon.name: "media-skip-forward"
|
||||
//onClicked: UserPlaylistModel.next()
|
||||
//}
|
||||
|
||||
//Controls.BusyIndicator {
|
||||
//Layout.fillHeight: true
|
||||
//visible: info.loading
|
||||
//}
|
||||
|
||||
//ColumnLayout {
|
||||
//Layout.fillHeight: true
|
||||
//Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
//Layout.bottomMargin: Kirigami.Units.smallSpacing
|
||||
|
||||
//Kirigami.Heading {
|
||||
//level: 3
|
||||
//Layout.fillWidth: true
|
||||
//elide: Qt.ElideRight
|
||||
//text: info.title ? info.title : i18n("No media playing")
|
||||
//}
|
||||
|
||||
//RowLayout{
|
||||
|
||||
//Controls.Label{
|
||||
//visible: info.title
|
||||
//text: PlayerUtils.formatTimestamp(audio.position)
|
||||
//}
|
||||
|
||||
//Controls.Slider {
|
||||
//Layout.fillWidth: true
|
||||
//from: 0
|
||||
//to: audio.duration
|
||||
//value: audio.position
|
||||
//enabled: audio.seekable
|
||||
//onMoved: {
|
||||
//console.log("Value:", value);
|
||||
//audio.seek(Math.floor(value));
|
||||
//}
|
||||
|
||||
//Behavior on value {
|
||||
//NumberAnimation {
|
||||
//duration: 1000
|
||||
//}
|
||||
|
||||
//}
|
||||
|
||||
//}
|
||||
|
||||
//Controls.Label{
|
||||
//visible: info.title
|
||||
//text: PlayerUtils.formatTimestamp(audio.duration)
|
||||
//}
|
||||
|
||||
//}
|
||||
|
||||
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
Controls.ToolButton {
|
||||
display: Controls.AbstractButton.IconOnly
|
||||
Layout.preferredWidth: parent.height
|
||||
text: i18n("Expand")
|
||||
enabled: playlistView.count > 0
|
||||
Layout.fillHeight: true
|
||||
icon.name: footerItem.maximized ? "arrow-down" : "arrow-up"
|
||||
onClicked: footerItem.maximized = !footerItem.maximized
|
||||
}
|
||||
//Controls.ToolButton {
|
||||
//display: Controls.AbstractButton.IconOnly
|
||||
//Layout.preferredWidth: parent.height
|
||||
//text: i18n("Expand")
|
||||
//enabled: playlistView.count > 0
|
||||
//Layout.fillHeight: true
|
||||
//icon.name: footerItem.maximized ? "arrow-down" : "arrow-up"
|
||||
//onClicked: footerItem.maximized = !footerItem.maximized
|
||||
//}
|
||||
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
}
|
||||
}
|
||||
//Behavior on height {
|
||||
//NumberAnimation {
|
||||
//}
|
||||
//}
|
||||
}
|
||||
@@ -13,27 +13,34 @@ Kirigami.ScrollablePage {
|
||||
property alias playlistId: playlistModel.playlistId
|
||||
title: playlistModel.title
|
||||
|
||||
actions {
|
||||
main: Kirigami.Action {
|
||||
icon.name: "media-playback-start"
|
||||
text: i18n("Play")
|
||||
onTriggered: {
|
||||
applicationWindow().playPlaylist(playlistModel.playlistId)
|
||||
}
|
||||
}
|
||||
right: Kirigami.Action {
|
||||
icon.name: "media-playlist-shuffle"
|
||||
text: i18n("Shuffle")
|
||||
onTriggered: {
|
||||
applicationWindow().playShufflePlaylist(playlistModel.playlistId)
|
||||
}
|
||||
}
|
||||
SongMenu {
|
||||
id: menu
|
||||
}
|
||||
|
||||
ListView {
|
||||
header: Kirigami.ItemViewHeader {
|
||||
backgroundImage.source: playlistModel.thumbnailUrl
|
||||
id: songList
|
||||
|
||||
header: ListHeader {
|
||||
visibleActions: [
|
||||
Kirigami.Action {
|
||||
icon.name: "media-playback-start"
|
||||
text: i18n("Play")
|
||||
onTriggered: {
|
||||
applicationWindow().playPlaylist(playlistModel.playlistId)
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "media-playlist-shuffle"
|
||||
text: i18n("Shuffle")
|
||||
onTriggered: {
|
||||
applicationWindow().playShufflePlaylist(playlistModel.playlistId)
|
||||
}
|
||||
}
|
||||
]
|
||||
title: playlistModel.title
|
||||
imageSourceURL: playlistModel.thumbnailUrl
|
||||
width: songList.width
|
||||
subtitle: i18n("Playlist")
|
||||
|
||||
}
|
||||
model: PlaylistModel {
|
||||
id: playlistModel
|
||||
@@ -46,31 +53,41 @@ Kirigami.ScrollablePage {
|
||||
required property string title
|
||||
required property string videoId
|
||||
required property var artists
|
||||
required property string thumbnailUrl
|
||||
required property string artistsDisplayString
|
||||
|
||||
|
||||
RowLayout {
|
||||
Layout.fillHeight: true
|
||||
Kirigami.Icon {
|
||||
Layout.fillHeight: true
|
||||
source: "emblem-music-symbolic"
|
||||
RoundedImage {
|
||||
source: delegateItem.thumbnailUrl
|
||||
height: 35
|
||||
width: height
|
||||
radius: 5
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: title
|
||||
elide: Qt.ElideRight
|
||||
ColumnLayout {
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: title
|
||||
elide: Qt.ElideRight
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
visible: delegateItem.artistsDisplayString
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
text: delegateItem.artistsDisplayString
|
||||
elide: Qt.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
icon.name: "go-next"
|
||||
text: i18n("Play Next")
|
||||
onTriggered: UserPlaylistModel.playNext(delegateItem.videoId, delegateItem.title, delegateItem.artists)
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "media-playlist-append"
|
||||
text: i18n("Add to Playlist")
|
||||
onTriggered: UserPlaylistModel.append(delegateItem.videoId, delegateItem.title, delegateItem.artists)
|
||||
icon.name: "view-more-horizontal-symbolic"
|
||||
text: i18n("More")
|
||||
onTriggered: menu.openForSong(delegateItem.videoId, delegateItem.title, delegateItem.artists, delegateItem.artistsDisplayString)
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: 2022 Mathis Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Window 2.15
|
||||
|
||||
Rectangle {
|
||||
property alias radius: mask.radius
|
||||
property alias source: image.source
|
||||
id: icon
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
id: imageSource
|
||||
anchors.fill: parent
|
||||
Image {
|
||||
id:image
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
sourceSize.width: parent.implicitWidth * Screen.devicePixelRatio
|
||||
}
|
||||
visible: false
|
||||
|
||||
layer.enabled: true
|
||||
}
|
||||
|
||||
RoundedMask {
|
||||
id: mask
|
||||
anchors.fill: parent
|
||||
colorSource: imageSource
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// SPDX-FileCopyrightText: Mathis Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
|
||||
Rectangle {
|
||||
id: mask
|
||||
|
||||
radius: 10
|
||||
layer.enabled: true
|
||||
layer.samplerName: "maskSource"
|
||||
property var colorSource
|
||||
|
||||
layer.effect: ShaderEffect {
|
||||
property var colorSource: mask.colorSource
|
||||
fragmentShader: "
|
||||
uniform lowp sampler2D colorSource;
|
||||
uniform lowp sampler2D maskSource;
|
||||
uniform lowp float qt_Opacity;
|
||||
varying highp vec2 qt_TexCoord0;
|
||||
void main() {
|
||||
gl_FragColor = texture2D(colorSource, qt_TexCoord0) * texture2D(maskSource, qt_TexCoord0).a * qt_Opacity;
|
||||
}"
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,27 @@ Kirigami.ScrollablePage {
|
||||
ListView {
|
||||
reuseItems: true
|
||||
|
||||
section.delegate: Kirigami.ListSectionHeader {
|
||||
required property string section
|
||||
text: {
|
||||
switch (parseInt(section)) {
|
||||
case SearchModel.Album:
|
||||
return i18n("Albums")
|
||||
case SearchModel.Artist:
|
||||
return i18n("Artists")
|
||||
case SearchModel.Playlist:
|
||||
return i18n("Playlists")
|
||||
case SearchModel.Song:
|
||||
return i18n("Songs")
|
||||
case SearchModel.Video:
|
||||
return i18n("Videos")
|
||||
}
|
||||
|
||||
return i18n("Unknown")
|
||||
}
|
||||
}
|
||||
section.property: "type"
|
||||
|
||||
model: SearchModel {
|
||||
id: searchModel
|
||||
|
||||
@@ -26,9 +47,11 @@ Kirigami.ScrollablePage {
|
||||
})
|
||||
}
|
||||
|
||||
onOpenArtist: (channelId) => {
|
||||
onOpenArtist: (channelId, radioId, shuffleId) => {
|
||||
pageStack.push("qrc:/ArtistPage.qml", {
|
||||
"channelId": channelId
|
||||
"channelId": channelId,
|
||||
"radioId": radioId,
|
||||
"shuffleId": shuffleId
|
||||
})
|
||||
}
|
||||
|
||||
@@ -43,63 +66,68 @@ Kirigami.ScrollablePage {
|
||||
}
|
||||
|
||||
onOpenVideo: (videoId, title) => {
|
||||
askPlayVideoAudio(videoId, title)
|
||||
videoPlayMessage.text = i18n("Video playback is not supported yet. Do you want to play only the audio of \"%1\"?", title)
|
||||
videoPlayMessage.visible = true
|
||||
videoPlayMessage.okAction = function() {
|
||||
play(videoId)
|
||||
videoPlayMessage.visible = false
|
||||
}
|
||||
videoPlayMessage.cancelAction = function() {
|
||||
videoPlayMessage.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SongMenu {
|
||||
id: menu
|
||||
}
|
||||
|
||||
delegate: Kirigami.SwipeListItem {
|
||||
|
||||
id: delegateItem
|
||||
|
||||
required property int index
|
||||
required property string title
|
||||
required property int type
|
||||
required property string videoId
|
||||
required property var artists
|
||||
required property string artistsDisplayString
|
||||
required property string radioPlaylistId
|
||||
required property string thumbnailUrl
|
||||
|
||||
RowLayout {
|
||||
Layout.fillHeight: true
|
||||
Kirigami.Icon {
|
||||
Layout.fillHeight: true
|
||||
source: {
|
||||
switch (type) {
|
||||
case SearchModel.Artist:
|
||||
return "view-media-artist"
|
||||
case SearchModel.Album:
|
||||
return "media-album-cover"
|
||||
case SearchModel.Playlist:
|
||||
return "view-media-playlist"
|
||||
case SearchModel.Song:
|
||||
return "emblem-music-symbolic"
|
||||
case SearchModel.Video:
|
||||
return "emblem-videos-symbolic"
|
||||
}
|
||||
}
|
||||
RoundedImage {
|
||||
source: delegateItem.thumbnailUrl
|
||||
height: 35
|
||||
width: height
|
||||
radius: delegateItem.type === SearchModel.Artist?height/2:5
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: title
|
||||
elide: Qt.ElideRight
|
||||
ColumnLayout {
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: title
|
||||
elide: Qt.ElideRight
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
visible: delegateItem.artistsDisplayString
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
text: delegateItem.artistsDisplayString
|
||||
elide: Qt.ElideRight
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
icon.name: "go-next"
|
||||
text: i18n("Play next")
|
||||
visible: delegateItem.type === SearchModel.Song
|
||||
onTriggered: UserPlaylistModel.playNext(delegateItem.videoId, delegateItem.title, delegateItem.artists)
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "media-playlist-append"
|
||||
text: i18n("Add to Playlist")
|
||||
visible: delegateItem.type === SearchModel.Song
|
||||
onTriggered: UserPlaylistModel.append(delegateItem.videoId, delegateItem.title, delegateItem.artists)
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "radio"
|
||||
text: i18n("Radio")
|
||||
visible: delegateItem.type === SearchModel.Artist && delegateItem.radioPlaylistId
|
||||
onTriggered: playPlaylist(delegateItem.radioPlaylistId)
|
||||
icon.name: "view-more-horizontal-symbolic"
|
||||
text: i18n("More")
|
||||
visible: delegateItem.type === SearchModel.Song || delegateItem.type === SearchModel.Video
|
||||
onTriggered: menu.openForSong(delegateItem.videoId, delegateItem.title, delegateItem.artists, delegateItem.artistsDisplayString)
|
||||
}
|
||||
]
|
||||
|
||||
@@ -123,4 +151,8 @@ Kirigami.ScrollablePage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer: ConfirmationMessage {
|
||||
id: videoPlayMessage
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// SPDX-FileCopyrightText: 2022 Mathis Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15 as Controls
|
||||
import org.kde.ytmusic 1.0
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
|
||||
Item{
|
||||
function openForSong(videoId, songTitle, artists, artistsDisplayString) {
|
||||
menu.videoId = videoId
|
||||
drawer.videoId = videoId
|
||||
|
||||
menu.songTitle = songTitle
|
||||
drawer.songTitle = songTitle
|
||||
|
||||
menu.artists = artists
|
||||
drawer.artists = artists
|
||||
|
||||
menu.artistsDisplayString = artistsDisplayString
|
||||
drawer.artistsDisplayString = artistsDisplayString
|
||||
|
||||
Kirigami.Settings.isMobile? drawer.open():menu.popup()
|
||||
}
|
||||
Controls.Drawer {
|
||||
edge: Qt.BottomEdge
|
||||
height:contents.implicitHeight+20
|
||||
width: applicationWindow().width
|
||||
id: drawer
|
||||
property string videoId
|
||||
property string songTitle
|
||||
property var artists
|
||||
property string artistsDisplayString
|
||||
ColumnLayout {
|
||||
id: contents
|
||||
anchors.fill: parent
|
||||
|
||||
Kirigami.Icon {
|
||||
Layout.margins: Kirigami.Units.smallSpacing
|
||||
source: "arrow-down"
|
||||
implicitWidth: Kirigami.Units.gridUnit
|
||||
implicitHeight: Kirigami.Units.gridUnit
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
Kirigami.BasicListItem{
|
||||
|
||||
label: i18n("Play Next")
|
||||
icon: "go-next"
|
||||
onClicked: {
|
||||
UserPlaylistModel.playNext(drawer.videoId, drawer.SongTitle, drawer.artists)
|
||||
drawer.close()
|
||||
}
|
||||
}
|
||||
Kirigami.BasicListItem{
|
||||
|
||||
label: i18n("Add to queue")
|
||||
icon: "media-playlist-append"
|
||||
onClicked: {
|
||||
UserPlaylistModel.append(drawer.videoId, drawer.songTitle, drawer.artists)
|
||||
drawer.close()
|
||||
}
|
||||
}
|
||||
Kirigami.BasicListItem{
|
||||
readonly property QtObject favouriteWatcher: Library.favouriteWatcher(drawer.videoId)
|
||||
|
||||
label: favouriteWatcher ? (favouriteWatcher.isFavourite ? i18n("Remove Favourite"): i18n("Add Favourite")): ""
|
||||
icon: favouriteWatcher ? (favouriteWatcher.isFavourite ? "starred-symbolic" : "non-starred-symbolic") : ""
|
||||
onClicked: {
|
||||
if (favouriteWatcher) {
|
||||
if (favouriteWatcher.isFavourite) {
|
||||
Library.removeFavourite(drawer.videoId)
|
||||
} else {
|
||||
Library.addFavourite(drawer.videoId, drawer.songTitle, drawer.artistsDisplayString, "")
|
||||
}
|
||||
}
|
||||
drawer.close()
|
||||
}
|
||||
}
|
||||
Item{
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Menu{
|
||||
property string videoId
|
||||
property string songTitle
|
||||
property var artists
|
||||
property string artistsDisplayString
|
||||
id: menu
|
||||
|
||||
Controls.MenuItem {
|
||||
text: i18n("Play Next")
|
||||
icon.name: "go-next"
|
||||
onTriggered: UserPlaylistModel.playNext(menu.videoId, menu.SongTitle, menu.artists)
|
||||
}
|
||||
|
||||
Controls.MenuItem {
|
||||
text: i18n("Add to queue")
|
||||
icon.name: "media-playlist-append"
|
||||
onTriggered: UserPlaylistModel.append(menu.videoId, menu.songTitle, menu.artists)
|
||||
}
|
||||
|
||||
Controls.MenuItem {
|
||||
readonly property QtObject favouriteWatcher: Library.favouriteWatcher(menu.videoId)
|
||||
text: favouriteWatcher ? (favouriteWatcher.isFavourite ? i18n("Remove Favourite"): i18n("Add Favourite")): ""
|
||||
icon.name: favouriteWatcher ? (favouriteWatcher.isFavourite ? "starred-symbolic" : "non-starred-symbolic") : ""
|
||||
onTriggered: {
|
||||
if (favouriteWatcher) {
|
||||
if (favouriteWatcher.isFavourite) {
|
||||
Library.removeFavourite(menu.videoId)
|
||||
} else {
|
||||
Library.addFavourite(menu.videoId, menu.songTitle, menu.artistsDisplayString, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+268
-28
@@ -12,10 +12,22 @@ import org.kde.ytmusic 1.0
|
||||
Kirigami.ApplicationWindow {
|
||||
id: root
|
||||
|
||||
property alias searchField: searchField
|
||||
property alias searchField: searchLoader.item // TODO
|
||||
|
||||
property bool wideScreen: width >= 600
|
||||
property bool showSearch: false // only applicable if not widescreen
|
||||
|
||||
// so that there is still a separator, since the header style is none
|
||||
Kirigami.Separator {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
visible: pageStack.currentItem.objectName == "libraryPage"
|
||||
&& pageStack.layers.depth == 1
|
||||
}
|
||||
|
||||
header: Controls.Control {
|
||||
visible: !footer.maximized
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
|
||||
background: Rectangle {
|
||||
@@ -26,37 +38,68 @@ Kirigami.ApplicationWindow {
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Header
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
}
|
||||
contentItem: RowLayout{
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: RowLayout {
|
||||
Controls.ToolButton {
|
||||
id: searchBack
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
visible:
|
||||
(!root.wideScreen && root.showSearch && root.searchField.text === "")
|
||||
|| pageStack.layers.depth > 1
|
||||
text: i18n("Back")
|
||||
icon.name: "go-previous-view"
|
||||
display: Controls.ToolButton.IconOnly
|
||||
onClicked: if (root.showSearch)
|
||||
root.showSearch = false
|
||||
else
|
||||
pageStack.layers.pop()
|
||||
}
|
||||
Kirigami.SearchField {
|
||||
id: searchField
|
||||
delaySearch: true
|
||||
selectByMouse: true
|
||||
|
||||
Kirigami.Heading {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
level: 1
|
||||
text: "AudioTube"
|
||||
visible: !root.wideScreen && !root.showSearch
|
||||
}
|
||||
|
||||
// spacer
|
||||
Item {
|
||||
Layout.fillWidth: !root.wideScreen
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: searchLoader
|
||||
visible: root.wideScreen || root.showSearch
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: 400
|
||||
onAccepted: {
|
||||
pageStack.clear()
|
||||
pageStack.push("qrc:/SearchPage.qml", {
|
||||
"searchQuery": text})
|
||||
}
|
||||
sourceComponent: searchFieldComponent
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Controls.ToolButton {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
visible: !root.wideScreen && !root.showSearch
|
||||
text: i18n("Search")
|
||||
icon.name: "search"
|
||||
display: Controls.ToolButton.TextBesideIcon
|
||||
onClicked: {
|
||||
root.showSearch = true
|
||||
root.searchField.forceActiveFocus();
|
||||
root.searchField.popup.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
title: i18n("AudioTube")
|
||||
|
||||
controlsVisible: !footer.maximized
|
||||
|
||||
contextDrawer: Kirigami.ContextDrawer {
|
||||
id: contextDrawer
|
||||
}
|
||||
|
||||
pageStack.initialPage: "qrc:/SearchPage.qml"
|
||||
pageStack.initialPage: "qrc:/LibraryPage.qml"
|
||||
pageStack.clip: true
|
||||
|
||||
function play(videoId) {
|
||||
UserPlaylistModel.initialVideoId = videoId
|
||||
@@ -71,14 +114,6 @@ Kirigami.ApplicationWindow {
|
||||
UserPlaylistModel.playlistId = playlistId
|
||||
}
|
||||
|
||||
function askPlayVideoAudio(videoId, title) {
|
||||
showPassiveNotification(i18n("Video playback is not supported yet. Do you want to play only the audio of \"%1\"?", title),
|
||||
"long",
|
||||
i18n("Play only Audio"),
|
||||
function() {
|
||||
play(videoId)
|
||||
})
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ErrorHandler
|
||||
@@ -88,5 +123,210 @@ Kirigami.ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
footer: PlayerFooter {}
|
||||
Component {
|
||||
id: searchAlbum
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
id: mpdelegateItem
|
||||
|
||||
width: 100
|
||||
Layout.maximumWidth: 70
|
||||
|
||||
Kirigami.ShadowedRectangle {
|
||||
id: recCover
|
||||
MouseArea {
|
||||
id: recArea
|
||||
anchors.fill: parent
|
||||
onClicked: play(model.videoId)
|
||||
hoverEnabled: !Kirigami.Settings.hasTransientTouchInput
|
||||
onEntered: {
|
||||
if (!Kirigami.Settings.hasTransientTouchInput)
|
||||
recSelected.visible = true
|
||||
}
|
||||
onExited: recSelected.visible = false
|
||||
|
||||
}
|
||||
Layout.margins: 5
|
||||
|
||||
width: 70
|
||||
height: 70
|
||||
radius: 10
|
||||
shadow.size: 15
|
||||
shadow.xOffset: 5
|
||||
shadow.yOffset: 5
|
||||
shadow.color: Qt.rgba(0, 0, 0, 0.2)
|
||||
Rectangle {
|
||||
width: 70
|
||||
height: 70
|
||||
|
||||
color: "transparent"
|
||||
|
||||
ThumbnailSource {
|
||||
id: thumbnailSource
|
||||
videoId: model ? model.videoId : ""
|
||||
}
|
||||
RoundedImage {
|
||||
source: thumbnailSource.cachedPath
|
||||
height: parent.height
|
||||
width: height
|
||||
radius: 10
|
||||
}
|
||||
Rectangle {
|
||||
id: recSelected
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Kirigami.Theme.hoverColor
|
||||
radius: 10
|
||||
opacity: 0.2
|
||||
}
|
||||
|
||||
visible: false
|
||||
anchors.fill: parent
|
||||
|
||||
radius: 9
|
||||
|
||||
border.color: Kirigami.Theme.hoverColor
|
||||
border.width: 2
|
||||
color: "transparent"
|
||||
}
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
leftPadding:5
|
||||
Layout.maximumWidth: 70
|
||||
text: model ? model.title : ""
|
||||
elide: Qt.ElideRight
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.maximumHeight: 40
|
||||
}
|
||||
Item {
|
||||
height: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: searchFieldComponent
|
||||
|
||||
Kirigami.SearchField {
|
||||
id: searchField
|
||||
|
||||
autoAccept: false
|
||||
selectByMouse: true
|
||||
onPressed: {
|
||||
popup.open()
|
||||
}
|
||||
|
||||
property alias popup: popup
|
||||
|
||||
property var filterExpression: new RegExp(`.*${searchField.text}.*`, "i")
|
||||
|
||||
Controls.Popup {
|
||||
padding: 1
|
||||
id: popup
|
||||
x: searchField.y
|
||||
y: searchField.y + searchField.height
|
||||
width: searchField.width
|
||||
height: completionList
|
||||
? Math.min(completionList.count * Kirigami.Units.gridUnit * 2 + Kirigami.Units.gridUnit * 2 + recents.implicitHeight, Kirigami.Units.gridUnit * 20)
|
||||
: Kirigami.Units.gridUnit * 20
|
||||
|
||||
contentItem: Controls.ScrollView {
|
||||
contentWidth: -1
|
||||
ColumnLayout {
|
||||
width: popup.width
|
||||
|
||||
Controls.ScrollView {
|
||||
id: recents
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: popup.width - 23
|
||||
|
||||
visible: searchField.text && recentsRepeater.count > 0
|
||||
|
||||
leftPadding: 10
|
||||
topPadding: 10
|
||||
Controls.ScrollBar.horizontal.policy: Controls.ScrollBar.AlwaysOff
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: popup.width - 23
|
||||
|
||||
Repeater {
|
||||
id: recentsRepeater
|
||||
Layout.fillWidth: true
|
||||
model: SortFilterModel {
|
||||
filterRole: PlaybackHistoryModel.Title
|
||||
filterRegularExpression: searchField.filterExpression
|
||||
sourceModel: Library.playbackHistory
|
||||
}
|
||||
delegate: Kirigami.DelegateRecycler {
|
||||
sourceComponent: searchAlbum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Kirigami.Separator{
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Repeater {
|
||||
Layout.fillWidth: true
|
||||
|
||||
id: completionList
|
||||
model: SortFilterModel {
|
||||
sourceModel: Library.searches
|
||||
filterRegularExpression: searchField.filterExpression
|
||||
}
|
||||
|
||||
delegate: Controls.ItemDelegate {
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||
Kirigami.Theme.inherit: false
|
||||
Layout.fillWidth: true
|
||||
|
||||
id: completionDelegate
|
||||
width: parent.width
|
||||
height: Kirigami.Units.gridUnit * 2
|
||||
text: model.display
|
||||
onClicked: {
|
||||
searchField.text = model.display
|
||||
searchField.accepted()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onAccepted: {
|
||||
while (pageStack.depth > 0) {
|
||||
pageStack.pop()
|
||||
}
|
||||
|
||||
pageStack.layers.clear()
|
||||
|
||||
if (text) {
|
||||
Library.addSearch(text)
|
||||
pageStack.push("qrc:/SearchPage.qml", {
|
||||
"searchQuery": text})
|
||||
} else {
|
||||
pageStack.push("qrc:/LibraryPage.qml")
|
||||
}
|
||||
|
||||
popup.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pageStack.anchors.bottomMargin: playerFooter.minimizedPlayerHeight + 1
|
||||
|
||||
// media player
|
||||
PlayerFooter {
|
||||
id: playerFooter
|
||||
anchors.topMargin: -root.header.height
|
||||
anchors.fill: parent
|
||||
|
||||
// only expand flicking area to full screen when it is open
|
||||
z: (contentY === 0) ? -1 : 999
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
int main() {
|
||||
const auto ytm = YTMusic();
|
||||
const auto results = ytm.search("Thomas Bangalter");
|
||||
const auto results = ytm.search("Another one bites the dust");
|
||||
|
||||
std::cout << "Found " << results.size() << " results." << std::endl;
|
||||
|
||||
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
// SPDX-FileCopyrightText: 2022 Jonah Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "library.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QDir>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QStringBuilder>
|
||||
|
||||
#include "asyncdatabase.h"
|
||||
|
||||
namespace ranges = std::ranges;
|
||||
|
||||
Library::Library(QObject *parent)
|
||||
: QObject{parent}
|
||||
, m_database(ThreadedDatabase::establishConnection([]() -> DatabaseConfiguration {
|
||||
const auto databaseDirectory = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
// Make sure the database directory exists
|
||||
QDir(databaseDirectory).mkpath(QStringLiteral("."));
|
||||
|
||||
DatabaseConfiguration config;
|
||||
config.setDatabaseName(databaseDirectory % QDir::separator() % "library.sqlite");
|
||||
config.setType(DATABASE_TYPE_SQLITE);
|
||||
return config;
|
||||
}()))
|
||||
{
|
||||
m_database->runMigrations(":/migrations/");
|
||||
}
|
||||
|
||||
Library::~Library() = default;
|
||||
|
||||
Library &Library::instance()
|
||||
{
|
||||
static Library inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
FavouritesModel *Library::favourites()
|
||||
{
|
||||
auto future = m_database->getResults<Song>("select * from favourites natural join songs order by favourites.rowid desc");
|
||||
return new FavouritesModel(std::move(future), this);
|
||||
}
|
||||
|
||||
void Library::addFavourite(const QString &videoId, const QString &title, const QString &artist, const QString &album)
|
||||
{
|
||||
connectFuture(addSong(videoId, title, artist, album), this, [=, this] {
|
||||
connectFuture(m_database->execute("insert or ignore into favourites (video_id) values (?)", videoId), this, &Library::favouritesChanged);
|
||||
});
|
||||
}
|
||||
|
||||
void Library::removeFavourite(const QString &videoId)
|
||||
{
|
||||
connectFuture(m_database->execute("delete from favourites where video_id = ?", videoId), this, &Library::favouritesChanged);
|
||||
}
|
||||
|
||||
FavouriteWatcher *Library::favouriteWatcher(const QString &videoId)
|
||||
{
|
||||
if (videoId.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return new FavouriteWatcher(this, videoId);
|
||||
}
|
||||
|
||||
SearchHistoryModel *Library::searches()
|
||||
{
|
||||
return new SearchHistoryModel(m_database->getResults<SingleValue<QString>>("select distinct (search_query) from searches order by search_id desc"), this);
|
||||
}
|
||||
|
||||
void Library::addSearch(const QString &text)
|
||||
{
|
||||
connectFuture(m_database->execute("insert into searches (search_query) values (?)", text), this, &Library::searchesChanged);
|
||||
}
|
||||
|
||||
PlaybackHistoryModel *Library::playbackHistory()
|
||||
{
|
||||
auto future = m_database->getResults<PlayedSong>("select * from played_songs natural join songs");
|
||||
return new PlaybackHistoryModel(std::move(future), this);
|
||||
}
|
||||
|
||||
void Library::addPlaybackHistoryItem(const QString &videoId, const QString &title, const QString &artist, const QString &album)
|
||||
{
|
||||
connectFuture(addSong(videoId, title, artist, album), this, [=, this] {
|
||||
connectFuture(m_database->execute("insert or ignore into played_songs (video_id, plays) values (?, ?)", videoId, 0), this, [=, this] {
|
||||
connectFuture(m_database->execute("update played_songs set plays = plays + 1 where video_id = ? ", videoId), this, &Library::playbackHistoryChanged);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
PlaybackHistoryModel *Library::mostPlayed()
|
||||
{
|
||||
auto future = m_database->getResults<PlayedSong>("select * from played_songs natural join songs order by plays desc limit 10");
|
||||
return new PlaybackHistoryModel(std::move(future), this);
|
||||
}
|
||||
|
||||
QNetworkAccessManager &Library::nam()
|
||||
{
|
||||
return m_networkImageCacher;
|
||||
}
|
||||
|
||||
QFuture<void> Library::addSong(const QString &videoId, const QString &title, const QString &artist, const QString &album)
|
||||
{
|
||||
// replace is used here to update songs from times when we didn't store artist and album
|
||||
return m_database->execute("insert or replace into songs (video_id, title, artist, album) values (?, ?, ?, ?)", videoId, title, artist, album);
|
||||
}
|
||||
|
||||
void ThumbnailSource::setVideoId(const QString &id) {
|
||||
if (m_videoId == id) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_videoId = id;
|
||||
Q_EMIT videoIdChanged();
|
||||
|
||||
const QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) % QDir::separator() % "thumbnails";
|
||||
QDir(cacheDir).mkpath(QStringLiteral("."));
|
||||
const QString cacheLocation = cacheDir % QDir::separator() % id % ".webp";
|
||||
|
||||
if (QFile::exists(cacheLocation)) {
|
||||
setCachedPath(QUrl::fromLocalFile(cacheLocation));
|
||||
return;
|
||||
}
|
||||
|
||||
auto *reply = Library::instance().nam().get(QNetworkRequest(QUrl("https://i.ytimg.com/vi_webp/" % m_videoId % "/maxresdefault.webp")));
|
||||
|
||||
auto storeResult = [this, cacheLocation](QNetworkReply *reply) {
|
||||
QFile file(cacheLocation);
|
||||
file.open(QFile::WriteOnly);
|
||||
file.write(reply->readAll());
|
||||
setCachedPath(QUrl::fromLocalFile(cacheLocation));
|
||||
|
||||
reply->deleteLater();
|
||||
};
|
||||
|
||||
connect(reply, &QNetworkReply::errorOccurred, this, [this, storeResult](auto error) {
|
||||
if (error == QNetworkReply::NetworkError::ContentNotFoundError) {
|
||||
qDebug() << "Naive thumbnail resolution failed, falling back to yt-dlp (slower)";
|
||||
|
||||
connectFuture(YTMusicThread::instance()->extractVideoInfo(m_videoId), this, [this, storeResult](auto info) {
|
||||
auto *reply = Library::instance().nam().get(QNetworkRequest(QUrl(QString::fromStdString(info.thumbnail))));
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, storeResult]() {
|
||||
storeResult(reply);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, storeResult]() {
|
||||
storeResult(reply);
|
||||
});
|
||||
}
|
||||
|
||||
PlaybackHistoryModel::PlaybackHistoryModel(QFuture<std::vector<PlayedSong> > &&songs, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
connectFuture(songs, this, [this](const auto songs) {
|
||||
beginResetModel();
|
||||
m_playedSongs = songs;
|
||||
endResetModel();
|
||||
});
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> PlaybackHistoryModel::roleNames() const {
|
||||
return {
|
||||
{Roles::VideoId, "videoId"},
|
||||
{Roles::Title, "title"},
|
||||
{Roles::Artists, "artists"},
|
||||
{Roles::ArtistsDisplayString, "artistsDisplayString"},
|
||||
{Roles::Plays, "plays"}
|
||||
};
|
||||
}
|
||||
|
||||
int PlaybackHistoryModel::rowCount(const QModelIndex &parent) const {
|
||||
return parent.isValid() ? 0 : m_playedSongs.size();
|
||||
}
|
||||
|
||||
QVariant PlaybackHistoryModel::data(const QModelIndex &index, int role) const {
|
||||
switch (role) {
|
||||
case Roles::VideoId:
|
||||
return m_playedSongs.at(index.row()).videoId;
|
||||
case Roles::Title:
|
||||
return m_playedSongs.at(index.row()).title;
|
||||
case Roles::Artists:
|
||||
return QVariant::fromValue(std::vector<meta::Artist> {
|
||||
{
|
||||
m_playedSongs.at(index.row()).artist.toStdString(),
|
||||
{}
|
||||
}
|
||||
});
|
||||
case Roles::ArtistsDisplayString:
|
||||
return m_playedSongs.at(index.row()).artist;
|
||||
case Roles::Plays:
|
||||
return m_playedSongs.at(index.row()).plays;
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
FavouritesModel::FavouritesModel(QFuture<std::vector<Song>> &&songs, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
connectFuture(songs, this, [this](const auto songs) {
|
||||
beginResetModel();
|
||||
m_favouriteSongs = songs;
|
||||
endResetModel();
|
||||
});
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> FavouritesModel::roleNames() const {
|
||||
return {
|
||||
{Roles::VideoId, "videoId"},
|
||||
{Roles::Title, "title"},
|
||||
{Roles::Artists, "artists"},
|
||||
{Roles::ArtistsDisplayString, "artistsDisplayString"}
|
||||
};
|
||||
}
|
||||
|
||||
int FavouritesModel::rowCount(const QModelIndex &parent) const {
|
||||
return parent.isValid() ? 0 : m_favouriteSongs.size();
|
||||
}
|
||||
|
||||
QVariant FavouritesModel::data(const QModelIndex &index, int role) const {
|
||||
switch (role) {
|
||||
case Roles::VideoId:
|
||||
return m_favouriteSongs.at(index.row()).videoId;
|
||||
case Roles::Title:
|
||||
return m_favouriteSongs.at(index.row()).title;
|
||||
case Roles::ArtistsDisplayString:
|
||||
return m_favouriteSongs.at(index.row()).artist;
|
||||
case Roles::Artists:
|
||||
return QVariant::fromValue(std::vector<meta::Artist> {
|
||||
{
|
||||
m_favouriteSongs.at(index.row()).artist.toStdString(),
|
||||
{}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
FavouriteWatcher::FavouriteWatcher(Library *library, const QString &videoId)
|
||||
: QObject(library), m_videoId(videoId), m_library(library)
|
||||
{
|
||||
auto update = [this] {
|
||||
connectFuture(m_library->database().getResult<SingleValue<bool>>("select count(*) > 0 from favourites where video_id = ?", m_videoId), this, [this](auto count) {
|
||||
if (count) {
|
||||
m_isFavourite = count->value;
|
||||
Q_EMIT isFavouriteChanged();
|
||||
}
|
||||
});
|
||||
};
|
||||
update();
|
||||
connect(library, &Library::favouritesChanged, this, update);
|
||||
}
|
||||
|
||||
bool FavouriteWatcher::isFavourite() const {
|
||||
return m_isFavourite;
|
||||
}
|
||||
|
||||
SearchHistoryModel::SearchHistoryModel(QFuture<std::vector<SingleValue<QString>>> &&historyFuture, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
connectFuture(historyFuture, this, [this](const auto history) {
|
||||
beginResetModel();
|
||||
m_history = history;
|
||||
endResetModel();
|
||||
});
|
||||
}
|
||||
|
||||
int SearchHistoryModel::rowCount(const QModelIndex &parent) const {
|
||||
return parent.isValid() ? 0 : m_history.size();
|
||||
}
|
||||
|
||||
QVariant SearchHistoryModel::data(const QModelIndex &index, int role) const {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return m_history[index.row()].value;
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
// SPDX-FileCopyrightText: 2022 Jonah Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QQuickAsyncImageProvider>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "asyncytmusic.h"
|
||||
#include "asyncdatabase.h"
|
||||
|
||||
class FavouriteWatcher;
|
||||
|
||||
struct Song {
|
||||
using ColumnTypes = std::tuple<QString, QString, QString, QString>;
|
||||
|
||||
static Song fromSql(ColumnTypes tuple) {
|
||||
auto [videoId, title, artist, album] = tuple;
|
||||
return Song {videoId, title, artist, album};
|
||||
}
|
||||
|
||||
QString videoId;
|
||||
QString title;
|
||||
QString artist;
|
||||
QString album;
|
||||
};
|
||||
|
||||
class FavouritesModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
|
||||
enum Roles {
|
||||
VideoId = Qt::UserRole + 1,
|
||||
Title,
|
||||
Artists,
|
||||
ArtistsDisplayString
|
||||
};
|
||||
|
||||
public:
|
||||
FavouritesModel(QFuture<std::vector<Song>> &&songs, QObject *parent = nullptr);
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
private:
|
||||
std::vector<Song> m_favouriteSongs;
|
||||
};
|
||||
|
||||
struct PlayedSong {
|
||||
using ColumnTypes = std::tuple<QString, int, QString, QString, QString>;
|
||||
|
||||
static PlayedSong fromSql(ColumnTypes tuple) {
|
||||
auto [videoId, plays, title, artist, album] = tuple;
|
||||
return PlayedSong {videoId, title, artist, album, plays};
|
||||
}
|
||||
|
||||
QString videoId;
|
||||
QString title;
|
||||
QString artist;
|
||||
QString album;
|
||||
int plays;
|
||||
};
|
||||
|
||||
class PlaybackHistoryModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
VideoId = Qt::UserRole + 1,
|
||||
Title,
|
||||
Artists,
|
||||
ArtistsDisplayString,
|
||||
Plays
|
||||
};
|
||||
Q_ENUM(Roles);
|
||||
|
||||
PlaybackHistoryModel(QFuture<std::vector<PlayedSong>> &&songs, QObject *parent = nullptr);
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
private:
|
||||
std::vector<PlayedSong> m_playedSongs;
|
||||
};
|
||||
|
||||
class SearchHistoryModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SearchHistoryModel(QFuture<std::vector<SingleValue<QString>>> &&historyFuture, QObject *parent = nullptr);
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
private:
|
||||
std::vector<SingleValue<QString>> m_history;
|
||||
};
|
||||
|
||||
class Library : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QAbstractListModel *favourites READ favourites NOTIFY favouritesChanged)
|
||||
Q_PROPERTY(QAbstractListModel *searches READ searches NOTIFY searchesChanged)
|
||||
Q_PROPERTY(QAbstractListModel *playbackHistory READ playbackHistory NOTIFY playbackHistoryChanged)
|
||||
Q_PROPERTY(QAbstractListModel *mostPlayed READ mostPlayed NOTIFY playbackHistoryChanged)
|
||||
|
||||
public:
|
||||
explicit Library(QObject *parent = nullptr);
|
||||
~Library();
|
||||
|
||||
static Library &instance();
|
||||
|
||||
FavouritesModel *favourites();
|
||||
Q_SIGNAL void favouritesChanged();
|
||||
Q_INVOKABLE void addFavourite(const QString &videoId, const QString &title, const QString &artist, const QString &album);
|
||||
Q_INVOKABLE void removeFavourite(const QString &videoId);
|
||||
Q_INVOKABLE FavouriteWatcher *favouriteWatcher(const QString &videoId);
|
||||
|
||||
SearchHistoryModel *searches();
|
||||
Q_SIGNAL void searchesChanged();
|
||||
Q_INVOKABLE void addSearch(const QString &text);
|
||||
|
||||
PlaybackHistoryModel *playbackHistory();
|
||||
Q_SIGNAL void playbackHistoryChanged();
|
||||
Q_INVOKABLE void addPlaybackHistoryItem(const QString &videoId, const QString &title, const QString &artist, const QString &album);
|
||||
|
||||
PlaybackHistoryModel *mostPlayed();
|
||||
|
||||
QNetworkAccessManager &nam();
|
||||
ThreadedDatabase &database() {
|
||||
return *m_database;
|
||||
}
|
||||
|
||||
private:
|
||||
QFuture<void> addSong(const QString &videoId, const QString &title, const QString &artist, const QString &album);
|
||||
|
||||
QNetworkAccessManager m_networkImageCacher;
|
||||
std::unique_ptr<ThreadedDatabase> m_database;
|
||||
};
|
||||
|
||||
|
||||
class ThumbnailSource : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString videoId READ videoId WRITE setVideoId NOTIFY videoIdChanged)
|
||||
Q_PROPERTY(QUrl cachedPath READ cachedPath NOTIFY cachedPathChanged)
|
||||
|
||||
QString videoId() const {
|
||||
return m_videoId;
|
||||
}
|
||||
void setVideoId(const QString &id);
|
||||
Q_SIGNAL void videoIdChanged();
|
||||
|
||||
QUrl cachedPath() const {
|
||||
return m_cachedPath;
|
||||
}
|
||||
void setCachedPath(const QUrl &path) {
|
||||
m_cachedPath = path;
|
||||
cachedPathChanged();
|
||||
}
|
||||
Q_SIGNAL void cachedPathChanged();
|
||||
|
||||
private:
|
||||
QString m_videoId;
|
||||
QUrl m_cachedPath;
|
||||
};
|
||||
|
||||
class FavouriteWatcher : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool isFavourite READ isFavourite NOTIFY isFavouriteChanged)
|
||||
|
||||
public:
|
||||
FavouriteWatcher(Library *library, const QString &videoId);
|
||||
|
||||
bool isFavourite() const;
|
||||
Q_SIGNAL void isFavouriteChanged();
|
||||
|
||||
Q_SIGNAL void videoIdChanged();
|
||||
|
||||
private:
|
||||
QString m_videoId;
|
||||
Library *m_library;
|
||||
bool m_isFavourite = false;
|
||||
};
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <QApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QtQml>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QUrl>
|
||||
#include <KLocalizedContext>
|
||||
#include <KLocalizedString>
|
||||
@@ -19,6 +20,9 @@
|
||||
#include "errorhandler.h"
|
||||
#include "playlistmodel.h"
|
||||
#include "playerutils.h"
|
||||
#include "library.h"
|
||||
|
||||
#include "asyncdatabase.h"
|
||||
|
||||
constexpr auto URI = "org.kde.ytmusic";
|
||||
|
||||
@@ -42,6 +46,8 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
||||
qmlRegisterType<VideoInfoExtractor>(URI, 1, 0, "VideoInfoExtractor");
|
||||
qmlRegisterType<ArtistModel>(URI, 1, 0, "ArtistModel");
|
||||
qmlRegisterType<PlaylistModel>(URI, 1, 0, "PlaylistModel");
|
||||
qmlRegisterUncreatableType<PlaybackHistoryModel>(URI, 1, 0, "PlaybackHistoryModel","");
|
||||
qmlRegisterType<QSortFilterProxyModel>(URI, 1, 0, "SortFilterModel");
|
||||
qmlRegisterSingletonType<UserPlaylistModel>(URI, 1, 0, "UserPlaylistModel", [](QQmlEngine *, QJSEngine *) {
|
||||
return new UserPlaylistModel();
|
||||
});
|
||||
@@ -51,6 +57,9 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
||||
qmlRegisterSingletonType<PlayerUtils>(URI, 1, 0, "PlayerUtils", [](QQmlEngine *, QJSEngine *) {
|
||||
return new PlayerUtils();
|
||||
});
|
||||
qmlRegisterSingletonInstance<Library>(URI, 1, 0, "Library", &Library::instance());
|
||||
qmlRegisterType<ThumbnailSource>(URI, 1, 0, "ThumbnailSource");
|
||||
qmlRegisterAnonymousType<FavouriteWatcher>(URI, 1);
|
||||
|
||||
engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
|
||||
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
|
||||
|
||||
Whitespace-only changes.
@@ -0,0 +1,8 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Jonah Brüchert <[email protected]>
|
||||
--
|
||||
-- SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
drop table songs;
|
||||
drop table played_songs;
|
||||
drop table favourites;
|
||||
drop table searches;
|
||||
@@ -0,0 +1,26 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Jonah Brüchert <[email protected]>
|
||||
--
|
||||
-- SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
create table songs (
|
||||
video_id Text primary key not null,
|
||||
title Text not null,
|
||||
artist Text,
|
||||
album Text
|
||||
);
|
||||
|
||||
create table played_songs (
|
||||
video_id Text primary key not null,
|
||||
plays Int not null,
|
||||
foreign key (video_id) references songs(video_id)
|
||||
);
|
||||
|
||||
create table favourites (
|
||||
video_id Text primary key not null,
|
||||
foreign key (video_id) references songs(video_id)
|
||||
);
|
||||
|
||||
create table searches (
|
||||
search_id integer primary key autoincrement not null,
|
||||
search_query Text not null
|
||||
);
|
||||
+49
-52
@@ -6,71 +6,68 @@
|
||||
|
||||
#include <variant>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <span>
|
||||
#include <QtGlobal>
|
||||
|
||||
// MultiIterableView is usually used on a small number of vectors.
|
||||
// The number is already known, so we can convert this into an if else if else etc tree
|
||||
// instead of recursively calling the function
|
||||
#ifdef __GNUC__
|
||||
#define REMOVE_RECURSION __attribute__((always_inline))
|
||||
#else
|
||||
#define REMOVE_RECURSION
|
||||
#endif
|
||||
template <typename Tuple, typename Func, std::size_t i>
|
||||
inline constexpr void iterate_impl(Tuple &tup, Func fun)
|
||||
{
|
||||
if constexpr(i >= std::tuple_size_v<std::decay_t<decltype(tup)>>) {
|
||||
return;
|
||||
} else {
|
||||
fun(std::get<i>(tup));
|
||||
return iterate_impl<Tuple, Func, i + 1>(tup, fun);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tuple, typename Func>
|
||||
inline constexpr void iterate_tuple(Tuple &tup, Func fun)
|
||||
{
|
||||
iterate_impl<Tuple, Func, 0>(tup, fun);
|
||||
}
|
||||
|
||||
/// MultiIterableView is a view over multiple contigous memory arrays, like std::vector or std::array.
|
||||
/// The elements of the arrays do not need to be of the same type.
|
||||
template <typename... Arguments>
|
||||
class MultiIterableView {
|
||||
private:
|
||||
template<typename T, size_t i, size_t len>
|
||||
REMOVE_RECURSION inline size_t count(const T &tuple, int initial_size = 0) const {
|
||||
if constexpr(i < len) {
|
||||
return count<T, i + 1, len>(tuple, initial_size + std::get<i>(tuple).size());
|
||||
} else {
|
||||
return initial_size;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, size_t tuple_i, size_t tuple_len>
|
||||
REMOVE_RECURSION inline std::variant<Arguments...> get_item(const T &tuple, size_t i) const {
|
||||
if constexpr(tuple_i < tuple_len) {
|
||||
if (i < std::get<tuple_i>(tuple).size()) {
|
||||
return std::get<tuple_i>(tuple)[i];
|
||||
} else {
|
||||
return get_item<T, tuple_i + 1, tuple_len>(tuple, i - std::get<tuple_i>(tuple).size());
|
||||
}
|
||||
} else {
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, size_t i, size_t len>
|
||||
REMOVE_RECURSION inline bool everything_empty(const T &tuple, bool initial_state = true) const {
|
||||
if constexpr(i < len) {
|
||||
return everything_empty<T, i + 1, len>(tuple, initial_state && std::get<i>(tuple).empty());
|
||||
} else {
|
||||
return initial_state;
|
||||
}
|
||||
}
|
||||
public:
|
||||
explicit MultiIterableView(std::vector<Arguments> &&...lists)
|
||||
: m_vectors(std::make_tuple(lists...))
|
||||
explicit MultiIterableView(std::span<Arguments>... lists)
|
||||
: m_vectors(std::forward_as_tuple(lists...))
|
||||
{
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
constexpr size_t nvecs = std::tuple_size_v<decltype(m_vectors)>;
|
||||
return count<decltype(m_vectors), 0, nvecs>(m_vectors);
|
||||
explicit MultiIterableView(std::vector<Arguments> &...lists)
|
||||
: MultiIterableView(std::span{lists}...)
|
||||
{
|
||||
}
|
||||
|
||||
std::variant<Arguments...> operator[](size_t i) const {
|
||||
constexpr size_t nvecs = std::tuple_size_v<decltype(m_vectors)>;
|
||||
return get_item<decltype(m_vectors), 0, nvecs>(m_vectors, i);
|
||||
[[nodiscard]] constexpr size_t size() const {
|
||||
size_t s = 0;
|
||||
iterate_tuple(m_vectors, [&](auto &vec) {
|
||||
s += vec.size();
|
||||
});
|
||||
return s;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
constexpr size_t nvecs = std::tuple_size_v<decltype(m_vectors)>;
|
||||
return everything_empty<decltype(m_vectors), 0, nvecs>(m_vectors);
|
||||
[[nodiscard]] constexpr std::variant<Arguments...> operator[](size_t i) const {
|
||||
size_t s = 0;
|
||||
std::variant<Arguments...> out;
|
||||
iterate_tuple(m_vectors, [&](auto &vec) {
|
||||
if (i >= s && i < s + vec.size()) {
|
||||
out = vec[i - s];
|
||||
}
|
||||
s += vec.size();
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const {
|
||||
bool empty = true;
|
||||
iterate_tuple(m_vectors, [&](auto &elem) {
|
||||
empty &= elem.empty();
|
||||
});
|
||||
return empty;
|
||||
}
|
||||
private:
|
||||
std::tuple<std::vector<Arguments>...> m_vectors;
|
||||
std::tuple<std::span<Arguments>...> m_vectors;
|
||||
};
|
||||
+22
-12
@@ -13,19 +13,19 @@
|
||||
PlaylistModel::PlaylistModel(QObject *parent)
|
||||
: AbstractYTMusicModel(parent)
|
||||
{
|
||||
connect(this, &PlaylistModel::playlistIdChanged, this, [=] {
|
||||
connect(this, &PlaylistModel::playlistIdChanged, this, [=, this] {
|
||||
setLoading(true);
|
||||
YTMusicThread::instance()->fetchPlaylist(m_playlistId);
|
||||
});
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchPlaylistFinished, this, [=](const playlist::Playlist &playlist) {
|
||||
setLoading(false);
|
||||
beginResetModel();
|
||||
m_playlist = playlist;
|
||||
std::sort(m_playlist.thumbnails.begin(), m_playlist.thumbnails.end());
|
||||
endResetModel();
|
||||
auto future = YTMusicThread::instance()->fetchPlaylist(m_playlistId);
|
||||
connectFuture(future, this, [=, this](const playlist::Playlist &playlist) {
|
||||
setLoading(false);
|
||||
beginResetModel();
|
||||
m_playlist = playlist;
|
||||
std::sort(m_playlist.thumbnails.begin(), m_playlist.thumbnails.end());
|
||||
endResetModel();
|
||||
|
||||
Q_EMIT titleChanged();
|
||||
Q_EMIT thumbnailUrlChanged();
|
||||
Q_EMIT titleChanged();
|
||||
Q_EMIT thumbnailUrlChanged();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ QHash<int, QByteArray> PlaylistModel::roleNames() const
|
||||
return {
|
||||
{Title, "title"},
|
||||
{Artists, "artists"},
|
||||
{VideoId, "videoId"}
|
||||
{VideoId, "videoId"},
|
||||
{ThumbnailUrl, "thumbnailUrl"},
|
||||
{ArtistsDisplayString, "artistsDisplayString"}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -55,6 +57,14 @@ QVariant PlaylistModel::data(const QModelIndex &index, int role) const
|
||||
return QString::fromStdString(*m_playlist.tracks[index.row()].video_id);
|
||||
}
|
||||
return {};
|
||||
case ThumbnailUrl:
|
||||
if (!m_playlist.tracks[index.row()].thumbnails.empty()) {
|
||||
return QString::fromStdString(m_playlist.tracks[index.row()].thumbnails.front().url);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
case ArtistsDisplayString:
|
||||
return PlaylistUtils::artistsToString(m_playlist.tracks[index.row()].artists);
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
|
||||
+3
-1
@@ -26,7 +26,9 @@ public:
|
||||
enum Role {
|
||||
Title,
|
||||
Artists,
|
||||
VideoId
|
||||
VideoId,
|
||||
ThumbnailUrl,
|
||||
ArtistsDisplayString
|
||||
};
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
|
||||
@@ -15,11 +15,12 @@ namespace PlaylistUtils {
|
||||
QString artistsToString(const std::vector<meta::Artist> &artists)
|
||||
{
|
||||
if (!artists.empty()) {
|
||||
return std::accumulate(artists.begin() + 1, artists.end(),
|
||||
QString::fromStdString(artists.front().name),
|
||||
[](QString &string, const meta::Artist &artist) {
|
||||
return string.append(QStringLiteral(", %1").arg(QString::fromStdString(artist.name)));
|
||||
QString string = QString::fromStdString(artists.front().name);
|
||||
std::for_each(artists.begin() + 1, artists.end(),
|
||||
[&string](const meta::Artist &artist) {
|
||||
string.append(QStringLiteral(", %1").arg(QString::fromStdString(artist.name)));
|
||||
});
|
||||
return string;
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
@@ -12,5 +12,16 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
|
||||
<file alias="PlayerFooter.qml">contents/ui/PlayerFooter.qml</file>
|
||||
<file alias="SearchPage.qml">contents/ui/SearchPage.qml</file>
|
||||
<file alias="PlaylistPage.qml">contents/ui/PlaylistPage.qml</file>
|
||||
<file alias="ConfirmationMessage.qml">contents/ui/ConfirmationMessage.qml</file>
|
||||
<file alias="LibraryPage.qml">contents/ui/LibraryPage.qml</file>
|
||||
<file alias="MinimizedPlayerControls.qml">contents/ui/MinimizedPlayerControls.qml</file>
|
||||
<file alias="MaximizedPlayerPage.qml">contents/ui/MaximizedPlayerPage.qml</file>
|
||||
<file>migrations/2022-05-20-194850_init/down.sql</file>
|
||||
<file>migrations/2022-05-20-194850_init/up.sql</file>
|
||||
<file alias="PlaybackHistory.qml">contents/ui/PlaybackHistory.qml</file>
|
||||
<file alias="RoundedMask.qml">contents/ui/RoundedMask.qml</file>
|
||||
<file alias="SongMenu.qml">contents/ui/SongMenu.qml</file>
|
||||
<file alias="ListHeader.qml">contents/ui/ListHeader.qml</file>
|
||||
<file alias="RoundedImage.qml">contents/ui/RoundedImage.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
+55
-10
@@ -3,11 +3,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "searchmodel.h"
|
||||
#include "playlistutils.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
SearchModel::SearchModel(QObject *parent)
|
||||
: AbstractYTMusicModel(parent)
|
||||
{
|
||||
connect(this, &SearchModel::searchQueryChanged, this, [=] {
|
||||
connect(this, &SearchModel::searchQueryChanged, this, [this] {
|
||||
if (m_searchQuery.isEmpty()) {
|
||||
beginResetModel();
|
||||
m_searchResults.clear();
|
||||
@@ -16,15 +19,16 @@ SearchModel::SearchModel(QObject *parent)
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
YTMusicThread::instance()->search(m_searchQuery);
|
||||
auto future = YTMusicThread::instance()->search(m_searchQuery);
|
||||
connectFuture(future, this, [=, this](const std::vector<search::SearchResultItem> &results) {
|
||||
beginResetModel();
|
||||
setLoading(false);
|
||||
m_searchResults = results;
|
||||
|
||||
endResetModel();
|
||||
});
|
||||
});
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::searchFinished, this, [=](const std::vector<search::SearchResultItem> &results) {
|
||||
beginResetModel();
|
||||
setLoading(false);
|
||||
m_searchResults = results;
|
||||
endResetModel();
|
||||
});
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [=] {
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [this] {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
@@ -117,6 +121,24 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const
|
||||
|
||||
return QString();
|
||||
}, m_searchResults.at(index.row()));
|
||||
case ThumbnailUrl:
|
||||
return std::visit([&](auto &&arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if (!arg.thumbnails.empty()) {
|
||||
return QString::fromStdString(arg.thumbnails.front().url);
|
||||
}
|
||||
|
||||
return QString();
|
||||
}, m_searchResults.at(index.row()));
|
||||
case ArtistsDisplayString:
|
||||
return QVariant::fromValue(std::visit([&](auto&& arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, search::Song> || std::is_same_v<T, search::Video> || std::is_same_v<T, search::Album>) {
|
||||
return PlaylistUtils::artistsToString(arg.artists);
|
||||
}
|
||||
return QString();
|
||||
}, m_searchResults.at(index.row())));
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
@@ -131,7 +153,9 @@ QHash<int, QByteArray> SearchModel::roleNames() const
|
||||
{Type, "type"},
|
||||
{VideoId, "videoId"},
|
||||
{Artists, "artists"},
|
||||
{ArtistsDisplayString, "artistsDisplayString"},
|
||||
{RadioPlaylistId, "radioPlaylistId"},
|
||||
{ThumbnailUrl, "thumbnailUrl"}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -153,7 +177,7 @@ void SearchModel::triggerItem(int row)
|
||||
if constexpr (std::is_same_v<T, search::Album>) {
|
||||
Q_EMIT openAlbum(QString::fromStdString(arg.browse_id));
|
||||
} else if constexpr (std::is_same_v<T, search::Artist>) {
|
||||
Q_EMIT openArtist(QString::fromStdString(arg.browse_id));
|
||||
Q_EMIT openArtist(QString::fromStdString(arg.browse_id), QString::fromStdString(arg.radio_id.value_or("")), QString::fromStdString(arg.shuffle_id.value_or("")));
|
||||
} else if constexpr (std::is_same_v<T, search::Playlist>) {
|
||||
Q_EMIT openPlaylist(QString::fromStdString(arg.browse_id));
|
||||
} else if constexpr (std::is_same_v<T, search::Song>) {
|
||||
@@ -165,3 +189,24 @@ void SearchModel::triggerItem(int row)
|
||||
}
|
||||
}, m_searchResults.at(row));
|
||||
}
|
||||
|
||||
|
||||
int SearchModel::itemType(search::SearchResultItem const &item)
|
||||
{
|
||||
return std::visit([&](auto &&arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr(std::is_same_v<T, search::Album>) {
|
||||
return SearchModel::Type::Album;
|
||||
} else if constexpr(std::is_same_v<T, search::Artist>) {
|
||||
return SearchModel::Type::Artist;
|
||||
} else if constexpr(std::is_same_v<T, search::Playlist>) {
|
||||
return SearchModel::Type::Playlist;
|
||||
} else if constexpr(std::is_same_v<T, search::Song>) {
|
||||
return SearchModel::Type::Song;
|
||||
} else if constexpr(std::is_same_v<T, search::Video>) {
|
||||
return SearchModel::Type::Video;
|
||||
} else {
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}, item);
|
||||
}
|
||||
+5
-2
@@ -19,6 +19,7 @@ class SearchModel : public AbstractYTMusicModel
|
||||
public:
|
||||
enum Type {
|
||||
Artist,
|
||||
ArtistsDisplayString,
|
||||
Album,
|
||||
Playlist,
|
||||
Song,
|
||||
@@ -31,7 +32,8 @@ public:
|
||||
Type,
|
||||
VideoId,
|
||||
Artists,
|
||||
RadioPlaylistId
|
||||
RadioPlaylistId,
|
||||
ThumbnailUrl
|
||||
};
|
||||
|
||||
explicit SearchModel(QObject *parent = nullptr);
|
||||
@@ -47,7 +49,7 @@ public:
|
||||
Q_INVOKABLE void triggerItem(int row);
|
||||
|
||||
Q_SIGNAL void openAlbum(const QString &browseId);
|
||||
Q_SIGNAL void openArtist(const QString &browseId);
|
||||
Q_SIGNAL void openArtist(const QString &browseId,const QString &radioId, const QString &shuffleId);
|
||||
Q_SIGNAL void openPlaylist(const QString &browseId);
|
||||
Q_SIGNAL void openSong(const QString &videoId);
|
||||
Q_SIGNAL void openVideo(const QString &videoId, const QString &title);
|
||||
@@ -55,4 +57,5 @@ public:
|
||||
private:
|
||||
QString m_searchQuery;
|
||||
std::vector<search::SearchResultItem> m_searchResults;
|
||||
static int itemType(search::SearchResultItem const &item);
|
||||
};
|
||||
+68
-24
@@ -9,29 +9,16 @@
|
||||
#include <random>
|
||||
|
||||
#include <QRandomGenerator>
|
||||
#include <QFutureWatcher>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "playlistutils.h"
|
||||
|
||||
UserPlaylistModel::UserPlaylistModel(QObject *parent)
|
||||
: AbstractYTMusicModel(parent)
|
||||
{
|
||||
connect(this, &UserPlaylistModel::initialVideoIdChanged, this, [=] {
|
||||
if (m_initialVideoId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
YTMusicThread::instance()->fetchWatchPlaylist(m_initialVideoId);
|
||||
});
|
||||
connect(this, &UserPlaylistModel::playlistIdChanged, this, [=] {
|
||||
if (m_playlistId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
YTMusicThread::instance()->fetchWatchPlaylist(std::nullopt, m_playlistId);
|
||||
});
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchWatchPlaylistFinished, this, [=](const watch::Playlist &playlist) {
|
||||
auto handleResult = [=, this](const watch::Playlist &playlist) {
|
||||
setLoading(false);
|
||||
|
||||
beginResetModel();
|
||||
@@ -48,10 +35,37 @@ UserPlaylistModel::UserPlaylistModel(QObject *parent)
|
||||
} else {
|
||||
setCurrentVideoId({});
|
||||
}
|
||||
};
|
||||
connect(this, &UserPlaylistModel::initialVideoIdChanged, this, [=, this] {
|
||||
if (m_initialVideoId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
auto future = YTMusicThread::instance()->fetchWatchPlaylist(m_initialVideoId);
|
||||
connectFuture(future, this, handleResult);
|
||||
});
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [=] {
|
||||
connect(this, &UserPlaylistModel::playlistIdChanged, this, [=, this] {
|
||||
if (m_playlistId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
auto future = YTMusicThread::instance()->fetchWatchPlaylist(std::nullopt, m_playlistId);
|
||||
connectFuture(future, this, handleResult);;
|
||||
});
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [this] {
|
||||
setLoading(false);
|
||||
});
|
||||
connect(this, &UserPlaylistModel::currentVideoIdChanged, this, [this]() {
|
||||
// Clear lyrics, so we won't display old ones if the next song doesn't have any.
|
||||
m_lyrics = {};
|
||||
Q_EMIT lyricsChanged();
|
||||
|
||||
if (!m_currentVideoId.isEmpty()) {
|
||||
fetchLyrics(m_currentVideoId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int UserPlaylistModel::rowCount(const QModelIndex &parent) const
|
||||
@@ -68,6 +82,8 @@ QVariant UserPlaylistModel::data(const QModelIndex &index, int role) const
|
||||
return QString::fromStdString(m_playlist.tracks[index.row()].video_id);
|
||||
case Artists:
|
||||
return PlaylistUtils::artistsToString(m_playlist.tracks[index.row()].artists);
|
||||
case Album:
|
||||
return QString::fromStdString(m_playlist.tracks[index.row()].album.value_or(meta::Album()).name);
|
||||
case IsCurrent:
|
||||
return m_playlist.tracks[index.row()].video_id == m_currentVideoId.toStdString();
|
||||
}
|
||||
@@ -83,7 +99,8 @@ QHash<int, QByteArray> UserPlaylistModel::roleNames() const
|
||||
{Title, "title"},
|
||||
{VideoId, "videoId"},
|
||||
{Artists, "artists"},
|
||||
{IsCurrent, "isCurrent"}
|
||||
{Album, "album"},
|
||||
{IsCurrent, "isCurrent"},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -101,7 +118,7 @@ void UserPlaylistModel::setInitialVideoId(const QString &videoId)
|
||||
QString UserPlaylistModel::nextVideoId() const
|
||||
{
|
||||
auto currentTrack = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
|
||||
[=](const watch::Playlist::Track &track) {
|
||||
[this](const watch::Playlist::Track &track) {
|
||||
return track.video_id == m_currentVideoId.toStdString();
|
||||
});
|
||||
|
||||
@@ -126,10 +143,20 @@ void UserPlaylistModel::setCurrentVideoId(const QString &videoId)
|
||||
Q_EMIT canSkipChanged();
|
||||
}
|
||||
|
||||
int UserPlaylistModel::currentIndex() const
|
||||
{
|
||||
auto currentTrack = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
|
||||
[this](const watch::Playlist::Track &track) {
|
||||
return track.video_id == m_currentVideoId.toStdString();
|
||||
});
|
||||
|
||||
return std::distance(m_playlist.tracks.begin(), currentTrack);
|
||||
}
|
||||
|
||||
bool UserPlaylistModel::canSkip() const
|
||||
{
|
||||
const auto currentTrackIt = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
|
||||
[=](const watch::Playlist::Track &track) {
|
||||
[this](const watch::Playlist::Track &track) {
|
||||
return track.video_id == m_currentVideoId.toStdString();
|
||||
});
|
||||
|
||||
@@ -157,7 +184,7 @@ void UserPlaylistModel::skipTo(const QString &videoId)
|
||||
void UserPlaylistModel::playNext(const QString &videoId, const QString &title, const std::vector<meta::Artist> &artists)
|
||||
{
|
||||
const auto currentIt = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
|
||||
[=](const watch::Playlist::Track &track) {
|
||||
[this](const watch::Playlist::Track &track) {
|
||||
return track.video_id == m_currentVideoId.toStdString();
|
||||
});
|
||||
|
||||
@@ -239,7 +266,7 @@ void UserPlaylistModel::shufflePlaylist()
|
||||
// Only shuffle playlist after current track
|
||||
if (!m_currentVideoId.isEmpty()) {
|
||||
const auto currentIt = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
|
||||
[=](const watch::Playlist::Track &track) {
|
||||
[this](const watch::Playlist::Track &track) {
|
||||
return track.video_id == m_currentVideoId.toStdString();
|
||||
});
|
||||
|
||||
@@ -257,7 +284,7 @@ void UserPlaylistModel::emitCurrentVideoChanged(const QString &oldVideoId)
|
||||
return track.video_id == oldVideoId.toStdString();
|
||||
});
|
||||
const auto currentVideoIt = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
|
||||
[=](const watch::Playlist::Track &track) {
|
||||
[this](const watch::Playlist::Track &track) {
|
||||
return track.video_id == m_currentVideoId.toStdString();
|
||||
});
|
||||
|
||||
@@ -268,11 +295,28 @@ void UserPlaylistModel::emitCurrentVideoChanged(const QString &oldVideoId)
|
||||
Q_EMIT dataChanged(index(newIndex), index(newIndex), {IsCurrent});
|
||||
}
|
||||
|
||||
void UserPlaylistModel::fetchLyrics(const QString &videoId)
|
||||
{
|
||||
auto future = YTMusicThread::instance()->fetchWatchPlaylist(videoId);
|
||||
connectFuture(future, this, [=, this](const auto &playlist) {
|
||||
if (playlist.lyrics) {
|
||||
connectFuture(YTMusicThread::instance()->fetchLyrics(QString::fromStdString(*playlist.lyrics)), this, [=, this](const auto &lyrics) {
|
||||
m_lyrics = lyrics;
|
||||
Q_EMIT lyricsChanged();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool UserPlaylistModel::shuffle() const
|
||||
{
|
||||
return m_shuffle;
|
||||
}
|
||||
|
||||
QString UserPlaylistModel::lyrics() const {
|
||||
return QString::fromStdString(m_lyrics.lyrics);
|
||||
}
|
||||
|
||||
void UserPlaylistModel::setShuffle(bool shuffle)
|
||||
{
|
||||
m_shuffle = shuffle;
|
||||
|
||||
+14
-1
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QFuture>
|
||||
|
||||
#include <ytmusic.h>
|
||||
|
||||
@@ -20,15 +21,19 @@ class UserPlaylistModel : public AbstractYTMusicModel
|
||||
|
||||
// output
|
||||
Q_PROPERTY(QString currentVideoId READ currentVideoId NOTIFY currentVideoIdChanged)
|
||||
Q_PROPERTY(int currentIndex READ currentIndex NOTIFY currentVideoIdChanged)
|
||||
Q_PROPERTY(bool canSkip READ canSkip NOTIFY canSkipChanged)
|
||||
Q_PROPERTY(QString lyrics READ lyrics NOTIFY lyricsChanged)
|
||||
|
||||
public:
|
||||
enum Role {
|
||||
Title = Qt::UserRole + 1,
|
||||
VideoId,
|
||||
Artists,
|
||||
IsCurrent
|
||||
Album,
|
||||
IsCurrent,
|
||||
};
|
||||
Q_ENUM(Role);
|
||||
|
||||
explicit UserPlaylistModel(QObject *parent = nullptr);
|
||||
|
||||
@@ -46,6 +51,8 @@ public:
|
||||
void setCurrentVideoId(const QString &videoId);
|
||||
Q_SIGNAL void currentVideoIdChanged();
|
||||
|
||||
int currentIndex() const;
|
||||
|
||||
bool canSkip() const;
|
||||
Q_SIGNAL void canSkipChanged();
|
||||
|
||||
@@ -57,6 +64,9 @@ public:
|
||||
bool shuffle() const;
|
||||
Q_SIGNAL void shuffleChanged();
|
||||
|
||||
QString lyrics() const;
|
||||
Q_SIGNAL void lyricsChanged();
|
||||
|
||||
Q_INVOKABLE void next();
|
||||
Q_INVOKABLE void skipTo(const QString &videoId);
|
||||
Q_INVOKABLE void playNext(const QString &videoId, const QString &title, const std::vector<meta::Artist> &artists);
|
||||
@@ -68,10 +78,13 @@ public:
|
||||
private:
|
||||
void emitCurrentVideoChanged(const QString &oldVideoId);
|
||||
|
||||
void fetchLyrics(const QString &videoId);
|
||||
|
||||
QString m_initialVideoId;
|
||||
QString m_playlistId;
|
||||
QString m_currentVideoId;
|
||||
bool m_shuffle = false;
|
||||
|
||||
watch::Playlist m_playlist;
|
||||
::Lyrics m_lyrics;
|
||||
};
|
||||
+38
-22
@@ -4,39 +4,46 @@
|
||||
|
||||
#include "videoinfoextractor.h"
|
||||
|
||||
#include <asyncytmusic.h>
|
||||
#include <QFutureWatcher>
|
||||
|
||||
#include "asyncytmusic.h"
|
||||
#include "library.h"
|
||||
|
||||
VideoInfoExtractor::VideoInfoExtractor(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
connect(this, &VideoInfoExtractor::videoIdChanged, this, [=] {
|
||||
connect(this, &VideoInfoExtractor::videoIdChanged, this, [this] {
|
||||
if (m_videoId.isEmpty()) {
|
||||
m_videoInfo = {};
|
||||
Q_EMIT audioUrlChanged();
|
||||
Q_EMIT titleChanged();
|
||||
Q_EMIT artistChanged();
|
||||
Q_EMIT channelChanged();
|
||||
Q_EMIT songChanged();
|
||||
Q_EMIT thumbnailChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
YTMusicThread::instance()->extractVideoInfo(QString::fromStdString(m_videoId.toStdString()));
|
||||
});
|
||||
|
||||
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::extractVideoInfoFinished, this, [=](const video_info::VideoInfo &info) {
|
||||
m_videoInfo = info;
|
||||
setLoading(false);
|
||||
Q_EMIT audioUrlChanged();
|
||||
Q_EMIT titleChanged();
|
||||
Q_EMIT songChanged();
|
||||
Q_EMIT thumbnailChanged();
|
||||
auto future = YTMusicThread::instance()->extractVideoInfo(QString::fromStdString(m_videoId.toStdString()));
|
||||
connectFuture(future, this, [this](const video_info::VideoInfo &videoInfo) {
|
||||
m_videoInfo = videoInfo;
|
||||
setLoading(false);
|
||||
Q_EMIT audioUrlChanged();
|
||||
Q_EMIT titleChanged();
|
||||
Q_EMIT artistChanged();
|
||||
Q_EMIT channelChanged();
|
||||
Q_EMIT songChanged();
|
||||
Q_EMIT thumbnailChanged();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
QUrl VideoInfoExtractor::audioUrl() const
|
||||
{
|
||||
if (m_videoInfo.formats.empty()) {
|
||||
return QUrl();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<video_info::Format> audioFormats;
|
||||
@@ -48,17 +55,13 @@ QUrl VideoInfoExtractor::audioUrl() const
|
||||
});
|
||||
|
||||
if (audioFormats.empty()) {
|
||||
return QUrl();
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
struct {
|
||||
bool operator()(const video_info::Format &a, const video_info::Format &b) {
|
||||
return a.quality > b.quality;
|
||||
}
|
||||
} qualitySort;
|
||||
|
||||
std::sort(audioFormats.begin(), audioFormats.end(), qualitySort);
|
||||
std::sort(audioFormats.begin(), audioFormats.end(),
|
||||
[](const video_info::Format &a, const video_info::Format &b) {
|
||||
return a.quality > b.quality;
|
||||
});
|
||||
|
||||
return QUrl(QString::fromStdString(audioFormats.front().url));
|
||||
}
|
||||
@@ -70,6 +73,9 @@ QString VideoInfoExtractor::videoId() const
|
||||
|
||||
void VideoInfoExtractor::setVideoId(const QString &videoId)
|
||||
{
|
||||
if (m_videoId == videoId || videoId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
m_videoId = videoId;
|
||||
Q_EMIT videoIdChanged();
|
||||
}
|
||||
@@ -79,9 +85,19 @@ QString VideoInfoExtractor::title() const
|
||||
return QString::fromStdString(m_videoInfo.title);
|
||||
}
|
||||
|
||||
QString VideoInfoExtractor::artist() const
|
||||
{
|
||||
return QString::fromStdString(m_videoInfo.artist);
|
||||
}
|
||||
|
||||
QString VideoInfoExtractor::channel() const
|
||||
{
|
||||
return QString::fromStdString(m_videoInfo.channel);
|
||||
}
|
||||
|
||||
QString VideoInfoExtractor::thumbnail() const
|
||||
{
|
||||
return QString::fromStdString(m_videoInfo.thumnnail);
|
||||
return QString::fromStdString(m_videoInfo.thumbnail);
|
||||
}
|
||||
|
||||
bool VideoInfoExtractor::loading() const
|
||||
|
||||
@@ -17,6 +17,8 @@ class VideoInfoExtractor : public QObject
|
||||
|
||||
Q_PROPERTY(QUrl audioUrl READ audioUrl NOTIFY audioUrlChanged)
|
||||
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
|
||||
Q_PROPERTY(QString artist READ artist NOTIFY artistChanged) // may be empty if it is a video
|
||||
Q_PROPERTY(QString channel READ channel NOTIFY channelChanged)
|
||||
Q_PROPERTY(QString thumbnail READ thumbnail NOTIFY thumbnailChanged)
|
||||
Q_PROPERTY(bool loading READ loading WRITE setLoading NOTIFY loadingChanged)
|
||||
|
||||
@@ -32,6 +34,12 @@ public:
|
||||
|
||||
QString title() const;
|
||||
Q_SIGNAL void titleChanged();
|
||||
|
||||
QString artist() const;
|
||||
Q_SIGNAL void artistChanged();
|
||||
|
||||
QString channel() const;
|
||||
Q_SIGNAL void channelChanged();
|
||||
|
||||
QString thumbnail() const;
|
||||
Q_SIGNAL void thumbnailChanged();
|
||||
|
||||
+88
-57
@@ -5,6 +5,7 @@
|
||||
#include "ytmusic.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include <pybind11/embed.h>
|
||||
#include <pybind11/stl.h>
|
||||
@@ -13,9 +14,15 @@ namespace py = pybind11;
|
||||
|
||||
using namespace py::literals;
|
||||
|
||||
/// Useful for debugging
|
||||
void pyPrintPretty(py::handle obj) {
|
||||
auto json = py::module::import("json");
|
||||
py::print(json.attr("dumps")(obj, "indent"_a=py::int_(4)));
|
||||
}
|
||||
|
||||
#define UNEXPORT __attribute__ ((visibility("hidden")))
|
||||
|
||||
constexpr auto TESTED_YTMUSICAPI_VERSION = "0.18.0";
|
||||
constexpr auto TESTED_YTMUSICAPI_VERSION = "0.24.0";
|
||||
|
||||
struct UNEXPORT YTMusicPrivate {
|
||||
py::scoped_interpreter guard {};
|
||||
@@ -34,10 +41,16 @@ struct UNEXPORT YTMusicPrivate {
|
||||
// Some of the called python code randomly fails if the encoding is not utf8
|
||||
setenv("LC_ALL", "en_US.utf8", true);
|
||||
|
||||
const auto version = module.attr("_version").attr("__version__").cast<std::string>();
|
||||
if (version != TESTED_YTMUSICAPI_VERSION) {
|
||||
std::cerr << "Running with untested version of ytmusicapi." << std::endl;
|
||||
auto oldVersion = module.attr("__dict__").contains("_version");
|
||||
if (oldVersion) {
|
||||
std::cerr << "Running with outdated and untested version of ytmusicapi." << std::endl;
|
||||
std::cerr << "The currently tested and supported version is " << TESTED_YTMUSICAPI_VERSION << std::endl;
|
||||
} else {
|
||||
const auto version = module.attr("version")("ytmusicapi").cast<std::string>();
|
||||
if (version != TESTED_YTMUSICAPI_VERSION) {
|
||||
std::cerr << "Running with untested version of ytmusicapi." << std::endl;
|
||||
std::cerr << "The currently tested and supported version is " << TESTED_YTMUSICAPI_VERSION << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +60,7 @@ struct UNEXPORT YTMusicPrivate {
|
||||
py::object get_ytdl() {
|
||||
// lazy initialization
|
||||
if (ytdl.is_none()) {
|
||||
ytdl = py::module::import("youtube_dl").attr("YoutubeDL")(py::dict());
|
||||
ytdl = py::module::import("yt_dlp").attr("YoutubeDL")(py::dict());
|
||||
}
|
||||
|
||||
return ytdl;
|
||||
@@ -64,7 +77,7 @@ std::optional<T> optional_key(py::handle obj, const char *name) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return obj[name].cast<T>();
|
||||
return obj[name].cast<std::optional<T>>();
|
||||
}
|
||||
|
||||
meta::Thumbnail extract_thumbnail(py::handle thumbnail) {
|
||||
@@ -82,28 +95,10 @@ meta::Artist extract_meta_artist(py::handle artist) {
|
||||
};
|
||||
};
|
||||
|
||||
album::Track extract_album_track(py::handle track) {
|
||||
return {
|
||||
track["index"].cast<std::string>(),
|
||||
track["title"].cast<std::string>(),
|
||||
track["artists"].cast<std::string>(),
|
||||
track["videoId"].cast<std::optional<std::string>>(), // E rated songs don't have a videoId
|
||||
track["lengthMs"].cast<std::optional<std::string>>(), //
|
||||
track["likeStatus"].cast<std::optional<std::string>>()
|
||||
};
|
||||
}
|
||||
|
||||
video_info::Format extract_format(py::handle format) {
|
||||
return {
|
||||
optional_key<int>(format, "quality"),
|
||||
format["url"].cast<std::string>(),
|
||||
format["vcodec"].cast<std::string>(),
|
||||
format["acodec"].cast<std::string>()
|
||||
};
|
||||
}
|
||||
|
||||
playlist::Track extract_playlist_track(py::handle track);
|
||||
watch::Playlist::Track extract_watch_track(py::handle track);
|
||||
album::Track extract_album_track(py::handle track);
|
||||
video_info::Format extract_format(py::handle format);
|
||||
|
||||
template <typename T>
|
||||
inline auto extract_py_list(py::handle obj) {
|
||||
@@ -135,6 +130,27 @@ inline auto extract_py_list(py::handle obj) {
|
||||
return output;
|
||||
}
|
||||
|
||||
album::Track extract_album_track(py::handle track) {
|
||||
return {
|
||||
track["isExplicit"].cast<bool>(),
|
||||
track["title"].cast<std::string>(),
|
||||
extract_py_list<meta::Artist>(track["artists"]),
|
||||
track["album"].cast<std::optional<std::string>>(),
|
||||
track["videoId"].cast<std::optional<std::string>>(), // E rated songs don't have a videoId
|
||||
track["duration"].cast<std::optional<std::string>>(), //
|
||||
track["likeStatus"].cast<std::optional<std::string>>()
|
||||
};
|
||||
}
|
||||
|
||||
video_info::Format extract_format(py::handle format) {
|
||||
return {
|
||||
optional_key<int>(format, "quality"),
|
||||
format["url"].cast<std::string>(),
|
||||
format["vcodec"].cast<std::string>(),
|
||||
format["acodec"].cast<std::string>()
|
||||
};
|
||||
}
|
||||
|
||||
meta::Album extract_meta_album(py::handle album) {
|
||||
return meta::Album {
|
||||
album["name"].cast<std::string>(),
|
||||
@@ -259,7 +275,8 @@ std::optional<search::SearchResultItem> extract_search_result(py::handle result)
|
||||
result["videoId"].cast<std::string>(),
|
||||
result["title"].cast<std::string>(),
|
||||
extract_py_list<meta::Artist>(result["artists"]),
|
||||
result["views"].cast<std::string>()
|
||||
result["views"].cast<std::string>(),
|
||||
extract_py_list<meta::Thumbnail>(result["thumbnails"])
|
||||
},
|
||||
result["duration"].cast<std::string>()
|
||||
};
|
||||
@@ -269,7 +286,8 @@ std::optional<search::SearchResultItem> extract_search_result(py::handle result)
|
||||
result["videoId"].cast<std::string>(),
|
||||
result["title"].cast<std::string>(),
|
||||
extract_py_list<meta::Artist>(result["artists"]),
|
||||
result["duration"].cast<std::string>()
|
||||
result["duration"].cast<std::string>(),
|
||||
extract_py_list<meta::Thumbnail>(result["thumbnails"])
|
||||
},
|
||||
extract_meta_album(result["album"]),
|
||||
result["isExplicit"].cast<bool>()
|
||||
@@ -280,26 +298,30 @@ std::optional<search::SearchResultItem> extract_search_result(py::handle result)
|
||||
result["title"].cast<std::string>(),
|
||||
result["type"].cast<std::string>(),
|
||||
extract_py_list<meta::Artist>(result["artists"]),
|
||||
result["year"].cast<std::string>(),
|
||||
result["isExplicit"].cast<bool>()
|
||||
result["year"].cast<std::optional<std::string>>(),
|
||||
result["isExplicit"].cast<bool>(),
|
||||
extract_py_list<meta::Thumbnail>(result["thumbnails"])
|
||||
};
|
||||
} else if (resultType == "playlist") {
|
||||
return search::Playlist {
|
||||
result["browseId"].cast<std::string>(),
|
||||
result["title"].cast<std::string>(),
|
||||
result["author"].cast<std::string>(),
|
||||
result["itemCount"].cast<std::string>()
|
||||
result["itemCount"].cast<std::string>(),
|
||||
extract_py_list<meta::Thumbnail>(result["thumbnails"])
|
||||
};
|
||||
} else if (resultType == "artist") {
|
||||
return search::Artist {
|
||||
result["browseId"].cast<std::string>(),
|
||||
result["artist"].cast<std::string>(),
|
||||
optional_key<std::string>(result, "shuffleId"),
|
||||
optional_key<std::string>(result, "radioId")
|
||||
optional_key<std::string>(result, "radioId"),
|
||||
extract_py_list<meta::Thumbnail>(result["thumbnails"])
|
||||
};
|
||||
} else {
|
||||
std::cerr << "Warning: Unsupported search result type found" << std::endl;
|
||||
std::cerr << "It's called: " << resultType;
|
||||
std::cerr << "It's called: " << resultType << std::endl;
|
||||
pyPrintPretty(result);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
@@ -324,10 +346,11 @@ YTMusic::~YTMusic() = default;
|
||||
std::vector<search::SearchResultItem> YTMusic::search(
|
||||
const std::string &query,
|
||||
const std::optional<std::string> &filter,
|
||||
const std::optional<std::string> &scope,
|
||||
const int limit,
|
||||
const bool ignore_spelling) const
|
||||
{
|
||||
const auto results = d->get_ytmusic().attr("search")(query, filter, limit, ignore_spelling).cast<py::list>();
|
||||
const auto results = d->get_ytmusic().attr("search")("query"_a=query, "filter"_a=filter, "scope"_a=scope, "limit"_a = limit, "ignore_spelling"_a = ignore_spelling).cast<py::list>();
|
||||
|
||||
std::vector<search::SearchResultItem> output;
|
||||
for (const auto &result : results) {
|
||||
@@ -343,11 +366,11 @@ artist::Artist YTMusic::get_artist(const std::string &channel_id) const
|
||||
{
|
||||
const auto artist = d->get_ytmusic().attr("get_artist")(channel_id);
|
||||
return artist::Artist {
|
||||
artist["description"].cast<std::optional<std::string>>(),
|
||||
optional_key<std::string>(artist, "description"),
|
||||
artist["views"].cast<std::optional<std::string>>(),
|
||||
artist["name"].cast<std::string>(),
|
||||
artist["channelId"].cast<std::string>(),
|
||||
artist["subscribers"].cast<std::string>(),
|
||||
artist["subscribers"].cast<std::optional<std::string>>(),
|
||||
artist["subscribed"].cast<bool>(),
|
||||
extract_py_list<meta::Thumbnail>(artist["thumbnails"]),
|
||||
extract_artist_section<artist::Artist::Song>(artist, "songs"),
|
||||
@@ -360,31 +383,28 @@ artist::Artist YTMusic::get_artist(const std::string &channel_id) const
|
||||
album::Album YTMusic::get_album(const std::string &browseId) const
|
||||
{
|
||||
const auto album = d->get_ytmusic().attr("get_album")(browseId);
|
||||
|
||||
return {
|
||||
album["title"].cast<std::string>(),
|
||||
album["trackCount"].cast<std::string>(),
|
||||
album["durationMs"].cast<std::string>(),
|
||||
album["playlistId"].cast<std::string>(),
|
||||
[&]() -> album::Album::ReleaseDate {
|
||||
const auto date = album["releaseDate"];
|
||||
return {
|
||||
date["year"].cast<int>(),
|
||||
date["month"].cast<int>(),
|
||||
date["day"].cast<int>()
|
||||
};
|
||||
}(),
|
||||
album["description"].cast<std::string>(),
|
||||
album["trackCount"].cast<int>(),
|
||||
album["duration"].cast<std::string>(),
|
||||
album["audioPlaylistId"].cast<std::string>(),
|
||||
album["year"].cast<std::string>(),
|
||||
optional_key<std::string>(album, "description"),
|
||||
extract_py_list<meta::Thumbnail>(album["thumbnails"]),
|
||||
extract_py_list<album::Track>(album["tracks"])
|
||||
extract_py_list<album::Track>(album["tracks"]),
|
||||
extract_py_list<meta::Artist>(album["artists"])
|
||||
};
|
||||
}
|
||||
|
||||
song::Song YTMusic::get_song(const std::string &video_id) const
|
||||
std::optional<song::Song> YTMusic::get_song(const std::string &video_id) const
|
||||
{
|
||||
const auto song = d->get_ytmusic().attr("get_song")(video_id);
|
||||
|
||||
return {
|
||||
if (!song.cast<py::dict>().contains("videoId")) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return song::Song {
|
||||
song["videoId"].cast<std::string>(),
|
||||
song["title"].cast<std::string>(),
|
||||
song["lengthSeconds"].cast<std::string>(),
|
||||
@@ -452,10 +472,12 @@ video_info::VideoInfo YTMusic::extract_video_info(const std::string &video_id) c
|
||||
using namespace pybind11::literals;
|
||||
|
||||
const auto info = d->get_ytdl().attr("extract_info")(video_id, "download"_a=py::bool_(false));
|
||||
|
||||
|
||||
return {
|
||||
info["id"].cast<std::string>(),
|
||||
info["title"].cast<std::string>(),
|
||||
info.contains("artist") ? info["artist"].cast<std::string>() : "",
|
||||
info.contains("channel") ? info["channel"].cast<std::string>() : "",
|
||||
extract_py_list<video_info::Format>(info["formats"]),
|
||||
info["thumbnail"].cast<std::string>()
|
||||
};
|
||||
@@ -463,16 +485,25 @@ video_info::VideoInfo YTMusic::extract_video_info(const std::string &video_id) c
|
||||
|
||||
watch::Playlist YTMusic::get_watch_playlist(const std::optional<std::string> &videoId,
|
||||
const std::optional<std::string> &playlistId,
|
||||
int limit,
|
||||
const std::optional<std::string> ¶ms) const
|
||||
int limit) const
|
||||
{
|
||||
const auto playlist = d->get_ytmusic().attr("get_watch_playlist")("videoId"_a = videoId,
|
||||
"playlistId"_a = playlistId,
|
||||
"limit"_a = py::int_(limit),
|
||||
"params"_a = params);
|
||||
"limit"_a = py::int_(limit));
|
||||
|
||||
return {
|
||||
extract_py_list<watch::Playlist::Track>(playlist["tracks"]),
|
||||
playlist["lyrics"].cast<std::optional<std::string>>()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Lyrics YTMusic::get_lyrics(const std::string &browse_id) const
|
||||
{
|
||||
auto lyrics = d->get_ytmusic().attr("get_lyrics")(browse_id);
|
||||
|
||||
return {
|
||||
lyrics["source"].cast<std::string>(),
|
||||
lyrics["lyrics"].cast<std::string>()
|
||||
};
|
||||
}
|
||||
+30
-15
@@ -44,6 +44,7 @@ struct Media {
|
||||
std::string title;
|
||||
std::vector<meta::Artist> artists;
|
||||
std::string duration;
|
||||
std::vector<meta::Thumbnail> thumbnails;
|
||||
};
|
||||
|
||||
struct Video : public Media {
|
||||
@@ -55,6 +56,7 @@ struct Playlist {
|
||||
std::string title;
|
||||
std::string author;
|
||||
std::string item_count;
|
||||
std::vector<meta::Thumbnail> thumbnails;
|
||||
};
|
||||
|
||||
struct Song : public Media {
|
||||
@@ -67,8 +69,9 @@ struct Album {
|
||||
std::string title;
|
||||
std::string type;
|
||||
std::vector<meta::Artist> artists;
|
||||
std::string year;
|
||||
std::optional<std::string> year;
|
||||
bool is_explicit;
|
||||
std::vector<meta::Thumbnail> thumbnails;
|
||||
};
|
||||
|
||||
struct Artist {
|
||||
@@ -76,6 +79,7 @@ struct Artist {
|
||||
std::string artist;
|
||||
std::optional<std::string> shuffle_id;
|
||||
std::optional<std::string> radio_id;
|
||||
std::vector<meta::Thumbnail> thumbnails;
|
||||
};
|
||||
|
||||
using SearchResultItem = std::variant<Video, Playlist, Song, Album, Artist>;
|
||||
@@ -122,7 +126,7 @@ struct Artist {
|
||||
|
||||
struct Single {
|
||||
std::string title;
|
||||
std::vector<meta::Thumbnail> thumnnails;
|
||||
std::vector<meta::Thumbnail> thumbnails;
|
||||
std::string year;
|
||||
std::string browse_id;
|
||||
};
|
||||
@@ -131,7 +135,7 @@ struct Artist {
|
||||
std::optional<std::string> views;
|
||||
std::string name;
|
||||
std::string channel_id;
|
||||
std::string subscribers;
|
||||
std::optional<std::string> subscribers;
|
||||
bool subscribed;
|
||||
std::vector<meta::Thumbnail> thumbnails;
|
||||
std::optional<Section<Song>> songs;
|
||||
@@ -143,11 +147,12 @@ struct Artist {
|
||||
|
||||
namespace album {
|
||||
struct Track {
|
||||
std::string index;
|
||||
bool is_explicit;
|
||||
std::string title;
|
||||
std::string artists;
|
||||
std::vector<meta::Artist> artists;
|
||||
std::optional<std::string> album;
|
||||
std::optional<std::string> video_id;
|
||||
std::optional<std::string> length_ms;
|
||||
std::optional<std::string> duration;
|
||||
std::optional<std::string> like_status;
|
||||
};
|
||||
|
||||
@@ -159,13 +164,14 @@ namespace album {
|
||||
};
|
||||
|
||||
std::string title;
|
||||
std::string track_count;
|
||||
std::string duration_ms;
|
||||
std::string playlist_id;
|
||||
ReleaseDate release_date;
|
||||
std::string description;
|
||||
int track_count;
|
||||
std::string duration;
|
||||
std::string audio_playlist_id;
|
||||
std::string year;
|
||||
std::optional<std::string> description;
|
||||
std::vector<meta::Thumbnail> thumbnails;
|
||||
std::vector<Track> tracks;
|
||||
std::vector<meta::Artist> artists;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -239,8 +245,10 @@ struct Format {
|
||||
struct VideoInfo {
|
||||
std::string id;
|
||||
std::string title;
|
||||
std::string artist;
|
||||
std::string channel;
|
||||
std::vector<Format> formats;
|
||||
std::string thumnnail;
|
||||
std::string thumbnail;
|
||||
|
||||
// More, but not interesting for us right now
|
||||
};
|
||||
@@ -264,6 +272,11 @@ struct Playlist {
|
||||
};
|
||||
}
|
||||
|
||||
struct Lyrics {
|
||||
std::string source;
|
||||
std::string lyrics;
|
||||
};
|
||||
|
||||
class YTMusic
|
||||
{
|
||||
public:
|
||||
@@ -277,6 +290,7 @@ public:
|
||||
|
||||
std::vector<search::SearchResultItem> search(const std::string &query,
|
||||
const std::optional<std::string> &filter = std::nullopt,
|
||||
const std::optional<std::string> &scope = std::nullopt,
|
||||
const int limit = 20,
|
||||
const bool ignore_spelling = false) const;
|
||||
|
||||
@@ -287,7 +301,7 @@ public:
|
||||
album::Album get_album(const std::string &browse_id) const;
|
||||
|
||||
/// https://ytmusicapi.readthedocs.io/en/latest/reference.html#ytmusicapi.YTMusic.get_song
|
||||
song::Song get_song(const std::string &video_id) const;
|
||||
std::optional<song::Song> get_song(const std::string &video_id) const;
|
||||
|
||||
/// https://ytmusicapi.readthedocs.io/en/latest/reference.html#ytmusicapi.YTMusic.get_playlist
|
||||
playlist::Playlist get_playlist(const std::string &playlist_id, int limit = 100) const;
|
||||
@@ -301,8 +315,9 @@ public:
|
||||
/// https://ytmusicapi.readthedocs.io/en/latest/reference.html#ytmusicapi.YTMusic.get_watch_playlist
|
||||
watch::Playlist get_watch_playlist(const std::optional<std::string> &videoId = std::nullopt,
|
||||
const std::optional<std::string> &playlistId = std::nullopt,
|
||||
int limit = 25,
|
||||
const std::optional<std::string> ¶ms = std::nullopt) const;
|
||||
int limit = 25) const;
|
||||
|
||||
Lyrics get_lyrics(const std::string &browse_id) const;
|
||||
|
||||
// TODO wrap more methods
|
||||
|
||||
|
||||
Reference in new issue
Block a user