mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-14 04:18:36 +00:00
Added a bunch of boring parsing and indexing logic.
This commit is contained in:
parent
3a1f5d073c
commit
e4c2a5b085
@ -303,25 +303,12 @@ static int64_t writeToTracksTable(
|
||||
see if we can find the corresponding ID. this can happen when
|
||||
IInputSource plugins are reading/writing track data. */
|
||||
if (id == 0) {
|
||||
if (sourceId == 0) {
|
||||
db::Statement stmt("SELECT id FROM tracks WHERE source_id=? AND external_id=?", dbConnection);
|
||||
stmt.BindInt32(0, sourceId);
|
||||
stmt.BindText(1, externalId);
|
||||
if (stmt.Step() == db::Row) {
|
||||
track.SetId(stmt.ColumnInt64(0));
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string fn = track.GetString("filename");
|
||||
if (fn.size()) {
|
||||
db::Statement stmt("SELECT id, external_id FROM tracks WHERE filename=?", dbConnection);
|
||||
stmt.BindText(0, track.GetString("filename"));
|
||||
if (stmt.Step() == db::Row) {
|
||||
id = stmt.ColumnInt64(0);
|
||||
track.SetId(id);
|
||||
track.SetValue("external_id", stmt.ColumnText(1));
|
||||
}
|
||||
}
|
||||
db::Statement stmt("SELECT id FROM tracks WHERE source_id=? AND external_id=?", dbConnection);
|
||||
stmt.BindInt32(0, sourceId);
|
||||
stmt.BindText(1, externalId);
|
||||
if (stmt.Step() == db::Row) {
|
||||
id = stmt.ColumnInt64(0);
|
||||
track.SetId(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
set (gmedecoder_SOURCES
|
||||
plugin.cpp
|
||||
GmeDataStream.cpp
|
||||
GmeDecoder.cpp
|
||||
GmeIndexerSource.cpp
|
||||
gme/c140.c
|
||||
|
@ -48,6 +48,37 @@
|
||||
static const std::string PLUGIN_NAME = "GME IDecoder";
|
||||
|
||||
static const std::set<std::string> FORMATS = {
|
||||
"vgm", "gym", "spc", "sap", "nsfe",
|
||||
"nsf", "ay", "gbs", "hes", "kss"
|
||||
};
|
||||
".vgm", ".gym", ".spc", ".sap", ".nsfe",
|
||||
".nsf", ".ay", ".gbs", ".hes", ".kss"
|
||||
};
|
||||
|
||||
static inline bool canHandle(const std::string& fn) {
|
||||
for (auto& ext : FORMATS) {
|
||||
if (fn.rfind(ext) == fn.size() - ext.size()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool parseExternalId(const std::string& externalId, std::string& fn, int& track) {
|
||||
if (externalId.find("gme://") == 0) {
|
||||
std::string trimmed = externalId.substr(6);
|
||||
auto slash = trimmed.find("/");
|
||||
if (slash != std::string::npos) {
|
||||
try {
|
||||
track = std::stoi(trimmed.substr(0, slash));
|
||||
fn = trimmed.substr(slash + 1);
|
||||
return true;
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline std::string createExternalId(const std::string& fn, int track) {
|
||||
return "gme://" + std::to_string(track) + "/" + fn;
|
||||
}
|
104
src/plugins/gmedecoder/GmeDataStream.cpp
Normal file
104
src/plugins/gmedecoder/GmeDataStream.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2004-2019 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Constants.h"
|
||||
#include "GmeDataStream.h"
|
||||
#include <core/sdk/IEnvironment.h>
|
||||
|
||||
using namespace musik::core::sdk;
|
||||
|
||||
extern IEnvironment* environment;
|
||||
|
||||
bool GmeDataStream::Open(const char *uri, unsigned int options) {
|
||||
std::string fn;
|
||||
if (parseExternalId(uri, fn, this->trackNumber)) {
|
||||
this->stream = environment->GetDataStream(fn.c_str());
|
||||
if (this->stream) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GmeDataStream::Close() {
|
||||
return this->stream->Close();
|
||||
}
|
||||
|
||||
void GmeDataStream::Interrupt() {
|
||||
this->stream->Interrupt();
|
||||
}
|
||||
|
||||
void GmeDataStream::Release() {
|
||||
if (stream) {
|
||||
stream->Release();
|
||||
stream = nullptr;
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
|
||||
PositionType GmeDataStream::Read(void *buffer, PositionType readBytes) {
|
||||
return this->stream->Read(buffer, readBytes);
|
||||
}
|
||||
|
||||
bool GmeDataStream::SetPosition(PositionType position) {
|
||||
return this->stream->SetPosition(position);
|
||||
}
|
||||
|
||||
PositionType GmeDataStream::Position() {
|
||||
return this->stream->Position();
|
||||
}
|
||||
|
||||
bool GmeDataStream::Seekable() {
|
||||
return this->stream->Seekable();
|
||||
}
|
||||
|
||||
bool GmeDataStream::Eof() {
|
||||
return this->stream->Eof();
|
||||
}
|
||||
|
||||
long GmeDataStream::Length() {
|
||||
return this->stream->Length();
|
||||
}
|
||||
|
||||
const char* GmeDataStream::Type() {
|
||||
return this->stream->Type();
|
||||
}
|
||||
|
||||
const char* GmeDataStream::Uri() {
|
||||
return this->stream->Uri();
|
||||
}
|
||||
|
||||
bool GmeDataStream::CanPrefetch() {
|
||||
return this->stream->CanPrefetch();
|
||||
}
|
63
src/plugins/gmedecoder/GmeDataStream.h
Normal file
63
src/plugins/gmedecoder/GmeDataStream.h
Normal file
@ -0,0 +1,63 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2004-2019 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <core/sdk/IDataStream.h>
|
||||
#include <string>
|
||||
|
||||
class GmeDataStream: public musik::core::sdk::IDataStream {
|
||||
public:
|
||||
using PositionType = musik::core::sdk::PositionType;
|
||||
|
||||
virtual bool Open(const char *uri, unsigned int options = 0) override;
|
||||
virtual bool Close() override;
|
||||
virtual void Interrupt() override;
|
||||
virtual void Release() override;
|
||||
virtual PositionType Read(void *buffer, PositionType readBytes) override;
|
||||
virtual bool SetPosition(PositionType position) override;
|
||||
virtual PositionType Position() override;
|
||||
virtual bool Seekable() override;
|
||||
virtual bool Eof() override;
|
||||
virtual long Length() override;
|
||||
virtual const char* Type() override;
|
||||
virtual const char* Uri() override;
|
||||
virtual bool CanPrefetch() override;
|
||||
|
||||
int GetTrackNumber() { return this->trackNumber; }
|
||||
|
||||
private:
|
||||
int trackNumber { 0 };
|
||||
musik::core::sdk::IDataStream* stream { nullptr };
|
||||
};
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include "Constants.h"
|
||||
#include "GmeDecoder.h"
|
||||
#include <cassert>
|
||||
|
||||
GmeDecoder::GmeDecoder() {
|
||||
}
|
||||
@ -41,8 +42,10 @@ GmeDecoder::GmeDecoder() {
|
||||
GmeDecoder::~GmeDecoder() {
|
||||
}
|
||||
|
||||
bool GmeDecoder::Open(musik::core::sdk::IDataStream *stream){
|
||||
return false;
|
||||
bool GmeDecoder::Open(musik::core::sdk::IDataStream *stream) {
|
||||
this->stream = dynamic_cast<GmeDataStream*>(stream);
|
||||
assert(this->stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GmeDecoder::Release() {
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <core/sdk/constants.h>
|
||||
#include <core/sdk/IDecoder.h>
|
||||
#include <core/sdk/IDataStream.h>
|
||||
#include "GmeDataStream.h"
|
||||
#include <stddef.h>
|
||||
|
||||
using namespace musik::core::sdk;
|
||||
@ -52,4 +53,9 @@ class GmeDecoder: public musik::core::sdk::IDecoder {
|
||||
virtual double GetDuration() override;
|
||||
virtual bool Open(musik::core::sdk::IDataStream *stream) override;
|
||||
virtual bool Exhausted() override;
|
||||
|
||||
private:
|
||||
GmeDataStream* stream { nullptr };
|
||||
|
||||
|
||||
};
|
||||
|
@ -39,44 +39,89 @@
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <gme.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace musik::core::sdk;
|
||||
|
||||
static std::vector<std::string> tokenize(const std::string& str, char delim = '/') {
|
||||
std::vector<std::string> result;
|
||||
std::istringstream iss(str);
|
||||
std::string token;
|
||||
|
||||
while (std::getline(iss, token, delim)) {
|
||||
result.push_back(token);
|
||||
static std::string getM3uFor(const std::string& fn) {
|
||||
size_t lastDot = fn.find_last_of(".");
|
||||
if (lastDot != std::string::npos) {
|
||||
std::string m3u = fn.substr(0, lastDot) + ".m3u";
|
||||
if (access(m3u.c_str(), R_OK) != -1) {
|
||||
return m3u;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string createExternalId(const std::string& fn, int track) {
|
||||
return "gme/" + std::to_string(track) + "/" + fn;
|
||||
return "";
|
||||
}
|
||||
|
||||
static bool exists(const std::string& externalId) {
|
||||
return false;
|
||||
std::string fn;
|
||||
int trackNum;
|
||||
if (!parseExternalId(externalId, fn, trackNum)) {
|
||||
return false;
|
||||
}
|
||||
return access(fn.c_str(), R_OK) != -1;
|
||||
}
|
||||
|
||||
static void updateMetadata(const std::string& fn, IIndexerWriter* indexer) {
|
||||
// gme_t* data = nullptr;
|
||||
// gme_err_t err = gme_open_file("/tmp/mario.nsf", &data, 44100);
|
||||
// if (err) {
|
||||
// std::cerr << "error: " << err << "\n";
|
||||
// }
|
||||
// else {
|
||||
// gme_info_t* info = nullptr;
|
||||
// err = gme_track_info(data, &info, 0);
|
||||
// if (err) {
|
||||
// std::cerr << "error: " << err << "\n";
|
||||
// }
|
||||
// gme_free_info(info);
|
||||
// }
|
||||
// gme_delete(data);
|
||||
static void updateMetadata(IIndexerSource* source, const std::string& fn, IIndexerWriter* indexer) {
|
||||
gme_t* data = nullptr;
|
||||
gme_err_t err = gme_open_file(fn.c_str(), &data, 44100);
|
||||
if (err) {
|
||||
std::cerr << "error opening file: " << err << "\n";
|
||||
}
|
||||
else {
|
||||
std::string m3u = getM3uFor(fn);
|
||||
if (m3u.size()) {
|
||||
err = gme_load_m3u(data, m3u.c_str());
|
||||
if (err) {
|
||||
std::cerr << "m3u found, but load failed: " << err << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < gme_track_count(data); i++) {
|
||||
gme_info_t* info = nullptr;
|
||||
err = gme_track_info(data, &info, i);
|
||||
if (err) {
|
||||
std::cerr << "error getting track: " << err << "\n";
|
||||
}
|
||||
else if (info) {
|
||||
auto track = indexer->CreateWriter();
|
||||
|
||||
const std::string trackNum = std::to_string(i + 1).c_str();
|
||||
const std::string defaultTitle = "Track " + std::to_string(1 + i);
|
||||
const std::string duration = std::to_string((float) info->play_length / 1000.0f);
|
||||
const std::string externalId = createExternalId(fn, i);
|
||||
|
||||
track->SetValue("album", info->game);
|
||||
track->SetValue("album_artist", info->system);
|
||||
track->SetValue("genre", info->system);
|
||||
track->SetValue("track", trackNum.c_str());
|
||||
track->SetValue("duration", duration.c_str());
|
||||
track->SetValue("filename", externalId.c_str());
|
||||
|
||||
if (strlen(info->author)) {
|
||||
track->SetValue("artist", info->author);
|
||||
}
|
||||
else {
|
||||
track->SetValue("artist", info->system);
|
||||
}
|
||||
|
||||
if (strlen(info->song)) {
|
||||
track->SetValue("title", info->song);
|
||||
}
|
||||
else {
|
||||
track->SetValue("title", defaultTitle.c_str());
|
||||
}
|
||||
|
||||
indexer->Save(source, track, externalId.c_str());
|
||||
|
||||
track->Release();
|
||||
}
|
||||
gme_free_info(info);
|
||||
}
|
||||
}
|
||||
gme_delete(data);
|
||||
}
|
||||
|
||||
static void scanDirectory(const std::string& path, IIndexerWriter* indexer) {
|
||||
@ -107,6 +152,9 @@ ScanResult GmeIndexerSource::Scan(
|
||||
for (size_t i = 0; i < indexerPathsCount; i++) {
|
||||
scanDirectory(std::string(indexerPaths[i]), indexer);
|
||||
}
|
||||
|
||||
updateMetadata(this, "/tmp/mario.nsf", indexer);
|
||||
|
||||
return ScanCommit;
|
||||
}
|
||||
|
||||
@ -119,9 +167,9 @@ void GmeIndexerSource::ScanTrack(
|
||||
ITagStore* tagStore,
|
||||
const char* externalId)
|
||||
{
|
||||
// if (!exists(this->discIds, this->model, externalId)) {
|
||||
// indexer->RemoveByExternalId(this, externalId);
|
||||
// }
|
||||
if (!exists(externalId)) {
|
||||
indexer->RemoveByExternalId(this, externalId);
|
||||
}
|
||||
}
|
||||
|
||||
int GmeIndexerSource::SourceId() {
|
||||
|
@ -30,7 +30,10 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <core/sdk/IIndexerSource.h>
|
||||
#include <functional>
|
||||
|
@ -36,25 +36,23 @@
|
||||
#include <core/sdk/constants.h>
|
||||
#include <core/sdk/IPlugin.h>
|
||||
#include <core/sdk/IDecoderFactory.h>
|
||||
#include <core/sdk/IDataStreamFactory.h>
|
||||
#include <core/sdk/IEnvironment.h>
|
||||
#include "GmeDecoder.h"
|
||||
#include "GmeIndexerSource.h"
|
||||
#include "GmeDataStream.h"
|
||||
|
||||
#ifdef WIN32
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
return true;
|
||||
}
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool supported(const std::string& s) {
|
||||
for (auto& ext : FORMATS) {
|
||||
if (s.rfind(ext) == s.size() - ext.size()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
using namespace musik::core::sdk;
|
||||
|
||||
class GmePlugin : public musik::core::sdk::IPlugin {
|
||||
IEnvironment* environment = nullptr;
|
||||
|
||||
class GmePlugin: public IPlugin {
|
||||
public:
|
||||
virtual void Release() { delete this; };
|
||||
virtual const char* Name() { return PLUGIN_NAME.c_str(); }
|
||||
@ -67,15 +65,9 @@ class GmePlugin : public musik::core::sdk::IPlugin {
|
||||
virtual int SdkVersion() { return musik::core::sdk::SdkVersion; }
|
||||
};
|
||||
|
||||
class GmeDecoderFactory : public musik::core::sdk::IDecoderFactory {
|
||||
class GmeDecoderFactory: public IDecoderFactory {
|
||||
public:
|
||||
GmeDecoderFactory() {
|
||||
}
|
||||
|
||||
~GmeDecoderFactory() {
|
||||
}
|
||||
|
||||
virtual musik::core::sdk::IDecoder* CreateDecoder() override {
|
||||
virtual IDecoder* CreateDecoder() override {
|
||||
return new GmeDecoder();
|
||||
}
|
||||
|
||||
@ -84,18 +76,47 @@ class GmeDecoderFactory : public musik::core::sdk::IDecoderFactory {
|
||||
}
|
||||
|
||||
virtual bool CanHandle(const char* type) const override {
|
||||
return supported(std::string(type));
|
||||
return canHandle(std::string(type));
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" DLLEXPORT musik::core::sdk::IPlugin* GetPlugin() {
|
||||
class GmeDataStreamFactory: public IDataStreamFactory{
|
||||
public:
|
||||
virtual bool CanRead(const char *uri) override {
|
||||
std::string str = uri;
|
||||
return str.find("gme://") == 0 && canHandle(str);
|
||||
}
|
||||
|
||||
virtual IDataStream* Open(const char *uri, unsigned int options = 0) {
|
||||
auto result = new GmeDataStream();
|
||||
if (result->Open(uri, options)) {
|
||||
return result;
|
||||
}
|
||||
result->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void Release() {
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" DLLEXPORT IPlugin* GetPlugin() {
|
||||
return new GmePlugin();
|
||||
}
|
||||
|
||||
extern "C" DLLEXPORT musik::core::sdk::IDecoderFactory* GetDecoderFactory() {
|
||||
extern "C" DLLEXPORT IDecoderFactory* GetDecoderFactory() {
|
||||
return new GmeDecoderFactory();
|
||||
}
|
||||
|
||||
extern "C" DLLEXPORT IDataStreamFactory* GetDataStreamFactory() {
|
||||
return new GmeDataStreamFactory();
|
||||
}
|
||||
|
||||
extern "C" DLLEXPORT IIndexerSource* GetIndexerSource() {
|
||||
return new GmeIndexerSource();
|
||||
}
|
||||
|
||||
extern "C" DLLEXPORT void SetEnvironment(IEnvironment* environment) {
|
||||
::environment = environment;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user