Greasy Fork is available in English.

alt+单击图片自动下载

在图片对象上面:1、按alt单击图片自动下载(默认转换为JPG格式);2、按ctrl+alt 单击图片会弹窗选择命名方式(刷新网页全局生效),文件名可以根据当前日期时间time、网页域名domain、网页标题title,或用户自定义进行命名。

// ==UserScript==
// @name         alt+单击图片自动下载
// @namespace    https://www.techwb.cn/
// @version      1.1
// @description  在图片对象上面:1、按alt单击图片自动下载(默认转换为JPG格式);2、按ctrl+alt 单击图片会弹窗选择命名方式(刷新网页全局生效),文件名可以根据当前日期时间time、网页域名domain、网页标题title,或用户自定义进行命名。
// @author       Techwb.cn
// @match        *://*/*
// @grant        GM_download
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function() {
  'use strict';
  // 用于判断当前是否点击了图片
  var clickedImage = null;
  // 获取命名方式
  var nameOption = GM_getValue('nameOption', 'time'); //默认命名方式time(日期时间)、domain(域名)、title(网页标题)
  var customName = GM_getValue('customName', '');
  // 监听左键单击事件
  document.addEventListener('mousedown', function(event) {
    var target = event.target;
    if (target.tagName === 'IMG' && event.button === 0) {
      clickedImage = target;
      if (event.altKey && !event.ctrlKey) {
        // 如果按下 alt 键,自动下载
        handleDownload();
      } else if (event.altKey && event.ctrlKey) {
        // 如果同时按下 alt 和 ctrl 键,弹出命名对话框,再下载
        handleNaming();
      }
    }
  });

  // 下载图片并命名
function handleDownload() {
  if (!clickedImage) return;
  var imgSrc = clickedImage.src;

  // 使用 fetch 方法获取图片数据,加上 mode: 'cors' 以允许跨域请求
  fetch(imgSrc, { mode: 'cors' })
    .then(function(response) {
      // 将响应数据转为 Blob 对象
      return response.blob();
    })
    .then(function(blob) {
      // 创建 FileReader 对象,以读取 Blob 对象的数据
      var reader = new FileReader();
      reader.readAsDataURL(blob);
      reader.onloadend = function() {
        var base64data = reader.result;

        // 创建 <a> 元素,并设置下载链接和文件名
        var a = document.createElement('a');
        var fileName = '';
        if (nameOption === 'time') {
          fileName = '图片_' + getDate() + '.jpg';
        } else if (nameOption === 'domain') {
          fileName = getDomain() + '.jpg';
        } else if (nameOption === 'title') {
          fileName = getTitle() + '.jpg';
        } else {
          fileName = customName + '.jpg';
        }
        a.download = fileName;

        // 将图片转为 JPG 格式
        var img = new Image();
        img.src = base64data;
        img.onload = function() {
          var canvas = document.createElement('canvas');
          canvas.width = img.width;
          canvas.height = img.height;
          var context = canvas.getContext('2d');
          context.drawImage(img, 0, 0);
          a.href = canvas.toDataURL('image/jpeg');
          // 添加 <a> 元素到 DOM 中,模拟点击下载链接
          document.body.appendChild(a);
          a.click();
          // 下载完成后移除 <a> 元素
          document.body.removeChild(a);
          document.body.removeChild(canvas);
        };
      }
    });
}

// 弹出命名对话框并下载图片
function handleNaming() {
var dateTime = getDate();
var domainName = getDomain();
var titleName = getTitle();

var nameOptions = {
'time': '时间命名方式',
'domain': '域名命名方式',
'title': '标题命名方式',
'custom': '自定义命名方式'
};

var defaultName = dateTime + '' + titleName + '' + domainName + '.jpg';

var nameOption = GM_getValue('nameOption', 'time');
var customName = GM_getValue('customName', '');

var optionsHtml = '';
for (var option in nameOptions) {
optionsHtml += '<option value="' + option + '" ' + (nameOption === option ? 'selected' : '') + '>' + nameOptions[option] + '</option>';
}
var html = '<div><label for="nameOption">命名方式:</label><select id="nameOption">' + optionsHtml + '</select></div>' +
'<div><label for="customName">自定义文件名:</label><input type="text" id="customName" value="' + customName + '"></div>' +
'<div><label for="fileName">文件名:</label><input type="text" id="fileName" value="' + defaultName + '"></div>';
var dialog = document.createElement('div');
dialog.innerHTML = html;
dialog.style.position = 'fixed';
dialog.style.top = '50%';
dialog.style.left = '50%';
dialog.style.transform = 'translate(-50%, -50%)';
dialog.style.backgroundColor = '#fff';
dialog.style.padding = '20px';
dialog.style.borderRadius = '5px';
dialog.style.boxShadow = '0px 0px 10px rgba(0, 0, 0, 0.5)';
dialog.style.zIndex = '9999';
document.body.appendChild(dialog);
var select = dialog.querySelector('#nameOption');
var customNameInput = dialog.querySelector('#customName');
var fileNameInput = dialog.querySelector('#fileName');
select.addEventListener('change', function() {
  var option = select.value;
  if (option === 'custom') {
    customNameInput.style.display = 'block';
  } else {
    customNameInput.style.display = 'none';
  }
  updateFileName(option);
});
customNameInput.addEventListener('input', function() {
  updateFileName('custom');
});
function updateFileName(option) {
  var fileName = '';
  if (option === 'time') {
    fileName = '图片_'+dateTime+ '.jpg';
  } else if (option === 'domain') {
    fileName = domainName + '.jpg';
  } else if (option === 'title') {
    fileName = titleName + '.jpg';
  } else {
    fileName = customNameInput.value + '.jpg';
  }
  fileNameInput.value = fileName;
}
fileNameInput.addEventListener('input', function() {
  var fileName = fileNameInput.value;
  customNameInput.value = fileName.substring(0, fileName.lastIndexOf('.jpg'));
  updateFileName('custom');
});
var confirmButton = document.createElement('button');
confirmButton.innerText = '确定';
confirmButton.style.marginTop = '20px';
confirmButton.style.padding = '5px 10px';
confirmButton.style.backgroundColor = '#2ecc71';
confirmButton.style.border = 'none';
confirmButton.style.color = '#fff';
confirmButton.style.borderRadius = '3px';
confirmButton.style.cursor = 'pointer';
confirmButton.addEventListener('click', function() {
  var option = select.value;
  if (option === 'custom') {
    customName = customNameInput.value;
  } else {
    customName = '';
  }
  var fileName = fileNameInput.value;
  GM_setValue('nameOption', option);
  GM_setValue('customName', customName);
  handleDownload();
  document.body.removeChild(dialog);
});
var cancelButton = document.createElement('button');
cancelButton.innerText = '取消';
cancelButton.style.marginTop = '20px';
cancelButton.style.marginLeft = '20px';
cancelButton.style.padding = '5px 10px';
cancelButton.style.backgroundColor = '#e74c3c';
cancelButton.style.border = 'none';
cancelButton.style.color = '#fff';
cancelButton.style.borderRadius = '3px';
cancelButton.style.cursor = 'pointer';
cancelButton.addEventListener('click', function() {
document.body.removeChild(dialog);
});

dialog.appendChild(confirmButton);
dialog.appendChild(cancelButton);
updateFileName(nameOption);
select.dispatchEvent(new Event('change'));
  }
  // 获取当前日期时间字符串
  function getDate() {
    var now = new Date();
    var date = now.getFullYear() + '-' + (now.getMonth() + 1).toString().padStart(2, '0') + '-' + now.getDate().toString().padStart(2, '0') + '_' + now.getHours().toString().padStart(2, '0') + now.getMinutes().toString().padStart(2, '0') + now.getSeconds().toString().padStart(2, '0');
    return date;
  }
  // 获取当前页面域名
  function getDomain() {
    var url = window.location.href;
    var domain = url.split('/')[2];
    domain = domain.replace(/www\./, '');
    return domain;
  }
  // 获取当前页面标题前10个字符
  function getTitle() {
    var title =document.title;
    return title.substring(0, 10);
    }
})();