rss-bridge/bridges/NintendoBridge.php

490 lines
18 KiB
PHP
Raw Normal View History

<?php
class NintendoBridge extends XPathAbstract
{
const NAME = 'Nintendo Software Updates';
const URI = 'https://www.nintendo.co.uk/Support/Welcome-to-Nintendo-Support-11593.html';
const DESCRIPTION = self::NAME;
const MAINTAINER = 'Niehztog';
const PARAMETERS = [
'' => [
'category' => [
'name' => 'Category',
'type' => 'list',
'values' => [
'All' => 'all',
'Mario Kart 8 Deluxe' => 'mk8d',
'Splatoon 2' => 's2',
'Super Mario 3D All-Stars' => 'sm3as',
'Super Mario 3D World + Bowsers Fury' => 'sm3wbf',
'Super Mario Bros. Wonder' => 'smbw',
'Super Mario Maker 2' => 'smm2',
'Super Mario Odyssey' => 'smo',
'Super Smash Bros. Ultimate' => 'ssbu',
'Switch Firmware' => 'sf',
'The Legend of Zelda: Links Awakening' => 'tlozla',
'The Legend of Zelda: Skyward Sword HD' => 'tlozss',
'The Legend of Zelda: Tears of the Kingdom' => 'tloztotk',
'Xenoblade Chronicles 2' => 'xc2',
],
'defaultValue' => 'mk8d',
'title' => 'Select category'
],
'country' => [
'name' => 'Country',
'type' => 'list',
'values' => [
'België' => 'be/nl',
'Belgique' => 'be/fr',
'Deutschland' => 'de',
'España' => 'es',
'France' => 'fr',
'Italia' => 'it',
'Nederland' => 'nl',
'Österreich' => 'at',
'Portugal' => 'pt',
'Schweiz' => 'ch/de',
'Suisse' => 'ch/fr',
'Svizzera' => 'ch/it',
'UK & Ireland' => 'co.uk',
'South Africa' => 'co.za'
],
'defaultValue' => 'co.uk',
'title' => 'Select your country'
]
]
];
const CACHE_TIMEOUT = 3600;
const FEED_SOURCE_URL = [
'mk8d' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-Mario-Kart-8-Deluxe-1482895.html',
's2' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-Splatoon-2-1482897.html',
'sm3as' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-Super-Mario-3D-All-Stars-1844226.html',
'sm3wbf' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-Super-Mario-3D-World-Bowser-s-Fury-1920668.html',
'smbw' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-Super-Mario-Bros-Wonder-2485410.html',
'smm2' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-Super-Mario-Maker-2-1586745.html',
'smo' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-Super-Mario-Odyssey-1482901.html',
'ssbu' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-Super-Smash-Bros-Ultimate-1484130.html',
'sf' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/System-Updates/Nintendo-Switch-System-Updates-and-Change-History-1445507.html',
'tlozla' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-The-Legend-of-Zelda-Link-s-Awakening-1666739.html',
'tlozss' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-The-Legend-of-Zelda-Skyward-Sword-HD-2022801.html',
'tloztotk' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-The-Legend-of-Zelda-Tears-of-the-Kingdom-2388231.html',
'xc2' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/Xenoblade-Chronicles-2-Update-History-1482911.html',
];
const XPATH_EXPRESSION_ITEM = '//div[@class="col-xs-12 content"]/div[starts-with(@id,"v") and @class="collapse"]';
const XPATH_EXPRESSION_ITEM_FIRMWARE = '//div[@id="latest" and @class="collapse" and @rel="1"]';
const XPATH_EXPRESSION_ITEM_TITLE = '(.//h2[1] | .//strong[1])[1]/node()';
const XPATH_EXPRESSION_ITEM_CONTENT = '.';
const XPATH_EXPRESSION_ITEM_URI = '//link[@rel="canonical"]/@href';
//const XPATH_EXPRESSION_ITEM_AUTHOR = '';
const XPATH_EXPRESSION_ITEM_TIMESTAMP_PART = 'substring-after(//a[@class="collapse_link collapsed" and @data-target="#{{id_here}}"]/text(), "{{label_here}}")';
const XPATH_EXPRESSION_ITEM_TIMESTAMP = 'substring(' . self::XPATH_EXPRESSION_ITEM_TIMESTAMP_PART . ', 1, string-length('
. self::XPATH_EXPRESSION_ITEM_TIMESTAMP_PART . ') - 1)';
//const XPATH_EXPRESSION_ITEM_ENCLOSURES = '';
//const XPATH_EXPRESSION_ITEM_CATEGORIES = '';
const SETTING_FIX_ENCODING = false;
const SETTING_USE_RAW_ITEM_CONTENT = true;
private const GAME_COUNTRY_DATE_SUBSTRING_PART = [
'mk8d' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'atée du ',
'it' => 'ubblicata il ',
'nl' => 'itgebracht op ',
'pt' => 'ançada no dia ',
'en' => 'eleased ',
],
's2' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'atée du ',
'it' => 'ubblicata il ',
'nl' => 'itgebracht op ',
'pt' => 'ançada a ',
'en' => 'eleased ',
],
'sm3as' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'ubliée le ',
'it' => 'istribuita il ',
'nl' => 'itgebracht op ',
'pt' => 'ançada a ',
'en' => 'eleased ',
],
'sm3wbf' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'atée du ',
'it' => 'istribuita il ',
'nl' => 'itgebracht op ',
'pt' => 'ançada no dia ',
'en' => 'eleased ',
],
'smbw' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'atée du ',
'it' => 'istribuita il ',
'nl' => 'itgebracht op ',
'pt' => 'ançada a ',
'en' => 'eleased ',
],
'smm2' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'ubliée le ',
'it' => 'istribuita il ',
'nl' => 'itgebracht op ',
'pt' => 'ançada no dia ',
'en' => 'eleased ',
],
'smo' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'atée du ',
'it' => 'istribuita il ',
'nl' => 'itgebracht op ',
'pt' => 'ançada no dia ',
'en' => 'eleased ',
],
'ssbu' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'atée du ',
'it' => 'istribuita il ',
'nl' => 'itgebracht op ',
'pt' => 'ançada no dia ',
'en' => 'eleased ',
],
'sf' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'ise en ligne le ',
'it' => 'ubblicata il ',
'nl' => 'itgebracht op ',
'pt' => 'ançada no dia ',
'en' => 'istributed ',
],
'tlozla' => [
'de' => 'eröffentlicht ',
'es' => 'ublicada el ',
'fr' => 'atée du ',
'it' => 'istribuita il ',
'nl' => 'itgegeven op ',
'pt' => 'ançada a ',
'en' => 'eleased ',
],
'tlozss' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'atée du ',
'it' => 'ubblicata l\'',
'nl' => 'itgebracht op ',
'pt' => 'ançada a ',
'en' => 'eleased ',
],
'tloztotk' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'ubliée le ',
'it' => 'ubblicata il ',
'nl' => 'erschenen op ',
'pt' => 'ançada a ',
'en' => 'eleased ',
],
'xc2' => [
'de' => 'eröffentlicht am ',
'es' => 'isponible desde el ',
'fr' => 'atée du ',
'it' => 'istribuita il ',
'nl' => 'itgebracht op ',
'pt' => 'ançada a ',
'en' => 'eleased ',
],
];
private const GAME_COUNTRY_DATE_FORMAT = [
'mk8d' => [
'de' => 'd.m.y',
'es' => 'd-m-y',
'fr' => 'd/m/Y',
'it' => 'd/m/y',
'nl' => 'd m Y',
'pt' => 'd/m/y',
'en' => 'd/m/y',
],
's2' => [
'de' => 'd.m.Y',
'es' => 'd-m-Y',
'fr' => 'd/m/y',
'it' => 'd/m/y',
'nl' => 'd/m/y',
'pt' => 'd/m/y',
'en' => 'd F Y',
],
'sm3as' => [
'de' => 'j. m Y',
'es' => 'j \d\e m \d\e Y',
'fr' => 'j m Y',
'it' => 'j m Y',
'nl' => 'j m Y',
'pt' => 'j \d\e m \d\e Y',
'en' => 'j F Y',
],
'sm3wbf' => [
'de' => 'd.m.y',
'es' => 'd-m-y',
'fr' => 'd/m/y',
'it' => 'd/m/y',
'nl' => 'd m Y',
'pt' => 'd/m/y',
'en' => 'F j, Y',
],
'smbw' => [
'de' => 'd. m Y',
'es' => 'j \d\e m \d\e Y',
'fr' => 'd/m/Y',
'it' => 'j m Y',
'nl' => 'd m Y',
'pt' => 'j \d\e m \d\e Y',
'en' => 'j F Y',
],
'smm2' => [
'de' => 'd.m.Y',
'es' => 'd-m-Y',
'fr' => 'd/m/Y',
'it' => 'd/m/Y',
'nl' => 'd m Y',
'pt' => 'd/m/y',
'en' => 'd/m/y',
],
'smo' => [
'de' => 'd.m.Y',
'es' => 'd-m-Y',
'fr' => 'd/m/Y',
'it' => 'd/m/y',
'nl' => 'd m Y',
'pt' => 'd/m/y',
'en' => 'd/m/y',
],
'ssbu' => [
'de' => 'd. m Y',
'es' => 'j \d\e m \d\e Y',
'fr' => 'j m Y',
'it' => 'j m Y',
'nl' => 'd m Y',
'pt' => 'd/m/Y',
'en' => 'j F Y',
],
'sf' => [
'de' => 'd.m.Y',
'es' => 'd-m-y',
'fr' => 'd/m/Y',
'it' => 'd/m/Y',
'nl' => 'd m Y',
'pt' => 'd/m/Y',
'en' => 'd/m/Y',
],
'tlozla' => [
'de' => 'd. m Y',
'es' => 'j m \d\e Y',
'fr' => 'd/m/y',
'it' => 'j m Y',
'nl' => 'd m Y',
'pt' => 'j \d\e m \d\e Y',
'en' => 'j F y',
],
'tlozss' => [
'de' => 'd. m Y',
'es' => 'j \d\e m \d\e Y',
'fr' => 'd/m/y',
'it' => 'j m Y',
'nl' => 'd m Y',
'pt' => 'j \d\e m \d\e Y',
'en' => 'j F Y',
],
'tloztotk' => [
'de' => 'd. m Y',
'es' => 'j \d\e m \d\e Y',
'fr' => 'j m Y',
'it' => 'j m Y',
'nl' => 'd m Y',
'pt' => 'j \d\e m \d\e Y',
'en' => 'j F Y',
],
'xc2' => [
'de' => 'd.m.y',
'es' => 'd-m-y',
'fr' => 'd/m/Y',
'it' => 'd/m/y',
'nl' => 'd m Y',
'pt' => 'd/m/y',
'en' => 'd/m/y',
],
];
private const FOREIGN_MONTH_NAMES = [
'nl' => ['01' => 'januari', '02' => 'februari', '03' => 'maart', '04' => 'april', '05' => 'mei', '06' => 'juni', '07' => 'juli', '08' => 'augustus',
'09' => 'september', '10' => 'oktober', '11' => 'november', '12' => 'december'],
'fr' => ['01' => 'janvier', '02' => 'février', '03' => 'mars', '04' => 'avril', '05' => 'mai', '06' => 'juin', '07' => 'juillet', '08' => 'août',
'09' => 'septembre', '10' => 'octobre', '11' => 'novembre', '12' => 'décembre'],
'de' => ['01' => 'Januar', '02' => 'Februar', '03' => 'März', '04' => 'April', '05' => 'Mai', '06' => 'Juni', '07' => 'Juli', '08' => 'August',
'09' => 'September', '10' => 'Oktober', '11' => 'November', '12' => 'Dezember'],
'es' => ['01' => 'enero', '02' => 'febrero', '03' => 'marzo', '04' => 'abril', '05' => 'mayo', '06' => 'junio', '07' => 'julio', '08' => 'agosto',
'09' => 'septiembre', '10' => 'octubre', '11' => 'noviembre', '12' => 'diciembre'],
'it' => ['01' => 'gennaio', '02' => 'febbraio', '03' => 'marzo', '04' => 'aprile', '05' => 'maggio', '06' => 'giugno', '07' => 'luglio', '08' => 'agosto',
'09' => 'settembre', '10' => 'ottobre', '11' => 'novembre', '12' => 'dicembre'],
'pt' => ['01' => 'janeiro', '02' => 'fevereiro', '03' => 'março', '04' => 'abril', '05' => 'maio', '06' => 'junho', '07' => 'julho', '08' => 'agosto',
'09' => 'setembro', '10' => 'outubro', '11' => 'novembro', '12' => 'dezembro'],
];
const LANGUAGE_REWRITE = ['co.uk' => 'en', 'co.za' => 'en', 'at' => 'de'];
private string $lastId = '';
private ?string $currentCategory = '';
private function getCurrentCategory()
{
if (empty($this->currentCategory)) {
$category = $this->getInput('category');
$this->currentCategory = empty($category) ? self::PARAMETERS['']['category']['defaultValue'] : $category;
}
return $this->currentCategory;
}
public function getIcon()
{
return 'https://www.nintendo.co.uk/favicon.ico';
}
public function getURI()
{
$category = $this->getInput('category');
if ('all' === $category) {
return self::URI;
} else {
return $this->getSourceUrl();
}
}
protected function provideFeedTitle(\DOMXPath $xpath)
{
$category = $this->getInput('category');
$categoryName = array_search($category, self::PARAMETERS['']['category']['values']);
return 'all' === $category ? self::NAME : $categoryName . ' Software-Updates';
}
protected function getSourceUrl()
{
$country = $this->getInput('country') ?? '';
$category = $this->getCurrentCategory();
return str_replace(self::PARAMETERS['']['country']['defaultValue'], $country, self::FEED_SOURCE_URL[$category]);
}
protected function getExpressionItem()
{
$category = $this->getCurrentCategory();
return 'sf' === $category ? self::XPATH_EXPRESSION_ITEM_FIRMWARE : self::XPATH_EXPRESSION_ITEM;
}
protected function getExpressionItemTimestamp()
{
if (empty($this->lastId)) {
return null;
}
$country = $this->getInput('country');
$category = $this->getCurrentCategory();
$language = $this->getLanguageFromCountry($country);
return str_replace(
['{{id_here}}', '{{label_here}}'],
[$this->lastId, static::GAME_COUNTRY_DATE_SUBSTRING_PART[$category][$language]],
static::XPATH_EXPRESSION_ITEM_TIMESTAMP
);
}
protected function getExpressionItemCategories()
{
$category = $this->getCurrentCategory();
$categoryName = array_search($category, self::PARAMETERS['']['category']['values']);
return 'string("' . $categoryName . '")';
}
public function collectData()
{
$category = $this->getCurrentCategory();
if ('all' === $category) {
$allItems = [];
foreach (self::PARAMETERS['']['category']['values'] as $catKey) {
if ('all' === $catKey) {
continue;
}
$this->currentCategory = $catKey;
$this->items = [];
parent::collectData();
$allItems = [...$allItems, ...$this->items];
}
$this->currentCategory = 'all';
$this->items = $allItems;
} else {
parent::collectData();
}
}
protected function formatItemTitle($value)
{
if (false !== strpos($value, ' (')) {
$value = substr($value, 0, strpos($value, ' ('));
}
if ('all' === $this->getInput('category')) {
$category = $this->getCurrentCategory();
$categoryName = array_search($category, self::PARAMETERS['']['category']['values']);
return $categoryName . ' ' . $value;
}
return $value;
}
protected function formatItemContent($value)
{
$result = preg_match('~<div class="collapse" id="([a-z0-9]+)" rel="1">(.*)</div>~', $value, $matches);
if (1 === $result) {
$this->lastId = $matches[1];
return trim($matches[2]);
}
return $value;
}
protected function formatItemTimestamp($value)
{
$country = $this->getInput('country');
$category = $this->getCurrentCategory();
$language = $this->getLanguageFromCountry($country);
$aMonthNames = self::FOREIGN_MONTH_NAMES[$language] ?? null;
if (null !== $aMonthNames) {
$value = str_replace(array_values($aMonthNames), array_keys($aMonthNames), $value);
}
$value = str_replace('­', '-', $value);
$value = str_replace('--', '-', $value);
$date = \DateTime::createFromFormat(self::GAME_COUNTRY_DATE_FORMAT[$category][$language], $value);
if (false === $date) {
$date = new \DateTime('now');
}
return $date->getTimestamp();
}
protected function generateItemId(array $item)
{
return $this->getCurrentCategory() . '-' . $this->lastId;
}
private function getLanguageFromCountry($country)
{
return (strpos($country, '/') !== false) ? substr($country, strpos($country, '/') + 1) : (self::LANGUAGE_REWRITE[$country] ?? $country);
}
}