瀏覽代碼

Разделено получение информации видео на БД и API

Вадим Королёв 1 年之前
父節點
當前提交
08365e159a

+ 10 - 5
lib/Database/database.cpp

@@ -33,9 +33,14 @@ namespace db {
                 \"id\"	INTEGER,\
                 \"yt_id\"	TEXT,\
                 \"title\"	TEXT NOT NULL,\
-                \"description\"	TEXT,\
+                \"description\"	TEXT NOT NULL,\
                 \"author_id\"	INTEGER NOT NULL,\
-                \"published_at\"	TEXT NOT NULL,\
+                \"published_at\"	DATETIME NOT NULL,\
+                \"dur_h\"	INTEGER NOT NULL DEFAULT 0,\
+                \"dur_m\"	INTEGER NOT NULL DEFAULT 0,\
+                \"dur_s\"	INTEGER NOT NULL DEFAULT 0,\
+                \"views_count\"	INTEGER NOT NULL DEFAULT 0,\
+                \"likes_count\"	INTEGER NOT NULL DEFAULT 0,\
                 PRIMARY KEY(\"id\" AUTOINCREMENT)\
             )"
         };
@@ -148,7 +153,7 @@ namespace db {
 
         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_bind_text(stmt, 2, a->name.c_str(), a->name.bytes(), SQLITE_STATIC);
         sqlite3_step(stmt);
 
         a->id = sqlite3_last_insert_rowid(DB);
@@ -166,8 +171,8 @@ namespace db {
 
         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_text(stmt, 2, v->title.c_str(), v->title.bytes(), SQLITE_STATIC);
+        sqlite3_bind_text(stmt, 3, v->description.c_str(), v->description.bytes(), 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);

+ 1 - 0
lib/Database/database.hpp

@@ -4,6 +4,7 @@
 #include <string>
 #include <iostream>
 #include <array>
+#include <glibmm/ustring.h>
 
 namespace db {
     // Путь к базе данных

+ 1 - 1
lib/Database/entities.hpp

@@ -1,6 +1,6 @@
 #pragma once
-#include <glibmm/ustring.h>
 #include <string>
+#include <glibmm/ustring.h>
 
 namespace db {
     // Канал

+ 56 - 51
lib/YoutubeApi/youtubeapi.cpp

@@ -1,6 +1,26 @@
 #include "youtubeapi.hpp"
 
 namespace ytapi {
+    
+    void youtubeInit(std::string key) {
+        api_key = key;
+    }
+
+    bool performCurlRequest(std::string url, std::stringstream* response) {
+        // Добавляем ключ к каждому запросу
+        url += "&key=";
+        url += api_key;
+        
+        CURL* handle = curl_easy_init();
+        if (!handle) return false;
+        curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
+        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &write_http_data);
+        curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
+        curl_easy_perform(handle);
+        curl_easy_cleanup(handle);
+        return true;
+    }
+    
     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);
@@ -27,74 +47,59 @@ namespace ytapi {
         return size * nmemb;
     }
 
-    std::vector<db::video> getVideosByQuery(std::string api_key, std::string query) {
+    std::vector<std::string> getVideoIDsByQuery(std::string query) {
         std::stringstream response;
         std::string url;
-        std::vector<db::video> output;
-        CURL* handle;
-
-        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;
-
-        curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
-        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &write_http_data);
-        curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response);
-        curl_easy_perform(handle);
-        curl_easy_cleanup(handle);
-
-        return output;
+        
+        performCurlRequest(url, &response);
+        return getVideoIDsFromJSON(response.str());
     }
 
-    std::vector<db::video> getVideosFromJSON(std::string input) {
+    std::vector<std::string> getVideoIDsFromJSON(std::string input) {
         auto json = nlohmann::json::parse(input);
         auto items = json["items"];
-        std::vector<db::video> output;
+        std::vector<std::string> output;
         
         for (auto it = items.begin(); it != items.end(); ++it) {
             auto item = it.value();
             auto yt_id = item["id"]["videoId"];
-            auto snippet = item["snippet"];
-
-            // Проверить существует ли видео в базе данных
-            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
+            output.push_back(yt_id);
+        }
 
-            // 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;
+        return output;
+    }
 
-            // 3. Добавляем видео в БД
-            db::addVideo(&current_video);
+    video_result getVideoByYTID(std::string yt_id) {
+        std::stringstream response;
+        std::string url;
+        video_result output;
 
-            // 4. И в выходной массив
-            output.push_back(current_video);
-        }
+        // Формирование URL
+        url += "https://youtube.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&id=";
+        url += yt_id;
+
+        // Выполнение запроса
+        performCurlRequest(url, &response);
+
+        // Парсинг
+        // TODO:stats
+        auto json = nlohmann::json::parse(response);
+        auto item = json["items"][0];
+        auto snippet = item["snippet"];
+        auto content_details = item["contentDetails"];
+        // auto stats = item["statistics"];
+
+        output.yt_id            = yt_id;
+        output.title            = Glib::ustring(snippet["title"]);
+        output.description      = Glib::ustring(snippet["description"]);
+        output.duration         = std::string(content_details["duration"]);
+        output.author_yt_id     = std::string(snippet["channelId"]);
+        output.author_name      = Glib::ustring(snippet["channelTitle"]);
+        output.published_at     = std::string(snippet["publishedAt"]);
 
         return output;
     }

+ 28 - 5
lib/YoutubeApi/youtubeapi.hpp

@@ -10,6 +10,24 @@
 #include <Database/database.hpp>
 
 namespace ytapi {
+
+    // Детали видео - необработанные
+    struct video_result {
+        std::string     yt_id;          // ID на YouTube
+        Glib::ustring   title;          // Название
+        Glib::ustring   description;    // Описание
+        std::string     duration;       // Длительность
+        std::string     author_yt_id;   // ID автора на YouTube
+        Glib::ustring   author_name;    // Имя автора на YouTube
+        std::string     published_at;   // Когда было опубликовано
+    };
+    
+    // API ключ
+    static std::string api_key;
+
+    // Записывает ключ API в api_key
+    void youtubeInit(std::string key);
+    
     // Функция записи данных в std::ostringstream
     size_t write_http_data(char *ptr, size_t size, size_t nmemb, void *userdata);
 
@@ -20,11 +38,16 @@ namespace ytapi {
     // Раскодирует URL-строку
     std::string urldecode(const std::string& encoded);
 
-    // Получает список видео по запросу
-    std::vector<db::video> getVideosByQuery(std::string api_key, std::string query);
+    // Получает список YT_ID видео по запросу
+    std::vector<std::string> getVideoIDsByQuery(std::string query);
 
-    
+    // Возвращает объект видео, получив данные по API
+    video_result getVideoByYTID(std::string yt_id);
+
+    // Возвращает список видео id из JSON списка видео
+    std::vector<std::string> getVideoIDsFromJSON(std::string input);
 
-    // Возвращает список видео из JSON
-    std::vector<db::video> getVideosFromJSON(std::string input);
+    // Подгатавливает, настраивает и выполняет CURL запрос. Возвращает
+    // успешность вызова
+    bool performCurlRequest(std::string url, std::stringstream* response);
 }

+ 52 - 13
src/YTMPV/ytmpv.cpp

@@ -1,25 +1,64 @@
-#include <YoutubeApi/youtubeapi.hpp>
-#include <Database/database.hpp>
-#include <fstream>
-#include <iostream>
+#include "ytmpv.hpp"
+
+db::video getVideoByYTID(std::string yt_id) {
+    db::video output;
+
+    // 1. Проверить есть ли видео в базе данных
+    if (db::getVideoByYTID(yt_id, &output)) {
+        // Видео в базе данных найдено
+        std::cout << "Видео найдено в базе данных!" << std::endl;
+        return output;
+    }
+
+    // Видео в базе данных нет. Получаем информацию о нём через ytapi
+    ytapi::video_result found_video = ytapi::getVideoByYTID(yt_id);
+    output.yt_id        = yt_id;
+    output.title        = found_video.title;
+    output.description  = found_video.description;
+    output.published_at = found_video.published_at;
+
+    // Ищем автора в базе данных
+    db::author video_author;
+    if (!db::getAuthorByYTID(found_video.author_yt_id, &video_author)) {
+        // Автора в базе данных нет. Добавляем
+        video_author.yt_id = found_video.author_yt_id;
+        video_author.name = found_video.author_name;
+        db::addAuthor(&video_author);
+    }
+    output.author_obj = video_author;
+
+    // Добавляем видео в БД
+    db::addVideo(&output);
+
+    return output;
+}
 
 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]);
 
-    // Инициализация базы данных
+    // --Инициализация--
+    std::locale::global(std::locale(""));
+    curl_global_init(CURL_GLOBAL_ALL);
     db::databaseInit(argv[1]);
     db::createTables();
+    ytapi::youtubeInit(argv[2]);
+
+    db::video found;
+    std::vector<std::string> video_ids = ytapi::getVideoIDsByQuery(argv[3]);
+    for (auto id : video_ids) {
+        found = getVideoByYTID(id);
+
+        std::cout << found.title << ":" << found.author_obj.name << std::endl;
+    }
 
-    std::ifstream ifs("example.json");
-    std::string content(
-        (std::istreambuf_iterator<char>(ifs)),
-        (std::istreambuf_iterator<char>())
-    );
+    //~ std::ifstream ifs("example.json");
+    //~ std::string content(
+        //~ (std::istreambuf_iterator<char>(ifs)),
+        //~ (std::istreambuf_iterator<char>())
+    //~ );
 
-    ytapi::getVideosFromJSON(content);
+    //~ ytapi::getVideosFromJSON(content);
 }

+ 7 - 0
src/YTMPV/ytmpv.hpp

@@ -0,0 +1,7 @@
+#include <YoutubeApi/youtubeapi.hpp>
+#include <Database/database.hpp>
+#include <fstream>
+#include <iostream>
+
+// Возвращает объект видео по его Youtube id
+db::video getVideoByYTID(std::string yt_id);