Created
July 21, 2024 16:09
-
-
Save and7ey/4f5480364077287a3770070dd4bf3baa to your computer and use it in GitHub Desktop.
Добавление рейтинга отеля с TripAdvisor в результаты поиска Level Travel (скрипт для Tampermonkey)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Level Travel + Trip Advisor | |
// @namespace http://tampermonkey.net/ | |
// @version 0.2 | |
// @description Enhance Level Travel site with TripAdvisor ratings | |
// @author You | |
// @match https://level.travel/search/* | |
// @grant GM_xmlhttpRequest | |
// ==/UserScript== | |
const apiKeyList = ['INSERT-YOUR-API-KEY-1', 'INSERT-YOUR-API-KEY-2', 'INSERT-YOUR-API-KEY-3']; | |
const apiKey = apiKeyList[1]; | |
(function() { | |
'use strict'; | |
const processedElements = new Set(); // Keep track of elements that have been processed | |
const observer = new MutationObserver(async (mutationsList, observer) => { | |
for(let mutation of mutationsList) { | |
if (mutation.type === 'childList') { | |
const hotelElements = document.querySelectorAll('a[data-testid="hotel-card__title"]'); | |
hotelElements.forEach(async (hotelElement) => { | |
// Check if this element has already been processed | |
const hotelName = hotelElement.textContent.trim(); | |
if (!processedElements.has(hotelName)) { | |
console.log(hotelName); | |
processedElements.add(hotelName); // Mark this element as processed | |
const locationId = await getLocationId(hotelName); | |
if(locationId) { | |
console.log(locationId); | |
const details = await getLocationDetails(locationId); | |
console.log(details.ratingImageUrl); | |
console.log(details.webUrl); | |
addRatingImage(hotelElement, details); | |
} | |
} | |
}); | |
} | |
} | |
}); | |
observer.observe(document.body, { childList: true, subtree: true }); | |
})(); | |
function setCache(key, value) { | |
const expiryDate = new Date(); | |
expiryDate.setMonth(expiryDate.getMonth() + 1); // Set expiry date one month from now | |
const item = { | |
value, | |
expiry: expiryDate.getTime() | |
}; | |
localStorage.setItem(key, JSON.stringify(item)); | |
} | |
function getCache(key) { | |
const itemStr = localStorage.getItem(key); | |
if (!itemStr) { | |
return null; | |
} | |
const item = JSON.parse(itemStr); | |
const now = new Date().getTime(); | |
if (now > item.expiry) { | |
localStorage.removeItem(key); | |
return null; | |
} | |
return item.value; | |
} | |
async function getLocationId(hotelName) { | |
const cacheKey = `locationId_${hotelName}`; | |
let locationId = getCache(cacheKey); | |
if (locationId === null) { // Cache miss or expired | |
const url = `https://api.content.tripadvisor.com/api/v1/location/search?searchQuery=${encodeURIComponent(hotelName)}&category=hotels&language=en&key=${apiKey}`; | |
return new Promise((resolve, reject) => { | |
GM_xmlhttpRequest({ | |
method: "GET", | |
url: url, | |
onload: function(response) { | |
try { | |
const jsonResponse = JSON.parse(response.responseText); | |
locationId = jsonResponse.data[0]?.location_id; // Get location ID from response | |
if (locationId) { | |
setCache(cacheKey, locationId); // Cache the result | |
} | |
resolve(locationId); | |
} catch(e) { | |
reject(e); | |
} | |
}, | |
onerror: function(error) { | |
reject(error); | |
} | |
}); | |
}); | |
} else { | |
return Promise.resolve(locationId); // Return cached location ID | |
} | |
} | |
async function getLocationDetails(locationId) { | |
const cacheKey = `details_${locationId}`; | |
let details = getCache(cacheKey); | |
if (details === null) { // Cache miss or expired | |
const url = `https://api.content.tripadvisor.com/api/v1/location/${locationId}/details?key=${apiKey}`; | |
return new Promise((resolve, reject) => { | |
GM_xmlhttpRequest({ | |
method: "GET", | |
url: url, | |
onload: function(response) { | |
try { | |
const jsonResponse = JSON.parse(response.responseText); | |
details = { | |
ratingImageUrl: jsonResponse.rating_image_url, | |
webUrl: jsonResponse.web_url, | |
reviewsCount: jsonResponse.num_reviews, | |
rankingData: jsonResponse.ranking_data | |
}; | |
setCache(cacheKey, details); // Cache the result | |
resolve(details); | |
} catch(e) { | |
reject(e); | |
} | |
}, | |
onerror: function(error) { | |
reject(error); | |
} | |
}); | |
}); | |
} else { | |
return Promise.resolve(details); // Return cached details | |
} | |
} | |
function addRatingImage(hotelElement, details) { | |
const img = document.createElement('img'); | |
img.src = details.ratingImageUrl; | |
img.style.maxWidth = '100px'; | |
// Wrap the image in an anchor tag with the web URL | |
const link = document.createElement('a'); | |
link.href = details.webUrl; | |
link.target = '_blank'; // Open in a new tab | |
link.appendChild(img); | |
const div = document.createElement('div'); | |
div.innerText = details.reviewsCount + ' reviews | ' + details.rankingData.ranking_string; | |
hotelElement.parentElement.insertBefore(div, hotelElement.nextSibling); | |
hotelElement.parentElement.insertBefore(link, hotelElement.nextSibling); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment