diff --git a/resources/translations/cs.txt b/resources/translations/cs.txt index 6185b574..69552421 100644 --- a/resources/translations/cs.txt +++ b/resources/translations/cs.txt @@ -673,7 +673,7 @@ countries: cz "Not running: %1" = "Neběží: %1" "Running. Open on this network:" = "Běží. Otevřete v této síti:" "Running. Open on this computer:" = "Běží. Otevřete na tomto počítači:" -"Reads the newest version's number from masterpieceorgan.com, a few bytes, and offers the download page when it is newer. Nothing about you is sent." = "Načte číslo nejnovější verze z masterpieceorgan.com, pár bajtů, a nabídne stránku ke stažení, když je novější. O vás se nic neodesílá." +"Reads the newest version's number from GitHub and offers its download page when it is newer. Nothing about you is sent." = "Načte číslo nejnovější verze z GitHubu a nabídne její stránku ke stažení, když je novější. O vás se nic neodesílá." "Drive a console display" = "Ovládat displej hracího stolu" "Send to display" = "Odeslat na displej" "What was there before is saved in %1." = "To, co tam bylo dříve, je uloženo v %1." diff --git a/resources/translations/de.txt b/resources/translations/de.txt index 243beac3..ec0fa2e3 100644 --- a/resources/translations/de.txt +++ b/resources/translations/de.txt @@ -673,7 +673,7 @@ countries: de at ch li lu "Not running: %1" = "Läuft nicht: %1" "Running. Open on this network:" = "Läuft. In diesem Netzwerk öffnen:" "Running. Open on this computer:" = "Läuft. Auf diesem Computer öffnen:" -"Reads the newest version's number from masterpieceorgan.com, a few bytes, and offers the download page when it is newer. Nothing about you is sent." = "Liest die Nummer der neuesten Version von masterpieceorgan.com, wenige Bytes, und bietet die Download-Seite an, wenn sie neuer ist. Über Sie wird nichts gesendet." +"Reads the newest version's number from GitHub and offers its download page when it is newer. Nothing about you is sent." = "Liest die Nummer der neuesten Version von GitHub und bietet deren Download-Seite an, wenn sie neuer ist. Über Sie wird nichts gesendet." "Drive a console display" = "Spieltisch-Anzeige ansteuern" "Send to display" = "An Anzeige senden" "What was there before is saved in %1." = "Was vorher da war, ist in %1 gesichert." diff --git a/resources/translations/es.txt b/resources/translations/es.txt index a9434773..42df03f1 100644 --- a/resources/translations/es.txt +++ b/resources/translations/es.txt @@ -673,7 +673,7 @@ countries: es ar bo cl co cr cu do ec gt hn mx ni pa pe pr py sv uy ve "Not running: %1" = "No está en marcha: %1" "Running. Open on this network:" = "En marcha. Abrir en esta red:" "Running. Open on this computer:" = "En marcha. Abrir en este ordenador:" -"Reads the newest version's number from masterpieceorgan.com, a few bytes, and offers the download page when it is newer. Nothing about you is sent." = "Lee el número de la versión más reciente en masterpieceorgan.com, unos pocos bytes, y ofrece la página de descarga cuando es más nueva. No se envía nada sobre ti." +"Reads the newest version's number from GitHub and offers its download page when it is newer. Nothing about you is sent." = "Lee el número de la versión más reciente en GitHub y ofrece su página de descarga cuando es más nueva. No se envía nada sobre ti." "Drive a console display" = "Controlar una pantalla de consola" "Send to display" = "Enviar a la pantalla" "What was there before is saved in %1." = "Lo que había antes está guardado en %1." diff --git a/resources/translations/fr.txt b/resources/translations/fr.txt index f9cfa2a4..7d04196a 100644 --- a/resources/translations/fr.txt +++ b/resources/translations/fr.txt @@ -673,7 +673,7 @@ countries: fr be ca ch lu mc "Not running: %1" = "Arrêté : %1" "Running. Open on this network:" = "En marche. Ouvrir sur ce réseau :" "Running. Open on this computer:" = "En marche. Ouvrir sur cet ordinateur :" -"Reads the newest version's number from masterpieceorgan.com, a few bytes, and offers the download page when it is newer. Nothing about you is sent." = "Lit le numéro de la dernière version sur masterpieceorgan.com, quelques octets, et propose la page de téléchargement quand elle est plus récente. Rien sur vous n'est envoyé." +"Reads the newest version's number from GitHub and offers its download page when it is newer. Nothing about you is sent." = "Lit le numéro de la dernière version sur GitHub et propose sa page de téléchargement quand elle est plus récente. Rien sur vous n'est envoyé." "Drive a console display" = "Piloter un afficheur de console" "Send to display" = "Envoyer à l'afficheur" "What was there before is saved in %1." = "Ce qui était là auparavant est enregistré dans %1." diff --git a/resources/translations/it.txt b/resources/translations/it.txt index 5db39d11..4b941387 100644 --- a/resources/translations/it.txt +++ b/resources/translations/it.txt @@ -673,7 +673,7 @@ countries: it ch sm va "Not running: %1" = "Non attivo: %1" "Running. Open on this network:" = "Attivo. Apri in questa rete:" "Running. Open on this computer:" = "In funzione. Aprire su questo computer:" -"Reads the newest version's number from masterpieceorgan.com, a few bytes, and offers the download page when it is newer. Nothing about you is sent." = "Legge il numero della versione più recente da masterpieceorgan.com, pochi byte, e propone la pagina di download quando è più nuova. Nulla su di te viene inviato." +"Reads the newest version's number from GitHub and offers its download page when it is newer. Nothing about you is sent." = "Legge il numero della versione più recente da GitHub e propone la sua pagina di download quando è più nuova. Nulla su di te viene inviato." "Drive a console display" = "Comanda un display della consolle" "Send to display" = "Invia al display" "What was there before is saved in %1." = "Ciò che c\'era prima è salvato in %1." diff --git a/resources/translations/nl.txt b/resources/translations/nl.txt index ce4bebba..1d039ede 100644 --- a/resources/translations/nl.txt +++ b/resources/translations/nl.txt @@ -673,7 +673,7 @@ countries: nl be sr "Not running: %1" = "Draait niet: %1" "Running. Open on this network:" = "Draait. Openen in dit netwerk:" "Running. Open on this computer:" = "Actief. Openen op deze computer:" -"Reads the newest version's number from masterpieceorgan.com, a few bytes, and offers the download page when it is newer. Nothing about you is sent." = "Leest het nummer van de nieuwste versie van masterpieceorgan.com, een paar bytes, en biedt de downloadpagina aan als die nieuwer is. Er wordt niets over jou verstuurd." +"Reads the newest version's number from GitHub and offers its download page when it is newer. Nothing about you is sent." = "Leest het nummer van de nieuwste versie van GitHub en biedt de downloadpagina ervan aan als die nieuwer is. Er wordt niets over jou verstuurd." "Drive a console display" = "Een speeltafeldisplay aansturen" "Send to display" = "Naar display sturen" "What was there before is saved in %1." = "Wat er eerder was, is opgeslagen in %1." diff --git a/resources/translations/pl.txt b/resources/translations/pl.txt index 13b1a978..913dac24 100644 --- a/resources/translations/pl.txt +++ b/resources/translations/pl.txt @@ -673,7 +673,7 @@ countries: pl "Not running: %1" = "Nie działa: %1" "Running. Open on this network:" = "Działa. Otwórz w tej sieci:" "Running. Open on this computer:" = "Działa. Otwórz na tym komputerze:" -"Reads the newest version's number from masterpieceorgan.com, a few bytes, and offers the download page when it is newer. Nothing about you is sent." = "Odczytuje numer najnowszej wersji z masterpieceorgan.com, kilka bajtów, i proponuje stronę pobierania, gdy jest nowsza. Nic o tobie nie jest wysyłane." +"Reads the newest version's number from GitHub and offers its download page when it is newer. Nothing about you is sent." = "Odczytuje numer najnowszej wersji z GitHuba i proponuje jej stronę pobierania, gdy jest nowsza. Nic o tobie nie jest wysyłane." "Drive a console display" = "Steruj wyświetlaczem kontuaru" "Send to display" = "Wyślij na wyświetlacz" "What was there before is saved in %1." = "To, co było wcześniej, zapisano w %1." diff --git a/resources/translations/strings.txt b/resources/translations/strings.txt index ccaa2e67..46e70d72 100644 --- a/resources/translations/strings.txt +++ b/resources/translations/strings.txt @@ -593,7 +593,7 @@ countries: gb us "No log is being written." = "No log is being written." "For keys or pedals that do nothing, or the wrong thing. Until Masterpiece is closed." = "For keys or pedals that do nothing, or the wrong thing. Until Masterpiece is closed." "For a click, a noise or a note that goes on sounding when keys are let go. Until Masterpiece is closed." = "For a click, a noise or a note that goes on sounding when keys are let go. Until Masterpiece is closed." -"Reads the newest version's number from masterpieceorgan.com, a few bytes, and offers the download page when it is newer. Nothing about you is sent." = "Reads the newest version's number from masterpieceorgan.com, a few bytes, and offers the download page when it is newer. Nothing about you is sent." +"Reads the newest version's number from GitHub and offers its download page when it is newer. Nothing about you is sent." = "Reads the newest version's number from GitHub and offers its download page when it is newer. Nothing about you is sent." "Remote control" = "Remote control" "A page any browser on this network can open to draw stops, press pistons and move the shoes, and the API that consoles and scripts use (HTTP, JSON). Off by default." = "A page any browser on this network can open to draw stops, press pistons and move the shoes, and the API that consoles and scripts use (HTTP, JSON). Off by default." "Off, the network can only read: the stops drawn, the levels, the organ loaded." = "Off, the network can only read: the stops drawn, the levels, the organ loaded." diff --git a/src/mp_ui/Settings.cpp b/src/mp_ui/Settings.cpp index 77a9b994..edca6b54 100644 --- a/src/mp_ui/Settings.cpp +++ b/src/mp_ui/Settings.cpp @@ -3275,8 +3275,8 @@ LogPanel::LogPanel(MasterpieceProcessor& p) : proc_(p) { releases_.onClick = [this] { proc_.setReleaseLogging(releases_.getToggleState()); }; addAndMakeVisible(releases_); updates_.setToggleState(proc_.updateCheckEnabled(), juce::dontSendNotification); - updates_.setTooltip(TRANS("Reads the newest version's number from masterpieceorgan.com, a few bytes, " - "and offers the download page when it is newer. Nothing about you is sent.")); + updates_.setTooltip(TRANS("Reads the newest version's number from GitHub and offers its download page " + "when it is newer. Nothing about you is sent.")); updates_.onClick = [this] { proc_.setUpdateCheckEnabled(updates_.getToggleState()); }; addAndMakeVisible(updates_); } diff --git a/src/mp_ui/UpdateCheck.cpp b/src/mp_ui/UpdateCheck.cpp index eab571d5..ddd12b3a 100644 --- a/src/mp_ui/UpdateCheck.cpp +++ b/src/mp_ui/UpdateCheck.cpp @@ -6,8 +6,13 @@ namespace mp::ui { namespace { -const char* const kVersionUrl = "https://masterpieceorgan.com/version.txt"; -const char* const kDownloadUrl = "https://masterpieceorgan.com/#platforms"; +// GitHub's own record of the newest release: drafts and pre-releases are +// left out of "latest". Asked once a day, well inside the hourly allowance +// GitHub gives a request that carries no account. +const char* const kVersionUrl = "https://api.github.com/repos/bonninr/masterpiece/releases/latest"; +const char* const kRequestHeaders = "User-Agent: Masterpiece\r\nAccept: application/vnd.github+json"; +// The newest release's page, with its downloads, on the same host. +const char* const kDownloadUrl = "https://github.com/bonninr/masterpiece/releases/latest"; constexpr int kShownMs = 30000; // The newest version's number, or empty. JUCE fetches it everywhere but on @@ -19,7 +24,8 @@ juce::String fetchLatest() { juce::String text; #if JUCE_LINUX juce::ChildProcess curl; - if (curl.start(juce::StringArray{"curl", "-fsSL", "--max-time", "5", url}, + if (curl.start(juce::StringArray{"curl", "-fsSL", "--max-time", "5", "-H", "User-Agent: Masterpiece", "-H", + "Accept: application/vnd.github+json", url}, juce::ChildProcess::wantStdOut)) { text = curl.readAllProcessOutput(); // returns when curl ends, in 5 s at most if (curl.getExitCode() != 0) text.clear(); @@ -27,12 +33,11 @@ juce::String fetchLatest() { #else const auto options = juce::URL::InputStreamOptions(juce::URL::ParameterHandling::inAddress) .withConnectionTimeoutMs(5000) - .withNumRedirectsToFollow(3); + .withNumRedirectsToFollow(3) + .withExtraHeaders(kRequestHeaders); if (auto in = juce::URL(url).createInputStream(options)) text = in->readEntireStreamAsString(); #endif - // A version, and nothing else: a captive portal's page is not one. - text = text.trim(); - return text.containsOnly("0123456789.") && text.contains(".") && text.length() <= 20 ? text : juce::String(); + return versionFromAnswer(text); } std::vector parts(const juce::String& v) { @@ -43,6 +48,17 @@ std::vector parts(const juce::String& v) { } // namespace +juce::String versionFromAnswer(const juce::String& answer) { + auto text = answer.trim(); + // GitHub's release record names the release by its tag, "v0.9.0". A plain + // number is read as it is: a test server, or a copy given by + // MASTERPIECE_UPDATE_URL. + if (text.startsWithChar('{')) text = juce::JSON::parse(text)["tag_name"].toString().trim(); + if (text.startsWithIgnoreCase("v")) text = text.substring(1); + // A version, and nothing else: a captive portal's page is not one. + return text.containsOnly("0123456789.") && text.contains(".") && text.length() <= 20 ? text : juce::String(); +} + bool isNewerVersion(const juce::String& latest, const juce::String& current) { const auto a = parts(latest), b = parts(current); for (size_t i = 0; i < std::max(a.size(), b.size()); ++i) { diff --git a/src/mp_ui/UpdateCheck.h b/src/mp_ui/UpdateCheck.h index bd4a7bcf..cee0f336 100644 --- a/src/mp_ui/UpdateCheck.h +++ b/src/mp_ui/UpdateCheck.h @@ -1,7 +1,7 @@ // Whether a newer Masterpiece is out, asked once a day. // -// The application reads one short file, masterpieceorgan.com/version.txt, -// which the site's publishing writes with the newest release's number. It +// The application reads GitHub's record of the project's newest release, +// over HTTPS from api.github.com, and takes the number from its tag. It // sends nothing about the player beyond what any request for a web page // carries. When the number is newer than this program's, a notice at the // right of the status bar offers the download page until 30 seconds after @@ -25,6 +25,10 @@ namespace ui { // compared part by part ("0.10.0" is newer than "0.9.2"). bool isNewerVersion(const juce::String& latest, const juce::String& current); +// The version an answer names: GitHub's release record by its tag ("v0.9.0" +// gives "0.9.0"), or a plain number. Empty for anything else. +juce::String versionFromAnswer(const juce::String& answer); + // The check, when the player has it on and a day has passed since the last. // The file is read on a thread of its own; `onNewer` is called on the message // thread with the newer version's number. diff --git a/tests/test_core.cpp b/tests/test_core.cpp index 7aedf3f0..5367262c 100644 --- a/tests/test_core.cpp +++ b/tests/test_core.cpp @@ -13942,6 +13942,18 @@ class UpdateCheckTest final : public mp::test::Test { !isNewerVersion("0.8", "0.8.0"), "the same version, or an older one, is not"); + // The answer: GitHub's release record, named by its tag, or a plain number. + using mp::ui::versionFromAnswer; + MP_CHECK(versionFromAnswer("{\"url\":\"x\",\"tag_name\":\"v0.9.0\",\"name\":\"0.9.0\",\"assets\":[]}") == "0.9.0", + "the release record gives the tag's number, got " + + versionFromAnswer("{\"tag_name\":\"v0.9.0\"}").toStdString()); + MP_CHECK(versionFromAnswer("0.8.1\n") == "0.8.1" && versionFromAnswer("{\"tag_name\":\"0.8.2\"}") == "0.8.2", + "a plain number, and a tag without its v, are read as they are"); + MP_CHECK(versionFromAnswer("Sign in to the network").isEmpty() && + versionFromAnswer("{\"message\":\"API rate limit exceeded\"}").isEmpty() && + versionFromAnswer("{\"tag_name\":\"nightly\"}").isEmpty() && versionFromAnswer("").isEmpty(), + "a portal's page, a refusal, a tag that is not a version, and nothing, give nothing"); + const juce::File global = juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory) .getChildFile("Masterpiece").getChildFile("settings.mpglobal"); const bool had = global.existsAsFile();