From c6d9c7e097049006addcb757ac71a12b997d56bc Mon Sep 17 00:00:00 2001 From: witnessmenow Date: Wed, 20 May 2020 22:03:47 +0100 Subject: [PATCH 1/4] Re-working for V2, untested --- .gitignore | 2 + README.md | 10 ++- library.properties | 3 +- src/YoutubeApi.cpp | 214 +++++++++++++++++++++++++++------------------ src/YoutubeApi.h | 24 +++-- 5 files changed, 158 insertions(+), 95 deletions(-) diff --git a/.gitignore b/.gitignore index 4a0fc91..648f8cc 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ .piolibdeps .clang_complete .gcc-flags.json +.pio/ +.vscode/ diff --git a/README.md b/README.md index 65a4b40..2fe2a76 100644 --- a/README.md +++ b/README.md @@ -5,19 +5,21 @@ Currently the only implemented method is getting the channel statistics but it c ![Imgur](http://i.imgur.com/FmXyW4E.png) +### Support what I do! + +I have created a lot of different Arduino libraries that I hope people can make use of. [If you enjoy my work, please consider becoming a Github sponsor!](https://github.com/sponsors/witnessmenow/) + ## Getting a Google Apps API key (Required!) * Create an application [here](https://console.developers.google.com) * On the API Manager section, go to "Credentials" and create a new API key * Enable your application to communicate the YouTube Api [here](https://console.developers.google.com/apis/api/youtube) * Make sure the following URL works for you in your browser (Change the key at the end!): -https://www.googleapis.com/youtube/v3/channels?part=statistics&id=UCu7_D0o48KbfhpEohoP7YSQ&key=PutYourNewlyGeneratedKeyHere +https://www.googleapis.com/youtube/v3/channels?part=statistics&id=UCezJOfu7OtqGzd5xrP3q6WA&key=PutYourNewlyGeneratedKeyHere ## Installing -The downloaded code can be included as a new library into the IDE selecting the menu: - - Sketch / include Library / Add .Zip library +The easiest way to install this library is through the aduino library manager, just search for "Youtube" You also have to install the ArduinoJson library written by [BenoƮt Blanchon](https://github.com/bblanchon). Search for it on the Arduino Library manager or get it from [here](https://github.com/bblanchon/ArduinoJson). diff --git a/library.properties b/library.properties index ce3e47f..5765479 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=YoutubeApi -version=1.1.0 +version=2.0.0 author=Brian Lough maintainer=Brian Lough sentence=A wrapper for the YouTube API for Arduino (supports ESP8266 & WiFi101 boards) @@ -7,3 +7,4 @@ paragraph=Use this library to get YouTube channel statistics category=Communication url=https://github.com/witnessmenow/arduino-youtube-api architectures=* +depends=ArduinoJson diff --git a/src/YoutubeApi.cpp b/src/YoutubeApi.cpp index 4047667..e0e581a 100644 --- a/src/YoutubeApi.cpp +++ b/src/YoutubeApi.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2017 Brian Lough. All right reserved. + Copyright (c) 2020 Brian Lough. All right reserved. YoutubeApi - An Arduino wrapper for the YouTube API @@ -22,97 +22,143 @@ #include "YoutubeApi.h" YoutubeApi::YoutubeApi(String apiKey, Client &client) { + int strLen = apiKey.length() + 1; + char tempStr[strLen]; + apiKey.toCharArray(tempStr, strLen); + + YoutubeApi(tempStr, client); +} + +YoutubeApi::YoutubeApi(char *apiKey, Client &client) { _apiKey = apiKey; this->client = &client; } -String YoutubeApi::sendGetToYoutube(String command) { - String headers=""; - String body=""; - bool finishedHeaders = false; - bool currentLineIsBlank = true; - unsigned long now; - bool avail; - // Connect with youtube api over ssl - if (client->connect(YTAPI_HOST, YTAPI_SSL_PORT)) { - if(_debug) { Serial.println(".... connected to server"); } - String a=""; - char c; - int ch_count=0; - client->println("GET " + command + "&key=" + _apiKey + " HTTP/1.1"); - client->print("HOST: "); - client->println(YTAPI_HOST); - client->println(); - now=millis(); - avail=false; - while (millis() - now < YTAPI_TIMEOUT) { - while (client->available()) { - - // Allow body to be parsed before finishing - avail = finishedHeaders; - char c = client->read(); - //Serial.write(c); - - if(!finishedHeaders){ - if (currentLineIsBlank && c == '\n') { - finishedHeaders = true; - } - else{ - headers = headers + c; - - } - } else { - if (ch_count < maxMessageLength) { - body=body+c; - ch_count++; - } - } - - if (c == '\n') { - currentLineIsBlank = true; - }else if (c != '\r') { - currentLineIsBlank = false; - } - } - if (avail) { - if(_debug) { - Serial.println("Body:"); - Serial.println(body); - Serial.println("END"); - } - break; - } - } - } - closeClient(); - return body; +int YoutubeApi::sendGetToYoutube(char *command) { + client->flush(); + client->setTimeout(YTAPI_TIMEOUT); + if (!client->connect(YTAPI_HOST, YTAPI_SSL_PORT)) + { + Serial.println(F("Connection failed")); + return false; + } + // give the esp a breather + yield(); + + // Send HTTP request + client->print(F("GET ")); + client->print(command); + client->println(F(" HTTP/1.1")); + + //Headers + client->print(F("Host: ")); + client->println(YTAPI_HOST); + + client->println(F("Cache-Control: no-cache")); + + if (client->println() == 0) + { + Serial.println(F("Failed to send request")); + return -1; + } + + int statusCode = getHttpStatusCode(); + + // Let the caller of this method parse the JSon from the client + skipHeaders(); + return statusCode; } bool YoutubeApi::getChannelStatistics(String channelId){ - String command="/youtube/v3/channels?part=statistics&id="+channelId; //If you can't find it(for example if you have a custom url) look here: https://www.youtube.com/account_advanced - if(_debug) { Serial.println(F("Closing client")); } - String response = sendGetToYoutube(command); //recieve reply from youtube - DynamicJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.parseObject(response); - if(root.success()) { - if (root.containsKey("items")) { - long subscriberCount = root["items"][0]["statistics"]["subscriberCount"]; - long viewCount = root["items"][0]["statistics"]["viewCount"]; - long commentCount = root["items"][0]["statistics"]["commentCount"]; - long hiddenSubscriberCount = root["items"][0]["statistics"]["hiddenSubscriberCount"]; - long videoCount = root["items"][0]["statistics"]["videoCount"]; - - channelStats.viewCount = viewCount; - channelStats.subscriberCount = subscriberCount; - channelStats.commentCount = commentCount; - channelStats.hiddenSubscriberCount = hiddenSubscriberCount; - channelStats.videoCount = videoCount; - - return true; - } - } - return false; + int strLen = channelId.length() + 1; + char tempStr[strLen]; + channelId.toCharArray(tempStr, strLen); + + return getChannelStatistics(tempStr); +} + +bool YoutubeApi::getChannelStatistics(char *channelId){ + char command[150] = YTAPI_CHANNEL_ENDPOINT; + strcat(command, "?part=statistics&id=%s"); + sprintf(command, command, channelId); + + if (_debug) + { + Serial.println(command); + } + + bool hasError = true; + + // Get from https://arduinojson.org/v6/assistant/ + const size_t bufferSize = JSON_ARRAY_SIZE(1) + + JSON_OBJECT_SIZE(2) + + 2*JSON_OBJECT_SIZE(4) + + JSON_OBJECT_SIZE(5); + + if (sendGetToYoutube(command) == 200) + { + // Allocate DynamicJsonDocument + DynamicJsonDocument doc(bufferSize); + + // Parse JSON object + DeserializationError error = deserializeJson(doc, *client); + if (!error) + { + hasError = false; + + JsonObject itemStatistics = doc["items"][0]["statistics"]; + + channelStats.viewCount = itemStatistics["viewCount"].as(); + channelStats.subscriberCount = itemStatistics["subscriberCount"].as(); + channelStats.commentCount = itemStatistics["commentCount"].as(); + channelStats.hiddenSubscriberCount = itemStatistics["hiddenSubscriberCount"].as(); + channelStats.videoCount = itemStatistics["videoCount"].as(); + } + else + { + Serial.print(F("deserializeJson() failed with code ")); + Serial.println(error.c_str()); + } + } + closeClient(); + + return hasError; +} + +void YoutubeApi::skipHeaders() +{ + // Skip HTTP headers + char endOfHeaders[] = "\r\n\r\n"; + if (!client->find(endOfHeaders)) + { + Serial.println(F("Invalid response")); + return; + } + + // Was getting stray characters between the headers and the body + // This should toss them away + while (client->available() && client->peek() != '{') + { + char c = 0; + client->readBytes(&c, 1); + if (_debug) + { + Serial.print("Tossing an unexpected character: "); + Serial.println(c); + } + } +} + +int YoutubeApi::getHttpStatusCode() +{ + // Check HTTP status + if(client->find("HTTP/1.1")){ + int statusCode = client->parseInt(); + return statusCode; + } + + return -1; } void YoutubeApi::closeClient() { diff --git a/src/YoutubeApi.h b/src/YoutubeApi.h index 1b52abc..72818c9 100644 --- a/src/YoutubeApi.h +++ b/src/YoutubeApi.h @@ -18,6 +18,15 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#if defined(__GNUC__) || defined(__clang__) +#define DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: You need to implement DEPRECATED for this compiler") +#define DEPRECATED +#endif + #ifndef YoutubeApi_h #define YoutubeApi_h @@ -30,6 +39,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define YTAPI_SSL_PORT 443 #define YTAPI_TIMEOUT 1500 +#define YTAPI_CHANNEL_ENDPOINT "/youtube/v3/channels" struct channelStatistics{ long viewCount; @@ -42,17 +52,19 @@ struct channelStatistics{ class YoutubeApi { public: - YoutubeApi (String apiKey, Client &client); - String sendGetToYoutube(String command); - bool getChannelStatistics(String channelId); + YoutubeApi (char *apiKey, Client &client); + DEPRECATED YoutubeApi (String apiKey, Client &client); + int sendGetToYoutube(char *command); + bool getChannelStatistics(char *channelId); + DEPRECATED bool getChannelStatistics(String channelId); channelStatistics channelStats; bool _debug = false; private: - String _apiKey; + char *_apiKey; Client *client; - const int maxMessageLength = 1000; - bool checkForOkResponse(String response); + int getHttpStatusCode(); + void skipHeaders(); void closeClient(); }; From a17d89e462a5543dab42f59ecbfcafb41f66eb59 Mon Sep 17 00:00:00 2001 From: witnessmenow Date: Wed, 20 May 2020 22:39:08 +0100 Subject: [PATCH 2/4] Updating ESP8266 Channel Stats example. not working though --- .../ChannelStatistics/ChannelStatistics.ino | 52 ++++++++++++++----- src/YoutubeApi.cpp | 10 +++- src/YoutubeApi.h | 4 +- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/examples/ESP8266/ChannelStatistics/ChannelStatistics.ino b/examples/ESP8266/ChannelStatistics/ChannelStatistics.ino index d676198..b6447d9 100644 --- a/examples/ESP8266/ChannelStatistics/ChannelStatistics.ino +++ b/examples/ESP8266/ChannelStatistics/ChannelStatistics.ino @@ -1,28 +1,55 @@ /******************************************************************* - * Read YouTube Channel statistics from the YouTube API * - * * - * By Brian Lough * - * https://www.youtube.com/channel/UCezJOfu7OtqGzd5xrP3q6WA * + Read YouTube Channel statistics from the YouTube API + + Parts: + D1 Mini ESP8266 (or any ESP8266) * - http://s.click.aliexpress.com/e/uzFUnIe + * = Affilate + + If you find what I do useful and would like to support me, + please consider becoming a sponsor on Github + https://github.com/sponsors/witnessmenow/ + + Written by Brian Lough + YouTube: https://www.youtube.com/brianlough + Tindie: https://www.tindie.com/stores/brianlough/ + Twitter: https://twitter.com/witnessmenow *******************************************************************/ -#include +// ---------------------------- +// Standard Libraries +// ---------------------------- + #include #include -#include // This Sketch doesn't technically need this, but the library does so it must be installed. +// ---------------------------- +// Additional Libraries - each one of these will need to be installed. +// ---------------------------- + +#include +// Library for connecting to the Youtube API + +// Search for "youtube" in the Arduino Library Manager +// https://github.com/witnessmenow/arduino-youtube-api + +#include +// Library used for parsing Json from the API responses + +// Search for "Arduino Json" in the Arduino Library manager +// https://github.com/bblanchon/ArduinoJson //------- Replace the following! ------ char ssid[] = "xxx"; // your network SSID (name) char password[] = "yyyy"; // your network key #define API_KEY "zzzz" // your google apps API Token #define CHANNEL_ID "UCezJOfu7OtqGzd5xrP3q6WA" // makes up the url of channel - +//------- ---------------------- ------ WiFiClientSecure client; YoutubeApi api(API_KEY, client); -unsigned long api_mtbs = 60000; //mean time between api requests -unsigned long api_lasttime; //last time api request has been done +unsigned long timeBetweenRequests = 60000; +unsigned long nextRunTime; long subs = 0; @@ -50,12 +77,13 @@ void setup() { IPAddress ip = WiFi.localIP(); Serial.println(ip); - + // Required if you are using ESP8266 V2.5 or above + client.setInsecure(); } void loop() { - if (millis() - api_lasttime > api_mtbs) { + if (millis() > nextRunTime) { if(api.getChannelStatistics(CHANNEL_ID)) { Serial.println("---------Stats---------"); @@ -73,6 +101,6 @@ void loop() { Serial.println("------------------------"); } - api_lasttime = millis(); + nextRunTime = millis() + timeBetweenRequests; } } diff --git a/src/YoutubeApi.cpp b/src/YoutubeApi.cpp index e0e581a..3bb5a09 100644 --- a/src/YoutubeApi.cpp +++ b/src/YoutubeApi.cpp @@ -71,6 +71,7 @@ int YoutubeApi::sendGetToYoutube(char *command) { bool YoutubeApi::getChannelStatistics(String channelId){ + Serial.println("Deprecated, user a char* rather than String"); int strLen = channelId.length() + 1; char tempStr[strLen]; channelId.toCharArray(tempStr, strLen); @@ -82,6 +83,8 @@ bool YoutubeApi::getChannelStatistics(char *channelId){ char command[150] = YTAPI_CHANNEL_ENDPOINT; strcat(command, "?part=statistics&id=%s"); sprintf(command, command, channelId); + strcat(command, "&key=%s"); + sprintf(command, command, _apiKey); if (_debug) { @@ -96,7 +99,9 @@ bool YoutubeApi::getChannelStatistics(char *channelId){ + 2*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5); - if (sendGetToYoutube(command) == 200) + int httpStatus = sendGetToYoutube(command); + + if (httpStatus == 200) { // Allocate DynamicJsonDocument DynamicJsonDocument doc(bufferSize); @@ -120,6 +125,9 @@ bool YoutubeApi::getChannelStatistics(char *channelId){ Serial.print(F("deserializeJson() failed with code ")); Serial.println(error.c_str()); } + } else { + Serial.print("Unexpected HTTP Status Code: "); + Serial.println(httpStatus); } closeClient(); diff --git a/src/YoutubeApi.h b/src/YoutubeApi.h index 72818c9..a8d3b47 100644 --- a/src/YoutubeApi.h +++ b/src/YoutubeApi.h @@ -53,10 +53,10 @@ class YoutubeApi { public: YoutubeApi (char *apiKey, Client &client); - DEPRECATED YoutubeApi (String apiKey, Client &client); + YoutubeApi (String apiKey, Client &client); int sendGetToYoutube(char *command); bool getChannelStatistics(char *channelId); - DEPRECATED bool getChannelStatistics(String channelId); + bool getChannelStatistics(String channelId); channelStatistics channelStats; bool _debug = false; From 1516e74bc8b53f5d513fef429bf92c79b895bff9 Mon Sep 17 00:00:00 2001 From: witnessmenow Date: Wed, 20 May 2020 23:07:46 +0100 Subject: [PATCH 3/4] Now working --- src/YoutubeApi.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/YoutubeApi.cpp b/src/YoutubeApi.cpp index 3bb5a09..58c7ee5 100644 --- a/src/YoutubeApi.cpp +++ b/src/YoutubeApi.cpp @@ -81,23 +81,23 @@ bool YoutubeApi::getChannelStatistics(String channelId){ bool YoutubeApi::getChannelStatistics(char *channelId){ char command[150] = YTAPI_CHANNEL_ENDPOINT; - strcat(command, "?part=statistics&id=%s"); - sprintf(command, command, channelId); - strcat(command, "&key=%s"); - sprintf(command, command, _apiKey); + char params[120]; + sprintf(params, "?part=statistics&id=%s&key=%s", channelId, _apiKey); + strcat(command, params); if (_debug) { Serial.println(command); } - bool hasError = true; + bool wasSuccessful = false; // Get from https://arduinojson.org/v6/assistant/ const size_t bufferSize = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(2) + 2*JSON_OBJECT_SIZE(4) - + JSON_OBJECT_SIZE(5); + + JSON_OBJECT_SIZE(5) + + 330; int httpStatus = sendGetToYoutube(command); @@ -110,7 +110,7 @@ bool YoutubeApi::getChannelStatistics(char *channelId){ DeserializationError error = deserializeJson(doc, *client); if (!error) { - hasError = false; + wasSuccessful = true; JsonObject itemStatistics = doc["items"][0]["statistics"]; @@ -131,7 +131,7 @@ bool YoutubeApi::getChannelStatistics(char *channelId){ } closeClient(); - return hasError; + return wasSuccessful; } void YoutubeApi::skipHeaders() From 89bec62d30326e69bef7afa7286e2845ae50bcd2 Mon Sep 17 00:00:00 2001 From: witnessmenow Date: Wed, 20 May 2020 23:30:09 +0100 Subject: [PATCH 4/4] Updated ESp32 example, removed extra ESP8266 examples (too complicated) --- .../ChannelStatistics/ChannelStatistics.ino | 56 +++-- .../ChannelStatistics/ChannelStatistics.ino | 6 +- .../ChannelStatisticsWithWifiManager.ino | 174 -------------- ...tatisticsWithWifiManagerAndDoubleReset.ino | 213 ------------------ src/YoutubeApi.cpp | 1 - src/YoutubeApi.h | 12 +- 6 files changed, 47 insertions(+), 415 deletions(-) delete mode 100644 examples/ESP8266/ChannelStatisticsWithWifiManager/ChannelStatisticsWithWifiManager.ino delete mode 100644 examples/ESP8266/ChannelStatisticsWithWifiManagerAndDoubleReset/ChannelStatisticsWithWifiManagerAndDoubleReset.ino diff --git a/examples/ESP32/ChannelStatistics/ChannelStatistics.ino b/examples/ESP32/ChannelStatistics/ChannelStatistics.ino index 11b3477..4534862 100644 --- a/examples/ESP32/ChannelStatistics/ChannelStatistics.ino +++ b/examples/ESP32/ChannelStatistics/ChannelStatistics.ino @@ -1,29 +1,55 @@ /******************************************************************* - * Read YouTube Channel statistics from the YouTube API using an - * ESP32 - * - * By Brian Lough - * https://www.youtube.com/channel/UCezJOfu7OtqGzd5xrP3q6WA + Read YouTube Channel statistics from the YouTube API on + an ESP32 and print them to the serial monitor + + Parts: + Any ESP32 board + + If you find what I do useful and would like to support me, + please consider becoming a sponsor on Github + https://github.com/sponsors/witnessmenow/ + + Written by Brian Lough + YouTube: https://www.youtube.com/brianlough + Tindie: https://www.tindie.com/stores/brianlough/ + Twitter: https://twitter.com/witnessmenow *******************************************************************/ -#include +// ---------------------------- +// Standard Libraries +// ---------------------------- + #include #include -#include // This Sketch doesn't technically need this, but the library does so it must be installed. +// ---------------------------- +// Additional Libraries - each one of these will need to be installed. +// ---------------------------- + +#include +// Library for connecting to the Youtube API + +// Search for "youtube" in the Arduino Library Manager +// https://github.com/witnessmenow/arduino-youtube-api + +#include +// Library used for parsing Json from the API responses + +// Search for "Arduino Json" in the Arduino Library manager +// https://github.com/bblanchon/ArduinoJson //------- Replace the following! ------ -char ssid[] = "ssid"; // your network SSID (name) -char password[] = "password"; // your network key -#define API_KEY "ENTER_YOUR_API_KEY" // your google apps API Token +char ssid[] = "xxx"; // your network SSID (name) +char password[] = "yyyy"; // your network key +#define API_KEY "zzzz" // your google apps API Token #define CHANNEL_ID "UCezJOfu7OtqGzd5xrP3q6WA" // makes up the url of channel - +//------- ---------------------- ------ WiFiClientSecure client; YoutubeApi api(API_KEY, client); -unsigned long api_mtbs = 60000; //mean time between api requests -unsigned long api_lasttime; //last time api request has been done +unsigned long timeBetweenRequests = 60000; +unsigned long nextRunTime; long subs = 0; @@ -55,7 +81,7 @@ void setup() { void loop() { - if (millis() - api_lasttime > api_mtbs) { + if (millis() > nextRunTime) { if(api.getChannelStatistics(CHANNEL_ID)) { Serial.println("---------Stats---------"); @@ -73,6 +99,6 @@ void loop() { Serial.println("------------------------"); } - api_lasttime = millis(); + nextRunTime = millis() + timeBetweenRequests; } } diff --git a/examples/ESP8266/ChannelStatistics/ChannelStatistics.ino b/examples/ESP8266/ChannelStatistics/ChannelStatistics.ino index b6447d9..3b7d4c6 100644 --- a/examples/ESP8266/ChannelStatistics/ChannelStatistics.ino +++ b/examples/ESP8266/ChannelStatistics/ChannelStatistics.ino @@ -1,5 +1,6 @@ /******************************************************************* - Read YouTube Channel statistics from the YouTube API + Read YouTube Channel statistics from the YouTube API on + an ESP8266 and print them to the serial monitor Parts: D1 Mini ESP8266 (or any ESP8266) * - http://s.click.aliexpress.com/e/uzFUnIe @@ -79,6 +80,9 @@ void setup() { // Required if you are using ESP8266 V2.5 or above client.setInsecure(); + + // If you want to enable some extra debugging + api._debug = true; } void loop() { diff --git a/examples/ESP8266/ChannelStatisticsWithWifiManager/ChannelStatisticsWithWifiManager.ino b/examples/ESP8266/ChannelStatisticsWithWifiManager/ChannelStatisticsWithWifiManager.ino deleted file mode 100644 index 5b95752..0000000 --- a/examples/ESP8266/ChannelStatisticsWithWifiManager/ChannelStatisticsWithWifiManager.ino +++ /dev/null @@ -1,174 +0,0 @@ -/******************************************************************* - * Read YouTube Channel statistics from the YouTube API * - * This sketch uses the WiFiManager Library for configuraiton * - * * - * By Brian Lough * - * https://www.youtube.com/channel/UCezJOfu7OtqGzd5xrP3q6WA * - *******************************************************************/ - -#include -#include -#include - -// For storing configurations -#include "FS.h" -#include - -// WiFiManager Libraries -#include //Local DNS Server used for redirecting all rs to the configuration portal -#include //Local WebServer used to serve the configuration portal -#include //https://github.com/tzapu/WiFiManager WiFi Configuration Magic - -const int resetConfigPin = D8; //When high will reset the wifi manager config - -char apiKey[45] = ""; -char channelId[30] = "UCezJOfu7OtqGzd5xrP3q6WA"; - -WiFiClientSecure client; -YoutubeApi *api; - -unsigned long api_mtbs = 60000; //mean time between api requests -unsigned long api_lasttime; //last time api request has been done - -long subs = 0; - -// flag for saving data -bool shouldSaveConfig = false; - -//callback notifying us of the need to save config -void saveConfigCallback () { - Serial.println("Should save config"); - shouldSaveConfig = true; -} - -void setup() { - - Serial.begin(115200); - - if (!SPIFFS.begin()) { - Serial.println("Failed to mount FS"); - return; - } - - pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output - digitalWrite(LED_BUILTIN, LOW); // Turn the LED on (Note that LOW is the voltage level - loadConfig(); - - WiFiManager wifiManager; - wifiManager.setSaveConfigCallback(saveConfigCallback); - - // Adding an additional config on the WIFI manager webpage for the API Key and Channel ID - WiFiManagerParameter customApiKey("apiKey", "API Key", apiKey, 50); - WiFiManagerParameter customChannelId("channelId", "Channel ID", channelId, 35); - wifiManager.addParameter(&customApiKey); - wifiManager.addParameter(&customChannelId); - - // If it fails to connect it will create a YouTube-Counter access point - wifiManager.autoConnect("YouTube-Counter", "supersecret"); - - strcpy(apiKey, customApiKey.getValue()); - strcpy(channelId, customChannelId.getValue()); - - if (shouldSaveConfig) { - saveConfig(); - } - - digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH - // Force Config mode if there is no API key - if(strcmp(apiKey, "") > 0) { - Serial.println("Init YouTube API"); - api = new YoutubeApi(apiKey, client); - } else { - Serial.println("Forcing Config Mode"); - forceConfigMode(); - } - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - IPAddress ip = WiFi.localIP(); - Serial.println(ip); - -} - -bool loadConfig() { - File configFile = SPIFFS.open("/config.json", "r"); - if (!configFile) { - Serial.println("Failed to open config file"); - return false; - } - - size_t size = configFile.size(); - if (size > 1024) { - Serial.println("Config file size is too large"); - return false; - } - - // Allocate a buffer to store contents of the file. - std::unique_ptr buf(new char[size]); - - configFile.readBytes(buf.get(), size); - - StaticJsonBuffer<200> jsonBuffer; - JsonObject& json = jsonBuffer.parseObject(buf.get()); - - if (!json.success()) { - Serial.println("Failed to parse config file"); - return false; - } - - strcpy(apiKey, json["apiKey"]); - strcpy(channelId, json["channelId"]); - return true; -} - -bool saveConfig() { - StaticJsonBuffer<200> jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - json["apiKey"] = apiKey; - json["channelId"] = channelId; - - File configFile = SPIFFS.open("/config.json", "w"); - if (!configFile) { - Serial.println("Failed to open config file for writing"); - return false; - } - - json.printTo(configFile); - return true; -} - -void forceConfigMode() { - Serial.println("Reset"); - WiFi.disconnect(); - Serial.println("Dq"); - delay(500); - ESP.restart(); - delay(5000); -} - -void loop() { - - if (digitalRead(resetConfigPin) == HIGH) { - forceConfigMode(); - } - if (millis() - api_lasttime > api_mtbs) { - if(api->getChannelStatistics(channelId)) - { - Serial.println("---------Stats---------"); - Serial.print("Subscriber Count: "); - Serial.println(api->channelStats.subscriberCount); - Serial.print("View Count: "); - Serial.println(api->channelStats.viewCount); - Serial.print("Comment Count: "); - Serial.println(api->channelStats.commentCount); - Serial.print("Video Count: "); - Serial.println(api->channelStats.videoCount); - // Probably not needed :) - //Serial.print("hiddenSubscriberCount: "); - //Serial.println(api->channelStats.hiddenSubscriberCount); - Serial.println("------------------------"); - - } - api_lasttime = millis(); - } -} diff --git a/examples/ESP8266/ChannelStatisticsWithWifiManagerAndDoubleReset/ChannelStatisticsWithWifiManagerAndDoubleReset.ino b/examples/ESP8266/ChannelStatisticsWithWifiManagerAndDoubleReset/ChannelStatisticsWithWifiManagerAndDoubleReset.ino deleted file mode 100644 index 93c9c74..0000000 --- a/examples/ESP8266/ChannelStatisticsWithWifiManagerAndDoubleReset/ChannelStatisticsWithWifiManagerAndDoubleReset.ino +++ /dev/null @@ -1,213 +0,0 @@ -/******************************************************************* - * Read YouTube Channel statistics from the YouTube API * - * This sketch uses the WiFiManager Library for configuraiton * - * Using DoubleResetDetector to launch config mode * - * * - * By Brian Lough * - * https://www.youtube.com/channel/UCezJOfu7OtqGzd5xrP3q6WA * - *******************************************************************/ - -#include -#include -#include - - -#include -// For entering Config mode by pressing reset twice -// Available on the library manager (DoubleResetDetector) -// https://github.com/datacute/DoubleResetDetector - -#include -// Required for the YouTubeApi and used for the config file -// Available on the library manager (ArduinoJson) -// https://github.com/bblanchon/ArduinoJson - -#include -// For configuring the Wifi credentials without re-programing -// Availalbe on library manager (WiFiManager) -// https://github.com/tzapu/WiFiManager - -// For storing configurations -#include "FS.h" - -// Additional libraries needed by WiFiManager -#include //Local DNS Server used for redirecting all rs to the configuration portal -#include //Local WebServer used to serve the configuration portal - -char apiKey[45] = ""; -char channelId[30] = "UCezJOfu7OtqGzd5xrP3q6WA"; - -WiFiClientSecure client; -YoutubeApi *api; - -unsigned long api_mtbs = 60000; //mean time between api requests -unsigned long api_lasttime; //last time api request has been done - -long subs = 0; - -// flag for saving data -bool shouldSaveConfig = false; - -// Number of seconds after reset during which a -// subseqent reset will be considered a double reset. -// This sketch uses drd.stop() rather than relying on the timeout -#define DRD_TIMEOUT 10 - -// RTC Memory Address for the DoubleResetDetector to use -#define DRD_ADDRESS 0 - -DoubleResetDetector drd(DRD_TIMEOUT, DRD_ADDRESS); - -//callback notifying us of the need to save config -void saveConfigCallback () { - Serial.println("Should save config"); - shouldSaveConfig = true; -} - -void configModeCallback (WiFiManager *myWiFiManager) { - Serial.println("Entered config mode"); - Serial.println(WiFi.softAPIP()); - - // You could indicate on your screen or by an LED you are in config mode here - - // We don't want the next time the boar resets to be considered a double reset - // so we remove the flag - drd.stop(); -} - -void setup() { - - Serial.begin(115200); - - if (!SPIFFS.begin()) { - Serial.println("Failed to mount FS"); - return; - } - - pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output - digitalWrite(LED_BUILTIN, LOW); // Turn the LED on (Note that LOW is the voltage level - loadConfig(); - - WiFiManager wifiManager; - wifiManager.setAPCallback(configModeCallback); - wifiManager.setSaveConfigCallback(saveConfigCallback); - - // Adding an additional config on the WIFI manager webpage for the API Key and Channel ID - WiFiManagerParameter customApiKey("apiKey", "API Key", apiKey, 50); - WiFiManagerParameter customChannelId("channelId", "Channel ID", channelId, 35); - wifiManager.addParameter(&customApiKey); - wifiManager.addParameter(&customChannelId); - - if (drd.detectDoubleReset()) { - Serial.println("Double Reset Detected"); - wifiManager.startConfigPortal("YouTube-Counter", "supersecret"); - } else { - Serial.println("No Double Reset Detected"); - wifiManager.autoConnect("YouTube-Counter", "supersecret"); - } - - strcpy(apiKey, customApiKey.getValue()); - strcpy(channelId, customChannelId.getValue()); - - if (shouldSaveConfig) { - saveConfig(); - } - - digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH - // Force Config mode if there is no API key - if(strcmp(apiKey, "") > 0) { - Serial.println("Init YouTube API"); - api = new YoutubeApi(apiKey, client); - } else { - Serial.println("Forcing Config Mode"); - forceConfigMode(); - } - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - IPAddress ip = WiFi.localIP(); - Serial.println(ip); - - drd.stop(); - -} - -bool loadConfig() { - File configFile = SPIFFS.open("/config.json", "r"); - if (!configFile) { - Serial.println("Failed to open config file"); - return false; - } - - size_t size = configFile.size(); - if (size > 1024) { - Serial.println("Config file size is too large"); - return false; - } - - // Allocate a buffer to store contents of the file. - std::unique_ptr buf(new char[size]); - - configFile.readBytes(buf.get(), size); - - StaticJsonBuffer<200> jsonBuffer; - JsonObject& json = jsonBuffer.parseObject(buf.get()); - - if (!json.success()) { - Serial.println("Failed to parse config file"); - return false; - } - - strcpy(apiKey, json["apiKey"]); - strcpy(channelId, json["channelId"]); - return true; -} - -bool saveConfig() { - StaticJsonBuffer<200> jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - json["apiKey"] = apiKey; - json["channelId"] = channelId; - - File configFile = SPIFFS.open("/config.json", "w"); - if (!configFile) { - Serial.println("Failed to open config file for writing"); - return false; - } - - json.printTo(configFile); - return true; -} - -void forceConfigMode() { - Serial.println("Reset"); - WiFi.disconnect(); - Serial.println("Dq"); - delay(500); - ESP.restart(); - delay(5000); -} - -void loop() { - - if (millis() - api_lasttime > api_mtbs) { - if(api->getChannelStatistics(channelId)) - { - Serial.println("---------Stats---------"); - Serial.print("Subscriber Count: "); - Serial.println(api->channelStats.subscriberCount); - Serial.print("View Count: "); - Serial.println(api->channelStats.viewCount); - Serial.print("Comment Count: "); - Serial.println(api->channelStats.commentCount); - Serial.print("Video Count: "); - Serial.println(api->channelStats.videoCount); - // Probably not needed :) - //Serial.print("hiddenSubscriberCount: "); - //Serial.println(api->channelStats.hiddenSubscriberCount); - Serial.println("------------------------"); - - } - api_lasttime = millis(); - } -} diff --git a/src/YoutubeApi.cpp b/src/YoutubeApi.cpp index 58c7ee5..acbe6df 100644 --- a/src/YoutubeApi.cpp +++ b/src/YoutubeApi.cpp @@ -71,7 +71,6 @@ int YoutubeApi::sendGetToYoutube(char *command) { bool YoutubeApi::getChannelStatistics(String channelId){ - Serial.println("Deprecated, user a char* rather than String"); int strLen = channelId.length() + 1; char tempStr[strLen]; channelId.toCharArray(tempStr, strLen); diff --git a/src/YoutubeApi.h b/src/YoutubeApi.h index a8d3b47..99e4b4e 100644 --- a/src/YoutubeApi.h +++ b/src/YoutubeApi.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2017 Brian Lough. All right reserved. +Copyright (c) 2020 Brian Lough. All right reserved. YoutubeApi - An Arduino wrapper for the YouTube API @@ -18,16 +18,6 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#if defined(__GNUC__) || defined(__clang__) -#define DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) -#define DEPRECATED __declspec(deprecated) -#else -#pragma message("WARNING: You need to implement DEPRECATED for this compiler") -#define DEPRECATED -#endif - - #ifndef YoutubeApi_h #define YoutubeApi_h