新闻速递

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

// ==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);

})();