Skip to content

Commit

Permalink
Added support for youtube videos as audio source
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilInTheGaps committed Dec 11, 2023
1 parent 9f3c07a commit 9c1fa8f
Show file tree
Hide file tree
Showing 54 changed files with 1,707 additions and 150 deletions.
2 changes: 2 additions & 0 deletions app/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "filesystem/file.h"
#include "logger.h"
#include "services/nextcloud/nextcloud.h"
#include "services/youtube/youtube.h"
#include "settings/quick/settingsmanager.h"
#include "tools/audio/thumbnails/audiothumbnailprovider.h"
#include "updates/version.h"
Expand Down Expand Up @@ -140,6 +141,7 @@ auto main(int argc, char *argv[]) -> int

// Misc
Files::File::init(Services::NextCloud::qmlInstance(&engine));
Services::YouTube::instance()->setNetworkManager(engine.networkAccessManager());

engine.addImageProvider(u"audioElementIcons"_s, new AudioThumbnailProvider());
engine.loadFromModule("ui"_L1, "Main"_L1);
Expand Down
105 changes: 51 additions & 54 deletions app/ui/tools/audio/editor/views/ElementFileAddView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,16 @@ Item {

function setMode(mode) {
if (root.mode !== mode) {
url_text_field.clear()
url_text_field.clear();
}

root.mode = mode
root.mode = mode;
}

Connections {
target: AudioTool.editor

function onCurrentElementChanged() {
root.setMode(0)
root.setMode(0);
}
}

Expand Down Expand Up @@ -54,8 +53,7 @@ Item {

CustomButton {
id: spotify_button
visible: AudioTool.editor.currentElement
&& AudioTool.editor.currentElement.type === 0
visible: AudioTool.editor.currentElement && AudioTool.editor.currentElement.type === 0

iconText: FontAwesome.spotify
iconFont: FontAwesome.fontBrands
Expand Down Expand Up @@ -142,56 +140,55 @@ Item {
iconText: FontAwesome.plus

onClicked: {
AudioTool.editor.addUrl(url_text_field.text, root.mode)
AudioTool.editor.addUrl(url_text_field.text, root.mode);
}
}
}

// Rectangle {
// id: youtube_adder
// visible: root.mode > 1 && AudioTool.editor.currentElement
// && AudioTool.editor.currentElement.type < 2
// anchors.topMargin: 5
// anchors.top: url_adder.bottom
// anchors.right: parent.right
// anchors.left: parent.left

// height: Sizes.toolbarHeight
// color: palette.alternateBase

// CustomToolBarButton {
// id: youtube_adder_icon
// anchors.left: parent.left
// anchors.leftMargin: 10
// enabled: false

// iconText: FontAwesome.youtube
// iconFont: FontAwesome.fontBrands
// }

// TextField {
// id: youtube_text_field
// anchors.left: youtube_adder_icon.right
// anchors.right: youtube_adder_button.left
// anchors.top: parent.top
// anchors.bottom: parent.bottom
// anchors.leftMargin: 10
// anchors.rightMargin: 10

// selectByMouse: true
// placeholderText: qsTr("YouTube URL")
// }

// CustomToolBarButton {
// id: youtube_adder_button
// anchors.right: parent.right
// anchors.rightMargin: 10

// iconText: FontAwesome.plus

// onClicked: {
// AudioTool.editor.addYtUrl(youtube_text_field.text)
// }
// }
// }
Rectangle {
id: youtube_adder
visible: root.mode > 1 && AudioTool.editor.currentElement && AudioTool.editor.currentElement.type < 2
anchors.topMargin: 5
anchors.top: url_adder.bottom
anchors.right: parent.right
anchors.left: parent.left

height: Sizes.toolbarHeight
color: palette.alternateBase

CustomToolBarButton {
id: youtube_adder_icon
anchors.left: parent.left
anchors.leftMargin: 10
enabled: false

iconText: FontAwesome.youtube
iconFont: FontAwesome.fontBrands
}

TextField {
id: youtube_text_field
anchors.left: youtube_adder_icon.right
anchors.right: youtube_adder_button.left
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.leftMargin: 10
anchors.rightMargin: 10

selectByMouse: true
placeholderText: qsTr("YouTube URL")
}

CustomToolBarButton {
id: youtube_adder_button
anchors.right: parent.right
anchors.rightMargin: 10

iconText: FontAwesome.plus

onClicked: {
AudioTool.editor.addYtUrl(youtube_text_field.text);
}
}
}
}
2 changes: 1 addition & 1 deletion misc/scripts/generate-coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ if [ -z "$dir" ]; then echo "Please specify a directory!" && exit 1; fi
fastcov --include src/ --lcov -o $dir/$filename
lcov --remove $dir/$filename -o $dir/$filename_filtered '/usr/*' '*/**/tests/*' '*/**/*plugin_*.*' '*/**/*_qmltyperegistrations.cpp' '*/**/thirdparty/*' '*/**/*_autogen/*' --ignore-errors unused,unused

genhtml --ignore-errors unmapped -o $dir/coverage_html $dir/$filename_filtered
genhtml --synthesize-missing --ignore-errors source,unmapped -o $dir/coverage_html $dir/$filename_filtered
5 changes: 4 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ set(SRC_AUDIO
tools/audio/thumbnails/loaders/tagimageloader.h
tools/audio/thumbnails/loaders/tagimageloader.cpp
tools/audio/thumbnails/loaders/webimageloader.h
tools/audio/thumbnails/loaders/webimageloader.cpp)
tools/audio/thumbnails/loaders/webimageloader.cpp
tools/audio/thumbnails/loaders/youtubeimageloader.h
tools/audio/thumbnails/loaders/youtubeimageloader.cpp
)

set_source_files_properties(${SRC_AUDIO} PROPERTIES UNITY_GROUP "audio")

Expand Down
1 change: 1 addition & 0 deletions src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ target_link_libraries(common
Qt6::Qml
Qt6::Quick
Qt6::Network
Qt6::Multimedia
PRIVATE
${MARKDOWN_LIBRARY}
${QTKEYCHAIN_LIBRARY})
22 changes: 21 additions & 1 deletion src/common/utils/fileutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,32 @@ auto FileUtils::getMimeType(const QString &filename) -> FileUtils::MimeType
{
if (const auto extension = FileUtils::suffix(filename); extensionToMimeType.contains(extension))
{
return extensionToMimeType[extension];
return extensionToMimeType.value(extension);
}

return MimeType::Unknown;
}

auto FileUtils::mimeTypeStringToFileFormat(const QString &string) -> QMediaFormat::FileFormat
{
if (mimeTypeToFileQtFormat.contains(string))
{
return mimeTypeToFileQtFormat.value(string);
}

return QMediaFormat::FileFormat::UnspecifiedFormat;
}

auto FileUtils::audioCodecNameToEnum(const QString &string) -> QMediaFormat::AudioCodec
{
if (audioCodecToQtCodec.contains(string))
{
return audioCodecToQtCodec.value(string);
}

return QMediaFormat::AudioCodec::Unspecified;
}

auto FileUtils::splitFileNameAndSuffix(const QString &fileName) -> std::pair<QString, QString>
{
auto suffix = FileUtils::suffix(fileName);
Expand Down
30 changes: 29 additions & 1 deletion src/common/utils/fileutils.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <QHash>
#include <QMediaFormat>
#include <QString>
#include <QStringList>

Expand Down Expand Up @@ -40,7 +41,9 @@ class FileUtils
XM
};

static auto getMimeType(const QString &filename) -> MimeType;
[[nodiscard]] static auto getMimeType(const QString &filename) -> MimeType;
[[nodiscard]] static auto mimeTypeStringToFileFormat(const QString &string) -> QMediaFormat::FileFormat;
[[nodiscard]] static auto audioCodecNameToEnum(const QString &string) -> QMediaFormat::AudioCodec;

private:
static auto splitFileNameAndSuffix(const QString &fileName) -> std::pair<QString, QString>;
Expand All @@ -62,6 +65,31 @@ class FileUtils
{QStringLiteral("nst"), MimeType::MOD}, {QStringLiteral("wow"), MimeType::MOD},
{QStringLiteral("s3m"), MimeType::S3M}, {QStringLiteral("it"), MimeType::IT},
{QStringLiteral("xm"), MimeType::XM},
};

inline static const auto mimeTypeToFileQtFormat = QHash<QString, QMediaFormat::FileFormat>{
{QStringLiteral("audio/aac"), QMediaFormat::FileFormat::AAC},
{QStringLiteral("audio/mpeg"), QMediaFormat::FileFormat::MP3},
{QStringLiteral("audio/ogg"), QMediaFormat::FileFormat::Ogg},
{QStringLiteral("audio/wav"), QMediaFormat::FileFormat::Wave},
{QStringLiteral("audio/webm"), QMediaFormat::FileFormat::WebM},
{QStringLiteral("audio/mp4"), QMediaFormat::FileFormat::Mpeg4Audio},
};

inline static const auto audioCodecToQtCodec = QHash<QString, QMediaFormat::AudioCodec>{
{QStringLiteral("opus"), QMediaFormat::AudioCodec::Opus},
{QStringLiteral("mp4a.40.1"), QMediaFormat::AudioCodec::AAC},
{QStringLiteral("mp4a.40.2"), QMediaFormat::AudioCodec::AAC},
{QStringLiteral("mp4a.40.17"), QMediaFormat::AudioCodec::AAC},
{QStringLiteral("vorbis"), QMediaFormat::AudioCodec::Vorbis},
{QStringLiteral("wma"), QMediaFormat::AudioCodec::WMA},
{QStringLiteral("ac3"), QMediaFormat::AudioCodec::AC3},
{QStringLiteral("aac"), QMediaFormat::AudioCodec::AAC},
{QStringLiteral("alac"), QMediaFormat::AudioCodec::ALAC},
{QStringLiteral("eac3"), QMediaFormat::AudioCodec::EAC3},
{QStringLiteral("mp3"), QMediaFormat::AudioCodec::MP3},
{QStringLiteral("wav"), QMediaFormat::AudioCodec::Wave},
{QStringLiteral("wave"), QMediaFormat::AudioCodec::Wave},
{QStringLiteral("flac"), QMediaFormat::AudioCodec::FLAC},
};
};
15 changes: 14 additions & 1 deletion src/services/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ set(SRC_GOOGLEDRIVE
google/googledrivereply.h
)

set(SRC_YOUTUBE
youtube/youtube.h
youtube/youtube.cpp
youtube/pipedconnector.h
youtube/pipedconnector.cpp
youtube/videoid.h
youtube/videoid.cpp
youtube/playlistid.h
youtube/playlistid.cpp
)

qt_add_library(services STATIC)

qt_add_qml_module(services
Expand All @@ -87,6 +98,7 @@ qt_add_qml_module(services
${SRC_REST}
${SRC_SPOTIFY}
${SRC_NEXTCLOUD}
${SRC_YOUTUBE}
# GoogleDrive support is disabled, see comment in googledrive.h
# ${SRC_GOOGLEDRIVE}
)
Expand All @@ -105,7 +117,8 @@ target_include_directories(services
${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/spotify
${CMAKE_CURRENT_SOURCE_DIR}/nextcloud)
${CMAKE_CURRENT_SOURCE_DIR}/nextcloud
${CMAKE_CURRENT_SOURCE_DIR}/youtube)
# ${CMAKE_CURRENT_SOURCE_DIR}/google

target_link_libraries(services
Expand Down
14 changes: 12 additions & 2 deletions src/services/rest/restserviceconnector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@ using namespace Services;

constexpr auto RATELIMIT_TIMEOUT = std::chrono::seconds(2);

RESTServiceConnector::RESTServiceConnector(QNetworkAccessManager &networkManager,
RESTServiceConnector::RESTServiceConnector(QNetworkAccessManager *networkManager,
const QLoggingCategory &loggingCategory, QStringList &&recoverableErrors,
QObject *parent)
: QObject(parent), m_networkManager(networkManager), m_loggingCategory(loggingCategory),
: QObject(parent), m_loggingCategory(loggingCategory), m_networkManager(networkManager),
m_recoverableErrors(std::move(recoverableErrors))
{
}

auto RESTServiceConnector::networkManager() const -> QNetworkAccessManager *
{
return m_networkManager;
}

void RESTServiceConnector::setNetworkManager(QNetworkAccessManager *networkManager)
{
m_networkManager = networkManager;
}

auto RESTServiceConnector::isOnCooldown() const -> bool
{
return m_isOnCooldown;
Expand Down
7 changes: 5 additions & 2 deletions src/services/rest/restserviceconnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class RESTServiceConnector : public QObject
{
Q_OBJECT
public:
RESTServiceConnector(QNetworkAccessManager &networkManager, const QLoggingCategory &loggingCategory,
RESTServiceConnector(QNetworkAccessManager *networkManager, const QLoggingCategory &loggingCategory,
QStringList &&recoverableErrors, QObject *parent = nullptr);

virtual void grantAccess() = 0;
Expand All @@ -35,6 +35,9 @@ class RESTServiceConnector : public QObject
virtual auto customRequest(const QNetworkRequest &req, const QByteArray &verb, const QByteArray &data)
-> QFuture<RestReply> = 0;

[[nodiscard]] auto networkManager() const -> QNetworkAccessManager *;
void setNetworkManager(QNetworkAccessManager *networkManager);

signals:
void accessGranted();
void statusChanged(const Status::Type &type, const QString &message);
Expand Down Expand Up @@ -68,7 +71,6 @@ protected slots:
void updateTokenExpireTime(std::chrono::seconds expiresIn);
[[nodiscard]] auto isTokenExpired() const -> bool;

QNetworkAccessManager &m_networkManager;
const QLoggingCategory &m_loggingCategory;
bool m_wasConfigured = false;

Expand All @@ -79,6 +81,7 @@ protected slots:
void handleRateLimit(std::pair<QPromise<RestReply>, RestRequest> &&pair,
const QList<QNetworkReply::RawHeaderPair> &headers);

QNetworkAccessManager *m_networkManager = nullptr;
bool m_isOnCooldown = false;
size_t m_maxConcurrentRequests = 1;
int m_nextQueueId = 1;
Expand Down
4 changes: 2 additions & 2 deletions src/services/rest/restserviceconnectorlocal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ using namespace Qt::Literals::StringLiterals;
using namespace Services;
using namespace Common::Settings;

RESTServiceConnectorLocal::RESTServiceConnectorLocal(QNetworkAccessManager &networkManager, O2 *o2,
RESTServiceConnectorLocal::RESTServiceConnectorLocal(QNetworkAccessManager *networkManager, O2 *o2,
const QLoggingCategory &loggingCategory, QObject *parent = nullptr)
: RESTServiceConnector(networkManager, loggingCategory, {}, parent), m_o2(o2)
{
Expand Down Expand Up @@ -207,7 +207,7 @@ auto RESTServiceConnectorLocal::customRequest(const QNetworkRequest &request, co

auto RESTServiceConnectorLocal::makeRequestor() -> O2Requestor *
{
auto *requestor = new O2Requestor(&m_networkManager, m_o2, this);
auto *requestor = new O2Requestor(networkManager(), m_o2, this);

connect(requestor,
QOverload<int, QNetworkReply::NetworkError, QString, QByteArray, QList<QNetworkReply::RawHeaderPair>>::of(
Expand Down
2 changes: 1 addition & 1 deletion src/services/rest/restserviceconnectorlocal.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class RESTServiceConnectorLocal : public RESTServiceConnector
{
Q_OBJECT
public:
RESTServiceConnectorLocal(QNetworkAccessManager &networkManager, O2 *o2, const QLoggingCategory &loggingCategory,
RESTServiceConnectorLocal(QNetworkAccessManager *networkManager, O2 *o2, const QLoggingCategory &loggingCategory,
QObject *parent);

void grantAccess() override;
Expand Down
Loading

0 comments on commit 9c1fa8f

Please sign in to comment.