2023-10-30 13:47:25 +03:00
< ? 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 + Bowser’ s Fury' => 'sm3wbf' ,
2023-11-30 19:53:47 +03:00
'Super Mario Bros. Wonder' => 'smbw' ,
2023-10-30 13:47:25 +03:00
'Super Mario Maker 2' => 'smm2' ,
'Super Mario Odyssey' => 'smo' ,
'Super Smash Bros. Ultimate' => 'ssbu' ,
'Switch Firmware' => 'sf' ,
'The Legend of Zelda: Link’ s 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' ,
2023-11-30 19:53:47 +03:00
'smbw' => 'https://www.nintendo.co.uk/Support/Nintendo-Switch/Game-Updates/How-to-Update-Super-Mario-Bros-Wonder-2485410.html' ,
2023-10-30 13:47:25 +03:00
'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"]' ;
2023-11-30 19:53:47 +03:00
const XPATH_EXPRESSION_ITEM_TITLE = '(.//h2[1] | .//strong[1])[1]/node()' ;
2023-10-30 13:47:25 +03:00
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 ' ,
],
2023-11-30 19:53:47 +03:00
'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 ' ,
],
2023-10-30 13:47:25 +03:00
'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' ,
],
2023-11-30 19:53:47 +03:00
'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' ,
],
2023-10-30 13:47:25 +03:00
'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' );
2024-01-24 01:02:06 +03:00
if ( 'all' === $category ) {
return self :: URI ;
} else {
return $this -> getSourceUrl ();
}
2023-10-30 13:47:25 +03:00
}
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 ()
{
2024-01-24 01:02:06 +03:00
$country = $this -> getInput ( 'country' ) ? ? '' ;
2023-10-30 13:47:25 +03:00
$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 ( FeedItem $item )
{
return $this -> getCurrentCategory () . '-' . $this -> lastId ;
}
private function getLanguageFromCountry ( $country )
{
return ( strpos ( $country , '/' ) !== false ) ? substr ( $country , strpos ( $country , '/' ) + 1 ) : ( self :: LANGUAGE_REWRITE [ $country ] ? ? $country );
}
}