Allegro Seller Info 0.1.8

Nastąpiły kolejne zmiany na stronach serwisu aukcyjnego Allegro.pl, zatem przyszła pora na szybkie poprawki w moim user-js-owym skrypcie 'allegro-seller-info.user.js'.

...

Wczoraj zauważyłem ze na listach aukcji nie pojawiają się informacje dodawane przez skrypt. Po szybkim wybadaniu sprawy okazało się, że nieszczęsny obiekt __listing_StoreState_base używany do wykrywania strony z listą zniknął z głównej przestrzeni nazw. Na szczęście, podobnie jak to miało miejsce wcześniej na stronach przedmiotów (czego dotyczyła poprawka w wersji 0.1.7), bez problemu można było oprzeć się na strukturze strony i prostym selektorem załatwić sprawę.

Poprzednio używany w dalszej części skryptu element z klasą opbox-listing--base zawierający w sobie listę ofert nadal istnieje. Teraz tylko jest dostępny pod dedykowanym identyfikatorem i nadal tylko na stronach z listami, więc aktualne wykrywanie takich stron wygląda tak:

// strona z lista aukcji
const listing = document.getElementById('opbox-listing--base');
if (listing) { }

Taka ciekawostka, ten nieszczęsny obiekt bazowy, który do tej pory leżał gdzieś w kodzie JS strony tak naprawdę nie zniknął definitywnie, przebrandowano go na jakiś JSON-owy kod i zapewne nadal jest wykorzystywany przy tworzeniu/manipulowaniu bazową listą aukcji (tą widoczną) po bezpośrednim załadowaniu strony.

To w sumie nie jest zbyt istotne, ale zmiana ta w pewnych okolicznościach wpływa na błędne zachowanie skryptu. Objawia się to tym, że czasami po załadowaniu strony skrypt nie dodaje informacji o lokalizacji. Dzieje się to dlatego, że w czasie jego wykonania poszczególne elementy listy nie zawierają reactowych "internalsów", z których to dane czerpie skrypt. Ewidentnie czai się tu jakiś wyścig przy wykonywaniu kodu skryptu z tym ze strony.

Zapewne związane jest to z tym JSON-em, który teraz musi zostać sparsowany i przemielony, a to dokonuje się jakoś asynchronicznie po załadowaniu strony. Udało mi się na szybko zdebugować kilka fragmentów kodu i ustalić, że po tym "przemieleniu" kontener zawierający listę ofert dostaje pole z _reactRootContainer z jakimiś tam obiektami. Fakt ten wykorzystałem do odświeżenia listy:

function UpdateListBase() {
	if (listing._reactRootContainer)
		UpdateList();
	else
		setTimeout(UpdateListBase, 100);
}
 
UpdateListBase();

Teraz zamiast bezpośredniego wywołania funkcji UpdateList na koniec działania skryptu w kontekście strony listującej aukcje używany jest helper UpdateListBase. Sprawdza on czy już nadszedł czas na "odświeżenie" listy i dodanie wstawek, a jeśli nie to ponawia swoje wykonanie za 100 milisekund. Tym prostym hackiem udało się wygrać wyścig i rozwiązać problem.

...

Przy okazji nowej wersji postanowiłem naprawić też inny problem jaki występuje na stronach opisowych aukcji, a który to już zauważałem jakiś czas temu, ale nie miałem okazji go ogarnąć. Czasami wykonanie kodu niekoniecznie kończy się wyświetleniem informacji o lokalizacji, ale za to psuje wygląd strony, co można zobaczyć na poniższym obrazku.

Wykluczając tezę, że to może "nie mój problem", a jakieś akcje z kodem allegro, CSS-ami, czy innymi zcacheowanymi danymi, przyjrzałem się mojemu mechanizmowi wykrywania przebudowania części informacyjnej aukcji. Jak ktoś śledzi rozwój tego skryptu lub przeglądał źródła to pewnie orientuje się, że od wersji 0.1.5 wykorzystywany jest MutationObserver do wykrywania pewnym zdarzeń na części drzewa DOM - usunięcia elementów wstrzykniętych przez skrypt.

var mutationObserver = new MutationObserver(function (mutations) {
	var delEvt = mutations.findIndex(m => m.removedNodes.length != 0) != -1;
	if (delEvt && itemNode.getElementsByClassName(cssName).length == 0)
		UpdateOffer();
});
mutationObserver.observe(itemNode, { childList: true, subtree: true });

Kod strony przebudowuje w run-time niektóre elementy opisowe aukcji, akurat tam gdzie skrypt wstrzykuje swoje elementy. Do tej pory odświeżanie wyglądało mniej więcej tak, że najpierw usuwane były zbędne elementy (w tym wstrzyknięty kod) i dodawane nowe. Obecnie po zajrzeniu do DOM-a po zreprodukowaniu problemu zauważyłem coś dziwnego.

Jak pokazuje powyższy obrazek, główny kontener przechowujący wstrzyknięte elementy potraktowany został jako jeden z elementów strony i nie został usunięty, a wykorzystany i zmodyfikowany. A to wszystko tłumaczy - czemu dodane elementy zniknęły ze strony i nie wykryto tego faktu przez obserwatora, a także czemu wygląd się rozjechał (brak odpowiednich klas stylów w kontenerze i zastosowanie CSS-a ze wstrzykiwanego kodu).

Po kilku eksperymentach okazało się, że przy użyciu innej nazwy lub struktury, wstrzyknięty element nie zostanie omyłkowo wykorzystany przez kod strony do swoich celów. Ostatecznie zdecydowałem się, że zamiast używania kontenera <div class="asiXXX"/> z losową klasą stylującą użyję dedykowanego elementu z losową nazwą tagu <asiXXX/>. To zapewni, że w przyszłości nie powinien powtórzyć się podobny scenariusz, a tym bardziej nie powinno być żadnej potencjalnej interakcji z kodem strony.

O poprawce w CSS-ach, aby wstawka lepiej komponowała się z aktualną wersją strony to już nie będę wspominał, bo to drobny szczegół.

...

Aktualna wersja dostępna w moim repozytorium UserScripts. Standardowo aktualizacja powinna nastąpić automatycznie, chyba że używany jest jakiś silnik UserJS nie wspierający takiej możliwości. Wtedy pozostaje ręczna zabawa.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *