浏览代码

Добавлена база данных

Вадим Королёв 1 年之前
父节点
当前提交
e24be5fe9d

+ 1 - 0
.gitignore

@@ -1 +1,2 @@
 example.json
+db.sqlite3

+ 17 - 4
YTMPV.geany

@@ -20,6 +20,8 @@ indent_mode=2
 [project]
 name=YTMPV
 base_path=/home/vad/Code/YTMPV/
+description=
+file_patterns=
 
 [long line marker]
 long_line_behaviour=1
@@ -27,10 +29,10 @@ long_line_column=80
 
 [files]
 current_page=3
-FILE_NAME_0=1967;C++;0;EUTF-8;0;1;0;%2Fhome%2Fvad%2FCode%2FYTMPV%2Flib%2FYoutubeApi%2Fyoutubeapi.cpp;0;4
-FILE_NAME_1=491;C++;0;EUTF-8;0;1;0;%2Fhome%2Fvad%2FCode%2FYTMPV%2Flib%2FYoutubeApi%2Fyoutubeapi.hpp;0;4
-FILE_NAME_2=376;JSON;0;EUTF-8;0;1;0;%2Fhome%2Fvad%2FCode%2FYTMPV%2Fexample.json;0;2
-FILE_NAME_3=166;C++;0;EUTF-8;0;1;0;%2Fhome%2Fvad%2FCode%2FYTMPV%2Fsrc%2FYTMPV%2Fytmpv.cpp;0;4
+FILE_NAME_0=638;C++;0;EUTF-8;0;1;0;%2Fhome%2Fvad%2FCode%2FYTMPV%2Flib%2FDatabase%2Fdatabase.hpp;0;4
+FILE_NAME_1=2005;C++;0;EUTF-8;0;1;0;%2Fhome%2Fvad%2FCode%2FYTMPV%2Flib%2FDatabase%2Fdatabase.cpp;0;4
+FILE_NAME_2=362;C++;0;EUTF-8;0;1;0;%2Fhome%2Fvad%2FCode%2FYTMPV%2Flib%2FDatabase%2Fentities.hpp;0;4
+FILE_NAME_3=476;C++;0;EUTF-8;0;1;0;%2Fhome%2Fvad%2FCode%2FYTMPV%2Fsrc%2FYTMPV%2Fytmpv.cpp;0;4
 
 [prjorg]
 source_patterns=*.c;*.C;*.cpp;*.cxx;*.c++;*.cc;*.m;
@@ -40,3 +42,14 @@ ignored_file_patterns=*.o;*.obj;*.a;*.lib;*.so;*.dll;*.lo;*.la;*.class;*.jar;*.p
 generate_tag_prefs=0
 show_empty_dirs=true
 external_dirs=
+
+[build-menu]
+NF_00_LB=_Собрать
+NF_00_CM=
+NF_00_WD=
+EX_00_LB=_Execute
+EX_00_CM=./bin/src/YTMPV/ytmpv db.sqlite3
+EX_00_WD=/home/vad/Code/YTMPV/
+
+[VTE]
+last_dir=/home/vad/Code/YTMPV

+ 106 - 0
lib/Database/database.cpp

@@ -0,0 +1,106 @@
+#include "database.hpp"
+
+namespace db {
+    // Объект работы с БД
+    static sqlite3* DB;
+    
+    void database_init(std::string filename) {
+        db_path = filename;
+    }
+
+    int database_open() {
+        return sqlite3_open(db_path.c_str(), &DB);
+    }
+
+    void database_close() {
+        sqlite3_close(DB);
+    }
+
+    // Для каждого запроса на создание таблиц из массива quieries мы вызываем
+    // sqlite3_exec. Если запрос провалится, выводим сообщение об ошибке 
+    void create_tables() {
+        char* message_error;
+        int status;
+        std::array<std::string, 2> queries = {
+            "CREATE TABLE IF NOT EXISTS \"author\" (\
+                \"id\"	INTEGER,\
+                \"yt_id\"	TEXT,\
+                \"name\"	TEXT,\
+                PRIMARY KEY(\"id\" AUTOINCREMENT)\
+            )",
+
+            "CREATE TABLE IF NOT EXISTS \"video\" (\
+                \"id\"	INTEGER,\
+                \"yt_id\"	TEXT,\
+                \"title\"	TEXT NOT NULL,\
+                \"description\"	TEXT,\
+                \"author_id\"	INTEGER NOT NULL,\
+                \"published_at\"	TEXT NOT NULL,\
+                PRIMARY KEY(\"id\" AUTOINCREMENT)\
+            )"
+        };
+
+        database_open();
+        for (int i = 0; i < 2; i++) {
+            status = sqlite3_exec(DB, queries[i].c_str(), NULL, 0, &message_error);
+
+            if (status != SQLITE_OK) {
+                std::cerr << "Error creating tables" << std::endl; 
+                sqlite3_free(message_error);
+                return;
+            }
+        }
+        database_close();
+    }
+
+    bool get_video_by_ytid(std::string ytid, video* output) {
+        sqlite3_stmt* stmt;
+        std::string query =
+        "SELECT v.id,v.yt_id,v.title,v.description,a.id,a.yt_id,a.name"
+        " FROM video v LEFT JOIN author a ON v.author_id=a.id"
+        " WHERE v.yt_id=?";
+        database_open();
+        author video_author;
+
+        // Подготовка
+        sqlite3_prepare_v2(DB, query.c_str(), query.length(), &stmt, nullptr);
+
+        // Привязка данных
+        sqlite3_bind_text(stmt, 1, ytid.c_str(), ytid.length(), SQLITE_STATIC);
+
+        // Выполнение
+        int result = sqlite3_step(stmt);
+        if (result == SQLITE_DONE) {
+            // Видео не найдено
+            return false;
+        }
+
+        // Заполнение данными
+        // unsigned const char* конвертируется в std::string
+        // https://stackoverflow.com/a/804131
+        video_author.id = sqlite3_column_int(stmt, 4);
+        video_author.yt_id = std::string(reinterpret_cast<const char*>(
+            sqlite3_column_text(stmt, 5)
+        ));
+        video_author.name = Glib::ustring(reinterpret_cast<const char*>(
+            sqlite3_column_text(stmt, 6)
+        ));
+
+        output->id = sqlite3_column_int(stmt, 0);
+        output->yt_id = std::string(reinterpret_cast<const char*>(
+            sqlite3_column_text(stmt, 1)
+        ));
+        output->title = Glib::ustring(reinterpret_cast<const char*>(
+            sqlite3_column_text(stmt, 2)
+        ));
+        output->description = Glib::ustring(reinterpret_cast<const char*>(
+            sqlite3_column_text(stmt, 3)
+        ));
+        output->author_obj = video_author;
+
+        // Завершение
+        sqlite3_finalize(stmt);
+        database_close();
+        return true;
+    }
+}

+ 25 - 0
lib/Database/database.hpp

@@ -0,0 +1,25 @@
+#pragma once
+#include "entities.hpp"
+#include <sqlite3.h>
+#include <string>
+#include <iostream>
+#include <array>
+
+namespace db {
+    // Путь к базе данных
+    static std::string db_path;
+
+    // Записывает путь к базе данных в db_path
+    void database_init(std::string filename);
+
+    // Открывает подключение к БД
+    int database_open();
+
+    // Закрывает подключение к БД
+    void database_close();
+
+    // Создаёт необходимые таблицы
+    void create_tables();
+
+    bool get_video_by_ytid(std::string ytid, video* output);
+}

+ 21 - 0
lib/Database/entities.hpp

@@ -0,0 +1,21 @@
+#pragma once
+#include <glibmm/ustring.h>
+#include <string>
+
+namespace db {
+    // Канал
+    struct author {
+        int id;
+        std::string yt_id;
+        Glib::ustring name;
+    };
+
+    // Видео
+    struct video {
+        int id;
+        std::string yt_id;
+        Glib::ustring title;
+        Glib::ustring description;
+        author author_obj;
+    };
+}

+ 6 - 0
lib/Database/meson.build

@@ -0,0 +1,6 @@
+database_lib = library(
+    'database',
+    ['database.cpp'],
+    include_directories: [dir_includes],
+    dependencies: [glibmm_dep, sqlite3_dep]
+)

+ 3 - 1
lib/YoutubeApi/meson.build

@@ -1,5 +1,7 @@
 ytapi_lib = library(
     'ytapi',
     ['youtubeapi.cpp'],
-    dependencies: [glibmm_dep, curlpp_dep, json_dep]
+    include_directories: [dir_includes],
+    dependencies: [glibmm_dep, curlpp_dep, json_dep],
+    link_with: [database_lib]
 )

+ 55 - 53
lib/YoutubeApi/youtubeapi.cpp

@@ -1,66 +1,68 @@
 #include "youtubeapi.hpp"
 
-std::string urlencode(const std::string& decoded) {
-    const auto encoded_value = curl_easy_escape(nullptr, decoded.c_str(), static_cast<int>(decoded.length()));
-    std::string result(encoded_value);
-    curl_free(encoded_value);
-    return result;
-}
+namespace ytapi {
+    std::string urlencode(const std::string& decoded) {
+        const auto encoded_value = curl_easy_escape(nullptr, decoded.c_str(), static_cast<int>(decoded.length()));
+        std::string result(encoded_value);
+        curl_free(encoded_value);
+        return result;
+    }
 
-std::string urldecode(const std::string& encoded) {
-    int output_length;
-    const auto decoded_value = curl_easy_unescape(
-        nullptr,
-        encoded.c_str(),
-        static_cast<int>(encoded.length()),
-        &output_length
-    );
-    std::string result(decoded_value, output_length);
-    curl_free(decoded_value);
-    return result;
-}
+    std::string urldecode(const std::string& encoded) {
+        int output_length;
+        const auto decoded_value = curl_easy_unescape(
+            nullptr,
+            encoded.c_str(),
+            static_cast<int>(encoded.length()),
+            &output_length
+        );
+        std::string result(decoded_value, output_length);
+        curl_free(decoded_value);
+        return result;
+    }
 
-// если что, добавить static.
-size_t write_data(char* ptr, size_t size, size_t nmemb, void* userdata) {
-    std::string data((const char*) ptr, (size_t) size * nmemb);
-    *((std::stringstream*) userdata) << data;
-    return size * nmemb;
-}
+    // если что, добавить static.
+    size_t write_data(char* ptr, size_t size, size_t nmemb, void* userdata) {
+        std::string data((const char*) ptr, (size_t) size * nmemb);
+        *((std::stringstream*) userdata) << data;
+        return size * nmemb;
+    }
 
-std::vector<video> get_videos_by_request(std::string api_key, std::string query) {
-    std::stringstream response;
-    std::string url;
-    std::vector<video> output;
-    CURL* handle;
+    std::vector<db::video> get_videos_by_request(std::string api_key, std::string query) {
+        std::stringstream response;
+        std::string url;
+        std::vector<db::video> output;
+        CURL* handle;
 
-    handle = curl_easy_init();
-    if (!handle) {
-        return output;
-    }
+        handle = curl_easy_init();
+        if (!handle) {
+            return output;
+        }
 
-    // Формирование URL
-    url += "https://youtube.googleapis.com/youtube/v3/search?type=video&part=snippet&maxResult=25&q=";
-    url += urlencode(query);
-    url += "&key=";
-    url += api_key;
+        // Формирование URL
+        url += "https://youtube.googleapis.com/youtube/v3/search?type=video&part=snippet&maxResult=25&q=";
+        url += urlencode(query);
+        url += "&key=";
+        url += api_key;
 
-    curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
-    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &write_data);
-    curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response);
-    curl_easy_perform(handle);
-    curl_easy_cleanup(handle);
+        curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
+        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &write_data);
+        curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response);
+        curl_easy_perform(handle);
+        curl_easy_cleanup(handle);
 
-    return output;
-}
+        return output;
+    }
 
-std::vector<video> get_videos_from_json(std::string input) {
-    auto json = nlohmann::json::parse(input);
-    auto items = json["items"];
-    for (auto it = items.begin(); it != items.end(); ++it) {
-        auto id = it.value()["id"]["videoId"];
+    std::vector<db::video> get_videos_from_json(std::string input) {
+        auto json = nlohmann::json::parse(input);
+        auto items = json["items"];
+        for (auto it = items.begin(); it != items.end(); ++it) {
+            auto id = it.value()["id"]["videoId"];
 
-        // Проверить существует ли видео в базе данных
-        
-        std::cout << id << std::endl;
+            // Проверить существует ли видео в базе данных
+            
+            std::cout << id << std::endl;
+        }
     }
 }

+ 15 - 26
lib/YoutubeApi/youtubeapi.hpp

@@ -6,34 +6,23 @@
 #include <sstream>
 #include <nlohmann/json.hpp>
 #include <iostream>
+#include <Database/entities.hpp>
 
-// Канал
-struct channel {
-    Glib::ustring id;
-    Glib::ustring name;
-};
+namespace ytapi {
+    // Функция записи данных в std::ostringstream
+    // если что, добавить static.
+    size_t write_data(char *ptr, size_t size, size_t nmemb, void *userdata);
 
-// Видео
-struct video {
-    Glib::ustring id;
-    Glib::ustring title;
-    Glib::ustring description;
-    channel author;
-};
+    // Кодирует URL-строку
+    // https://stackoverflow.com/a/154627
+    std::string urlencode(const std::string& decoded);
 
-// Функция записи данных в std::ostringstream
-// если что, добавить static.
-size_t write_data(char *ptr, size_t size, size_t nmemb, void *userdata);
+    // Раскодирует URL-строку
+    std::string urldecode(const std::string& encoded);
 
-// Кодирует URL-строку
-// https://stackoverflow.com/a/154627
-std::string urlencode(const std::string& decoded);
+    // Получает список видео по запросу
+    std::vector<db::video> get_videos_by_request(std::string api_key, std::string query);
 
-// Раскодирует URL-строку
-std::string urldecode(const std::string& encoded);
-
-// Получает список видео по запросу
-std::vector<video> get_videos_by_request(std::string api_key, std::string query);
-
-// Возвращает список видео из JSON
-std::vector<video> get_videos_from_json(std::string input);
+    // Возвращает список видео из JSON
+    std::vector<db::video> get_videos_from_json(std::string input);
+}

+ 2 - 1
lib/meson.build

@@ -1,2 +1,3 @@
-lib_includes = include_directories('.')
+dir_includes = include_directories('.')
+subdir('Database')
 subdir('YoutubeApi')

+ 3 - 0
meson.build

@@ -7,8 +7,11 @@ project('YTMPV', 'cpp',
     'default_library=static'
   ]
 )
+
 glibmm_dep = dependency('glibmm-2.68')
 curlpp_dep = dependency('curlpp')
 json_dep = dependency('nlohmann_json')
+sqlite3_dep = dependency('sqlite3')
+
 subdir('lib')
 subdir('src/YTMPV')

+ 2 - 2
src/YTMPV/meson.build

@@ -1,7 +1,7 @@
 ytmpv = executable(
   'ytmpv',
   'ytmpv.cpp',
-  link_with: [ytapi_lib],
-  include_directories: [lib_includes],
+  link_with: [ytapi_lib, database_lib],
+  include_directories: [dir_includes],
   dependencies: [glibmm_dep, curlpp_dep, json_dep]
 )

+ 10 - 6
src/YTMPV/ytmpv.cpp

@@ -1,14 +1,18 @@
 #include <YoutubeApi/youtubeapi.hpp>
+#include <Database/database.hpp>
 #include <fstream>
+#include <iostream>
 
 int main(int argc, char **argv) {
     //curl_global_init(CURL_GLOBAL_ALL);
     //get_videos_by_request("token", argv[1]);
 
-    std::ifstream ifs("example.json");
-    std::string content(
-        (std::istreambuf_iterator<char>(ifs)),
-        (std::istreambuf_iterator<char>())
-    );
-    get_videos_from_json(content);
+    // Инициализация базы данных
+    db::database_init(argv[1]);
+    db::create_tables();
+
+    db::video searched_video;
+    bool success = db::get_video_by_ytid("123", &searched_video);
+
+    std::cout << searched_video.description;
 }