Skip to content
This repository has been archived by the owner on Oct 9, 2019. It is now read-only.

Commit

Permalink
A wrapper from QFile to TagLib device, few fixes, and v1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
superfashi committed Feb 11, 2018
1 parent 28b7fb9 commit 9903511
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 25 deletions.
3 changes: 2 additions & 1 deletion bp_audio.pro
Expand Up @@ -14,6 +14,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

SOURCES += main.cpp
SOURCES += main.cpp \
file_stream.cpp
LIBS += -ltag -lz -lgumbo_query_static -lgumbo
QMAKE_CXXFLAGS += -DTAGLIB_STATIC
130 changes: 130 additions & 0 deletions file_stream.cpp
@@ -0,0 +1,130 @@
#include <QFile>
#include <taglib/tiostream.h>

class FileStream: public TagLib::IOStream {
QFile *file;
unsigned int bufferSize() const { return 1024; }
public:
FileStream(QFile *f): file(f) {}

bool readOnly() const {
return !file->isWritable();
}

bool isOpen() const {
return file->isOpen();
}

long tell() const {
return file->pos();
}

long length() {
return file->size();
}

void truncate(long length) {
file->resize(length);
}

void seek(long offset,
TagLib::IOStream::Position p = TagLib::IOStream::Beginning) {
switch (p) {
case TagLib::IOStream::Beginning:
file->seek(offset);
break;
case TagLib::IOStream::Current:
file->seek(file->pos() + offset);
break;
case TagLib::IOStream::End:
file->seek(file->size() + offset);
}
}

TagLib::FileName name() const {
return file->fileName().toStdWString().data();
}

TagLib::ByteVector readBlock(unsigned long length) {
TagLib::ByteVector bv(static_cast<unsigned int>(length));
const qint64 &l = file->read(bv.data(), length);
bv.resize(l);
return std::move(bv);
}

void writeBlock(const TagLib::ByteVector &data) {
file->write(data.data(), data.size());
}

void insert(const TagLib::ByteVector &data,
unsigned long start,
unsigned long replace) {
if (data.size() == replace) {
seek(start);
writeBlock(data);
return;
}
if (data.size() < replace) {
seek(start);
writeBlock(data);
removeBlock(start + data.size(), replace - data.size());
return;
}
unsigned long bufferLength = bufferSize();
while (data.size() - replace > bufferLength)
bufferLength += bufferSize();

long readPosition = start + replace;
long writePosition = start;

QByteArray buffer(data.data(), data.size());
QByteArray aboutToOverwrite;
aboutToOverwrite.resize(bufferLength);

while (true) {
seek(readPosition);
const qint64 &bytesRead = file->peek(aboutToOverwrite.data(), bufferLength);
aboutToOverwrite.resize(bytesRead);
readPosition += bufferLength;

if (bytesRead < bufferLength) clear();

seek(writePosition);
file->write(buffer);

if (bytesRead == 0) break;

writePosition += buffer.size();
buffer = aboutToOverwrite;
}
}

void removeBlock(unsigned long start, unsigned long length) {
unsigned long bufferLength = bufferSize();

long readPosition = start + length;
long writePosition = start;

QByteArray buffer;
buffer.resize(bufferLength);

for (qint64 bytesRead = -1; bytesRead != 0;)
{
seek(readPosition);
bytesRead = file->peek(buffer.data(), bufferLength);
readPosition += bytesRead;

if (bytesRead < buffer.size()) {
clear();
buffer.resize(bytesRead);
}

seek(writePosition);
file->write(buffer);

writePosition += bytesRead;
}

truncate(writePosition);
}
};
53 changes: 29 additions & 24 deletions main.cpp
Expand Up @@ -19,20 +19,13 @@
#include <gumbo-query/Document.h>
#include <gumbo-query/Node.h>

#include <Shlobj.h>
#include "file_stream.cpp"

class PictureWrapper {
TagLib::String mime_type;
TagLib::FLAC::Picture::Type t;
TagLib::ByteVector bv;
public:
PictureWrapper(const TagLib::String &mime,
const TagLib::FLAC::Picture::Type &type,
const QByteArray &byte):
mime_type(mime),
t(type),
bv(byte.data(), byte.length()) {}

PictureWrapper(QNetworkReply *resp) {
const QByteArray &bin = resp->readAll();
bv = TagLib::ByteVector(bin.data(), bin.length());
Expand All @@ -51,7 +44,7 @@ class PictureWrapper {

const int bar_width = 50;
const QString app_name = "bp_audio";
const QString app_version = "1.0";
const QString app_version = "1.1";

QCommandLineOption au_opt({"a", "au"}, "Audio AU number.", "au");
QCommandLineOption all_opt("menu", "Download whole menu.");
Expand All @@ -61,11 +54,26 @@ QScopedPointer<QNetworkAccessManager> session;
QDir output;
QHash<QString, QSharedPointer<PictureWrapper> > assets;

#ifdef _WIN32
#include <Shlobj.h>

QString santize_filename(const QString &name) {
std::array<wchar_t, MAX_PATH> buf{};
name.toWCharArray(buf.data());
PathCleanupSpec(output.absolutePath().toStdWString().data(), buf.data());
return std::move(QString::fromWCharArray(buf.data()));
}
#else
QString santize_filename(const QString &name) {
return name; // Yeah'em lazy.
}
#endif

QString find_audio(const QByteArray &data) {
CDocument doc;
doc.parse(data.toStdString());
CSelection audio = doc.find("audio");
return QString::fromStdString(audio.nodeAt(0).attribute("src"));
return std::move(QString::fromStdString(audio.nodeAt(0).attribute("src")));
}

void download_progress(const qint64 &bytes_received, const qint64 &bytes_total) {
Expand All @@ -81,9 +89,9 @@ void download_progress(const qint64 &bytes_received, const qint64 &bytes_total)
if (bytes_received >= bytes_total) std::cerr << '\n';
}

void write_metadata(const QString &file, const QJsonObject &data,
void write_metadata(QFile *file, const QJsonObject &data,
const int &track, const int &total) {
TagLib::FLAC::File f(TagLib::FileName(file.toStdWString().data()));
TagLib::FLAC::File f(new FileStream(file), nullptr);
if (!f.isValid()) {
qCritical("Downloaded song not valid");
std::exit(EXIT_FAILURE);
Expand Down Expand Up @@ -139,10 +147,7 @@ void write_metadata(const QString &file, const QJsonObject &data,

void download_song(const QJsonObject &data, const int &track = -1, const int &total = -1) {
QString file_name = QStringLiteral("%1 - %2.flac").arg(data["author"].toString(), data["title"].toString());
std::array<wchar_t, MAX_PATH> buf{};
file_name.toWCharArray(buf.data());
PathCleanupSpec(output.absolutePath().toStdWString().data(), buf.data());
file_name = QString::fromWCharArray(buf.data());
file_name = santize_filename(file_name);

const QString &au = QString::number(data["id"].toInt());
qInfo("Getting audio preview for %s...", qUtf8Printable(au));
Expand Down Expand Up @@ -178,7 +183,7 @@ void download_song(const QJsonObject &data, const int &track = -1, const int &to
file_name = output.filePath(file_name);
qInfo("Writing to %s...", qUtf8Printable(file_name));
QFile f(file_name);
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
if (f.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
do {
loop.exec();
if (song_res->error() != QNetworkReply::NoError) {
Expand All @@ -188,9 +193,9 @@ void download_song(const QJsonObject &data, const int &track = -1, const int &to
}
f.write(song_res->readAll());
} while (!song_res->isFinished());
f.close();
}
write_metadata(file_name, data, track, total);
write_metadata(&f, data, track, total);
f.close();
qInfo("Finished for %s", qUtf8Printable(file_name));
}

Expand Down Expand Up @@ -222,11 +227,11 @@ void get_menu_info(const QString &menuid) {

const QJsonObject &menus_response = data["menusRespones"].toObject();
QString folder_name = QStringLiteral("%1 - %2").arg(menus_response["mbnames"].toString(), menus_response["title"].toString());
std::array<wchar_t, MAX_PATH> buf{};
folder_name.toWCharArray(buf.data());
PathCleanupSpec(output.absolutePath().toStdWString().data(), buf.data());
folder_name = QString::fromWCharArray(buf.data());
output.mkdir(folder_name);
folder_name = santize_filename(folder_name);
if (!output.exists(folder_name) && !output.mkdir(folder_name)) {
qCritical("Error creating folder -- check permission");
std::exit(EXIT_FAILURE);
}
output.cd(folder_name);

const QJsonArray &songsList = data["songsList"].toArray();
Expand Down

0 comments on commit 9903511

Please sign in to comment.