Skip to content

Commit

Permalink
adapt to recent changes in Yahoo Finance Quotes API
Browse files Browse the repository at this point in the history
- fetch required cookies and crumb for V7 url
- set API default version to 7
  • Loading branch information
thegli committed May 25, 2023
1 parent cf00f92 commit ac7b729
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 26 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ Check out the desklet configuration settings, and choose the data refresh period

## Release Notes

### 0.8.5 - May 25, 2023

Bugfixes:

- adapt to recent changes in Yahoo Finance Quotes API

### 0.8.4 - May 8, 2023

Features:
Expand Down
143 changes: 125 additions & 18 deletions files/yfquotes@thegli/desklet.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const UUID = "yfquotes@thegli";
const DESKLET_DIR = imports.ui.deskletManager.deskletMeta[UUID].path;
const ABSENT = "N/A";
const YF_PAGE = "https://finance.yahoo.com/quote/";
const ERROR_RESPONSE_BEGIN="{\"quoteResponse\":{\"result\":[],\"error\":\"";
const ERROR_RESPONSE_END = "\"}}";

Gettext.bindtextdomain(UUID, GLib.get_home_dir() + "/.local/share/locale");

Expand All @@ -41,6 +43,11 @@ if (Soup.MAJOR_VERSION == 2) {
} else { //version 3
_httpSession = new Soup.Session();
}
_httpSession.timeout = 10;
_httpSession.idle_timeout = 10;

let _cookieStore = null;
let _crumb = null;

function _(str) {
return Gettext.dgettext(UUID, str);
Expand Down Expand Up @@ -70,31 +77,104 @@ let YahooFinanceQuoteReader = function () {};
YahooFinanceQuoteReader.prototype = {
constructor : YahooFinanceQuoteReader,

getAsyncResponse : function(quoteSymbols, apiVersion, callback) {
getCookie : function (callback) {
let here = this;
let message = Soup.Message.new("GET", "https://finance.yahoo.com/quote/%5EGSPC/options");
if (Soup.MAJOR_VERSION === 2) {
message.request_headers.append("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
message.request_headers.append("Accept-Encoding", "gzip, deflate");
_httpSession.queue_message(message, function (session, message) {
try {
callback.call(here, message);
} catch(e) {
global.logError(e);
}
});
} else { //version 3, untested!
message.get_request_headers().append("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
message.get_request_headers().append("Accept-Encoding", "gzip, deflate");
_httpSession.send_and_read_async(message, Soup.MessagePriority.NORMAL, null, function (session, result) {
try {
const bytes = _httpSession.send_and_read_finish(result);
callback.call(here, ByteArray.toString(bytes.get_data()));
} catch(e) {
global.logError(e);
}
});
}
},

getCrumb : function (callback) {
let here = this;
let message = Soup.Message.new("GET", "https://query2.finance.yahoo.com/v1/test/getcrumb");
if (Soup.MAJOR_VERSION === 2) {
message.request_headers.append("Accept", "*/*");
message.request_headers.append("Accept-Encoding", "gzip, deflate");
if (_cookieStore != null) {
Soup.cookies_to_request(_cookieStore, message);
}
_httpSession.queue_message(message, function (session, message) {
if (message.status_code === Soup.KnownStatusCode.OK) {
try {
callback.call(here, message.response_body);
} catch(e) {
global.logError(e);
}
} else {
global.logWarning("Error retrieving crumb! Status: " + message.status_code + ": " + message.reason_phrase);
callback.call(here, null);
}
});
} else { //version 3, untested!
message.get_request_headers().append("Accept", "*/*");
message.get_request_headers().append("Accept-Encoding", "gzip, deflate");
if (_cookieStore != null) {
Soup.cookies_to_request(_cookieStore, message);
}
_httpSession.send_and_read_async(message, Soup.MessagePriority.NORMAL, null, function (session, result) {
if( message.get_status() === Soup.Status.OK) {
try {
const bytes = _httpSession.send_and_read_finish(result);
callback.call(here, ByteArray.toString(bytes.get_data()));
} catch(e) {
global.logError(e);
}
} else {
global.logWarning("Error retrieving crumb! Status: " + message.get_status() + ": " + message.get_reason_phrase());
callback.call(here, null);
}
});
}
},

getFinanceData : function (quoteSymbols, apiVersion, callback) {
const requestUrl = this.createYahooQueryUrl(apiVersion, quoteSymbols);
const errorBegin="{\"quoteResponse\":{\"result\":[],\"error\":\"";
const errorEnd = "\"}}";

let here = this;
let message = Soup.Message.new("GET", requestUrl);
_httpSession.timeout = 10;
_httpSession.idle_timeout = 10;
if (Soup.MAJOR_VERSION === 2) {
if (apiVersion !== "6" && _cookieStore != null) {
Soup.cookies_to_request(_cookieStore, message);
}

_httpSession.queue_message(message, function (session, message) {
if( message.status_code === 200) {
if( message.status_code === Soup.KnownStatusCode.OK) {
try {
callback.call(here, message.response_body.data.toString());
} catch(e) {
global.logError(e);
}
} else {
global.logWarning("Error retrieving url " + requestUrl + ". Status: " + message.status_code + ": " + message.reason_phrase);
callback.call(here, errorBegin + _("Yahoo Finance service not available!") + errorEnd);
callback.call(here, here.buildErrorResponse(_("Yahoo Finance service not available!")));
}
});
} else { //version 3
} else { //version 3, untested!
if (apiVersion !== "6" && _cookieStore != null) {
Soup.cookies_to_request(_cookieStore, message);
}

_httpSession.send_and_read_async(message, Soup.MessagePriority.NORMAL, null, function (session, result) {
if( message.get_status() === 200) {
if( message.get_status() === Soup.Status.OK) {
try {
const bytes = _httpSession.send_and_read_finish(result);
callback.call(here, ByteArray.toString(bytes.get_data()));
Expand All @@ -103,14 +183,22 @@ YahooFinanceQuoteReader.prototype = {
}
} else {
global.logWarning("Error retrieving url " + requestUrl + ". Status: " + message.get_status() + ": " + message.get_reason_phrase());
callback.call(here, errorBegin + _("Yahoo Finance service not available!") + errorEnd);
callback.call(here, here.buildErrorResponse(_("Yahoo Finance service not available!")));
}
});
}
},

createYahooQueryUrl : function (apiVersion, quoteSymbols) {
return "https://query1.finance.yahoo.com/v" + apiVersion + "/finance/quote?symbols=" + quoteSymbols.join(",");
if (apiVersion === "6") {
return "https://query1.finance.yahoo.com/v6/finance/quote?symbols=" + quoteSymbols.join(",");
} else {
return "https://query1.finance.yahoo.com/v7/finance/quote?symbols=" + quoteSymbols.join(",") + "&crumb=" + _crumb;
}
},

buildErrorResponse : function (errorMsg) {
return ERROR_RESPONSE_BEGIN + errorMsg + ERROR_RESPONSE_END;
}
};

Expand Down Expand Up @@ -469,18 +557,37 @@ StockQuoteDesklet.prototype = {

onUpdate : function () {
const quoteSymbols = this.quoteSymbolsText.split("\n");
const yfApiVersion = this.apiVersion ? this.apiVersion : "6";
const yfApiVersion = this.apiVersion ? this.apiVersion : "7";
try {
const _that = this;
this.quoteReader.getAsyncResponse(quoteSymbols, yfApiVersion, function(response) {
let parsedResponse = JSON.parse(response);
_that.render([parsedResponse.quoteResponse.result, parsedResponse.quoteResponse.error]);
_that.setUpdateTimer();
});

if (yfApiVersion !== "6" && (_cookieStore == null || _crumb == null)) {
this.quoteReader.getCookie(function(responseMessage) {
_cookieStore = Soup.cookies_from_response(responseMessage);

_that.quoteReader.getCrumb(function(responseBody) {
if (responseBody) {
_crumb = responseBody.data.toString();
}
_that.renderFinanceData(quoteSymbols, yfApiVersion);
});
});
} else {
_that.renderFinanceData(quoteSymbols, yfApiVersion);
}
} catch (err) {
this.onError(quoteSymbols, err);
}
},

renderFinanceData : function (quoteSymbols, yfApiVersion) {
const _that = this;
this.quoteReader.getFinanceData(quoteSymbols, yfApiVersion, function(response) {
let parsedResponse = JSON.parse(response);
_that.render([parsedResponse.quoteResponse.result, parsedResponse.quoteResponse.error]);
_that.setUpdateTimer();
});
},

setUpdateTimer : function () {
this.updateLoop = Mainloop.timeout_add(this.delayMinutes * 60 * 1000, Lang.bind(this, this.onUpdate));
Expand Down
2 changes: 1 addition & 1 deletion files/yfquotes@thegli/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"name": "Yahoo Finance Quotes",
"prevent-decorations": true,
"max-instances": "10",
"version": "0.8.4",
"version": "0.8.5",
"uuid": "yfquotes@thegli"
}
12 changes: 6 additions & 6 deletions files/yfquotes@thegli/po/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-05-08 21:58+0200\n"
"POT-Creation-Date: 2023-05-25 23:25+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand All @@ -16,23 +16,23 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: desklet.js:92 desklet.js:106
#: desklet.js:168 desklet.js:186
msgid "Yahoo Finance service not available!"
msgstr ""

#: desklet.js:438
#: desklet.js:526
msgid "Updated at "
msgstr ""

#: desklet.js:445
#: desklet.js:533
msgid "Error: "
msgstr ""

#: desklet.js:490
#: desklet.js:597
msgid "Cannot display quotes information for symbols: "
msgstr ""

#: desklet.js:491
#: desklet.js:598
msgid "The following error occurred: "
msgstr ""

Expand Down
2 changes: 1 addition & 1 deletion files/yfquotes@thegli/settings-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
},
"apiVersion": {
"type": "radiogroup",
"default": "6",
"default": "7",
"options": {
"V6": "6",
"V7": "7"
Expand Down

0 comments on commit ac7b729

Please sign in to comment.