Răsfoiți Sursa

Реализован поиск видео и их авторов

Вадим Королёв 1 an în urmă
părinte
comite
d0075cd84c

+ 0 - 55
YTMPV.geany

@@ -1,55 +0,0 @@
-[editor]
-line_wrapping=false
-line_break_column=80
-auto_continue_multiline=true
-
-[file_prefs]
-final_new_line=false
-ensure_convert_new_lines=true
-strip_trailing_spaces=false
-replace_tabs=false
-
-[indentation]
-indent_width=4
-indent_type=0
-indent_hard_tab_width=8
-detect_indent=true
-detect_indent_width=true
-indent_mode=2
-
-[project]
-name=YTMPV
-base_path=/home/vad/Code/YTMPV/
-description=
-file_patterns=
-
-[long line marker]
-long_line_behaviour=1
-long_line_column=80
-
-[files]
-current_page=3
-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;
-header_patterns=*.h;*.H;*.hpp;*.hxx;*.h++;*.hh;
-ignored_dirs_patterns=.*;CVS;
-ignored_file_patterns=*.o;*.obj;*.a;*.lib;*.so;*.dll;*.lo;*.la;*.class;*.jar;*.pyc;*.mo;*.gmo;
-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

+ 85 - 11
lib/Database/database.cpp

@@ -4,21 +4,21 @@ namespace db {
     // Объект работы с БД
     static sqlite3* DB;
     
-    void database_init(std::string filename) {
+    void databaseInit(std::string filename) {
         db_path = filename;
     }
 
-    int database_open() {
+    int databaseOpen() {
         return sqlite3_open(db_path.c_str(), &DB);
     }
 
-    void database_close() {
+    void databaseClose() {
         sqlite3_close(DB);
     }
 
     // Для каждого запроса на создание таблиц из массива quieries мы вызываем
     // sqlite3_exec. Если запрос провалится, выводим сообщение об ошибке 
-    void create_tables() {
+    void createTables() {
         char* message_error;
         int status;
         std::array<std::string, 2> queries = {
@@ -40,7 +40,7 @@ namespace db {
             )"
         };
 
-        database_open();
+        databaseOpen();
         for (int i = 0; i < 2; i++) {
             status = sqlite3_exec(DB, queries[i].c_str(), NULL, 0, &message_error);
 
@@ -50,23 +50,23 @@ namespace db {
                 return;
             }
         }
-        database_close();
+        databaseClose();
     }
 
-    bool get_video_by_ytid(std::string ytid, video* output) {
+    bool getVideoByYTID(std::string yt_id, 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"
+        "SELECT v.id,v.yt_id,v.title,v.description,a.id,a.yt_id,a.name,v.published_at"
         " FROM video v LEFT JOIN author a ON v.author_id=a.id"
         " WHERE v.yt_id=?";
-        database_open();
+        databaseOpen();
         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);
+        sqlite3_bind_text(stmt, 1, yt_id.c_str(), yt_id.length(), SQLITE_STATIC);
 
         // Выполнение
         int result = sqlite3_step(stmt);
@@ -96,11 +96,85 @@ namespace db {
         output->description = Glib::ustring(reinterpret_cast<const char*>(
             sqlite3_column_text(stmt, 3)
         ));
+        output->published_at = std::string(reinterpret_cast<const char*>(
+            sqlite3_column_text(stmt, 7)
+        ));
         output->author_obj = video_author;
 
         // Завершение
         sqlite3_finalize(stmt);
-        database_close();
+        databaseClose();
         return true;
     }
+
+    bool getAuthorByYTID(std::string yt_id, author* output) {
+        sqlite3_stmt* stmt;
+        std::string query =
+        "SELECT a.id, a.name"
+        " FROM author a"
+        " WHERE a.yt_id=?";
+        databaseOpen();
+
+        // Подготовка
+        sqlite3_prepare_v2(DB, query.c_str(), query.length(), &stmt, nullptr);
+
+        // Привязка данных
+        sqlite3_bind_text(stmt, 1, yt_id.c_str(), yt_id.length(), SQLITE_STATIC);
+
+        // Выполнение
+        int result = sqlite3_step(stmt);
+        if (result == SQLITE_DONE) {
+            // Видео не найдено
+            return false;
+        }
+
+        // Заполнение данными
+        output->id = sqlite3_column_int(stmt, 0);
+        output->name = std::string(reinterpret_cast<const char*>(
+            sqlite3_column_text(stmt, 1)
+        ));
+
+        // Завершение
+        sqlite3_finalize(stmt);
+        databaseClose();
+        return true;
+    }
+
+    void addAuthor(author* a) {
+        sqlite3_stmt* stmt;
+        std::string query =
+        "INSERT INTO author (yt_id, name) VALUES(?, ?)";
+        databaseOpen();
+
+        sqlite3_prepare_v2(DB, query.c_str(), query.length(), &stmt, nullptr);
+        sqlite3_bind_text(stmt, 1, a->yt_id.c_str(), a->yt_id.length(), SQLITE_STATIC);
+        sqlite3_bind_text(stmt, 2, a->name.c_str(), a->name.length(), SQLITE_STATIC);
+        sqlite3_step(stmt);
+
+        a->id = sqlite3_last_insert_rowid(DB);
+
+        sqlite3_finalize(stmt);
+        databaseClose();
+    }
+
+    void addVideo(video* v) {
+        sqlite3_stmt* stmt;
+        std::string query =
+        "INSERT INTO video (yt_id, title, description, author_id, published_at)"
+        " VALUES(?, ?, ?, ?, ?)";
+        databaseOpen();
+
+        sqlite3_prepare_v2(DB, query.c_str(), query.length(), &stmt, nullptr);
+        sqlite3_bind_text(stmt, 1, v->yt_id.c_str(), v->yt_id.length(), SQLITE_STATIC);
+        sqlite3_bind_text(stmt, 2, v->title.c_str(), v->title.length(), SQLITE_STATIC);
+        sqlite3_bind_text(stmt, 3, v->description.c_str(), v->description.length(), SQLITE_STATIC);
+        sqlite3_bind_int(stmt, 4, v->author_obj.id);
+        sqlite3_bind_text(stmt, 5, v->published_at.c_str(), v->published_at.length(), SQLITE_STATIC);
+        sqlite3_step(stmt);
+
+        v->id = sqlite3_last_insert_rowid(DB);
+        
+        sqlite3_finalize(stmt);
+        databaseClose();
+    }
 }

+ 17 - 5
lib/Database/database.hpp

@@ -10,16 +10,28 @@ namespace db {
     static std::string db_path;
 
     // Записывает путь к базе данных в db_path
-    void database_init(std::string filename);
+    void databaseInit(std::string filename);
 
     // Открывает подключение к БД
-    int database_open();
+    int databaseOpen();
 
     // Закрывает подключение к БД
-    void database_close();
+    void databaseClose();
 
     // Создаёт необходимые таблицы
-    void create_tables();
+    void createTables();
 
-    bool get_video_by_ytid(std::string ytid, video* output);
+    // Получает видео по его youtube id. Возвращает true, если видео было
+    // найдено
+    bool getVideoByYTID(std::string yt_id, video* output);
+
+    // Получает автора видео по его youtube id. Возвращает true, если автор был
+    // найден
+    bool getAuthorByYTID(std::string yt_id, author* output);
+
+    // Добавляет видео в базу данных. Заполняет свойство id при добавлении
+    void addVideo(video* v);
+    
+    // Добавляет видео в базу данных
+    void addAuthor(author* a);
 }

+ 1 - 0
lib/Database/entities.hpp

@@ -16,6 +16,7 @@ namespace db {
         std::string yt_id;
         Glib::ustring title;
         Glib::ustring description;
+        std::string published_at;
         author author_obj;
     };
 }

+ 41 - 8
lib/YoutubeApi/youtubeapi.cpp

@@ -21,14 +21,13 @@ namespace ytapi {
         return result;
     }
 
-    // если что, добавить static.
-    size_t write_data(char* ptr, size_t size, size_t nmemb, void* userdata) {
+    size_t write_http_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<db::video> get_videos_by_request(std::string api_key, std::string query) {
+    std::vector<db::video> getVideosByQuery(std::string api_key, std::string query) {
         std::stringstream response;
         std::string url;
         std::vector<db::video> output;
@@ -46,7 +45,7 @@ namespace ytapi {
         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_WRITEFUNCTION, &write_http_data);
         curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response);
         curl_easy_perform(handle);
         curl_easy_cleanup(handle);
@@ -54,15 +53,49 @@ namespace ytapi {
         return output;
     }
 
-    std::vector<db::video> get_videos_from_json(std::string input) {
+    std::vector<db::video> getVideosFromJSON(std::string input) {
         auto json = nlohmann::json::parse(input);
         auto items = json["items"];
+        std::vector<db::video> output;
+        
         for (auto it = items.begin(); it != items.end(); ++it) {
-            auto id = it.value()["id"]["videoId"];
+            auto item = it.value();
+            auto yt_id = item["id"]["videoId"];
+            auto snippet = item["snippet"];
 
             // Проверить существует ли видео в базе данных
-            
-            std::cout << id << std::endl;
+            db::video current_video;
+            if (db::getVideoByYTID(yt_id, &current_video)) {
+                output.push_back(current_video);
+                continue;
+            }
+
+            // Видео в базе данных не существует. Добавляем!
+            // 1. Ищем автора по его yt_id
+            db::author current_author;
+            if (!db::getAuthorByYTID(snippet["channelId"], &current_author)) {
+                // 1.5 Автора в базе данных нет, создаём
+                current_author.yt_id   = snippet["channelId"];
+                current_author.name    = Glib::ustring(snippet["channelTitle"]);
+                db::addAuthor(&current_author);
+            }
+
+            // Перезаписать snippet
+
+            // 2. Заполняем объект видео данными из JSON
+            current_video.yt_id         = yt_id;
+            current_video.title         = Glib::ustring(snippet["title"]);
+            current_video.description   = Glib::ustring(snippet["description"]);
+            current_video.published_at  = std::string(snippet["publishedAt"]);
+            current_video.author_obj    = current_author;
+
+            // 3. Добавляем видео в БД
+            db::addVideo(&current_video);
+
+            // 4. И в выходной массив
+            output.push_back(current_video);
         }
+
+        return output;
     }
 }

+ 6 - 4
lib/YoutubeApi/youtubeapi.hpp

@@ -7,11 +7,11 @@
 #include <nlohmann/json.hpp>
 #include <iostream>
 #include <Database/entities.hpp>
+#include <Database/database.hpp>
 
 namespace ytapi {
     // Функция записи данных в std::ostringstream
-    // если что, добавить static.
-    size_t write_data(char *ptr, size_t size, size_t nmemb, void *userdata);
+    size_t write_http_data(char *ptr, size_t size, size_t nmemb, void *userdata);
 
     // Кодирует URL-строку
     // https://stackoverflow.com/a/154627
@@ -21,8 +21,10 @@ namespace ytapi {
     std::string urldecode(const std::string& encoded);
 
     // Получает список видео по запросу
-    std::vector<db::video> get_videos_by_request(std::string api_key, std::string query);
+    std::vector<db::video> getVideosByQuery(std::string api_key, std::string query);
+
+    
 
     // Возвращает список видео из JSON
-    std::vector<db::video> get_videos_from_json(std::string input);
+    std::vector<db::video> getVideosFromJSON(std::string input);
 }

+ 12 - 5
src/YTMPV/ytmpv.cpp

@@ -4,15 +4,22 @@
 #include <iostream>
 
 int main(int argc, char **argv) {
+    if (argc == 1) {
+        std::cout << "Программа не принимает 0 аргументов";
+        exit(1);
+    }
     //curl_global_init(CURL_GLOBAL_ALL);
     //get_videos_by_request("token", argv[1]);
 
     // Инициализация базы данных
-    db::database_init(argv[1]);
-    db::create_tables();
+    db::databaseInit(argv[1]);
+    db::createTables();
 
-    db::video searched_video;
-    bool success = db::get_video_by_ytid("123", &searched_video);
+    std::ifstream ifs("example.json");
+    std::string content(
+        (std::istreambuf_iterator<char>(ifs)),
+        (std::istreambuf_iterator<char>())
+    );
 
-    std::cout << searched_video.description;
+    ytapi::getVideosFromJSON(content);
 }