Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/framework/cloud/cloudtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#ifndef MUSE_CLOUD_CLOUDTYPES_H
#define MUSE_CLOUD_CLOUDTYPES_H

#include <optional>
#include <vector>

#include <QDate>
Expand All @@ -30,6 +31,8 @@

#include "types/id.h"

#include "musescorecom/converttypes.h"

namespace muse::cloud {
static const QString MUSESCORE_COM_CLOUD_CODE = "musescorecom";
static const QString AUDIO_COM_CLOUD_CODE = "audiocom";
Expand Down Expand Up @@ -126,6 +129,19 @@ struct ScoreInfo {
}
};

struct ScoreConversionInfo {
int id = 0;
ConvertType type = ConvertType::Omr;
ConvertStatus status = ConvertStatus::Unknown;

bool operator==(const ScoreConversionInfo& other) const
{
return id == other.id
&& type == other.type
&& status == other.status;
}
};

struct ScoresList {
struct Item {
int id = 0;
Expand All @@ -135,6 +151,7 @@ struct ScoresList {
QString thumbnailUrl;
Visibility visibility = Visibility::Private;
int viewCount = 0;
std::optional<ScoreConversionInfo> conversion; //! set if the score originated from a conversion
};

std::vector<Item> items;
Expand Down
13 changes: 10 additions & 3 deletions src/framework/cloud/internal/abstractcloudservice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,14 +358,21 @@ Promise<Ret> AbstractCloudService::checkCloudIsAvailableAsync() const
}

Progress progressVal = progress.val;
std::shared_ptr<bool> finished = std::make_shared<bool>(false);

QTimer* timer = new QTimer();
timer->setSingleShot(true);
QObject::connect(timer, &QTimer::timeout, [progressVal]() mutable {
progressVal.cancel();
QObject::connect(timer, &QTimer::timeout, [progressVal, finished]() mutable {
if (!*finished) {
progressVal.cancel();
}
});

progressVal.finished().onReceive(this, [resolve, timer](const ProgressResult& res) {
progressVal.finished().onReceive(this, [resolve, timer, finished](const ProgressResult& res) {
if (*finished) {
return;
}
*finished = true;
timer->stop();
timer->deleteLater();
(void)resolve(res.ret);
Expand Down
80 changes: 28 additions & 52 deletions src/framework/cloud/musescorecom/converttypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,27 @@

#pragma once

#include <memory>
#include <optional>
#include <string>
#include <variant>
#include <vector>

#include <QDateTime>
#include <QString>
#include <QStringList>
#include <QUrl>

#include "global/logstream.h"
#include "global/types/bytearray.h"
#include "global/types/flags.h"
#include "io/path.h"
#include "global/io/path.h"
#include "global/logstream.h"

namespace muse::cloud {
enum class ConvertType {
Omr,
Audio2Score
Omr = 0,
Audio2Score,

Last = Audio2Score
};

enum class ConvertStatus {
Expand Down Expand Up @@ -87,13 +91,12 @@ enum class ConvertErrorCode {
TooComplex,
DontRecognizeNotes,
GeneralFailure,
BadParams,
};

//! NOTE: key for ConvertErrorCode stored in Ret::data
static const std::string CONVERT_ERROR_CODE_KEY("errorCode");

static const qint64 MAX_CONVERT_FILE_SIZE_BYTES = 1024LL * 1024 * 1024; // 1 GB

enum class LinkSource {
NoSources = 0x0,
YouTube = 0x1,
Expand Down Expand Up @@ -141,67 +144,40 @@ struct ConvertConfig {
Audio2ScoreConfig audio2score;
};

struct OmrConvertInput {
muse::io::paths_t paths;
struct ConvertFileData {
muse::ByteArray data;
muse::io::path_t fileName; // basename, with extension
};
using ConvertFileDataList = std::vector<ConvertFileData>;

struct Audio2ScoreConvertInput {
std::variant<muse::io::paths_t, QString> data; // paths or link
struct ConvertUploadData {
ConvertType type = ConvertType::Omr;
ConvertFileDataList files;
QUrl link; // Audio2Score only
QString filename; // desired name for the converted score, no extension
};

using ConvertInput = std::variant<OmrConvertInput, Audio2ScoreConvertInput>;

inline ConvertType convertTypeOf(const ConvertInput& input)
{
return std::holds_alternative<OmrConvertInput>(input) ? ConvertType::Omr : ConvertType::Audio2Score;
}

inline muse::io::paths_t convertPathsOf(const ConvertInput& input)
{
if (const OmrConvertInput* omr = std::get_if<OmrConvertInput>(&input)) {
return omr->paths;
}

const muse::io::paths_t* paths = std::get_if<muse::io::paths_t>(&std::get<Audio2ScoreConvertInput>(input).data);
return paths ? *paths : muse::io::paths_t();
}

inline QString convertLinkOf(const ConvertInput& input)
{
const Audio2ScoreConvertInput* a2s = std::get_if<Audio2ScoreConvertInput>(&input);
if (!a2s) {
return QString();
}

const QString* link = std::get_if<QString>(&a2s->data);
return link ? *link : QString();
}
using ConvertUploadDataPtr = std::shared_ptr<const ConvertUploadData>;

struct ConvertResult {
int id = 0;
ConvertType type = ConvertType::Omr;
ConvertStatus status = ConvertStatus::Processing;
ConvertStatus status = ConvertStatus::Unknown;
};

struct ConvertQueueItem {
int id = 0;
ConvertType type = ConvertType::Omr;
ConvertStatus status = ConvertStatus::Processing;
ConvertStatus status = ConvertStatus::Unknown;
QString filename;
QString link; //! audio2score only
int scoreId = 0;
QDateTime createdAt;
QDateTime updatedAt;
std::optional<int> scoreId; //! set once the score is ready (AwaitingReview/Done)
QDateTime dataCreated;
QDateTime dataUpdated;
ConvertErrorCode errorCode = ConvertErrorCode::Unknown;
};

using ConvertQueueList = std::vector<ConvertQueueItem>;

struct SignedMsczUrl {
QUrl url;
int expiresInSeconds = 0;
};

//! NOTE: must be in sync with the musescore.com API
enum class ReviewRating {
Bad = 0,
Expand All @@ -220,8 +196,8 @@ inline muse::logger::Stream& operator<<(muse::logger::Stream& s, const muse::clo
<< ", link: \"" << item.link << "\""
<< ", type: " << muse::cloud::convertTypeToString(item.type)
<< ", status: " << muse::cloud::convertStatusToString(item.status)
<< ", scoreId: " << item.scoreId
<< ", createdAt: " << dateTimeToString(item.createdAt)
<< ", updatedAt: " << dateTimeToString(item.updatedAt);
<< ", scoreId: " << (item.scoreId ? QString::number(*item.scoreId) : QString("none"))
<< ", dataCreated: " << dateTimeToString(item.dataCreated)
<< ", dataUpdated: " << dateTimeToString(item.dataUpdated);
return s;
}
22 changes: 9 additions & 13 deletions src/framework/cloud/musescorecom/imusescorecomconvertservice.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,20 @@

#include "converttypes.h"

class QIODevice;
using DevicePtr = std::shared_ptr<QIODevice>;

namespace muse::cloud {
/// fetchConfig() can be called at any time (no authenticated user required) to get the
/// upload limits (max file size, page/image counts, allowed types) for client-side validation
/// before upload() is called.
///
/// Expected call order for a conversion (OMR or Audio2Score):
/// 1. upload() to submit the file(s) and start processing
/// 2. Poll fetchQueue() and watch the item's status
/// 3. As soon as the status is AwaitingReview or Done, the MSCZ is already
/// available: call fetchMsczUrl() then downloadConvertedScore() to get the score
/// 4. Rating the recognition quality (submitReview(), once AwaitingReview) is optional
/// and does not gate the download above; submitReviewComment() may attach a
/// comment afterwards, once the review has been submitted
/// 5. Keep polling fetchQueue() until the status is Failed, or the item disappears
/// 2. Poll fetchQueue() and watch the item's status; once it's AwaitingReview or Done, its
/// scoreId identifies the resulting score, already available via IMuseScoreComService
/// 3. Rating the recognition quality (submitReview(), once AwaitingReview) is optional;
/// submitReviewComment() may attach a comment afterwards, once the review has been submitted
/// 4. Keep polling fetchQueue() until the status is Failed, or the item disappears
/// from the queue (which should be treated the same as Done)
/// 5. deleteConversion() may be called at any point to remove an item from the queue
class IMuseScoreComConvertService : MODULE_CONTEXT_INTERFACE
{
INTERFACE_ID(IMuseScoreComConvertService)
Expand All @@ -56,15 +52,15 @@ class IMuseScoreComConvertService : MODULE_CONTEXT_INTERFACE

virtual async::Promise<RetVal<ConvertConfig> > fetchConfig() = 0;

virtual ProgressPtr upload(const ConvertInput& input) = 0;
virtual ProgressPtr downloadConvertedScore(const SignedMsczUrl& urlInfo, DevicePtr scoreData) = 0;
virtual ProgressPtr upload(const ConvertUploadDataPtr& data) = 0;

virtual async::Promise<RetVal<ConvertQueueList> > fetchQueue() = 0;
virtual async::Promise<RetVal<SignedMsczUrl> > fetchMsczUrl(ConvertType type, int id) = 0;

virtual async::Promise<RetVal<ConvertResult> > submitReview(ConvertType type, int id, ReviewRating review,
const QString& comment = QString()) = 0;
virtual async::Promise<RetVal<ConvertResult> > submitReviewComment(ConvertType type, int id, const QString& comment) = 0;

virtual async::Promise<Ret> deleteConversion(ConvertType type, int id) = 0;
};
using IMuseScoreComConvertServicePtr = std::shared_ptr<IMuseScoreComConvertService>;
}
Loading
Loading