Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc3710c200 | ||
|
|
48cf377194 | ||
|
|
07f5043016 | ||
|
|
2819ed9501 | ||
|
|
0c0dca262d | ||
|
|
b4a2331097 | ||
|
|
4ea2fa3a46 | ||
|
|
1d987c14cd | ||
|
|
35f38e8598 | ||
|
|
e015301863 | ||
|
|
94a8edeef3 | ||
|
|
34d9a0e3c1 | ||
|
|
a07002c6d7 | ||
|
|
5cfeda6500 | ||
|
|
cf4c12a4c1 | ||
|
|
0b70218876 | ||
|
|
344f17f6e7 | ||
|
|
40cda46d35 | ||
|
|
fe295a128c | ||
|
|
51839ae2b6 | ||
|
|
8078db7e95 | ||
|
|
d0e03351c6 | ||
|
|
99820c8592 | ||
|
|
71a1c024b5 |
No files matched your search
+4
-2
@@ -3,5 +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-utilities/raw/master/gitlab-templates/reuse-lint.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/flatpak.yml
|
||||
- project: sysadmin/ci-utilities
|
||||
file:
|
||||
- /gitlab-templates/reuse-lint.yml
|
||||
- /gitlab-templates/flatpak.yml
|
||||
+6
-12
@@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.16.0)
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "01")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "80")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "85")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
project(audiotube VERSION ${RELEASE_SERVICE_VERSION})
|
||||
@@ -17,20 +17,14 @@ include(FeatureSummary)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(QT_MIN_VERSION "5.15")
|
||||
set(KF_MIN_VERSION "5.81.0")
|
||||
set(QT_MIN_VERSION "6.4.0")
|
||||
set(KF_MIN_VERSION "5.80.0")
|
||||
set(KF_MAJOR_VERSION "6")
|
||||
set(QT_MAJOR_VERSION "6")
|
||||
|
||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "6")
|
||||
set(QT_MIN_VERSION "6.4.0")
|
||||
set(KF_MIN_VERSION "5.240.0")
|
||||
set(KF_MAJOR_VERSION "6")
|
||||
else()
|
||||
set(KF_MAJOR_VERSION "5")
|
||||
endif()
|
||||
|
||||
include(KDEInstallDirs)
|
||||
include(KDECMakeSettings)
|
||||
include(KDECompilerSettings NO_POLICY_SCOPE)
|
||||
@@ -53,7 +47,7 @@ find_package(Ytdlp REQUIRED RUNTIME)
|
||||
find_package(YTMusicAPI 1.0.2 REQUIRED RUNTIME)
|
||||
find_package(KF6KirigamiAddons 0.6.0 REQUIRED)
|
||||
find_package(FutureSQL${QT_MAJOR_VERSION} REQUIRED)
|
||||
find_package(QCoro${QT_MAJOR_VERSION} 0.9.0 REQUIRED COMPONENTS Core)
|
||||
find_package(QCoro${QT_MAJOR_VERSION} 0.10.0 REQUIRED COMPONENTS Core Network Qml)
|
||||
|
||||
ki18n_install(po)
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<name xml:lang="uk">AudioTube</name>
|
||||
<name xml:lang="x-test">xxAudioTubexx</name>
|
||||
<name xml:lang="zh-CN">AudioTube</name>
|
||||
<name xml:lang="zh-TW">AudioTube</name>
|
||||
<summary>YouTube Music App for phones and desktop computers</summary>
|
||||
<summary xml:lang="ca">Aplicació de YouTube Music per a telèfons i ordinadors d'escriptori</summary>
|
||||
<summary xml:lang="ca-valencia">Aplicació de YouTube Music per a telèfons i ordinadors d'escriptori</summary>
|
||||
@@ -60,6 +61,7 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<summary xml:lang="tr">Telefonlar ve masaüstü bilgisayarlar için YouTube Müzik uygulaması</summary>
|
||||
<summary xml:lang="uk">Додаток YouTube Music для телефонів та робочих станцій</summary>
|
||||
<summary xml:lang="x-test">xxYouTube Music App for phones and desktop computersxx</summary>
|
||||
<summary xml:lang="zh-TW">手機和電腦用的 YouTube Music 應用程式</summary>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-2.0+</project_license>
|
||||
<developer_name>KDE Community</developer_name>
|
||||
@@ -98,9 +100,11 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<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>
|
||||
<developer_name xml:lang="zh-TW">KDE 社群</developer_name>
|
||||
<content_rating type="oars-1.0"/>
|
||||
<url type="homepage">https://apps.kde.org/en/audiotube</url>
|
||||
<releases>
|
||||
<release version="23.08.4" date="2023-12-07"/>
|
||||
<release version="23.08.3" date="2023-11-09"/>
|
||||
<release version="23.08.2" date="2023-10-12"/>
|
||||
<release version="23.08.1" date="2023-09-14"/>
|
||||
@@ -208,5 +212,6 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<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>
|
||||
<p xml:lang="zh-TW">AudioTube 可以搜尋 YouTube Music、列出專輯與藝人、播放專輯或自動產生的播放清單,也讓您建立自己的播放清單。</p>
|
||||
</description>
|
||||
</component>
|
||||
@@ -34,6 +34,7 @@ Name[tr]=AudioTube
|
||||
Name[uk]=AudioTube
|
||||
Name[x-test]=xxAudioTubexx
|
||||
Name[zh_CN]=AudioTube
|
||||
Name[zh_TW]=AudioTube
|
||||
Comment=YouTube Music client
|
||||
Comment[ar]=عميل يوتيوب ميوزيك
|
||||
Comment[az]=YouTube Musiqi müştərisi
|
||||
@@ -70,6 +71,7 @@ Comment[tr]=YouTube Müzik İstemcisi
|
||||
Comment[uk]=Музичний клієнт YouTube
|
||||
Comment[x-test]=xxYouTube Music clientxx
|
||||
Comment[zh_CN]=YouTube Music 客户端
|
||||
Comment[zh_TW]=YouTube Music 用戶端
|
||||
Version=1.0
|
||||
Exec=audiotube
|
||||
Icon=org.kde.audiotube
|
||||
|
||||
+19
-8
@@ -4,7 +4,9 @@
|
||||
"runtime-version": "6.6",
|
||||
"sdk": "org.kde.Sdk",
|
||||
"command": "audiotube",
|
||||
"tags": ["nightly"],
|
||||
"tags": [
|
||||
"nightly"
|
||||
],
|
||||
"desktop-file-name-suffix": " (Nightly)",
|
||||
"finish-args": [
|
||||
"--share=ipc",
|
||||
@@ -20,7 +22,6 @@
|
||||
"/include/",
|
||||
"/share/cmake/"
|
||||
],
|
||||
|
||||
"modules": [
|
||||
"flatpak/python3-yt-dlp.json",
|
||||
"flatpak/python3-ytmusicapi.json",
|
||||
@@ -35,9 +36,9 @@
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/danvratil/qcoro",
|
||||
"branch": "main",
|
||||
"type": "archive",
|
||||
"url": "https://github.com/danvratil/qcoro/archive/refs/tags/v0.10.0.tar.gz",
|
||||
"sha256": "b7c8f00273ad27d85814bf4ec93eb6922c75656800a61d11854d36355a4a1aec",
|
||||
"x-checker-data": {
|
||||
"type": "anitya",
|
||||
"project-id": 236236,
|
||||
@@ -92,11 +93,21 @@
|
||||
},
|
||||
{
|
||||
"name": "org.kde.audiotube",
|
||||
"config-opts": ["-DPYBIND11_FINDPYTHON=ON", "-DQT_MAJOR_VERSION=6"],
|
||||
"config-opts": [
|
||||
"-DPYBIND11_FINDPYTHON=ON",
|
||||
"-DQT_MAJOR_VERSION=6"
|
||||
],
|
||||
"buildsystem": "cmake-ninja",
|
||||
"builddir": true,
|
||||
"sources": [ { "type": "dir", "path": ".", "skip": [".git"] } ]
|
||||
"sources": [
|
||||
{
|
||||
"type": "dir",
|
||||
"path": ".",
|
||||
"skip": [
|
||||
".git"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,534 @@
|
||||
# translation of audiotube.pot to esperanto
|
||||
# Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# Oliver Kellogg <[email protected], 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2023-11-23 00:41+0000\n"
|
||||
"PO-Revision-Date: 2023-11-30 18:56+0100\n"
|
||||
"Last-Translator: Oliver Kellogg <[email protected]>\n"
|
||||
"Language-Team: Esperanto <[email protected]>\n"
|
||||
"Language: eo\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: translate-po (https://github.com/zcribe/translate-po)\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
#: asyncytmusic.cpp:65
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Running with untested version of ytmusicapi %1. If you experience errors, "
|
||||
"please report them to your distribution."
|
||||
msgstr ""
|
||||
"Funkcianta kun neprovita versio de ytmusicapi %1. Se vi spertas erarojn, "
|
||||
"bonvolu raporti ilin al via distribuo."
|
||||
|
||||
#: contents/ui/AlbumPage.qml:71 contents/ui/LibraryPage.qml:38
|
||||
#: contents/ui/LibraryPage.qml:64 contents/ui/LibraryPage.qml:85
|
||||
#: contents/ui/LibraryPage.qml:225 contents/ui/LibraryPage.qml:251
|
||||
#: contents/ui/LibraryPage.qml:272 contents/ui/LocalPlaylistPage.qml:71
|
||||
#: contents/ui/LocalPlaylistPage.qml:93 contents/ui/PlaybackHistory.qml:67
|
||||
#: contents/ui/PlaybackHistory.qml:89 contents/ui/PlaylistPage.qml:66
|
||||
#: contents/ui/PlaylistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr "Ludi"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:78 contents/ui/ArtistPage.qml:83
|
||||
#: contents/ui/LibraryPage.qml:45 contents/ui/LibraryPage.qml:70
|
||||
#: contents/ui/LibraryPage.qml:93 contents/ui/LibraryPage.qml:232
|
||||
#: contents/ui/LibraryPage.qml:257 contents/ui/LibraryPage.qml:281
|
||||
#: contents/ui/LocalPlaylistPage.qml:66 contents/ui/LocalPlaylistPage.qml:100
|
||||
#: contents/ui/PlaybackHistory.qml:55 contents/ui/PlaybackHistory.qml:102
|
||||
#: contents/ui/PlaylistPage.qml:59 contents/ui/PlaylistPage.qml:94
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr "Miksi"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:86 contents/ui/LibraryPage.qml:75
|
||||
#: contents/ui/LibraryPage.qml:101 contents/ui/LibraryPage.qml:262
|
||||
#: contents/ui/LibraryPage.qml:289 contents/ui/LocalPlaylistPage.qml:106
|
||||
#: contents/ui/PlaybackHistory.qml:114 contents/ui/PlaylistPage.qml:102
|
||||
#, kde-format
|
||||
msgid "Append to queue"
|
||||
msgstr "Aldoni al vico"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:91 contents/ui/ArtistPage.qml:91
|
||||
#: contents/ui/PlaylistPage.qml:112
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr "Malfermi en Retumilo"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:96 contents/ui/ArtistPage.qml:96
|
||||
#: contents/ui/PlaylistPage.qml:117
|
||||
#, kde-format
|
||||
msgid "Share"
|
||||
msgstr "Kunhavigi"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:106
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr "Albumo • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:160 contents/ui/ArtistPage.qml:197
|
||||
#: contents/ui/LocalPlaylistPage.qml:171 contents/ui/PlaybackHistory.qml:195
|
||||
#: contents/ui/PlaylistPage.qml:189 contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Pli"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:77
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr "Radio"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:105
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr "Artisto"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:129 contents/ui/SearchPage.qml:72
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
"Video-reproduktado ankoraŭ ne estas subtenata. Ĉu vi volas ludi nur la "
|
||||
"sonojn de \"%1\"?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:146 contents/ui/SearchPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr "Albumoj"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:148
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr "Unuopaĵoj"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:150 contents/ui/SearchPage.qml:32
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr "Kantoj"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:152 contents/ui/SearchPage.qml:34
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr "Videoj"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr "bone"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr "Nuligi"
|
||||
|
||||
#: contents/ui/dialogs/AddPlaylistDialog.qml:17
|
||||
#, kde-format
|
||||
msgid "Add playlist"
|
||||
msgstr "Aldoni ludliston"
|
||||
|
||||
#: contents/ui/dialogs/AddPlaylistDialog.qml:23
|
||||
#: contents/ui/dialogs/RenamePlaylistDialog.qml:24
|
||||
#, kde-format
|
||||
msgid "Playlist Title"
|
||||
msgstr "Ludlista Titolo"
|
||||
|
||||
#: contents/ui/dialogs/AddPlaylistDialog.qml:28
|
||||
#: contents/ui/dialogs/RenamePlaylistDialog.qml:30
|
||||
#, kde-format
|
||||
msgid "Playlist Description"
|
||||
msgstr "Ludlisto Priskribo"
|
||||
|
||||
#: contents/ui/dialogs/ImportPlaylistDialog.qml:17
|
||||
#, kde-format
|
||||
msgid "Import playlist"
|
||||
msgstr "Importi ludliston"
|
||||
|
||||
#: contents/ui/dialogs/ImportPlaylistDialog.qml:23
|
||||
#, kde-format
|
||||
msgid "Playlist URL (Youtube)"
|
||||
msgstr "URL de Ludlisto (Youtube)"
|
||||
|
||||
#: contents/ui/dialogs/PlaylistDialog.qml:20
|
||||
#, kde-format
|
||||
msgid "Add Song to Playlist"
|
||||
msgstr "Aldoni Kanton al Ludlisto"
|
||||
|
||||
#: contents/ui/dialogs/PlaylistDialog.qml:29
|
||||
#: contents/ui/LocalPlaylistsPage.qml:103
|
||||
#: contents/ui/LocalPlaylistsPage.qml:129
|
||||
#: contents/ui/LocalPlaylistsPage.qml:144
|
||||
#, kde-format
|
||||
msgid "New Playlist"
|
||||
msgstr "Nova Ludlisto"
|
||||
|
||||
#: contents/ui/dialogs/RenamePlaylistDialog.qml:18
|
||||
#, kde-format
|
||||
msgid "Rename playlist"
|
||||
msgstr "Alinomi ludliston"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:125
|
||||
#: contents/ui/NavigationBar.qml:47 contents/ui/NavigationBar.qml:53
|
||||
#: contents/ui/Sidebar.qml:138 contents/ui/Sidebar.qml:143
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr "Plej ŝatataj"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:120 contents/ui/LibraryPage.qml:309
|
||||
#: contents/ui/LibraryPage.qml:408
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr "Montri Ĉion"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:150
|
||||
#, kde-format
|
||||
msgid "No Favourites Yet"
|
||||
msgstr "Neniuj Favoritoj Ankoraŭ"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:218
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr "Plej ludis"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:314 contents/ui/NavigationBar.qml:60
|
||||
#: contents/ui/NavigationBar.qml:66 contents/ui/Sidebar.qml:159
|
||||
#: contents/ui/Sidebar.qml:164
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr "Luditaj Kantoj"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:339
|
||||
#, kde-format
|
||||
msgid "No Songs Played Yet"
|
||||
msgstr "Ankoraŭ Neniuj Kantoj Luditaj"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:396 contents/ui/LocalPlaylistsPage.qml:19
|
||||
#: contents/ui/LocalPlaylistsPage.qml:80 contents/ui/NavigationBar.qml:74
|
||||
#: contents/ui/SearchPage.qml:30 contents/ui/Sidebar.qml:179
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr "Ludlistoj"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:435
|
||||
#, kde-format
|
||||
msgid "No Playlists Yet"
|
||||
msgstr "Neniuj Ludlistoj Ankoraŭ"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:455 contents/ui/LibraryPage.qml:477
|
||||
#: contents/ui/LocalPlaylistsPage.qml:34 contents/ui/LocalPlaylistsPage.qml:56
|
||||
#, kde-format
|
||||
msgid "Rename"
|
||||
msgstr "Alinomi"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:464 contents/ui/LibraryPage.qml:485
|
||||
#: contents/ui/LocalPlaylistsPage.qml:43 contents/ui/LocalPlaylistsPage.qml:64
|
||||
#, kde-format
|
||||
msgid "Delete"
|
||||
msgstr "Forigi"
|
||||
|
||||
#: contents/ui/LocalPlaylistPage.qml:22
|
||||
#, kde-format
|
||||
msgid "Remove from Playlist"
|
||||
msgstr "Forigi el Ludlisto"
|
||||
|
||||
#: contents/ui/LocalPlaylistPage.qml:80
|
||||
#, kde-format
|
||||
msgid "This playlist is still empty"
|
||||
msgstr "Ĉi tiu ludlisto ankoraŭ estas malplena"
|
||||
|
||||
#: contents/ui/LocalPlaylistsPage.qml:111
|
||||
#: contents/ui/LocalPlaylistsPage.qml:134
|
||||
#: contents/ui/LocalPlaylistsPage.qml:149 contents/ui/PlaylistPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Import Playlist"
|
||||
msgstr "Importi Ludliston"
|
||||
|
||||
#: contents/ui/main.qml:127 main.cpp:72
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/main.qml:280
|
||||
#, kde-format
|
||||
msgid "No song playing"
|
||||
msgstr "Neniu kanto ludanta"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:99
|
||||
#, kde-format
|
||||
msgid "Close Maximized Player"
|
||||
msgstr "Fermi Maksimumigitan Ludanton"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:205
|
||||
#: contents/ui/MinimizedPlayerControls.qml:113
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr "Neniu aŭdvidaĵo ludanta"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:428
|
||||
#, kde-format
|
||||
msgid "Remove from Favourites"
|
||||
msgstr "Forigi el Favoritoj"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:428
|
||||
#, kde-format
|
||||
msgid "Add to Favourites"
|
||||
msgstr "Aldoni al Favoritoj"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:453
|
||||
#, kde-format
|
||||
msgid "Open Volume Drawer"
|
||||
msgstr "Malfermi Voluman Keston"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:561
|
||||
#, kde-format
|
||||
msgid "Unmute Audio"
|
||||
msgstr "Malŝalti Audio"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:561
|
||||
#, kde-format
|
||||
msgid "Mute Audio"
|
||||
msgstr "Silentigi Audio"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:600
|
||||
#, kde-format
|
||||
msgid "%1%"
|
||||
msgstr "%1%"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:631
|
||||
#, kde-format
|
||||
msgid "Hide Lyrics"
|
||||
msgstr "Kaŝi Kantotekstojn"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:631
|
||||
#, kde-format
|
||||
msgid "Show Lyrics"
|
||||
msgstr "Montri kantotekstojn"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:651 contents/ui/SongMenu.qml:178
|
||||
#: contents/ui/SongMenu.qml:264
|
||||
#, kde-format
|
||||
msgid "Share Song"
|
||||
msgstr "Kunhavigi Kanton"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:692
|
||||
#, kde-format
|
||||
msgid "Add to a local playlist"
|
||||
msgstr "Aldoni al loka ludlisto"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:729
|
||||
#, kde-format
|
||||
msgid "Hide Queue"
|
||||
msgstr "Kaŝi Vicon"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:729
|
||||
#, kde-format
|
||||
msgid "Show Queue"
|
||||
msgstr "Montri Vicon"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:952
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1189
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Forigi Trakon"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:987
|
||||
#, kde-format
|
||||
msgid "Clear Queue"
|
||||
msgstr "Viŝi Vicon"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1012
|
||||
#, kde-format
|
||||
msgid "Shuffle Queue"
|
||||
msgstr "Miksi Vicon"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1042
|
||||
#, kde-format
|
||||
msgid "Upcoming Songs"
|
||||
msgstr "Venontaj Kantoj"
|
||||
|
||||
#: contents/ui/NavigationBar.qml:23 contents/ui/Sidebar.qml:108
|
||||
#, kde-format
|
||||
msgid "Library"
|
||||
msgstr "Biblioteko"
|
||||
|
||||
#: contents/ui/NavigationBar.qml:35 contents/ui/Sidebar.qml:119
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr "Serĉi"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:17
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr "Nekonata listo de kantoj"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:135
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr "Ankoraŭ neniuj kantoj ĉi tie"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:76
|
||||
#, kde-format
|
||||
msgid "Playlist successfully imported"
|
||||
msgstr "Ludlisto sukcese importita"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:128
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr "Ludlisto"
|
||||
|
||||
#: contents/ui/SearchHistoryPage.qml:82 contents/ui/SearchWithDropdown.qml:394
|
||||
#, kde-format
|
||||
msgid "remove from search history"
|
||||
msgstr "forigi el serĉhistorio"
|
||||
|
||||
#: contents/ui/SearchPage.qml:16
|
||||
#, kde-format
|
||||
msgid "Previous Searches:"
|
||||
msgstr "Antaŭaj Serĉoj:"
|
||||
|
||||
#: contents/ui/SearchPage.qml:28
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr "Artistoj"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Top Results"
|
||||
msgstr "Plej bonaj Rezultoj"
|
||||
|
||||
#: contents/ui/SearchPage.qml:39 playlistimporter.cpp:22
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Nekonata"
|
||||
|
||||
#: contents/ui/SearchWithDropdown.qml:340
|
||||
#, kde-format
|
||||
msgid "No matching previous searches"
|
||||
msgstr "Neniuj kongruaj antaŭaj serĉoj"
|
||||
|
||||
#: contents/ui/ShareMenu.qml:40
|
||||
#, kde-format
|
||||
msgid "Share to"
|
||||
msgstr "Kunhavigi al"
|
||||
|
||||
#: contents/ui/ShareMenu.qml:48 contents/ui/ShareMenu.qml:98
|
||||
#, kde-format
|
||||
msgid "Copy Link"
|
||||
msgstr "Kopii Ligilon"
|
||||
|
||||
#: contents/ui/ShareMenu.qml:53 contents/ui/ShareMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Link copied to clipboard"
|
||||
msgstr "Ligilo kopiita al tondujo"
|
||||
|
||||
#: contents/ui/Sidebar.qml:200
|
||||
#, kde-format
|
||||
msgid "About"
|
||||
msgstr "Pri"
|
||||
|
||||
#: contents/ui/Sidebar.qml:214
|
||||
#, kde-format
|
||||
msgid "Collapse Sidebar"
|
||||
msgstr "Malvastigi Flankbreton"
|
||||
|
||||
#: contents/ui/SongMenu.qml:103 contents/ui/SongMenu.qml:200
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr "Ludi Poste"
|
||||
|
||||
#: contents/ui/SongMenu.qml:111 contents/ui/SongMenu.qml:206
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr "Aldoni al vico"
|
||||
|
||||
#: contents/ui/SongMenu.qml:121 contents/ui/SongMenu.qml:216
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr "Forigi Favoriton"
|
||||
|
||||
#: contents/ui/SongMenu.qml:121 contents/ui/SongMenu.qml:216
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr "Aldoni Favoriton"
|
||||
|
||||
#: contents/ui/SongMenu.qml:138 contents/ui/SongMenu.qml:230
|
||||
#, kde-format
|
||||
msgid "Remove from History"
|
||||
msgstr "Forigi el Historio"
|
||||
|
||||
#: contents/ui/SongMenu.qml:151 contents/ui/SongMenu.qml:239
|
||||
#, kde-format
|
||||
msgid "Add to playlist"
|
||||
msgstr "Aldoni al ludlisto"
|
||||
|
||||
#: main.cpp:74
|
||||
#, kde-format
|
||||
msgctxt "YouTube Music is a music streaming service by Google"
|
||||
msgid "Stream music from YouTube Music"
|
||||
msgstr "Fluigi muzikon de YouTube Music"
|
||||
|
||||
#: main.cpp:76
|
||||
#, kde-format
|
||||
msgid "© 2021-2023 Jonah Brüchert, 2021-2023 KDE Community"
|
||||
msgstr "© 2021-2023 Jonah Brüchert, 2021-2023 KDE-Komunumo"
|
||||
|
||||
#: main.cpp:77
|
||||
#, kde-format
|
||||
msgid "Jonah Brüchert"
|
||||
msgstr "Jonah Brüchert"
|
||||
|
||||
#: main.cpp:77
|
||||
#, kde-format
|
||||
msgid "Maintainer"
|
||||
msgstr "Prizorganto"
|
||||
|
||||
#: main.cpp:78
|
||||
#, kde-format
|
||||
msgid "Mathis Brüchert"
|
||||
msgstr "Mathis Brüchert"
|
||||
|
||||
#: main.cpp:78
|
||||
#, kde-format
|
||||
msgid "Designer"
|
||||
msgstr "Dezajnisto"
|
||||
|
||||
#: main.cpp:79
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr "Oliver Kellogg"
|
||||
|
||||
#: main.cpp:79
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: main.cpp:86
|
||||
#, kde-format
|
||||
msgctxt "YouTube Music is a music streaming service by Google"
|
||||
msgid "Unofficial API for YouTube Music"
|
||||
msgstr "Neoficiala API por YouTube Music"
|
||||
|
||||
#: playlistimporter.cpp:22
|
||||
#, kde-format
|
||||
msgid "No description"
|
||||
msgstr "Neniu priskribo"
|
||||
|
||||
#: playlistimporter.cpp:56
|
||||
#, kde-format
|
||||
msgid "No title"
|
||||
msgstr "Neniu titolo"
|
||||
|
||||
#: playlistimporter.cpp:58
|
||||
#, kde-format
|
||||
msgid "No album"
|
||||
msgstr "Neniu albumo"
|
||||
+12
-12
@@ -6,7 +6,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2023-11-21 00:41+0000\n"
|
||||
"POT-Creation-Date: 2023-11-23 00:41+0000\n"
|
||||
"PO-Revision-Date: 2023-08-24 21:35+0200\n"
|
||||
"Last-Translator: Karl Ove Hufthammer <[email protected]>\n"
|
||||
"Language-Team: Norwegian Nynorsk <[email protected]>\n"
|
||||
@@ -75,8 +75,8 @@ msgid "Album • %1"
|
||||
msgstr "Album • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:160 contents/ui/ArtistPage.qml:197
|
||||
#: contents/ui/LocalPlaylistPage.qml:171 contents/ui/PlaybackHistory.qml:196
|
||||
#: contents/ui/PlaylistPage.qml:190 contents/ui/SearchPage.qml:146
|
||||
#: contents/ui/LocalPlaylistPage.qml:171 contents/ui/PlaybackHistory.qml:195
|
||||
#: contents/ui/PlaylistPage.qml:189 contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr "Meir"
|
||||
@@ -331,23 +331,23 @@ msgstr "Gøym avspelingskøen"
|
||||
msgid "Show Queue"
|
||||
msgstr "Vis avspelingskøen"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:949
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1186
|
||||
#: contents/ui/MaximizedPlayerPage.qml:952
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1189
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr "Fjern spor"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:983
|
||||
#: contents/ui/MaximizedPlayerPage.qml:987
|
||||
#, kde-format
|
||||
msgid "Clear Queue"
|
||||
msgstr "Tøm avspelingskøen"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1008
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1012
|
||||
#, kde-format
|
||||
msgid "Shuffle Queue"
|
||||
msgstr "Stokk om på avspelingskøen"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1038
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1042
|
||||
#, kde-format
|
||||
msgid "Upcoming Songs"
|
||||
msgstr "Framtidige songar"
|
||||
@@ -402,7 +402,7 @@ msgstr "Artistar"
|
||||
msgid "Top Results"
|
||||
msgstr "Toppresultat"
|
||||
|
||||
#: contents/ui/SearchPage.qml:39 playlistimporter.cpp:23
|
||||
#: contents/ui/SearchPage.qml:39 playlistimporter.cpp:22
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr "Ukjend"
|
||||
@@ -516,17 +516,17 @@ msgctxt "YouTube Music is a music streaming service by Google"
|
||||
msgid "Unofficial API for YouTube Music"
|
||||
msgstr ""
|
||||
|
||||
#: playlistimporter.cpp:23
|
||||
#: playlistimporter.cpp:22
|
||||
#, kde-format
|
||||
msgid "No description"
|
||||
msgstr "Inga skildring"
|
||||
|
||||
#: playlistimporter.cpp:57
|
||||
#: playlistimporter.cpp:56
|
||||
#, kde-format
|
||||
msgid "No title"
|
||||
msgstr "Utan tittel"
|
||||
|
||||
#: playlistimporter.cpp:59
|
||||
#: playlistimporter.cpp:58
|
||||
#, kde-format
|
||||
msgid "No album"
|
||||
msgstr "Ingen album"
|
||||
@@ -3,7 +3,7 @@ msgstr ""
|
||||
"Project-Id-Version: kdeorg\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2023-11-23 00:41+0000\n"
|
||||
"PO-Revision-Date: 2023-11-25 02:30\n"
|
||||
"PO-Revision-Date: 2023-12-17 11:26\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Chinese Simplified\n"
|
||||
"Language: zh_CN\n"
|
||||
@@ -14,8 +14,8 @@ msgstr ""
|
||||
"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"
|
||||
"X-Crowdin-File: /kf6-trunk/messages/audiotube/audiotube.pot\n"
|
||||
"X-Crowdin-File-ID: 48698\n"
|
||||
|
||||
#: asyncytmusic.cpp:65
|
||||
#, kde-format
|
||||
|
||||
+99
-96
@@ -2,21 +2,23 @@
|
||||
# audiotube 套件的正體中文翻譯.
|
||||
# Copyright (C) 2022 This file is copyright:
|
||||
# This file is distributed under the same license as the audiotube package.
|
||||
# Automatically generated, 2022.
|
||||
#
|
||||
# Automatically generated, 2022.
|
||||
# Kisaragi Hiu <[email protected]>, 2023.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: audiotube\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2023-11-23 00:41+0000\n"
|
||||
"PO-Revision-Date: 2022-05-30 00:47+0000\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
"PO-Revision-Date: 2023-12-15 20:37+0900\n"
|
||||
"Last-Translator: Kisaragi Hiu <[email protected]>\n"
|
||||
"Language-Team: Traditional Chinese <[email protected]>\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"
|
||||
"X-Generator: Lokalize 24.01.80\n"
|
||||
|
||||
#: asyncytmusic.cpp:65
|
||||
#, kde-format
|
||||
@@ -24,6 +26,7 @@ msgid ""
|
||||
"Running with untested version of ytmusicapi %1. If you experience errors, "
|
||||
"please report them to your distribution."
|
||||
msgstr ""
|
||||
"此次執行使用未測試的 ytmusicapi 版本 %1。發生問題時請回報給您的發行版。"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:71 contents/ui/LibraryPage.qml:38
|
||||
#: contents/ui/LibraryPage.qml:64 contents/ui/LibraryPage.qml:85
|
||||
@@ -34,7 +37,7 @@ msgstr ""
|
||||
#: contents/ui/PlaylistPage.qml:87
|
||||
#, kde-format
|
||||
msgid "Play"
|
||||
msgstr ""
|
||||
msgstr "播放"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:78 contents/ui/ArtistPage.qml:83
|
||||
#: contents/ui/LibraryPage.qml:45 contents/ui/LibraryPage.qml:70
|
||||
@@ -45,7 +48,7 @@ msgstr ""
|
||||
#: contents/ui/PlaylistPage.qml:59 contents/ui/PlaylistPage.qml:94
|
||||
#, kde-format
|
||||
msgid "Shuffle"
|
||||
msgstr ""
|
||||
msgstr "隨機播放"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:86 contents/ui/LibraryPage.qml:75
|
||||
#: contents/ui/LibraryPage.qml:101 contents/ui/LibraryPage.qml:262
|
||||
@@ -53,110 +56,110 @@ msgstr ""
|
||||
#: contents/ui/PlaybackHistory.qml:114 contents/ui/PlaylistPage.qml:102
|
||||
#, kde-format
|
||||
msgid "Append to queue"
|
||||
msgstr ""
|
||||
msgstr "加入待播清單末端"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:91 contents/ui/ArtistPage.qml:91
|
||||
#: contents/ui/PlaylistPage.qml:112
|
||||
#, kde-format
|
||||
msgid "Open in Browser"
|
||||
msgstr ""
|
||||
msgstr "在瀏覽器開啟"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:96 contents/ui/ArtistPage.qml:96
|
||||
#: contents/ui/PlaylistPage.qml:117
|
||||
#, kde-format
|
||||
msgid "Share"
|
||||
msgstr ""
|
||||
msgstr "分享"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:106
|
||||
#, kde-format
|
||||
msgid "Album • %1"
|
||||
msgstr ""
|
||||
msgstr "專輯 • %1"
|
||||
|
||||
#: contents/ui/AlbumPage.qml:160 contents/ui/ArtistPage.qml:197
|
||||
#: contents/ui/LocalPlaylistPage.qml:171 contents/ui/PlaybackHistory.qml:195
|
||||
#: contents/ui/PlaylistPage.qml:189 contents/ui/SearchPage.qml:146
|
||||
#, kde-format
|
||||
msgid "More"
|
||||
msgstr ""
|
||||
msgstr "更多"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:77
|
||||
#, kde-format
|
||||
msgid "Radio"
|
||||
msgstr ""
|
||||
msgstr "廣播"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:105
|
||||
#, kde-format
|
||||
msgid "Artist"
|
||||
msgstr ""
|
||||
msgstr "藝人"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:129 contents/ui/SearchPage.qml:72
|
||||
#, kde-format
|
||||
msgid ""
|
||||
"Video playback is not supported yet. Do you want to play only the audio of "
|
||||
"\"%1\"?"
|
||||
msgstr ""
|
||||
msgstr "尚不支援影片播放。您是否要只播放 \"%1\" 的音效?"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:146 contents/ui/SearchPage.qml:26
|
||||
#, kde-format
|
||||
msgid "Albums"
|
||||
msgstr ""
|
||||
msgstr "專輯"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:148
|
||||
#, kde-format
|
||||
msgid "Singles"
|
||||
msgstr ""
|
||||
msgstr "單曲"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:150 contents/ui/SearchPage.qml:32
|
||||
#, kde-format
|
||||
msgid "Songs"
|
||||
msgstr ""
|
||||
msgstr "歌曲"
|
||||
|
||||
#: contents/ui/ArtistPage.qml:152 contents/ui/SearchPage.qml:34
|
||||
#, kde-format
|
||||
msgid "Videos"
|
||||
msgstr ""
|
||||
msgstr "影片"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:16
|
||||
#, kde-format
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
msgstr "確定"
|
||||
|
||||
#: contents/ui/ConfirmationMessage.qml:21
|
||||
#, kde-format
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
msgstr "取消"
|
||||
|
||||
#: contents/ui/dialogs/AddPlaylistDialog.qml:17
|
||||
#, kde-format
|
||||
msgid "Add playlist"
|
||||
msgstr ""
|
||||
msgstr "新增播放清單"
|
||||
|
||||
#: contents/ui/dialogs/AddPlaylistDialog.qml:23
|
||||
#: contents/ui/dialogs/RenamePlaylistDialog.qml:24
|
||||
#, kde-format
|
||||
msgid "Playlist Title"
|
||||
msgstr ""
|
||||
msgstr "播放清單標題"
|
||||
|
||||
#: contents/ui/dialogs/AddPlaylistDialog.qml:28
|
||||
#: contents/ui/dialogs/RenamePlaylistDialog.qml:30
|
||||
#, kde-format
|
||||
msgid "Playlist Description"
|
||||
msgstr ""
|
||||
msgstr "播放清單描述"
|
||||
|
||||
#: contents/ui/dialogs/ImportPlaylistDialog.qml:17
|
||||
#, kde-format
|
||||
msgid "Import playlist"
|
||||
msgstr ""
|
||||
msgstr "匯入播放清單"
|
||||
|
||||
#: contents/ui/dialogs/ImportPlaylistDialog.qml:23
|
||||
#, kde-format
|
||||
msgid "Playlist URL (Youtube)"
|
||||
msgstr ""
|
||||
msgstr "播放清單網址 (Youtube)"
|
||||
|
||||
#: contents/ui/dialogs/PlaylistDialog.qml:20
|
||||
#, kde-format
|
||||
msgid "Add Song to Playlist"
|
||||
msgstr ""
|
||||
msgstr "將歌曲加入播放清單"
|
||||
|
||||
#: contents/ui/dialogs/PlaylistDialog.qml:29
|
||||
#: contents/ui/LocalPlaylistsPage.qml:103
|
||||
@@ -164,367 +167,367 @@ msgstr ""
|
||||
#: contents/ui/LocalPlaylistsPage.qml:144
|
||||
#, kde-format
|
||||
msgid "New Playlist"
|
||||
msgstr ""
|
||||
msgstr "新播放清單"
|
||||
|
||||
#: contents/ui/dialogs/RenamePlaylistDialog.qml:18
|
||||
#, kde-format
|
||||
msgid "Rename playlist"
|
||||
msgstr ""
|
||||
msgstr "重新命名播放清單"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:31 contents/ui/LibraryPage.qml:125
|
||||
#: contents/ui/NavigationBar.qml:47 contents/ui/NavigationBar.qml:53
|
||||
#: contents/ui/Sidebar.qml:138 contents/ui/Sidebar.qml:143
|
||||
#, kde-format
|
||||
msgid "Favourites"
|
||||
msgstr ""
|
||||
msgstr "最愛"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:120 contents/ui/LibraryPage.qml:309
|
||||
#: contents/ui/LibraryPage.qml:408
|
||||
#, kde-format
|
||||
msgid "Show All"
|
||||
msgstr ""
|
||||
msgstr "顯示全部"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:150
|
||||
#, kde-format
|
||||
msgid "No Favourites Yet"
|
||||
msgstr ""
|
||||
msgstr "尚無最愛"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:218
|
||||
#, kde-format
|
||||
msgid "Most played"
|
||||
msgstr ""
|
||||
msgstr "最常播放"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:314 contents/ui/NavigationBar.qml:60
|
||||
#: contents/ui/NavigationBar.qml:66 contents/ui/Sidebar.qml:159
|
||||
#: contents/ui/Sidebar.qml:164
|
||||
#, kde-format
|
||||
msgid "Played Songs"
|
||||
msgstr ""
|
||||
msgstr "履歷"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:339
|
||||
#, kde-format
|
||||
msgid "No Songs Played Yet"
|
||||
msgstr ""
|
||||
msgstr "尚無播放過的歌曲"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:396 contents/ui/LocalPlaylistsPage.qml:19
|
||||
#: contents/ui/LocalPlaylistsPage.qml:80 contents/ui/NavigationBar.qml:74
|
||||
#: contents/ui/SearchPage.qml:30 contents/ui/Sidebar.qml:179
|
||||
#, kde-format
|
||||
msgid "Playlists"
|
||||
msgstr ""
|
||||
msgstr "播放清單"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:435
|
||||
#, kde-format
|
||||
msgid "No Playlists Yet"
|
||||
msgstr ""
|
||||
msgstr "尚無播放清單"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:455 contents/ui/LibraryPage.qml:477
|
||||
#: contents/ui/LocalPlaylistsPage.qml:34 contents/ui/LocalPlaylistsPage.qml:56
|
||||
#, kde-format
|
||||
msgid "Rename"
|
||||
msgstr ""
|
||||
msgstr "重新命名"
|
||||
|
||||
#: contents/ui/LibraryPage.qml:464 contents/ui/LibraryPage.qml:485
|
||||
#: contents/ui/LocalPlaylistsPage.qml:43 contents/ui/LocalPlaylistsPage.qml:64
|
||||
#, kde-format
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
msgstr "刪除"
|
||||
|
||||
#: contents/ui/LocalPlaylistPage.qml:22
|
||||
#, kde-format
|
||||
msgid "Remove from Playlist"
|
||||
msgstr ""
|
||||
msgstr "從播放清單中移除"
|
||||
|
||||
#: contents/ui/LocalPlaylistPage.qml:80
|
||||
#, kde-format
|
||||
msgid "This playlist is still empty"
|
||||
msgstr ""
|
||||
msgstr "尚未加入歌曲到此播放清單"
|
||||
|
||||
#: contents/ui/LocalPlaylistsPage.qml:111
|
||||
#: contents/ui/LocalPlaylistsPage.qml:134
|
||||
#: contents/ui/LocalPlaylistsPage.qml:149 contents/ui/PlaylistPage.qml:107
|
||||
#, kde-format
|
||||
msgid "Import Playlist"
|
||||
msgstr ""
|
||||
msgstr "匯入播放清單"
|
||||
|
||||
#: contents/ui/main.qml:127 main.cpp:72
|
||||
#, kde-format
|
||||
msgid "AudioTube"
|
||||
msgstr ""
|
||||
msgstr "AudioTube"
|
||||
|
||||
#: contents/ui/main.qml:280
|
||||
#, kde-format
|
||||
msgid "No song playing"
|
||||
msgstr ""
|
||||
msgstr "沒有播放歌曲"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:99
|
||||
#, kde-format
|
||||
msgid "Close Maximized Player"
|
||||
msgstr ""
|
||||
msgstr "關閉最大化播放器"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:205
|
||||
#: contents/ui/MinimizedPlayerControls.qml:113
|
||||
#, kde-format
|
||||
msgid "No media playing"
|
||||
msgstr ""
|
||||
msgstr "沒有播放任何媒體"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:428
|
||||
#, kde-format
|
||||
msgid "Remove from Favourites"
|
||||
msgstr ""
|
||||
msgstr "從最愛中移除"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:428
|
||||
#, kde-format
|
||||
msgid "Add to Favourites"
|
||||
msgstr ""
|
||||
msgstr "加入最愛"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:453
|
||||
#, kde-format
|
||||
msgid "Open Volume Drawer"
|
||||
msgstr ""
|
||||
msgstr "開啟音量側邊欄"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:561
|
||||
#, kde-format
|
||||
msgid "Unmute Audio"
|
||||
msgstr ""
|
||||
msgstr "取消靜音"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:561
|
||||
#, kde-format
|
||||
msgid "Mute Audio"
|
||||
msgstr ""
|
||||
msgstr "靜音"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:600
|
||||
#, kde-format
|
||||
msgid "%1%"
|
||||
msgstr ""
|
||||
msgstr "%1%"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:631
|
||||
#, kde-format
|
||||
msgid "Hide Lyrics"
|
||||
msgstr ""
|
||||
msgstr "隱藏歌詞"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:631
|
||||
#, kde-format
|
||||
msgid "Show Lyrics"
|
||||
msgstr ""
|
||||
msgstr "顯示歌詞"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:651 contents/ui/SongMenu.qml:178
|
||||
#: contents/ui/SongMenu.qml:264
|
||||
#, kde-format
|
||||
msgid "Share Song"
|
||||
msgstr ""
|
||||
msgstr "分享歌曲"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:692
|
||||
#, kde-format
|
||||
msgid "Add to a local playlist"
|
||||
msgstr ""
|
||||
msgstr "加入至本地播放清單"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:729
|
||||
#, kde-format
|
||||
msgid "Hide Queue"
|
||||
msgstr ""
|
||||
msgstr "隱藏待播清單"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:729
|
||||
#, kde-format
|
||||
msgid "Show Queue"
|
||||
msgstr ""
|
||||
msgstr "顯示待播清單"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:952
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1189
|
||||
#, kde-format
|
||||
msgid "Remove Track"
|
||||
msgstr ""
|
||||
msgstr "移除音軌"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:987
|
||||
#, kde-format
|
||||
msgid "Clear Queue"
|
||||
msgstr ""
|
||||
msgstr "清除待播清單"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1012
|
||||
#, kde-format
|
||||
msgid "Shuffle Queue"
|
||||
msgstr ""
|
||||
msgstr "隨機排序待播清單"
|
||||
|
||||
#: contents/ui/MaximizedPlayerPage.qml:1042
|
||||
#, kde-format
|
||||
msgid "Upcoming Songs"
|
||||
msgstr ""
|
||||
msgstr "接下來的歌曲"
|
||||
|
||||
#: contents/ui/NavigationBar.qml:23 contents/ui/Sidebar.qml:108
|
||||
#, kde-format
|
||||
msgid "Library"
|
||||
msgstr ""
|
||||
msgstr "媒體庫"
|
||||
|
||||
#: contents/ui/NavigationBar.qml:35 contents/ui/Sidebar.qml:119
|
||||
#, kde-format
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
msgstr "搜尋"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:17
|
||||
#, kde-format
|
||||
msgid "Unknown list of songs"
|
||||
msgstr ""
|
||||
msgstr "未知的歌曲列表"
|
||||
|
||||
#: contents/ui/PlaybackHistory.qml:135
|
||||
#, kde-format
|
||||
msgid "No songs here yet"
|
||||
msgstr ""
|
||||
msgstr "這裡還沒有任何歌曲"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:76
|
||||
#, kde-format
|
||||
msgid "Playlist successfully imported"
|
||||
msgstr ""
|
||||
msgstr "成功匯入播放清單"
|
||||
|
||||
#: contents/ui/PlaylistPage.qml:128
|
||||
#, kde-format
|
||||
msgid "Playlist"
|
||||
msgstr ""
|
||||
msgstr "播放清單"
|
||||
|
||||
#: contents/ui/SearchHistoryPage.qml:82 contents/ui/SearchWithDropdown.qml:394
|
||||
#, kde-format
|
||||
msgid "remove from search history"
|
||||
msgstr ""
|
||||
msgstr "從搜尋歷史中移除"
|
||||
|
||||
#: contents/ui/SearchPage.qml:16
|
||||
#, kde-format
|
||||
msgid "Previous Searches:"
|
||||
msgstr ""
|
||||
msgstr "先前的搜尋:"
|
||||
|
||||
#: contents/ui/SearchPage.qml:28
|
||||
#, kde-format
|
||||
msgid "Artists"
|
||||
msgstr ""
|
||||
msgstr "藝人"
|
||||
|
||||
#: contents/ui/SearchPage.qml:36
|
||||
#, kde-format
|
||||
msgid "Top Results"
|
||||
msgstr ""
|
||||
msgstr "熱門搜尋結果"
|
||||
|
||||
#: contents/ui/SearchPage.qml:39 playlistimporter.cpp:22
|
||||
#, kde-format
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
msgstr "未知"
|
||||
|
||||
#: contents/ui/SearchWithDropdown.qml:340
|
||||
#, kde-format
|
||||
msgid "No matching previous searches"
|
||||
msgstr ""
|
||||
msgstr "沒有符合的先前的搜尋"
|
||||
|
||||
#: contents/ui/ShareMenu.qml:40
|
||||
#, kde-format
|
||||
msgid "Share to"
|
||||
msgstr ""
|
||||
msgstr "分享至"
|
||||
|
||||
#: contents/ui/ShareMenu.qml:48 contents/ui/ShareMenu.qml:98
|
||||
#, kde-format
|
||||
msgid "Copy Link"
|
||||
msgstr ""
|
||||
msgstr "複製連結"
|
||||
|
||||
#: contents/ui/ShareMenu.qml:53 contents/ui/ShareMenu.qml:103
|
||||
#, kde-format
|
||||
msgid "Link copied to clipboard"
|
||||
msgstr ""
|
||||
msgstr "連結已複製到剪貼簿"
|
||||
|
||||
#: contents/ui/Sidebar.qml:200
|
||||
#, kde-format
|
||||
msgid "About"
|
||||
msgstr ""
|
||||
msgstr "關於"
|
||||
|
||||
#: contents/ui/Sidebar.qml:214
|
||||
#, kde-format
|
||||
msgid "Collapse Sidebar"
|
||||
msgstr ""
|
||||
msgstr "折疊側邊欄"
|
||||
|
||||
#: contents/ui/SongMenu.qml:103 contents/ui/SongMenu.qml:200
|
||||
#, kde-format
|
||||
msgid "Play Next"
|
||||
msgstr ""
|
||||
msgstr "接著播放"
|
||||
|
||||
#: contents/ui/SongMenu.qml:111 contents/ui/SongMenu.qml:206
|
||||
#, kde-format
|
||||
msgid "Add to queue"
|
||||
msgstr ""
|
||||
msgstr "加入待播清單"
|
||||
|
||||
#: contents/ui/SongMenu.qml:121 contents/ui/SongMenu.qml:216
|
||||
#, kde-format
|
||||
msgid "Remove Favourite"
|
||||
msgstr ""
|
||||
msgstr "移除最愛"
|
||||
|
||||
#: contents/ui/SongMenu.qml:121 contents/ui/SongMenu.qml:216
|
||||
#, kde-format
|
||||
msgid "Add Favourite"
|
||||
msgstr ""
|
||||
msgstr "新增最愛"
|
||||
|
||||
#: contents/ui/SongMenu.qml:138 contents/ui/SongMenu.qml:230
|
||||
#, kde-format
|
||||
msgid "Remove from History"
|
||||
msgstr ""
|
||||
msgstr "從履歷中移除"
|
||||
|
||||
#: contents/ui/SongMenu.qml:151 contents/ui/SongMenu.qml:239
|
||||
#, kde-format
|
||||
msgid "Add to playlist"
|
||||
msgstr ""
|
||||
msgstr "加入至播放清單"
|
||||
|
||||
#: main.cpp:74
|
||||
#, kde-format
|
||||
msgctxt "YouTube Music is a music streaming service by Google"
|
||||
msgid "Stream music from YouTube Music"
|
||||
msgstr ""
|
||||
msgstr "從 YouTube Music 串流播放音樂"
|
||||
|
||||
#: main.cpp:76
|
||||
#, kde-format
|
||||
msgid "© 2021-2023 Jonah Brüchert, 2021-2023 KDE Community"
|
||||
msgstr ""
|
||||
msgstr "© 2021-2023 Jonah Brüchert, 2021-2023 KDE 社群"
|
||||
|
||||
#: main.cpp:77
|
||||
#, kde-format
|
||||
msgid "Jonah Brüchert"
|
||||
msgstr ""
|
||||
msgstr "Jonah Brüchert"
|
||||
|
||||
#: main.cpp:77
|
||||
#, kde-format
|
||||
msgid "Maintainer"
|
||||
msgstr ""
|
||||
msgstr "維護者"
|
||||
|
||||
#: main.cpp:78
|
||||
#, kde-format
|
||||
msgid "Mathis Brüchert"
|
||||
msgstr ""
|
||||
msgstr "Mathis Brüchert"
|
||||
|
||||
#: main.cpp:78
|
||||
#, kde-format
|
||||
msgid "Designer"
|
||||
msgstr ""
|
||||
msgstr "設計師"
|
||||
|
||||
#: main.cpp:79
|
||||
#, kde-format
|
||||
msgctxt "NAME OF TRANSLATORS"
|
||||
msgid "Your names"
|
||||
msgstr ""
|
||||
msgstr "Kisaragi Hiu"
|
||||
|
||||
#: main.cpp:79
|
||||
#, kde-format
|
||||
msgctxt "EMAIL OF TRANSLATORS"
|
||||
msgid "Your emails"
|
||||
msgstr ""
|
||||
msgstr "[email protected]"
|
||||
|
||||
#: main.cpp:86
|
||||
#, kde-format
|
||||
msgctxt "YouTube Music is a music streaming service by Google"
|
||||
msgid "Unofficial API for YouTube Music"
|
||||
msgstr ""
|
||||
msgstr "YouTube Music 非官方 API"
|
||||
|
||||
#: playlistimporter.cpp:22
|
||||
#, kde-format
|
||||
msgid "No description"
|
||||
msgstr ""
|
||||
msgstr "無描述"
|
||||
|
||||
#: playlistimporter.cpp:56
|
||||
#, kde-format
|
||||
msgid "No title"
|
||||
msgstr ""
|
||||
msgstr "無標題"
|
||||
|
||||
#: playlistimporter.cpp:58
|
||||
#, kde-format
|
||||
msgid "No album"
|
||||
msgstr ""
|
||||
msgstr "無專輯"
|
||||
@@ -35,6 +35,8 @@ add_executable(audiotube
|
||||
resources.qrc
|
||||
blur.cpp
|
||||
clipboard.cpp
|
||||
downloadmanager.cpp
|
||||
downloadedsongsmodel.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(audiotube
|
||||
@@ -54,6 +56,8 @@ target_link_libraries(audiotube
|
||||
FutureSQL${QT_MAJOR_VERSION}::FutureSQL
|
||||
QCoro${QT_MAJOR_VERSION}::Core
|
||||
qtmprisdeclarative
|
||||
QCoro${QT_MAJOR_VERSION}::Network
|
||||
QCoro${QT_MAJOR_VERSION}::Qml
|
||||
ytm
|
||||
)
|
||||
|
||||
|
||||
@@ -201,3 +201,29 @@ YTMusicThread::YTMusicThread()
|
||||
m_ytm->moveToThread(this);
|
||||
start();
|
||||
}
|
||||
|
||||
QUrl pickAudioUrl(const std::span<const video_info::Format> formats)
|
||||
{
|
||||
if (formats.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<video_info::Format> audioFormats;
|
||||
|
||||
// filter audio only formats
|
||||
std::copy_if(formats.begin(), formats.end(), std::back_inserter(audioFormats),
|
||||
[](const video_info::Format &format) {
|
||||
return format.acodec != "none" && format.vcodec == "none";
|
||||
});
|
||||
|
||||
if (audioFormats.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
+8
-5
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <span>
|
||||
|
||||
#include <ytmusic.h>
|
||||
|
||||
@@ -94,15 +95,15 @@ private:
|
||||
using ReturnType = std::invoke_result_t<Func>;
|
||||
auto interface = std::make_shared<QFutureInterface<ReturnType>>();
|
||||
QMetaObject::invokeMethod(this, [=, this]() {
|
||||
ReturnType val;
|
||||
try {
|
||||
ReturnType val = fun();
|
||||
interface->reportResult(val);
|
||||
interface->reportFinished();
|
||||
val = fun();
|
||||
} catch (const std::exception &err) {
|
||||
interface->reportResult({});
|
||||
interface->reportFinished();
|
||||
Q_EMIT errorOccurred(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
|
||||
interface->reportResult(val);
|
||||
interface->reportFinished();
|
||||
});
|
||||
return interface->future();
|
||||
}
|
||||
@@ -124,3 +125,5 @@ private:
|
||||
|
||||
AsyncYTMusic *m_ytm;
|
||||
};
|
||||
|
||||
QUrl pickAudioUrl(const std::span<const video_info::Format> formats);
|
||||
@@ -17,7 +17,7 @@ import "dialogs"
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var info // VideoInfoExtractor object
|
||||
required property VideoInfoExtractor info // VideoInfoExtractor object
|
||||
required property var audio // Audio object
|
||||
required property string thumbnail
|
||||
readonly property bool isWidescreen: width >= Kirigami.Units.gridUnit * 50
|
||||
@@ -439,6 +439,38 @@ Item {
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
id: downloadButton
|
||||
|
||||
DownloadedWatcher {
|
||||
id: downloadedWatcher
|
||||
videoId: info.videoId
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2.5
|
||||
Layout.maximumWidth: height
|
||||
Layout.preferredWidth: height
|
||||
onClicked: {
|
||||
if (downloadedWatcher.downloaded) {
|
||||
DownloadManager.deleteDownload(info.videoId)
|
||||
} else {
|
||||
DownloadManager.downloadSong(info.videoId)
|
||||
}
|
||||
}
|
||||
text: downloadedWatcher.downloaded ? i18n("Delete Download") : i18n("Download")
|
||||
icon.name: downloadedWatcher.downloaded ? "delete" : "download"
|
||||
icon.color: "white"
|
||||
display: AbstractButton.IconOnly
|
||||
|
||||
ToolTip.text: text
|
||||
ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
ToolTip.visible: Kirigami.Settings.isMobile ? pressed : hovered
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
id: volumeButtonSmallScreen
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||
|
||||
@@ -208,7 +208,6 @@ Item {
|
||||
onTriggered: UserPlaylistModel.append(menu.videoId, menu.songTitle, menu.artists)
|
||||
}
|
||||
|
||||
|
||||
Controls.MenuSeparator{}
|
||||
|
||||
Controls.MenuItem {
|
||||
@@ -240,6 +239,23 @@ Item {
|
||||
icon.name: "media-playlist-append"
|
||||
onTriggered: playlistDialog.open()
|
||||
}
|
||||
|
||||
Controls.MenuItem {
|
||||
DownloadedWatcher {
|
||||
id: downloadedWatcher
|
||||
videoId: root.videoId
|
||||
}
|
||||
|
||||
text: downloadedWatcher.downloaded ? i18n("Delete download") : i18n("Download")
|
||||
icon.name: downloadedWatcher.downloaded ? "delete" : "download"
|
||||
onTriggered: {
|
||||
if (downloadedWatcher.downloaded) {
|
||||
DownloadManager.deleteDownload(root.videoId)
|
||||
} else {
|
||||
DownloadManager.downloadSong(videoId).then(() => showPassiveNotification("Download finished"))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Page specific actions //
|
||||
|
||||
Controls.MenuSeparator{ visible: instantiator.count !== 0 }
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// SPDX-FileCopyrightText: 2023 Jonah Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "downloadedsongsmodel.h"
|
||||
|
||||
#include "downloadmanager.h"
|
||||
#include "library.h"
|
||||
|
||||
namespace ranges = std::ranges;
|
||||
|
||||
DownloadedSongsModel::DownloadedSongsModel(QObject *parent)
|
||||
: QAbstractListModel{parent}
|
||||
{
|
||||
auto update = [this]() {
|
||||
auto future = Library::instance().downloadedSongs();
|
||||
QCoro::connect(std::move(future), this, [this](auto &&songs) {
|
||||
beginResetModel();
|
||||
m_songs = std::move(songs);
|
||||
endResetModel();
|
||||
});
|
||||
};
|
||||
|
||||
update();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// SPDX-FileCopyrightText: 2023 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 <QAbstractListModel>
|
||||
|
||||
#include "library.h"
|
||||
|
||||
class DownloadedSongsModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DownloadedSongsModel(QObject *parent = nullptr);
|
||||
|
||||
enum Role {
|
||||
Title,
|
||||
Artist,
|
||||
VideoId
|
||||
};
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override {
|
||||
return {
|
||||
{ Title, "title" },
|
||||
{ Artist, "artist" },
|
||||
{ VideoId, "videoId" }
|
||||
};
|
||||
}
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override {
|
||||
return parent.isValid() ? 0 : m_songs.size();
|
||||
}
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override {
|
||||
auto &song = m_songs[index.row()];
|
||||
|
||||
switch (role) {
|
||||
case Role::Title:
|
||||
return song.title;
|
||||
case Role::Artist:
|
||||
return song.artist;
|
||||
case Role::VideoId:
|
||||
return song.videoId;
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Song> m_songs;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
// SPDX-FileCopyrightText: 2023 Jonah Brüchert <[email protected]>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "downloadmanager.h"
|
||||
|
||||
#include <QUrl>
|
||||
#include <QFile>
|
||||
#include <QStandardPaths>
|
||||
#include <QStringBuilder>
|
||||
|
||||
#include <QCoroNetworkReply>
|
||||
#include <QFile>
|
||||
|
||||
#include "asyncytmusic.h"
|
||||
#include "library.h"
|
||||
#include "qdir.h"
|
||||
|
||||
constexpr auto BUFFER_SIZE = 4096;
|
||||
|
||||
DownloadManager::DownloadManager(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QCoro::QmlTask DownloadManager::downloadSong(const QString &videoId)
|
||||
{
|
||||
return download(videoId);
|
||||
}
|
||||
|
||||
void DownloadManager::deleteDownload(const QString &videoId)
|
||||
{
|
||||
QString directory = downloadDirectory();
|
||||
QFile::remove(directory % videoId);
|
||||
|
||||
auto future = Library::instance().markSongDownloaded(videoId, false);
|
||||
QCoro::connect(std::move(future), &Library::instance(), [videoId]() {
|
||||
Q_EMIT Library::instance().downloadedChanged(videoId);
|
||||
});
|
||||
}
|
||||
|
||||
QString DownloadManager::localPathOf(const QString &videoId)
|
||||
{
|
||||
return downloadDirectory() % "/" % videoId;
|
||||
}
|
||||
|
||||
QCoro::Task<> DownloadManager::download(const QString videoId)
|
||||
{
|
||||
auto info = co_await YTMusicThread::instance()->extractVideoInfo(videoId);
|
||||
|
||||
// If we don't know anything about the song yet, save what we know
|
||||
// This allows searching for the song if it was just downloaded
|
||||
QCoro::connect(Library::instance().getSong(videoId), this, [=](auto &&song) {
|
||||
if (!song) {
|
||||
Library::instance().addSong(videoId, QString::fromStdString(info.title), QString::fromStdString(info.artist), {});
|
||||
}
|
||||
});
|
||||
|
||||
QUrl url = pickAudioUrl(info.formats);
|
||||
//qDebug() << url;
|
||||
|
||||
auto *reply = Library::instance().nam().get(QNetworkRequest(url));
|
||||
|
||||
QString directory = downloadDirectory();
|
||||
QDir(directory).mkpath(".");
|
||||
|
||||
QString downloadLocation = directory % "/" % videoId % ".part";
|
||||
|
||||
auto *file = new QFile(downloadLocation);
|
||||
if (!file->open(QFile::WriteOnly | QFile::Truncate)) {
|
||||
qDebug() << "Failed to open" << downloadLocation << "for writing";
|
||||
co_return;
|
||||
}
|
||||
|
||||
connect(reply, &QNetworkReply::readyRead, this, [reply, file]() {
|
||||
QByteArray buffer;
|
||||
buffer.reserve(BUFFER_SIZE);
|
||||
|
||||
int read = 0;
|
||||
do {
|
||||
read = reply->read(buffer.data(), BUFFER_SIZE);
|
||||
file->write(buffer.data(), read);
|
||||
} while (read > 0);
|
||||
});
|
||||
co_await reply;
|
||||
|
||||
file->close();
|
||||
file->deleteLater();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QString location = directory % "/" % videoId;
|
||||
QFile::rename(downloadLocation, location);
|
||||
|
||||
Library::instance().markSongDownloaded(videoId, true);
|
||||
Q_EMIT Library::instance().downloadedChanged(videoId);
|
||||
}
|
||||
}
|
||||
|
||||
QString DownloadManager::downloadDirectory()
|
||||
{
|
||||
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) % "/downloads/";
|
||||
}
|
||||
|
||||
DownloadedWatcher::DownloadedWatcher(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
auto update = [this]() {
|
||||
qDebug() << "checking downloaded";
|
||||
auto future = Library::instance().songDownloaded(m_videoId);
|
||||
|
||||
QCoro::connect(std::move(future), this, [this](auto downloaded) {
|
||||
m_downloaded = downloaded;
|
||||
qDebug() << "downloaded" << m_downloaded;
|
||||
Q_EMIT downloadedChanged();
|
||||
});
|
||||
};
|
||||
|
||||
connect(this, &DownloadedWatcher::videoIdChanged, this, update);
|
||||
|
||||
connect(&Library::instance(), &Library::downloadedChanged, this, [=, this](const QString &videoId) {
|
||||
if (m_videoId == videoId) {
|
||||
update();
|
||||
}
|
||||
});
|
||||
update();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: 2023 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 <QCoroTask>
|
||||
#include <QCoroQmlTask>
|
||||
|
||||
class DownloadManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DownloadManager(QObject *parent = nullptr);
|
||||
Q_INVOKABLE QCoro::QmlTask downloadSong(const QString &videoId);
|
||||
Q_INVOKABLE void deleteDownload(const QString &videoId);
|
||||
|
||||
static QString localPathOf(const QString &videoId);
|
||||
static QString downloadDirectory();
|
||||
|
||||
private:
|
||||
QCoro::Task<> download(const QString videoId);
|
||||
|
||||
};
|
||||
|
||||
class DownloadedWatcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString videoId MEMBER m_videoId NOTIFY videoIdChanged)
|
||||
Q_PROPERTY(bool downloaded MEMBER m_downloaded NOTIFY downloadedChanged)
|
||||
|
||||
public:
|
||||
explicit DownloadedWatcher(QObject *parent = nullptr);
|
||||
|
||||
Q_SIGNAL void downloadedChanged();
|
||||
Q_SIGNAL void videoIdChanged();
|
||||
|
||||
private:
|
||||
bool m_downloaded = false;
|
||||
QString m_videoId;
|
||||
};
|
||||
+45
-6
@@ -105,12 +105,12 @@ void Library::refreshPlaybackHistory()
|
||||
{
|
||||
// playbackHistory
|
||||
auto future = m_database->getResults<PlayedSong>(
|
||||
"select * from played_songs natural join songs");
|
||||
"select * from played_songs natural join songs left join downloaded_songs on songs.video_id = downloaded_songs.video_id");
|
||||
m_playbackHistory = new PlaybackHistoryModel(std::move(future), this);
|
||||
|
||||
// mostPlayed
|
||||
auto future2 = m_database->getResults<PlayedSong>(
|
||||
"select * from played_songs natural join songs order by plays desc limit 10");
|
||||
"select * from played_songs natural join songs left join downloaded_songs on songs.video_id = downloaded_songs.video_id order by plays desc limit 10");
|
||||
m_mostPlayed = new PlaybackHistoryModel(std::move(future2), this);
|
||||
Q_EMIT playbackHistoryChanged();
|
||||
}
|
||||
@@ -161,8 +161,45 @@ QNetworkAccessManager &Library::nam()
|
||||
|
||||
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);
|
||||
if (!videoId.isEmpty() && !title.isEmpty()) {
|
||||
// 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);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QFuture<std::optional<Song>> Library::getSong(const QString &videoId)
|
||||
{
|
||||
return m_database->getResult<Song>("select * from songs where video_id = ?", videoId);
|
||||
}
|
||||
|
||||
QFuture<std::vector<Song> > Library::downloadedSongs()
|
||||
{
|
||||
return m_database->getResults<Song>(
|
||||
"select * from downloaded_songs natural join songs");
|
||||
}
|
||||
|
||||
QFuture<void> Library::markSongDownloaded(const QString &videoId, bool downloaded)
|
||||
{
|
||||
if (downloaded) {
|
||||
return m_database->execute(
|
||||
"insert or replace into downloaded_songs values (?)", videoId);
|
||||
} else {
|
||||
return m_database->execute(
|
||||
"delete from downloaded_songs where video_id = ?", videoId);
|
||||
}
|
||||
}
|
||||
|
||||
QCoro::Task<bool> Library::songDownloaded(const QString &videoId)
|
||||
{
|
||||
auto downloaded = co_await Library::instance().database().getResult<SingleValue<bool>>(
|
||||
"select count(*) > 0 from downloaded_songs where video_id = ?", videoId);
|
||||
|
||||
if (downloaded) {
|
||||
co_return downloaded->value;
|
||||
} else {
|
||||
co_return false;
|
||||
}
|
||||
}
|
||||
|
||||
PlaybackHistoryModel::PlaybackHistoryModel(QFuture<std::vector<PlayedSong>> &&songs, QObject *parent)
|
||||
@@ -440,10 +477,12 @@ LocalSearchModel::LocalSearchModel(QObject *parent) : PlaybackHistoryModel(paren
|
||||
{
|
||||
connect(this, &LocalSearchModel::searchQueryChanged, this, [this]() {
|
||||
auto resultFuture = Library::instance().database()
|
||||
.getResults<PlayedSong>("select * from played_songs natural join songs "
|
||||
.getResults<PlayedSong>("select songs.video_id, plays, title, artist, album, not downloaded_songs.video_id is null "
|
||||
"from songs left join played_songs on songs.video_id = played_songs.video_id "
|
||||
"left join downloaded_songs on songs.video_id = downloaded_songs.video_id "
|
||||
"where title like '%" % m_searchQuery % "%' "
|
||||
"order by plays desc limit 10");
|
||||
QCoro::connect(std::move(resultFuture), this, [this](auto results) {
|
||||
QCoro::connect(std::move(resultFuture), this, [this](auto &&results) {
|
||||
beginResetModel();
|
||||
m_playedSongs = results;
|
||||
endResetModel();
|
||||
|
||||
+11
-12
@@ -22,11 +22,6 @@ class WasPlayedWatcher;
|
||||
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;
|
||||
@@ -56,18 +51,14 @@ private:
|
||||
};
|
||||
|
||||
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};
|
||||
}
|
||||
using ColumnTypes = std::tuple<QString, int, QString, QString, QString, bool>;
|
||||
|
||||
QString videoId;
|
||||
int plays;
|
||||
QString title;
|
||||
QString artist;
|
||||
QString album;
|
||||
int plays;
|
||||
bool downloaded;
|
||||
};
|
||||
|
||||
class PlaybackHistoryModel : public QAbstractListModel {
|
||||
@@ -183,6 +174,14 @@ public:
|
||||
return *m_database;
|
||||
}
|
||||
QFuture<void> addSong(const QString &videoId, const QString &title, const QString &artist, const QString &album);
|
||||
QFuture<std::optional<Song>> getSong(const QString &videoId);
|
||||
|
||||
QFuture<std::vector<Song>> downloadedSongs();
|
||||
|
||||
QFuture<void> markSongDownloaded(const QString &videoId, bool downloaded);
|
||||
QCoro::Task<bool> songDownloaded(const QString &videoId);
|
||||
|
||||
Q_SIGNAL void downloadedChanged(const QString &videoId);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <KCrash>
|
||||
#include <KAboutData>
|
||||
|
||||
#include <QCoroQml>
|
||||
|
||||
#include <mprisplugin.h>
|
||||
|
||||
#include "clipboard.h"
|
||||
@@ -34,6 +36,7 @@
|
||||
#include "localplaylistmodel.h"
|
||||
#include "localplaylistsmodel.h"
|
||||
#include "playlistimporter.h"
|
||||
#include "downloadmanager.h"
|
||||
|
||||
#include <ThreadedDatabase>
|
||||
|
||||
@@ -95,6 +98,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
MprisPlugin(&engine).registerTypes("org.nemomobile.qtmpris");
|
||||
QCoro::Qml::registerTypes();
|
||||
|
||||
qmlRegisterType<SearchModel>(URI, 1, 0, "SearchModel");
|
||||
qmlRegisterType<AlbumModel>(URI, 1, 0, "AlbumModel");
|
||||
@@ -125,9 +129,13 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
||||
qmlRegisterSingletonType<Clipboard>(URI, 1, 0, "Clipboard", [](QQmlEngine *, QJSEngine *) {
|
||||
return new Clipboard();
|
||||
});
|
||||
qmlRegisterSingletonType<DownloadManager>(URI, 1, 0, "DownloadManager", [](QQmlEngine *, QJSEngine *) {
|
||||
return new DownloadManager();
|
||||
});
|
||||
|
||||
qmlRegisterSingletonInstance<Library>(URI, 1, 0, "Library", &Library::instance());
|
||||
qmlRegisterType<ThumbnailSource>(URI, 1, 0, "ThumbnailSource");
|
||||
qmlRegisterType<DownloadedWatcher>(URI, 1, 0, "DownloadedWatcher");
|
||||
qmlRegisterAnonymousType<FavouriteWatcher>(URI, 1);
|
||||
qmlRegisterAnonymousType<WasPlayedWatcher>(URI, 1);
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
-- SPDX-FileCopyrightText: 2023 Jonah Brüchert <[email protected]>
|
||||
--
|
||||
-- SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
drop table downloaded_songs;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- SPDX-FileCopyrightText: 2023 Jonah Brüchert <[email protected]>
|
||||
--
|
||||
-- SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
create table downloaded_songs (video_id Text primary key not null);
|
||||
@@ -47,5 +47,7 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
|
||||
<file alias="AlbumCoverItem.qml">contents/ui/AlbumCoverItem.qml</file>
|
||||
<file alias="components/ActionButton.qml">contents/ui/components/ActionButton.qml</file>
|
||||
<file alias="components/DoubleActionButton.qml">contents/ui/components/DoubleActionButton.qml</file>
|
||||
<file>migrations/2023-08-10-212523_downloads/down.sql</file>
|
||||
<file>migrations/2023-08-10-212523_downloads/up.sql</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -31,13 +31,29 @@ UserPlaylistModel::UserPlaylistModel(QObject *parent)
|
||||
m_playlist = std::move(playlist);
|
||||
endResetModel();
|
||||
setCurrentVideoId({});
|
||||
if (m_shuffle) {
|
||||
shufflePlaylist();
|
||||
|
||||
// reset shuffle
|
||||
setShuffle(false);
|
||||
}
|
||||
if (!m_playlist.tracks.empty()) {
|
||||
if (m_playlist.tracks.empty()) {
|
||||
// offline mode
|
||||
QCoro::connect(Library::instance().getSong(m_initialVideoId), this, [this](auto song) {
|
||||
if (song) {
|
||||
watch::Playlist::Track track;
|
||||
track.video_id = m_initialVideoId.toStdString();
|
||||
track.title = song->title.toStdString();
|
||||
track.artists = {meta::Artist {song->artist.toStdString(), {}}};
|
||||
|
||||
beginResetModel();
|
||||
m_playlist.tracks.push_back(std::move(track));
|
||||
endResetModel();
|
||||
setCurrentVideoId(QString::fromStdString(m_playlist.tracks.front().video_id));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (m_shuffle) {
|
||||
shufflePlaylist();
|
||||
|
||||
// reset shuffle
|
||||
setShuffle(false);
|
||||
}
|
||||
setCurrentVideoId(QString::fromStdString(m_playlist.tracks.front().video_id));
|
||||
}
|
||||
};
|
||||
|
||||
+50
-28
@@ -5,11 +5,16 @@
|
||||
#include "videoinfoextractor.h"
|
||||
|
||||
#include "asyncytmusic.h"
|
||||
#include "library.h"
|
||||
#include "downloadmanager.h"
|
||||
|
||||
VideoInfoExtractor::VideoInfoExtractor(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
connect(&m_thumbnailSource, &ThumbnailSource::cachedPathChanged, this, &VideoInfoExtractor::songChanged);
|
||||
|
||||
connect(this, &VideoInfoExtractor::videoIdChanged, this, [this] {
|
||||
qDebug() << "video id changed to" << m_videoId;
|
||||
if (m_videoId.isEmpty()) {
|
||||
m_videoInfo = {};
|
||||
Q_EMIT songChanged();
|
||||
@@ -18,39 +23,44 @@ VideoInfoExtractor::VideoInfoExtractor(QObject *parent)
|
||||
|
||||
setLoading(true);
|
||||
|
||||
auto future = YTMusicThread::instance()->extractVideoInfo(QString::fromStdString(m_videoId.toStdString()));
|
||||
QCoro::connect(std::move(future), this, [this](const video_info::VideoInfo &videoInfo) {
|
||||
m_videoInfo = videoInfo;
|
||||
setLoading(false);
|
||||
Q_EMIT songChanged();
|
||||
QCoro::connect(Library::instance().songDownloaded(m_videoId), this, [this](bool downloaded) {
|
||||
m_downloaded = downloaded;
|
||||
if (downloaded) {
|
||||
m_thumbnailSource.setVideoId(m_videoId);
|
||||
|
||||
QCoro::connect(Library::instance().getSong(m_videoId), this, [this](auto &&song) {
|
||||
if (song) {
|
||||
m_localInfo = std::move(*song);
|
||||
setLoading(false);
|
||||
Q_EMIT songChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto future = YTMusicThread::instance()->extractVideoInfo(QString::fromStdString(m_videoId.toStdString()));
|
||||
QCoro::connect(std::move(future), this, [this](video_info::VideoInfo &&videoInfo) {
|
||||
if (videoInfo.id.empty()) {
|
||||
return;
|
||||
}
|
||||
m_videoInfo = std::move(videoInfo);
|
||||
setLoading(false);
|
||||
Q_EMIT songChanged();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
QUrl VideoInfoExtractor::audioUrl() const
|
||||
{
|
||||
if (m_videoInfo.formats.empty()) {
|
||||
if (m_videoId.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<video_info::Format> audioFormats;
|
||||
|
||||
// filter audio only formats
|
||||
std::copy_if(m_videoInfo.formats.begin(), m_videoInfo.formats.end(), std::back_inserter(audioFormats),
|
||||
[](const video_info::Format &format) {
|
||||
return format.acodec != "none" && format.vcodec == "none";
|
||||
});
|
||||
|
||||
if (audioFormats.empty()) {
|
||||
return {};
|
||||
if (!m_videoInfo) {
|
||||
return QUrl::fromLocalFile(DownloadManager::localPathOf(m_videoId));
|
||||
} else {
|
||||
return pickAudioUrl(m_videoInfo->formats);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
QString VideoInfoExtractor::videoId() const
|
||||
@@ -69,22 +79,34 @@ void VideoInfoExtractor::setVideoId(const QString &videoId)
|
||||
|
||||
QString VideoInfoExtractor::title() const
|
||||
{
|
||||
return QString::fromStdString(m_videoInfo.title);
|
||||
if (!m_videoInfo) {
|
||||
return m_localInfo.title;
|
||||
}
|
||||
return QString::fromStdString(m_videoInfo->title);
|
||||
}
|
||||
|
||||
QString VideoInfoExtractor::artist() const
|
||||
{
|
||||
return QString::fromStdString(m_videoInfo.artist);
|
||||
if (!m_videoInfo) {
|
||||
return m_localInfo.artist;
|
||||
}
|
||||
return QString::fromStdString(m_videoInfo->artist);
|
||||
}
|
||||
|
||||
QString VideoInfoExtractor::channel() const
|
||||
{
|
||||
return QString::fromStdString(m_videoInfo.channel);
|
||||
if (!m_videoInfo) {
|
||||
return {};
|
||||
}
|
||||
return QString::fromStdString(m_videoInfo->channel);
|
||||
}
|
||||
|
||||
QString VideoInfoExtractor::thumbnail() const
|
||||
QUrl VideoInfoExtractor::thumbnail() const
|
||||
{
|
||||
return QString::fromStdString(m_videoInfo.thumbnail);
|
||||
if (!m_videoInfo) {
|
||||
return m_thumbnailSource.cachedPath();
|
||||
}
|
||||
return QUrl(QString::fromStdString(m_videoInfo->thumbnail));
|
||||
}
|
||||
|
||||
bool VideoInfoExtractor::loading() const
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <QUrl>
|
||||
|
||||
#include <ytmusic.h>
|
||||
#include "library.h"
|
||||
#include "thumbnailsource.h"
|
||||
|
||||
class VideoInfoExtractor : public QObject
|
||||
{
|
||||
@@ -19,7 +21,7 @@ class VideoInfoExtractor : public QObject
|
||||
Q_PROPERTY(QString title READ title NOTIFY songChanged)
|
||||
Q_PROPERTY(QString artist READ artist NOTIFY songChanged) // may be empty if it is a video
|
||||
Q_PROPERTY(QString channel READ channel NOTIFY songChanged)
|
||||
Q_PROPERTY(QString thumbnail READ thumbnail NOTIFY songChanged)
|
||||
Q_PROPERTY(QUrl thumbnail READ thumbnail NOTIFY songChanged)
|
||||
Q_PROPERTY(bool loading READ loading WRITE setLoading NOTIFY songChanged)
|
||||
|
||||
public:
|
||||
@@ -37,7 +39,7 @@ public:
|
||||
|
||||
QString channel() const;
|
||||
|
||||
QString thumbnail() const;
|
||||
QUrl thumbnail() const;
|
||||
|
||||
bool loading() const;
|
||||
void setLoading(bool loading);
|
||||
@@ -48,5 +50,10 @@ public:
|
||||
private:
|
||||
bool m_loading = false;
|
||||
QString m_videoId;
|
||||
video_info::VideoInfo m_videoInfo;
|
||||
std::optional<video_info::VideoInfo> m_videoInfo;
|
||||
|
||||
// Fallback data used when offline
|
||||
bool m_downloaded = false;
|
||||
Song m_localInfo;
|
||||
ThumbnailSource m_thumbnailSource;
|
||||
};
|
||||
@@ -496,6 +496,7 @@ 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));
|
||||
pyPrintPretty(info);
|
||||
|
||||
return {
|
||||
info["id"].cast<std::string>(),
|
||||
|
||||
@@ -242,6 +242,8 @@ struct Format {
|
||||
std::string acodec;
|
||||
|
||||
// More, but not interesting for us right now
|
||||
|
||||
// TODO parse downloader_options, http_headers
|
||||
};
|
||||
|
||||
struct VideoInfo {
|
||||
|
||||
Reference in new issue
Block a user