新闻速递

Fetch news from API and open in a new tab with responsive design and translation.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        新闻速递
// @namespace   Violentmonkey Scripts
// @match       *://*/*
// @grant       GM_xmlhttpRequest
// @grant       GM_openInTab
// @grant       GM_registerMenuCommand
// @version     1.5
// @description Fetch news from API and open in a new tab with responsive design and translation.
// @run-at      document-end
// ==/UserScript==

(function() {
  'use strict';

  const apiKey = 'dac6abc0634b4de08429b2580628dba8';
  const apiUrl = `https://newsapi.org/v2/top-headlines?country=us&apiKey=${apiKey}`;

  // Function to fetch and display news
  function fetchAndDisplayNews() {
    GM_xmlhttpRequest({
      method: "GET",
      url: apiUrl,
      onload: function(response) {
        if (response.status === 200) {
          const data = JSON.parse(response.responseText);
          if (data.articles && data.articles.length > 0) {
            let newsContent = `
              <!DOCTYPE html>
              <html lang="zh-CN">
              <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>新闻列表</title>
                <style>
                  body { font-family: sans-serif; margin: 20px; }
                  h1 { text-align: center; }
                  ul { list-style: none; padding: 0; }
                  li { border: 1px solid #eee; padding: 15px; margin-bottom: 10px; border-radius: 5px; }
                  a { text-decoration: none; font-weight: bold; color: #333; }
                  p { color: #666; margin-top: 5px; }
                  a:hover { color: #0056b3; }
                  .translation { font-style: italic; color: #888; margin-top: 5px; }
                   @media (max-width: 600px) {
                      body { margin: 10px; }
                      li { padding: 10px; }
                      h1 {font-size: 1.5em;}
                  }
                </style>
              </head>
              <body>
              <h1>Latest News</h1>
              <ul>
            `;

            const translatePromises = data.articles.map(async (article) => {
                const translatedTitle = await translateText(article.title, 'en', 'zh-CN');
                const translatedDescription = article.description ? await translateText(article.description, 'en', 'zh-CN') : 'No translation available.';
                return { ...article, translatedTitle, translatedDescription };
            });

            Promise.all(translatePromises).then((translatedArticles) => {
              translatedArticles.forEach(article => {
                newsContent += `
                  <li>
                    <a href="${article.url}" target="_blank">${article.title}</a>
                      <p class="translation" style="color: green;">${article.translatedTitle}</p>
                    <p>${article.description || 'No description available.'}</p>
                     <p class="translation" style="color: green;">${article.translatedDescription}</p>
                  </li>
                `;
              });

              newsContent += `
                </ul>
                </body>
                </html>
              `;
              GM_openInTab(`data:text/html;charset=utf-8,${encodeURIComponent(newsContent)}`, { active: true });
            });

          } else {
            alert('No news found.');
          }
        } else {
          alert('Failed to fetch news. Status: ' + response.status);
        }
      },
      onerror: function(error) {
        console.error("Error fetching news:", error);
        alert('An error occurred while fetching news.');
      }
    });
  }

  async function translateText(text, sourceLang, targetLang) {
    if (!text) {
      return '';
    }
    const encodedText = encodeURIComponent(text);
    const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${sourceLang}&tl=${targetLang}&dt=t&q=${encodedText}`;

    try {
      const response = await fetch(url);
      if (!response.ok) {
        console.error("Translation API failed:", response.status);
        return 'Translation failed.';
      }
      const data = await response.json();
      return data[0][0][0];
    } catch (error) {
      console.error("Error during translation:", error);
      return 'Translation failed.';
    }
  }

  // Register the menu command
  GM_registerMenuCommand("Fetch Latest News", fetchAndDisplayNews);

})();