mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
import enex files from c++
This commit is contained in:
parent
40e9b82137
commit
84e15aa8d4
2
.gitignore
vendored
2
.gitignore
vendored
@ -18,4 +18,4 @@
|
||||
database.sqlite
|
||||
QtClient/build-*-Debug/
|
||||
*.pro.user
|
||||
notes.sqlite
|
||||
notes*.sqlite
|
@ -18,7 +18,8 @@ SOURCES += \
|
||||
services/notecache.cpp \
|
||||
models/qmlnote.cpp
|
||||
|
||||
RESOURCES += qml.qrc
|
||||
RESOURCES += qml.qrc \
|
||||
database.qrc
|
||||
|
||||
# Additional import path used to resolve QML modules in Qt Creator's code model
|
||||
QML_IMPORT_PATH =
|
||||
|
3
QtClient/JoplinQtClient/build.bat
Executable file
3
QtClient/JoplinQtClient/build.bat
Executable file
@ -0,0 +1,3 @@
|
||||
"C:\Qt\5.7\msvc2015\bin\qmake.exe" D:\Web\www\joplin\QtClient\JoplinQtClient\JoplinQtClient.pro -spec win32-msvc2015 "CONFIG+=debug" "CONFIG+=qml_debug"
|
||||
"C:\Qt\Tools\QtCreator\bin\jom.exe" qmake_all
|
||||
"C:\Qt\Tools\QtCreator\bin\jom.exe"
|
@ -5,7 +5,7 @@ using namespace jop;
|
||||
Database::Database(const QString &path) {
|
||||
version_ = -1;
|
||||
|
||||
//QFile::remove(path);
|
||||
QFile::remove(path);
|
||||
|
||||
db_ = QSqlDatabase::addDatabase("QSQLITE");
|
||||
db_.setDatabaseName(path);
|
||||
@ -16,7 +16,7 @@ Database::Database(const QString &path) {
|
||||
qDebug() << "Database: connection ok";
|
||||
}
|
||||
|
||||
//upgrade();
|
||||
upgrade();
|
||||
}
|
||||
|
||||
Database::Database() {}
|
||||
@ -52,6 +52,23 @@ int Database::version() const {
|
||||
return version_;
|
||||
}
|
||||
|
||||
QStringList Database::sqlStringToLines(const QString& sql) {
|
||||
QStringList statements;
|
||||
QStringList lines = sql.split("\n");
|
||||
QString statement;
|
||||
foreach (QString line, lines) {
|
||||
line = line.trimmed();
|
||||
if (line == "") continue;
|
||||
if (line.left(2) == "--") continue;
|
||||
statement += line;
|
||||
if (line[line.length() - 1] == ';') {
|
||||
statements.append(statement);
|
||||
statement = "";
|
||||
}
|
||||
}
|
||||
return statements;
|
||||
}
|
||||
|
||||
void Database::upgrade() {
|
||||
// INSTRUCTIONS TO UPGRADE THE DATABASE:
|
||||
//
|
||||
@ -75,19 +92,18 @@ void Database::upgrade() {
|
||||
|
||||
case 1:
|
||||
|
||||
db_.exec("CREATE TABLE version (version INT)");
|
||||
db_.exec("INSERT INTO version (version) VALUES (1)");
|
||||
QFile f(":/schema.sql");
|
||||
if (!f.open(QFile::ReadOnly | QFile::Text)) {
|
||||
qFatal("Cannot open database schema file");
|
||||
return;
|
||||
}
|
||||
QTextStream in(&f);
|
||||
QString schemaSql = in.readAll();
|
||||
|
||||
db_.exec("CREATE TABLE folders (id TEXT PRIMARY KEY, title TEXT, created_time INT)");
|
||||
|
||||
// for (int i = 1; i < 100; i++) {
|
||||
// QUuid uuid = QUuid::createUuid();
|
||||
// QString title = QString::number(i);
|
||||
// db_.exec(QString("INSERT INTO folders (id, title, created_time) VALUES (\"%1\", \"%2\", 1481235571)").arg(uuid.toString(), title.repeated(10)));
|
||||
// }
|
||||
|
||||
//db_.exec("INSERT INTO folders (id, title, created_time) VALUES (\"ed735d55415bee976b771989be8f7005\", \"bbbb\", 1481235571)");
|
||||
//db_.exec("INSERT INTO folders (id, title, created_time) VALUES (\"5d41402abc4b2a76b9719d911017c592\", \"cccc\", 1481235571)");
|
||||
QStringList lines = sqlStringToLines(schemaSql);
|
||||
foreach (const QString& line, lines) {
|
||||
db_.exec(line);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
@ -20,6 +20,7 @@ private:
|
||||
void upgrade();
|
||||
int version() const;
|
||||
mutable int version_;
|
||||
QStringList sqlStringToLines(const QString& sql);
|
||||
|
||||
};
|
||||
|
||||
|
5
QtClient/JoplinQtClient/database.qrc
Executable file
5
QtClient/JoplinQtClient/database.qrc
Executable file
@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>schema.sql</file>
|
||||
</qresource>
|
||||
</RCC>
|
23
QtClient/JoplinQtClient/schema.sql
Executable file
23
QtClient/JoplinQtClient/schema.sql
Executable file
@ -0,0 +1,23 @@
|
||||
CREATE TABLE folders (
|
||||
id INTEGER PRIMARY KEY,
|
||||
title TEXT,
|
||||
created_time INT,
|
||||
updated_time INT,
|
||||
remote_id TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE notes (
|
||||
id INTEGER PRIMARY KEY,
|
||||
title TEXT,
|
||||
body TEXT,
|
||||
parent_id INT,
|
||||
created_time INT,
|
||||
updated_time INT,
|
||||
remote_id TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE version (
|
||||
version INT
|
||||
);
|
||||
|
||||
INSERT INTO version (version) VALUES (1);
|
@ -19,6 +19,7 @@
|
||||
#include <QQuickView>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlProperty>
|
||||
#include <QSqlError>
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
|
23
QtClient/database.sql
Executable file
23
QtClient/database.sql
Executable file
@ -0,0 +1,23 @@
|
||||
CREATE TABLE folders (
|
||||
id INTEGER PRIMARY KEY,
|
||||
title TEXT,
|
||||
created_time INT,
|
||||
updated_time INT,
|
||||
remote_id TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE notes (
|
||||
id INTEGER PRIMARY KEY,
|
||||
title TEXT,
|
||||
body TEXT,
|
||||
parent_id INT,
|
||||
created_time INT,
|
||||
updated_time INT,
|
||||
remote_id TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE version (
|
||||
version INT
|
||||
);
|
||||
|
||||
INSERT INTO version (version) VALUES (1);
|
BIN
QtClient/dependencies/dll-debug/Qt5Cored.dll
Executable file
BIN
QtClient/dependencies/dll-debug/Qt5Cored.dll
Executable file
Binary file not shown.
BIN
QtClient/dependencies/dll-debug/Qt5Guid.dll
Executable file
BIN
QtClient/dependencies/dll-debug/Qt5Guid.dll
Executable file
Binary file not shown.
BIN
QtClient/dependencies/dll-debug/Qt5Networkd.dll
Executable file
BIN
QtClient/dependencies/dll-debug/Qt5Networkd.dll
Executable file
Binary file not shown.
BIN
QtClient/dependencies/dll-debug/Qt5Qmld.dll
Executable file
BIN
QtClient/dependencies/dll-debug/Qt5Qmld.dll
Executable file
Binary file not shown.
BIN
QtClient/dependencies/dll-debug/Qt5Quickd.dll
Executable file
BIN
QtClient/dependencies/dll-debug/Qt5Quickd.dll
Executable file
Binary file not shown.
BIN
QtClient/dependencies/dll-debug/Qt5Sqld.dll
Executable file
BIN
QtClient/dependencies/dll-debug/Qt5Sqld.dll
Executable file
Binary file not shown.
BIN
QtClient/dependencies/dll-debug/ucrtbased.dll
Executable file
BIN
QtClient/dependencies/dll-debug/ucrtbased.dll
Executable file
Binary file not shown.
9
QtClient/evernote-import/build.sh
Executable file
9
QtClient/evernote-import/build.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
"/opt/Qt/5.7/gcc_64/bin/qmake" /home/laurent/src/notes/evernote-import-qt/evernote-import-qt.pro -spec linux-g++ CONFIG+=debug CONFIG+=qml_debug
|
||||
"/usr/bin/make" qmake_all
|
||||
make
|
||||
|
||||
echo "============================================="
|
||||
./evernote-import-qt
|
BIN
QtClient/evernote-import/evernote-import-qt
Executable file
BIN
QtClient/evernote-import/evernote-import-qt
Executable file
Binary file not shown.
23
QtClient/evernote-import/evernote-import-qt.pro
Executable file
23
QtClient/evernote-import/evernote-import-qt.pro
Executable file
@ -0,0 +1,23 @@
|
||||
QT += core sql
|
||||
QT -= gui
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
TARGET = evernote-import-qt
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
|
||||
TEMPLATE = app
|
||||
|
||||
SOURCES += main.cpp
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which as been marked deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# 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
|
256
QtClient/evernote-import/main.cpp
Executable file
256
QtClient/evernote-import/main.cpp
Executable file
@ -0,0 +1,256 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QDateTime>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlRecord>
|
||||
|
||||
struct Resource {
|
||||
QString id;
|
||||
QString mime;
|
||||
QString filename;
|
||||
QByteArray data;
|
||||
time_t timestamp;
|
||||
|
||||
Resource() : timestamp(0) {}
|
||||
};
|
||||
|
||||
struct Note {
|
||||
int id;
|
||||
QString title;
|
||||
QString content;
|
||||
time_t created;
|
||||
time_t updated;
|
||||
QStringList tags;
|
||||
QString longitude;
|
||||
QString latitude;
|
||||
QString altitude;
|
||||
QString source;
|
||||
QString author;
|
||||
QString sourceUrl;
|
||||
QString reminderOrder;
|
||||
QString reminderDoneTime;
|
||||
QString reminderTime;
|
||||
QString sourceApplication;
|
||||
QString applicationData;
|
||||
std::vector<Resource> resources;
|
||||
|
||||
Note() : created(0), updated(0) {}
|
||||
};
|
||||
|
||||
time_t dateStringToTimestamp(const QString& s) {
|
||||
QDateTime d = QDateTime::fromString(s, "yyyyMMddThhmmssZ");
|
||||
d.setTimeSpec(Qt::UTC);
|
||||
if (!d.isValid()) return 0;
|
||||
return d.toTime_t();
|
||||
}
|
||||
|
||||
void parseAttributes(QXmlStreamReader& reader, Note& note) {
|
||||
while (reader.readNextStartElement()) {
|
||||
if (reader.name() == "longitude") {
|
||||
note.longitude = reader.readElementText();
|
||||
} else if (reader.name() == "latitude") {
|
||||
note.latitude = reader.readElementText();
|
||||
} else if (reader.name() == "altitude") {
|
||||
note.altitude = reader.readElementText();
|
||||
} else if (reader.name() == "source") {
|
||||
note.source = reader.readElementText();
|
||||
} else if (reader.name() == "author") {
|
||||
note.author = reader.readElementText();
|
||||
} else if (reader.name() == "source-url") {
|
||||
note.sourceUrl = reader.readElementText();
|
||||
} else if (reader.name() == "source-application") {
|
||||
note.sourceApplication = reader.readElementText();
|
||||
} else if (reader.name() == "reminder-order") {
|
||||
note.reminderOrder = reader.readElementText();
|
||||
} else if (reader.name() == "reminder-time") {
|
||||
note.reminderTime = reader.readElementText();
|
||||
} else if (reader.name() == "reminder-done-time") {
|
||||
note.reminderDoneTime = reader.readElementText();
|
||||
} else if (reader.name() == "application-data") {
|
||||
note.applicationData = reader.readElementText();
|
||||
} else {
|
||||
qWarning() << "Unsupported <note-attributes> element:" << reader.name();
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <resource>
|
||||
// <data encoding="base64">
|
||||
// ...........
|
||||
// ...........
|
||||
// </data>
|
||||
// <mime>image/png</mime>
|
||||
// <width>500</width>
|
||||
// <height>326</height>
|
||||
// <recognition>
|
||||
// <![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
// <!DOCTYPE recoIndex PUBLIC "SYSTEM" "http://xml.evernote.com/pub/recoIndex.dtd"><recoIndex docType="unknown" objType="image" objID="97db28a24bbb45c1b07e9a618cdb6835" engineVersion="6.6.33.5" recoType="service" lang="fr" objWidth="500" objHeight="326"/>
|
||||
// ]]>
|
||||
// </recognition>
|
||||
// <resource-attributes>
|
||||
// <file-name>NoeudDeChaise.png</file-name>
|
||||
// </resource-attributes>
|
||||
// </resource>
|
||||
|
||||
void parseResourceAttributes(QXmlStreamReader& reader, Resource& resource) {
|
||||
while (reader.readNextStartElement()) {
|
||||
if (reader.name() == "file-name") {
|
||||
resource.filename = reader.readElementText();
|
||||
} else if (reader.name() == "timestamp") {
|
||||
resource.timestamp = dateStringToTimestamp(reader.readElementText());
|
||||
} else if (reader.name() == "camera-make" || reader.name() == "source-url" || reader.name() == "attachment" || reader.name() == "longitude" || reader.name() == "latitude") {
|
||||
// Ignore it
|
||||
reader.skipCurrentElement();
|
||||
} else {
|
||||
qWarning() << "Unsupported <resource-attributes> element:" << reader.name();
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parseResourceRecognition(QXmlStreamReader& reader, Resource& resource) {
|
||||
QString recognitionXml = reader.readElementText();
|
||||
|
||||
QXmlStreamReader r(recognitionXml.toUtf8());
|
||||
|
||||
if (r.readNextStartElement()) {
|
||||
if (r.name() == "recoIndex") {
|
||||
QString objID;
|
||||
foreach (const QXmlStreamAttribute &attr, r.attributes()) {
|
||||
if (attr.name().toString() == "objID") {
|
||||
objID = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resource.id = objID;
|
||||
|
||||
r.skipCurrentElement();
|
||||
} else {
|
||||
qWarning() << "Unsupported <resource><recognition> element:" << r.name();
|
||||
r.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Resource parseResource(QXmlStreamReader& reader) {
|
||||
Resource output;
|
||||
while (reader.readNextStartElement()) {
|
||||
if (reader.name() == "data") {
|
||||
QString encoding = "";
|
||||
foreach (const QXmlStreamAttribute &attr, reader.attributes()) {
|
||||
if (attr.name().toString() == "encoding") {
|
||||
encoding = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (encoding != "base64") {
|
||||
qWarning() << "Unsupported <resource><data> encoding:" << encoding;
|
||||
return Resource();
|
||||
}
|
||||
|
||||
output.data = QByteArray::fromBase64(reader.readElementText().toUtf8());
|
||||
} else if (reader.name() == "mime") {
|
||||
output.mime = reader.readElementText();
|
||||
} else if (reader.name() == "resource-attributes") {
|
||||
parseResourceAttributes(reader, output);
|
||||
} else if (reader.name() == "width" || reader.name() == "height") {
|
||||
// Ignore it
|
||||
reader.skipCurrentElement();
|
||||
} else if (reader.name() == "recognition") {
|
||||
parseResourceRecognition(reader, output);
|
||||
} else {
|
||||
qWarning() << "Unsupported <resource> element:" << reader.name();
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
//qDebug() << output.id << output.mime << output.filename << output.timestamp;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
Note parseNote(QXmlStreamReader& reader) {
|
||||
Note note;
|
||||
|
||||
while (reader.readNextStartElement()) {
|
||||
if (reader.name() == "title") {
|
||||
note.title = reader.readElementText();
|
||||
} else if (reader.name() == "content") {
|
||||
note.content = reader.readElementText();
|
||||
} else if (reader.name() == "created") {
|
||||
note.created = dateStringToTimestamp(reader.readElementText());
|
||||
} else if (reader.name() == "updated") {
|
||||
note.updated = dateStringToTimestamp(reader.readElementText());
|
||||
} else if (reader.name() == "tag") {
|
||||
note.tags.append(reader.readElementText());
|
||||
} else if (reader.name() == "resource") {
|
||||
note.resources.push_back(parseResource(reader));
|
||||
} else if (reader.name() == "note-attributes") {
|
||||
parseAttributes(reader, note);
|
||||
} else {
|
||||
qWarning() << "Unsupported <note> element:" << reader.name();
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
//qDebug() << title << created << updated;
|
||||
|
||||
//qDebug() << note.longitude << note.latitude << note.source << note.author << note.sourceUrl;
|
||||
|
||||
//qDebug() << note.sourceApplication << note.reminderOrder << note.reminderDoneTime;
|
||||
|
||||
return note;
|
||||
}
|
||||
|
||||
std::vector<Note> parseXmlFile(const QString& filePath) {
|
||||
std::vector<Note> output;
|
||||
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qWarning() << "Cannot open file" << filePath;
|
||||
return output;
|
||||
}
|
||||
|
||||
QByteArray fileData = file.readAll();
|
||||
|
||||
QXmlStreamReader reader(fileData);
|
||||
|
||||
if (reader.readNextStartElement()) {
|
||||
while (reader.readNextStartElement()) {
|
||||
if (reader.name() == "note") {
|
||||
Note note = parseNote(reader);
|
||||
output.push_back(note);
|
||||
} else {
|
||||
qWarning() << "Unsupported element:" << reader.name();
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QCoreApplication a(argc, argv);
|
||||
|
||||
// QString dbPath = "D:/Web/www/joplin/QtClient/evernote-import/notes.sqlite";
|
||||
|
||||
// QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
|
||||
// db.setDatabaseName(path);
|
||||
|
||||
// if (!db_.open()) {
|
||||
// qDebug() << "Error: connection with database fail";
|
||||
// } else {
|
||||
// qDebug() << "Database: connection ok";
|
||||
// }
|
||||
|
||||
|
||||
//std::vector<Note> notes = parseXmlFile("/home/laurent/Downloads/Notes/Laurent.enex");
|
||||
std::vector<Note> notes = parseXmlFile("/home/laurent/Downloads/Notes/a_faire.enex");
|
||||
}
|
@ -11,10 +11,10 @@ class Eloquent {
|
||||
|
||||
$this->capsule_->addConnection([
|
||||
'driver' => 'mysql',
|
||||
'host' => 'localhost',
|
||||
'host' => '127.0.0.1',
|
||||
'database' => 'notes',
|
||||
'username' => 'root',
|
||||
'password' => 'pass',
|
||||
'password' => '',
|
||||
'charset' => 'utf8',
|
||||
'collation' => 'utf8_unicode_ci',
|
||||
'prefix' => '',
|
||||
|
Loading…
Reference in New Issue
Block a user