diff --git a/README.md b/README.md index 57d444b..7052f22 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

- +MYNT Logo
MYNT: Material You New Tab @@ -20,7 +20,7 @@ MYNT: Material You New Tab is a versatile browser extension that personalizes yo ![GitHub stars](https://img.shields.io/github/stars/prem-k-r/MaterialYouNewTab) ![GitHub forks](https://img.shields.io/github/forks/prem-k-r/MaterialYouNewTab) -[![](https://img.shields.io/chrome-web-store/v/jjpokbgpiljgndebfoljdeihhkpcpfgl.svg)](https://chrome.google.com/webstore/detail/mynt-material-you-new-tab/jjpokbgpiljgndebfoljdeihhkpcpfgl) [![](https://img.shields.io/chrome-web-store/rating/jjpokbgpiljgndebfoljdeihhkpcpfgl.svg)](https://chrome.google.com/webstore/detail/mynt-material-you-new-tab/jjpokbgpiljgndebfoljdeihhkpcpfgl) [![](https://img.shields.io/chrome-web-store/users/jjpokbgpiljgndebfoljdeihhkpcpfgl.svg)](https://chrome.google.com/webstore/detail/mynt-material-you-new-tab/jjpokbgpiljgndebfoljdeihhkpcpfgl) ▪️ [![](https://img.shields.io/amo/v/mynt.svg)](https://addons.mozilla.org/en-US/firefox/addon/mynt/) [![](https://img.shields.io/amo/rating/mynt.svg)](https://addons.mozilla.org/en-US/firefox/addon/mynt/) [![](https://img.shields.io/amo/users/mynt.svg)](https://addons.mozilla.org/en-US/firefox/addon/mynt/) ▪️ [![](https://img.shields.io/badge/dynamic/json?label=edge%20add-on&prefix=v&query=%24.version&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Flcgdmfjofmcblocogcabdpfidfbkblcd)](https://microsoftedge.microsoft.com/addons/detail/mynt-material-you-new-ta/lcgdmfjofmcblocogcabdpfidfbkblcd) +[![](https://img.shields.io/chrome-web-store/v/jjpokbgpiljgndebfoljdeihhkpcpfgl.svg)](https://chromewebstore.google.com/detail/mynt-material-you-new-tab/jjpokbgpiljgndebfoljdeihhkpcpfgl) [![](https://img.shields.io/chrome-web-store/rating/jjpokbgpiljgndebfoljdeihhkpcpfgl.svg)](https://chromewebstore.google.com/detail/mynt-material-you-new-tab/jjpokbgpiljgndebfoljdeihhkpcpfgl) [![](https://img.shields.io/chrome-web-store/users/jjpokbgpiljgndebfoljdeihhkpcpfgl.svg)](https://chromewebstore.google.com/detail/mynt-material-you-new-tab/jjpokbgpiljgndebfoljdeihhkpcpfgl) ▪️ [![](https://img.shields.io/amo/v/mynt.svg)](https://addons.mozilla.org/en-US/firefox/addon/mynt/) [![](https://img.shields.io/amo/rating/mynt.svg)](https://addons.mozilla.org/en-US/firefox/addon/mynt/) [![](https://img.shields.io/amo/users/mynt.svg)](https://addons.mozilla.org/en-US/firefox/addon/mynt/) ▪️ [![](https://img.shields.io/badge/dynamic/json?label=edge%20add-on&prefix=v&query=%24.version&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Flcgdmfjofmcblocogcabdpfidfbkblcd)](https://microsoftedge.microsoft.com/addons/detail/mynt-material-you-new-ta/lcgdmfjofmcblocogcabdpfidfbkblcd) [![](https://img.shields.io/badge/dynamic/json?label=rating&suffix=/5&query=%24.averageRating&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Flcgdmfjofmcblocogcabdpfidfbkblcd)](https://microsoftedge.microsoft.com/addons/detail/mynt-material-you-new-ta/lcgdmfjofmcblocogcabdpfidfbkblcd) [![](https://img.shields.io/badge/dynamic/json?label=users&query=%24.activeInstallCount&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Flcgdmfjofmcblocogcabdpfidfbkblcd)](https://microsoftedge.microsoft.com/addons/detail/mynt-material-you-new-ta/lcgdmfjofmcblocogcabdpfidfbkblcd) @@ -45,20 +45,21 @@ MYNT: Material You New Tab is a versatile browser extension that personalizes yo ## ✨ Features -- **Integrated Search**: Search directly from the New Tab using your preferred search engine — Google, DuckDuckGo, Bing, Brave Search, YouTube, Wikipedia, and more, with integrated voice typing. -- **Customizable Themes**: Choose from a selection of themes or use the built-in color picker to match your style. -- **Wallpaper**: Upload your own wallpapers or enable daily random images sourced from [Lorem Picsum](https://picsum.photos). -- **Personalized Greeting**: Add a custom message or your name, so you're greeted each time you open a new tab. -- **Clock & Time Display**: Choose between a modern analog or digital clock. -- **Live Weather Updates**: View real-time temperature, conditions, humidity, feels like, and max-min temperature values. Supports °C and °F with location customization. -- **Quick Shortcuts**: Access common platforms (YouTube, Email, WhatsApp, etc.) or add your own shortcuts for instant navigation. -- **AI Tools**: Open ChatGPT, Gemini, Copilot, Perplexity, Claude, DeepSeek, and more with one click. -- **To-Do List**: Manage daily tasks, pin important ones, and enjoy automatic cleanup at the start of each day (pinned tasks reset to pending). -- **Sidebar Bookmarks**: View, delete, and organize bookmarks in either list or grid layout. -- **Google Apps**: Quickly launch Gmail, Drive, Docs, and other Google services. -- **Backup & Reset**: Save or restore your setup anytime, or reset everything to default with one click. -- **Language Support**: Use the extension in your preferred language for better accessibility. -- **Browser Compatibility**: Supports all Chromium-based browsers, including **Chrome**, **Edge**, **Brave**, and **Opera**, as well as Firefox-based browsers like **Firefox** and **Zen**. +- 🔍 **Integrated Search**: Search directly from the New Tab using your preferred search engine — Google, DuckDuckGo, Bing, Brave Search, YouTube, Wikipedia, and more, with integrated voice typing. +- 🎨 **Customizable Themes & Transparency**: Switch between Light, Dark, or System mode, use the built-in color picker to match your style, and adjust widget transparency to blend perfectly with your chosen wallpaper. +- 🖼️ **Wallpapers**: Upload your own wallpapers or enable daily random images sourced from [Lorem Picsum](https://picsum.photos). +- 👋 **Personalized Greeting**: Add a custom message or your name, so you're greeted each time you open a new tab. +- ⏰ **Clock & Time Display**: Choose between a modern analog or digital clock. +- 🌤️ **Live Weather Updates**: View real-time temperature, conditions, humidity, feels like, and max-min temperature values. Supports °C and °F with location customization. +- ⚡ **Quick Shortcuts**: Access common platforms (YouTube, Email, WhatsApp, etc.), drag and drop to reorder, or add custom shortcuts with unique icons (via URL, upload, or pasted SVG). +- 💡 **Quotes**: Get motivated with daily or rotating motivational quotes featuring extensive multilingual support. +- 🤖 **AI Tools**: Open ChatGPT, Gemini, Copilot, Perplexity, Claude, DeepSeek, and more with one click. +- 📝 **To-Do List**: Manage daily tasks, pin important ones, and enjoy automatic cleanup at the start of each day (pinned tasks reset to pending). +- 🔖 **Sidebar Bookmarks**: View, delete, and organize bookmarks in either list or grid layout. +- 📱 **Google Apps**: Quickly launch Gmail, Drive, Docs, and other Google services. +- 💾 **Backup & Reset**: Save or restore your setup anytime, or reset everything to default with one click. +- 🌍 **Language Support**: Use the extension in your preferred language for better accessibility (32 languages natively supported). +- 🌐 **Browser Compatibility**: Supports all Chromium-based browsers, including **Chrome**, **Edge**, **Brave**, and **Opera**, as well as Firefox-based browsers like **Firefox** and **Zen**. ## 📥 Installation Guide @@ -242,7 +243,7 @@ For a step-by-step walkthrough, watch this [installation guide video](https://yo |   **Russian** - Русский | ru | [giwi](https://github.com/giwih/), [CodWiz](https://github.com/C0dwiz/) | |   **Slovenian** - Slovenščina | sl-SI | [Linux-Alex](https://github.com/Linux-Alex/) | |   **Spanish** - Español | es-ES | [XengShi](https://github.com/XengShi/), [Isaac Vergara](https://github.com/zRaidev), [Saúl Palacios](https://github.com/palacios22c) | -|   **Swedish** - Svenska | sv | [HELLOEMPO](https://github.com/empohello-imamempogitub/) | +|   **Swedish** - Svenska | sv | [HELLOEMPO](https://github.com/empohello-imamempogitub/) | |   **Tamil** - தமிழ் | ta | [தமிழ்நேரம்](https://TamilNeram.github.io/) | |   **Thai** - ภาษาไทย | th | [Prin](https://github.com/prinsasina) | |   **Turkish** - Türkçe | tr | [Nobody](https://github.com/Nobody9512), [Kerim Ölçer](https://github.com/kerimlcr) | diff --git a/index.html b/index.html index e138eb2..9435ae4 100644 --- a/index.html +++ b/index.html @@ -1607,6 +1607,19 @@

Material You New Tab

+
+
+
Weather Provider
+
Select the weather + service
+
+ +
+
Enter your Location
diff --git a/privacy-policy.html b/privacy-policy.html index 3fe70e5..b905c3c 100644 --- a/privacy-policy.html +++ b/privacy-policy.html @@ -192,20 +192,43 @@

External APIs

which sites the extension can access from your browser settings.

-
  • Location Detection (IPinfo): +
  • Location Detection (IPinfo / GeoJS):
    • https://ipinfo.io/json – fetches approximate city-level location based on your IP for local weather display.
    • +
    • https://get.geojs.io/v1/ip/geo.json – alternative used for IP-based geolocation + when Open-Meteo is active.
  • -
  • Weather Updates (WeatherAPI): +
  • Weather Updates:
      -
    • https://api.weatherapi.com/v1/forecast.json?key=* – retrieves daily forecasts based - on your location and language preferences.
    • - -
    • https://api.weatherapi.com/v1/search.json?key=* – used to fetch location - suggestions when searching for a city.
    • +
    • WeatherAPI +
        +
      • https://api.weatherapi.com/v1/forecast.json?key=* – retrieves daily + forecasts based + on your location and language preferences.
      • +
      • https://api.weatherapi.com/v1/search.json?key=* – used to fetch location + suggestions when searching for a city.
      • +
      • https://cdn.weatherapi.com/weather/128x128/ – retrieves weather condition + icons.
      • +
      +
    • +
    • Open-Meteo +
        +
      • https://api.open-meteo.com/v1/forecast – alternative provider for + retrieving forecasts.
      • +
      • https://geocoding-api.open-meteo.com/v1/search – alternative source for + finding location coordinates.
      • +
      +
    • +
    • Nominatim (OpenStreetMap) +
        +
      • https://nominatim.openstreetmap.org/reverse – converts GPS coordinates to + readable area names when Open-Meteo and Auto Location are enabled.
      • +
      +
  • diff --git a/scripts/weather.js b/scripts/weather.js index 81d0063..5a70d61 100644 --- a/scripts/weather.js +++ b/scripts/weather.js @@ -1,6 +1,6 @@ /* - * Material You NewTab - * Copyright (c) 2023-2025 XengShi + * Material You New Tab + * Copyright (c) 2024-2026 Prem, 2023-2025 XengShi * Licensed under the GNU General Public License v3.0 (GPL-3.0) * You should have received a copy of the GNU General Public License along with this program. * If not, see . @@ -162,18 +162,31 @@ async function getWeatherData() { } } - // Fetch location suggestions from weatherAPI + // Fetch location suggestions from weatherAPI or Open-Meteo async function fetchLocationSuggestions(query) { - if (!savedApiKey || query.length < 3) { + if (query.length < 3) { suggestions = []; locationSuggestions.style.display = "none"; toggleAutocomplete(); return; } + const weatherProvider = localStorage.getItem("weatherProviderSelect") || "weatherapi"; + try { - const response = await fetch(`https://api.weatherapi.com/v1/search.json?key=${savedApiKey}&q=${query}`); - suggestions = await response.json(); + if (weatherProvider === "openmeteo") { + const response = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${query}&count=5&language=en&format=json`); + const data = await response.json(); + suggestions = data.results ? data.results.map(r => ({ + name: r.name, + region: r.admin1 || "", + country: r.country || "" + })) : []; + } else { + // If weatherapi, use the active apiKey + const response = await fetch(`https://api.weatherapi.com/v1/search.json?key=${apiKey}&q=${query}`); + suggestions = await response.json(); + } if (suggestions.length > 0) { displaySuggestions(suggestions); @@ -371,42 +384,125 @@ async function getWeatherData() { // Language code for Weather API let lang = currentLanguage === "zh_TW" ? currentLanguage : currentLanguage.split("_")[0]; - // Fetch weather data using Weather API - let weatherApi = `https://api.weatherapi.com/v1/forecast.json?key=${apiKey}&q=${currentUserLocation}&days=1&aqi=no&alerts=no&lang=${lang}`; - - let data = await fetch(weatherApi); - parsedData = await data.json(); - if (!parsedData.error) { - // Extract only the necessary fields before saving - const filteredData = { - location: { - name: parsedData.location.name, - }, - current: { - condition: { - text: parsedData.current.condition.text, - icon: parsedData.current.condition.icon, + const weatherProvider = localStorage.getItem("weatherProviderSelect") || "weatherapi"; + let filteredData = null; + + let useWeatherApiFallback = false; + + if (weatherProvider === "openmeteo") { + try { + let lat, lon, nameValue; + nameValue = currentUserLocation; + if (currentUserLocation === "auto:ip") { + const ipGeoRes = await fetch("https://get.geojs.io/v1/ip/geo.json"); + const ipGeoData = await ipGeoRes.json(); + lat = ipGeoData.latitude; + lon = ipGeoData.longitude; + nameValue = ipGeoData.city || ipGeoData.region || "Current Location"; + } else if (/^-?\d+(\.\d+)?\s*,\s*-?\d+(\.\d+)?$/.test(currentUserLocation)) { + [lat, lon] = currentUserLocation.replace(/\s/g, '').split(","); + try { + const revGeoResponse = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lon}&zoom=10&accept-language=${lang}`); + const revGeoData = await revGeoResponse.json(); + nameValue = revGeoData.name || revGeoData.address?.city || revGeoData.address?.town || revGeoData.address?.village || revGeoData.address?.county || "Current Location"; + } catch (e) { + nameValue = "Current Location"; + } + } else { + const geoResponse = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(currentUserLocation)}&count=1&language=${lang}&format=json`); + const geoData = await geoResponse.json(); + if (geoData.results && geoData.results.length > 0) { + lat = geoData.results[0].latitude; + lon = geoData.results[0].longitude; + nameValue = geoData.results[0].name; + } else { + throw new Error("Location not found via Open-Meteo"); + } + } + + const url = `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,weather_code&daily=temperature_2m_max,temperature_2m_min&timezone=auto`; + const fApi = await fetch(url); + const oData = await fApi.json(); + + const map = { + 0: { text: "Clear", icon: "113" }, 1: { text: "Mainly Clear", icon: "116" }, 2: { text: "Partly Cloudy", icon: "116" }, 3: { text: "Overcast", icon: "122" }, + 45: { text: "Fog", icon: "248" }, 48: { text: "Depositing rime fog", icon: "248" }, 51: { text: "Drizzle Light", icon: "266" }, 53: { text: "Drizzle Moderate", icon: "266" }, + 55: { text: "Drizzle Dense", icon: "266" }, 56: { text: "Freezing Drizzle Light", icon: "281" }, 57: { text: "Freezing Drizzle Dense", icon: "281" }, + 61: { text: "Rain Slight", icon: "296" }, 63: { text: "Rain Moderate", icon: "302" }, 65: { text: "Rain Heavy", icon: "308" }, 66: { text: "Freezing Rain Light", icon: "311" }, + 67: { text: "Freezing Rain Heavy", icon: "314" }, 71: { text: "Snow Slight", icon: "326" }, 73: { text: "Snow Moderate", icon: "329" }, 75: { text: "Snow Heavy", icon: "332" }, + 77: { text: "Snow Grains", icon: "338" }, 80: { text: "Rain Showers Slight", icon: "353" }, 81: { text: "Rain Showers Moderate", icon: "356" }, + 82: { text: "Rain Showers Violent", icon: "359" }, 85: { text: "Snow Showers Slight", icon: "368" }, 86: { text: "Snow Showers Heavy", icon: "371" }, + 95: { text: "Thunderstorm", icon: "386" }, 96: { text: "Thunderstorm Slight Hail", icon: "389" }, 99: { text: "Thunderstorm Heavy Hail", icon: "392" }, + }; + const c = map[oData.current.weather_code] || { text: "Unknown", icon: "113" }; + const timeOfDay = oData.current.is_day ? "day" : "night"; + const mappedCode = { text: c.text, icon: `https://cdn.weatherapi.com/weather/128x128/${timeOfDay}/${c.icon}.png` }; + + const tempC = oData.current.temperature_2m; + const feelsC = oData.current.apparent_temperature; + const minC = oData.daily.temperature_2m_min[0]; + const maxC = oData.daily.temperature_2m_max[0]; + + filteredData = { + location: { name: nameValue }, + current: { + condition: { text: mappedCode.text, icon: mappedCode.icon }, + temp_c: tempC, temp_f: tempC * 9 / 5 + 32, + humidity: oData.current.relative_humidity_2m, + feelslike_c: feelsC, feelslike_f: feelsC * 9 / 5 + 32, + }, + forecast: { + forecastday: [{ + day: { mintemp_c: minC, maxtemp_c: maxC, mintemp_f: minC * 9 / 5 + 32, maxtemp_f: maxC * 9 / 5 + 32 } + }] + } + }; + } catch (e) { + console.warn("Open-Meteo failed, falling back to WeatherAPI:", e); + useWeatherApiFallback = true; + } + } + + if (weatherProvider !== "openmeteo" || useWeatherApiFallback) { + // Fetch weather data using Weather API + let weatherApi = `https://api.weatherapi.com/v1/forecast.json?key=${apiKey}&q=${currentUserLocation}&days=1&aqi=no&alerts=no&lang=${lang}`; + + let data = await fetch(weatherApi); + let rawData = await data.json(); + if (!rawData.error) { + filteredData = { + location: { + name: rawData.location.name, }, - temp_c: parsedData.current.temp_c, - temp_f: parsedData.current.temp_f, - humidity: parsedData.current.humidity, - feelslike_c: parsedData.current.feelslike_c, - feelslike_f: parsedData.current.feelslike_f, - }, - forecast: { - forecastday: [ - { - day: { - mintemp_c: parsedData.forecast.forecastday[0].day.mintemp_c, - maxtemp_c: parsedData.forecast.forecastday[0].day.maxtemp_c, - mintemp_f: parsedData.forecast.forecastday[0].day.mintemp_f, - maxtemp_f: parsedData.forecast.forecastday[0].day.maxtemp_f + current: { + condition: { + text: rawData.current.condition.text, + icon: rawData.current.condition.icon, + }, + temp_c: rawData.current.temp_c, + temp_f: rawData.current.temp_f, + humidity: rawData.current.humidity, + feelslike_c: rawData.current.feelslike_c, + feelslike_f: rawData.current.feelslike_f, + }, + forecast: { + forecastday: [ + { + day: { + mintemp_c: rawData.forecast.forecastday[0].day.mintemp_c, + maxtemp_c: rawData.forecast.forecastday[0].day.maxtemp_c, + mintemp_f: rawData.forecast.forecastday[0].day.mintemp_f, + maxtemp_f: rawData.forecast.forecastday[0].day.maxtemp_f + } } - } - ] - } - }; + ] + } + }; + } + } + if (filteredData) { + parsedData = filteredData; // Save filtered weather data to localStorage localStorage.setItem("weatherParsedData", JSON.stringify(filteredData)); localStorage.setItem("weatherParsedTime", Date.now()); // Save time of last fetching @@ -617,3 +713,13 @@ minMaxTempCheckbox.addEventListener("change", () => { localStorage.setItem("minMaxTempEnabled", isChecked); location.reload(); }); + +const weatherProviderSelect = document.getElementById("weatherProviderSelect"); +if (weatherProviderSelect) { + weatherProviderSelect.value = localStorage.getItem("weatherProviderSelect") || "weatherapi"; + weatherProviderSelect.addEventListener("change", (e) => { + localStorage.setItem("weatherProviderSelect", e.target.value); + localStorage.setItem("weatherParsedTime", "0"); + location.reload(); + }); +}