// ==UserScript== // @name 腾讯优酷爱奇艺B站小红书图片下载脚本 // @namespace http://tampermonkey.net/ // @version 0.9.0 // @description 右键点击图片以下载(支持bilibili、腾讯视频、优酷、爱奇艺、小红书等网站图片下载,支持批量下载和自定义重命名) // @author Derek Chen // @match *://www.bilibili.com/* // @include *://www.bilibili.com/video/av* // @include *://www.bilibili.com/read/cv* // @include *://t.bilibili.com/* // @include *://space.bilibili.com/* // @include *://www.bilibili.com/* // @include *://h.bilibili.com/* // @include *://game.bilibili.com/* // @include *://live.bilibili.com/* // @include *://search.bilibili.com/* // @include *://v.qq.com/* // @include *://film.qq.com/* // @include *://v.youku.com/* // @include *://www.youku.com/* // @include *://www.iqiyi.com/* // @include *://v.iqiyi.com/* // @include *://www.xiaohongshu.com/* // @include *://xiaohongshu.com/* // @grant none // @downloadURL https://update.greasyfork.icu/scripts/532758/%E8%85%BE%E8%AE%AF%E4%BC%98%E9%85%B7%E7%88%B1%E5%A5%87%E8%89%BAB%E7%AB%99%E5%B0%8F%E7%BA%A2%E4%B9%A6%E5%9B%BE%E7%89%87%E4%B8%8B%E8%BD%BD%E8%84%9A%E6%9C%AC.user.js // @updateURL https://update.greasyfork.icu/scripts/532758/%E8%85%BE%E8%AE%AF%E4%BC%98%E9%85%B7%E7%88%B1%E5%A5%87%E8%89%BAB%E7%AB%99%E5%B0%8F%E7%BA%A2%E4%B9%A6%E5%9B%BE%E7%89%87%E4%B8%8B%E8%BD%BD%E8%84%9A%E6%9C%AC.meta.js // ==/UserScript== let header = 'https:', acceptable_classes = [ // bilibili常见图片容器类 'user-head c-pointer', 'notice-img c-pointer', 'img-content', 'live-up-img', 'card-1', 'card-3', // 腾讯视频常见图片容器类 'figure_pic', 'figure_thumbnail', 'poster_figure', 'site_logo', 'avatar', // 优酷常见图片容器类 'movie-poster', 'lazyload-img', 'avatar-img', 'program-cover', 'card-img', // 爱奇艺常见图片容器类 'qy-player-thumbnail', 'qy-player-poster', 'header-userIcon', 'header-logo', 'qy-mod-link', // 小红书常见图片容器类 'cover', 'note-image', 'avatar-img', 'inner-img', 'cover-image', 'feed-image' ], final_url = "", header_test = new RegExp(/http*/), prompt = document.createElement("div"), first_hid = true, up_name_final = "", img_list = [], detail_ = {}, // 批量下载相关 selected_images = [], is_batch_mode = false, common_prefix = "", // 批量下载时的通用文件名前缀 is_edit_mode = false; // 是否处于编辑模式 // 更新CSS样式,全面美化界面 function addStyles() { const style = document.createElement('style'); style.textContent = ` .img-downloader-popup { font-family: "Microsoft YaHei", Arial, sans-serif; background: linear-gradient(to bottom, #ffffff, #f8f9fa); border-radius: 10px; box-shadow: 0 5px 15px rgba(0,0,0,0.15); border: 1px solid rgba(0,0,0,0.1); overflow: hidden; will-change: transform, left, top; user-select: none; } .img-downloader-popup .popup-header { display: flex; justify-content: space-between; align-items: center; padding: 10px 15px; background: linear-gradient(to right, #4568dc, #3d7edb); color: white; border-bottom: 1px solid rgba(0,0,0,0.1); } .img-downloader-popup h2 { margin: 0; font-size: 16px; color: white; text-align: center; flex: 1; font-weight: 500; text-shadow: 0 1px 2px rgba(0,0,0,0.1); } .img-downloader-popup .close-btn { background: none; border: none; width: 24px; height: 24px; font-size: 18px; cursor: pointer; color: rgba(255,255,255,0.9); display: flex; align-items: center; justify-content: center; border-radius: 50%; transition: all 0.2s; } .img-downloader-popup .close-btn:hover { background-color: rgba(255,255,255,0.2); color: white; } .img-downloader-popup .controls { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin: 10px; padding: 8px; background: rgba(0,0,0,0.03); border-radius: 6px; } .img-downloader-popup .controls button { background: #4e8df5; color: white; border: none; padding: 6px 10px; border-radius: 5px; cursor: pointer; font-size: 12px; font-weight: 500; transition: all 0.25s; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .img-downloader-popup .controls button:hover { background: #3a7cd8; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.1); } .img-downloader-popup .controls input { padding: 6px 10px; border: 1px solid #ddd; border-radius: 5px; width: 100%; font-size: 12px; transition: border 0.3s; } .img-downloader-popup .controls input:focus { border-color: #4e8df5; outline: none; box-shadow: 0 0 0 2px rgba(78,141,245,0.2); } .img-downloader-popup .content-wrapper { padding: 0 10px 10px; } .img-downloader-popup .img-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); gap: 8px; max-height: 55vh; overflow-y: auto; padding: 5px; scrollbar-width: thin; scrollbar-color: #c1c1c1 #f1f1f1; overscroll-behavior: contain; } .img-downloader-popup .img-container::-webkit-scrollbar { width: 6px; } .img-downloader-popup .img-container::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 8px; } .img-downloader-popup .img-container::-webkit-scrollbar-thumb { background: #c1c1c1; border-radius: 8px; } .img-downloader-popup .img-container::-webkit-scrollbar-thumb:hover { background: #a1a1a1; } .img-downloader-popup .img-item { position: relative; border-radius: 5px; overflow: hidden; background: white; box-shadow: 0 1px 4px rgba(0,0,0,0.08); transition: transform 0.15s ease-out, box-shadow 0.15s ease-out; } .img-downloader-popup .img-item:hover { transform: translateY(-2px); box-shadow: 0 3px 6px rgba(0,0,0,0.1); } .img-downloader-popup .img-item.selected { border: 1px solid #4e8df5; box-shadow: 0 0 0 2px rgba(78,141,245,0.2); } .img-downloader-popup .img-item .img-wrapper { height: 80px; overflow: hidden; display: flex; align-items: center; justify-content: center; background-color: #f8f9fa; } .img-downloader-popup .img-item img { width: 100%; height: 100%; object-fit: contain; transition: none; } .img-downloader-popup .img-item:hover img { transform: none; } .img-downloader-popup .img-info { padding: 6px 8px; } .img-downloader-popup .img-item .img-name { margin: 0; font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #333; } .img-downloader-popup .img-item .edit-name { width: 100%; margin: 3px 0; padding: 4px 6px; font-size: 11px; border: 1px solid #ddd; border-radius: 3px; box-sizing: border-box; } .img-downloader-popup .img-item .edit-name:focus { border-color: #4e8df5; outline: none; } .img-downloader-popup .img-item .checkbox { position: absolute; top: 5px; right: 5px; width: 16px; height: 16px; cursor: pointer; z-index: 10; opacity: 0.8; } .img-downloader-popup .img-item .checkbox:checked { opacity: 1; } .img-downloader-popup .img-item .download-btn { position: absolute; bottom: 6px; right: 6px; background: rgba(78,141,245,0.9); color: white; border: none; width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 11px; opacity: 0; transition: opacity 0.3s; } .img-downloader-popup .img-item:hover .download-btn { opacity: 1; } .img-downloader-popup .img-item .download-btn:hover { background: #4e8df5; } .img-downloader-popup .batch-download-bar { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; background: #f8f9fa; border-top: 1px solid #eee; position: sticky; bottom: 0; margin-top: 10px; } .img-downloader-popup .batch-download-bar button { background: #28a745; color: white; border: none; padding: 6px 12px; border-radius: 5px; cursor: pointer; font-weight: 500; transition: all 0.25s; box-shadow: 0 2px 4px rgba(0,0,0,0.1); font-size: 12px; } .img-downloader-popup .batch-download-bar button:hover { background: #218838; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.1); } .img-downloader-popup .batch-download-bar .counter { font-size: 12px; font-weight: 500; color: #555; } .img-downloader-popup .empty-state { text-align: center; padding: 25px 15px; color: #666; } .img-downloader-popup .empty-state .icon { font-size: 32px; margin-bottom: 10px; color: #ccc; } .img-downloader-popup .empty-state p { margin: 5px 0; font-size: 12px; } .img-downloader-popup .download-progress { position: fixed; bottom: 15px; right: 15px; background: rgba(0,0,0,0.8); color: white; padding: 8px 12px; border-radius: 6px; z-index: 999999; display: none; box-shadow: 0 4px 12px rgba(0,0,0,0.15); font-size: 12px; } .img-downloader-toast { transition: opacity 0.3s; border-radius: 5px; box-shadow: 0 3px 10px rgba(0,0,0,0.15); font-size: 12px; padding: 8px 12px; margin-bottom: 8px; } @keyframes fadeIn { from { opacity: 0; transform: translateY(15px); } to { opacity: 0.9; transform: translateY(0); } } @keyframes fadeOut { from { opacity: 0.9; } to { opacity: 0; } } `; document.head.appendChild(style); } initiate_pop(); addStyles(); // 添加拖拽功能 function makeDraggable(element) { if (!element) return; const header = element.querySelector('.popup-header'); if (!header) return; header.style.cursor = 'move'; // 使用这种方式可以避免事件监听器堆积 header.onmousedown = function(e) { // 如果点击的是关闭按钮,不启动拖拽 if (e.target.classList.contains('close-btn')) { return; } e.preventDefault(); // 添加拖动中的视觉样式 element.style.opacity = "0.92"; element.style.boxShadow = "0 8px 24px rgba(0,0,0,0.2)"; // 记录初始位置 const startX = e.clientX; const startY = e.clientY; const startLeft = parseInt(element.style.left) || 10; const startTop = parseInt(element.style.top) || 20; // 直接使用onmousemove而不是addEventListener document.onmousemove = function(e) { e.preventDefault(); // 直接计算位置差值,更高效 const xDiff = e.clientX - startX; const yDiff = e.clientY - startY; // 设置位置,限制不超出屏幕 const newLeft = Math.max(5, Math.min(window.innerWidth - element.offsetWidth - 5, startLeft + xDiff)); const newTop = Math.max(5, Math.min(window.innerHeight - element.offsetHeight - 5, startTop + yDiff)); // 直接设置样式,不经过计算 element.style.left = newLeft + 'px'; element.style.top = newTop + 'px'; }; // 鼠标释放时解除事件 document.onmouseup = function() { // 恢复正常样式 element.style.opacity = "1"; element.style.boxShadow = ""; document.onmousemove = null; document.onmouseup = null; }; }; } // 更新初始化弹窗函数 function initiate_pop() { prompt.setAttribute('id', 'pop'); prompt.classList.add('img-downloader-popup'); prompt.setAttribute('style', ` width:${Math.min(window.innerWidth * 0.4, 450)}px; min-height:100px; position:fixed; top: -800px; left:10px; z-index:2147483647; max-height:75vh; overflow: hidden; `); // 根据当前网站设置不同的标题 let domain = window.location.hostname; let title = "图片下载助手"; if(domain.includes('qq.com')) { title = "腾讯视频图片下载助手"; } else if(domain.includes('youku.com')) { title = "优酷图片下载助手"; } else if(domain.includes('iqiyi.com')) { title = "爱奇艺图片下载助手"; } else if(domain.includes('bilibili.com')) { title = "B站图片下载助手"; } else if(domain.includes('xiaohongshu.com')) { title = "小红书图片下载助手"; } prompt.innerHTML = `
🖼️

右键点击页面上的图片开始下载

或点击"刷新图片"查找当前页面所有图片

正在下载图片...
`; document.body.appendChild(prompt); // 使弹窗可拖动 makeDraggable(prompt); // 添加关闭按钮事件监听 document.querySelector('.close-btn').addEventListener('click', function() { document.getElementById('pop').style.top = '-800px'; first_hid = true; }); // 添加事件监听器 document.getElementById('toggle-batch').addEventListener('click', toggleBatchMode); document.getElementById('toggle-edit').addEventListener('click', toggleEditMode); document.getElementById('refresh-images').addEventListener('click', refreshImages); document.getElementById('common-prefix').addEventListener('input', updateCommonPrefix); document.getElementById('download-selected').addEventListener('click', downloadSelected); document.getElementById('show-help').addEventListener('click', showHelp); // 加载保存的设置 loadSettings(); } // 添加设置保存和恢复功能 function saveSettings() { const settings = { commonPrefix: common_prefix, batchMode: is_batch_mode, editMode: is_edit_mode }; localStorage.setItem('imgDownloaderSettings', JSON.stringify(settings)); } function loadSettings() { try { const savedSettings = localStorage.getItem('imgDownloaderSettings'); if (savedSettings) { const settings = JSON.parse(savedSettings); common_prefix = settings.commonPrefix || ''; is_batch_mode = settings.batchMode || false; is_edit_mode = settings.editMode || false; // 更新界面 const prefixInput = document.getElementById('common-prefix'); if (prefixInput && common_prefix) { prefixInput.value = common_prefix; } // 更新批量模式按钮 if (is_batch_mode) { document.getElementById('toggle-batch').click(); } // 更新编辑模式按钮 if (is_edit_mode) { document.getElementById('toggle-edit').click(); } } } catch (e) { console.error('加载设置失败:', e); } } // 在每次设置改变时保存 function updateCommonPrefix() { common_prefix = document.getElementById('common-prefix').value.trim(); saveSettings(); } function toggleBatchMode() { is_batch_mode = !is_batch_mode; const batchBtn = document.getElementById('toggle-batch'); const batchBar = document.querySelector('.batch-download-bar'); const imgItems = document.querySelectorAll('.img-item'); if (is_batch_mode) { batchBtn.textContent = '单个模式'; batchBtn.style.background = '#dc3545'; batchBar.style.display = 'flex'; // 显示所有复选框 imgItems.forEach(item => { const checkbox = item.querySelector('.checkbox'); if (checkbox) checkbox.style.display = 'block'; }); } else { batchBtn.textContent = '批量模式'; batchBtn.style.background = ''; batchBar.style.display = 'none'; // 隐藏所有复选框,并取消选择 imgItems.forEach(item => { item.classList.remove('selected'); const checkbox = item.querySelector('.checkbox'); if (checkbox) { checkbox.checked = false; checkbox.style.display = 'none'; } }); // 重置选择的图片 selected_images = []; updateSelectedCounter(); } saveSettings(); } function toggleEditMode() { is_edit_mode = !is_edit_mode; const editBtn = document.getElementById('toggle-edit'); const imgItems = document.querySelectorAll('.img-item'); if (is_edit_mode) { editBtn.textContent = '完成编辑'; editBtn.style.background = '#ffc107'; editBtn.style.color = '#000'; // 显示编辑输入框 imgItems.forEach(item => { const imgInfo = item.querySelector('.img-info'); const imgName = imgInfo.querySelector('.img-name'); if (imgName) { const currentName = imgName.textContent; const editInput = document.createElement('input'); editInput.type = 'text'; editInput.className = 'edit-name'; editInput.value = currentName; editInput.setAttribute('data-original', currentName); imgName.style.display = 'none'; imgInfo.appendChild(editInput); } }); } else { editBtn.textContent = '编辑名称'; editBtn.style.background = ''; editBtn.style.color = ''; // 保存编辑并删除输入框 imgItems.forEach(item => { const imgInfo = item.querySelector('.img-info'); const editInput = imgInfo.querySelector('.edit-name'); const imgName = imgInfo.querySelector('.img-name'); if (editInput && imgName) { imgName.textContent = editInput.value; imgName.style.display = ''; imgInfo.removeChild(editInput); // 更新选中图片的名称 if (is_batch_mode && item.classList.contains('selected')) { const imgSrc = item.querySelector('img').src; updateSelectedImageName(imgSrc, editInput.value); } } }); } saveSettings(); } function updateSelectedImageName(src, newName) { for (let i = 0; i < selected_images.length; i++) { if (selected_images[i].url === src) { selected_images[i].name = newName; break; } } } function updateSelectedCounter() { const counter = document.querySelector('.batch-download-bar .counter'); if (counter) { counter.textContent = `已选择: ${selected_images.length} 张图片`; } } function toggleImageSelection(e) { if (!is_batch_mode) return; const imgItem = this.closest('.img-item'); const checkbox = imgItem.querySelector('.checkbox'); const imgSrc = imgItem.querySelector('img').src; const imgName = is_edit_mode ? imgItem.querySelector('.edit-name').value : imgItem.querySelector('.img-name').textContent; if (checkbox.checked) { imgItem.classList.add('selected'); selected_images.push({ url: imgSrc, name: imgName }); } else { imgItem.classList.remove('selected'); selected_images = selected_images.filter(img => img.url !== imgSrc); } updateSelectedCounter(); } function refreshImages() { get_all_img(); } function downloadSelected() { if (selected_images.length === 0) { showToast('请至少选择一张图片!', 'error'); return; } // 显示下载进度 const progressEl = document.querySelector('.download-progress'); const progressCount = progressEl.querySelector('.progress-count'); progressEl.style.display = 'block'; // 使用Promise.all批量下载,确保所有图片都被处理 let downloadedCount = 0; const total = selected_images.length; const downloadPromises = selected_images.map((img, index) => { return new Promise((resolve) => { setTimeout(() => { // 根据是否有前缀决定是否添加序号 let filename; if (common_prefix) { // 使用前缀时添加序号保持顺序 filename = `${common_prefix}_${index+1}_${img.name}`; } else { // 没有前缀时直接使用文件名 filename = img.name; } download({ url: img.url, name: filename }, false); // 不显示每张图片的下载提示 downloadedCount++; progressCount.textContent = `${downloadedCount}/${total}`; resolve(); }, index * 300); // 每张图片间隔300ms,避免浏览器限制 }); }); Promise.all(downloadPromises).then(() => { // 下载完成后隐藏进度条并显示成功消息 setTimeout(() => { progressEl.style.display = 'none'; showToast(`成功下载了 ${total} 张图片!`); // 清空选中状态 selected_images = []; document.querySelectorAll('.img-item').forEach(item => { item.classList.remove('selected'); const checkbox = item.querySelector('.checkbox'); if (checkbox) checkbox.checked = false; }); updateSelectedCounter(); }, 1000); }); } function get_all_img() { let f_url_arr = [], u_name_arr = [], all_img = document.getElementsByTagName('img'); // 处理所有img标签 for(let a = 0; a < all_img.length; a++){ let imgUrl = all_img[a].src.split('@')[0].split('"')[0]; // 跳过空URL或太小的图片(可能是图标) if(!imgUrl || imgUrl === '' || (all_img[a].width > 0 && all_img[a].width < 50) || (all_img[a].height > 0 && all_img[a].height < 50)) { continue; } // 处理各平台图片链接 if(imgUrl.includes('youku') || imgUrl.includes('ykimg')) { imgUrl = imgUrl.split('?')[0]; } if(imgUrl.includes('iqiyi') || imgUrl.includes('qiyipic')) { imgUrl = imgUrl.split('?')[0]; } // 处理小红书图片链接 if(imgUrl.includes('xiaohongshu') || imgUrl.includes('xhscdn')) { // 移除参数获取高质量原图 imgUrl = imgUrl.split('?')[0]; // 处理特殊的缩略图URL if(imgUrl.includes('xhs-cn') && !imgUrl.includes('/fx')) { imgUrl = imgUrl.replace(/\/([^\/]+)$/, '/fx$1'); } } f_url_arr.push(imgUrl); u_name_arr.push(get_name(all_img[a])); } // 处理具有特定类名的元素 for (let i = 0; i < acceptable_classes.length; i++) { // 支持空格分隔的多个类名 let className = acceptable_classes[i].split(' ')[0]; let t = document.getElementsByClassName(className); for (let j = 0; j < t.length; j++) { if (t[j].nodeName === 'IMG') { let imgUrl = t[j].src.split('@')[0].split('"')[0]; // 处理各平台图片链接 if(imgUrl.includes('youku') || imgUrl.includes('ykimg')) { imgUrl = imgUrl.split('?')[0]; } if(imgUrl.includes('iqiyi') || imgUrl.includes('qiyipic')) { imgUrl = imgUrl.split('?')[0]; } // 处理小红书图片链接 if(imgUrl.includes('xiaohongshu') || imgUrl.includes('xhscdn')) { imgUrl = imgUrl.split('?')[0]; if(imgUrl.includes('xhs-cn') && !imgUrl.includes('/fx')) { imgUrl = imgUrl.replace(/\/([^\/]+)$/, '/fx$1'); } } u_name_arr.push(get_name(t[j])); f_url_arr.push(imgUrl); } else if (t[j].style && t[j].style.backgroundImage && t[j].style.backgroundImage !== '') { let bgUrl = ''; if (header_test.test(t[j].style.backgroundImage)) { bgUrl = t[j].style.backgroundImage .replace('url("', '') .replace('url(', '') .replace('")', '') .replace(')', '') .replace(/'/g, '') .split('@')[0] .split('"')[0]; } else { bgUrl = t[j].style.backgroundImage .replace('url("', header) .replace('url(', header) .replace('")', '') .replace(')', '') .replace(/'/g, '') .split('@')[0] .split('"')[0]; } // 处理各平台图片链接 if(bgUrl.includes('youku') || bgUrl.includes('ykimg')) { bgUrl = bgUrl.split('?')[0]; } if(bgUrl.includes('iqiyi') || bgUrl.includes('qiyipic')) { bgUrl = bgUrl.split('?')[0]; } // 处理小红书背景图片链接 if(bgUrl.includes('xiaohongshu') || bgUrl.includes('xhscdn')) { bgUrl = bgUrl.split('?')[0]; if(bgUrl.includes('xhs-cn') && !bgUrl.includes('/fx')) { bgUrl = bgUrl.replace(/\/([^\/]+)$/, '/fx$1'); } } u_name_arr.push(get_name(t[j])); f_url_arr.push(bgUrl); } } } // 额外查找可能的大图封面(针对视频网站) let possibleCoverSelectors = [ // 腾讯视频 '.site_player_inner', '.player_container', '.player_figure', // 优酷 '.player-container', '.youku-player', '.video-poster', // 爱奇艺 '.qy-player-box', '.player-wrapper', '.qy-flash-player', // 小红书 '.note-details', '.note-content', '.note-poster', '.image-wrapper', '.carousel' ]; for(let i = 0; i < possibleCoverSelectors.length; i++) { let covers = document.querySelectorAll(possibleCoverSelectors[i]); for(let j = 0; j < covers.length; j++) { if(covers[j].style && covers[j].style.backgroundImage && covers[j].style.backgroundImage !== '') { let bgUrl = ''; if (header_test.test(covers[j].style.backgroundImage)) { bgUrl = covers[j].style.backgroundImage .replace('url("', '') .replace('url(', '') .replace('")', '') .replace(')', '') .replace(/'/g, '') .split('@')[0] .split('"')[0]; } else { bgUrl = covers[j].style.backgroundImage .replace('url("', header) .replace('url(', header) .replace('")', '') .replace(')', '') .replace(/'/g, '') .split('@')[0] .split('"')[0]; } // 处理各平台图片链接 if(bgUrl.includes('youku') || bgUrl.includes('ykimg')) { bgUrl = bgUrl.split('?')[0]; } if(bgUrl.includes('iqiyi') || bgUrl.includes('qiyipic')) { bgUrl = bgUrl.split('?')[0]; } // 处理小红书背景图片链接 if(bgUrl.includes('xiaohongshu') || bgUrl.includes('xhscdn')) { bgUrl = bgUrl.split('?')[0]; if(bgUrl.includes('xhs-cn') && !bgUrl.includes('/fx')) { bgUrl = bgUrl.replace(/\/([^\/]+)$/, '/fx$1'); } } u_name_arr.push(get_name(covers[j])); f_url_arr.push(bgUrl); } } } // 特殊处理小红书笔记页面,查找高分辨率图片 if(window.location.hostname.includes('xiaohongshu.com')) { // 尝试使用特殊选择器查找小红书的高质量图片 try { // 查找笔记中的所有图片容器 const noteImages = document.querySelectorAll('.note-image, .image-wrapper img, .carousel img'); for(let i = 0; i < noteImages.length; i++) { if(noteImages[i].getAttribute('data-src')) { let imgUrl = noteImages[i].getAttribute('data-src').split('?')[0]; if(imgUrl.includes('xhs-cn') && !imgUrl.includes('/fx')) { imgUrl = imgUrl.replace(/\/([^\/]+)$/, '/fx$1'); } f_url_arr.push(imgUrl); u_name_arr.push(get_name(noteImages[i])); } } } catch(e) { console.error('提取小红书高质量图片失败:', e); } } make_img_list_prompt(f_url_arr, u_name_arr); } function check_identical(link) { if (img_list.length !== 0) { for (let i = 0; i < img_list.length; i++) { if (link === img_list[i]) { return true; } } } return false; } function get_url(target) { if (target.nodeName === 'IMG') { let imgUrl = target.src.split('@')[0].split('"')[0]; // 处理优酷和爱奇艺的图片链接,移除特定参数 if(imgUrl.includes('youku') || imgUrl.includes('ykimg')) { imgUrl = imgUrl.split('?')[0]; } if(imgUrl.includes('iqiyi') || imgUrl.includes('qiyipic')) { imgUrl = imgUrl.split('?')[0]; } final_url = { url: imgUrl, name: get_name(target) }; return true; } else { for (let i = 0; i < acceptable_classes.length; i++) { if (target.classList && target.classList.contains(acceptable_classes[i].split(' ')[0])) { if (target.nodeName !== 'IMG') { let bgUrl = header_test.test(target.style.backgroundImage) ? target.style.backgroundImage.replace('url("', '').replace('")', '').replace("')", "").split('@')[0].split('"')[0] : target.style.backgroundImage.replace('url("', header).replace('")', '').replace("')", "").split('@')[0].split('"')[0]; // 处理优酷和爱奇艺的图片链接,移除特定参数 if(bgUrl.includes('youku') || bgUrl.includes('ykimg')) { bgUrl = bgUrl.split('?')[0]; } if(bgUrl.includes('iqiyi') || bgUrl.includes('qiyipic')) { bgUrl = bgUrl.split('?')[0]; } final_url = { url: bgUrl, name: get_name(target) }; return true; } } } } } function download(url = final_url, show_progress = true) { console.log(final_url); if (!url || !url.url) { return; } if (check_identical(url.url) && show_progress) { // 使用非阻塞提示,避免弹窗 showToast("已经下载过这张图片了!"); return; } try{ // 确保URL是完整的 let fullUrl = url.url; if(!fullUrl.startsWith('http')) { fullUrl = 'https:' + fullUrl; } // 处理URL中的特殊字符 fullUrl = fullUrl.replace(/\\"/g, ''); // 处理小红书特殊图片URL if(window.location.hostname.includes('xiaohongshu.com')) { // 移除小红书图片URL中的参数,获取高质量原图 fullUrl = fullUrl.split('?')[0]; // 某些小红书图片需要替换URL if(fullUrl.includes('xhs-cn')) { fullUrl = fullUrl.replace(/\/([^\/]+)$/, '/fx$1'); } } let current_img_type = ".jpg"; // 默认使用jpg格式 // 保存原始扩展名,用于后续转换 let originalType = ""; // 从URL尝试获取文件扩展名 let lastSegment = fullUrl.split('/').pop(); if(lastSegment && lastSegment.includes('.')) { originalType = fullUrl.substring(fullUrl.lastIndexOf(".")).toLowerCase(); // 如果扩展名包含参数,只保留扩展名部分 if(originalType.includes('?')) { originalType = originalType.split('?')[0]; } // 限制扩展名长度,防止异常 if(originalType.length > 5) { originalType = ".jpg"; } } // 避免重复下载同一图片 if(!check_identical(fullUrl)) { img_list.push(fullUrl); } fetch(fullUrl).then(res => { if (!res.ok) { throw new Error(`Network response was not ok: ${res.status} ${res.statusText}`); } return res.blob(); }).then(blob => { // 如果需要转换为jpg格式,创建图片元素并使用canvas转换 if(originalType !== ".jpg" && originalType !== ".jpeg") { return convertToJpg(blob); } else { return blob; } }).then(finalBlob => { let a = document.createElement('a'); a.style.display = 'none'; a.href = URL.createObjectURL(finalBlob); // 确保文件名不含特殊字符并控制长度 let fileName = `${url.name}${current_img_type}`; if(fileName.length > 200) { fileName = fileName.substring(0, 195) + current_img_type; } a.download = fileName; document.body.appendChild(a); a.click(); document.body.removeChild(a); // 释放blob URL URL.revokeObjectURL(a.href); // 使用非阻塞提示,避免弹窗和界面弹起 if (show_progress) { showToast(`已下载: ${fileName}`); } }).catch(error => { console.error('下载图片失败:', error); if(show_progress) { showToast('下载失败,请稍后再试!', 'error'); } }); }catch(e){ console.error('下载图片出错:', e); }; } // 将其他格式的图片转换为JPG格式 function convertToJpg(blob) { return new Promise((resolve, reject) => { const img = new Image(); img.onload = function() { // 创建canvas元素 const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; // 在canvas上绘制图片 const ctx = canvas.getContext('2d'); ctx.fillStyle = 'white'; // 设置白色背景,处理透明图片 ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, 0, 0); // 将canvas内容转换为jpg格式的blob canvas.toBlob(blob => { resolve(blob); }, 'image/jpeg', 0.92); // 设置jpg质量为0.92 }; img.onerror = function() { // 如果转换失败,返回原始blob reject(new Error('图片转换失败')); }; // 加载图片 img.src = URL.createObjectURL(blob); }).catch(error => { console.error('图片转换失败:', error); return blob; // 如果转换失败,返回原始blob }); } function make_img_list_prompt(arr, u_arr) { let done = [], current_index = -1; // 根据当前网站设置不同的标题 let domain = window.location.hostname; let title = "图片下载助手"; if(domain.includes('qq.com')) { title = "腾讯视频图片下载助手"; } else if(domain.includes('youku.com')) { title = "优酷图片下载助手"; } else if(domain.includes('iqiyi.com')) { title = "爱奇艺图片下载助手"; } else if(domain.includes('bilibili.com')) { title = "B站图片下载助手"; } else if(domain.includes('xiaohongshu.com')) { title = "小红书图片下载助手"; } const popupContent = document.getElementById('pop'); // 保留控制按钮和头部布局 const headerHTML = ``; let controlsHTML = popupContent.querySelector('.controls').outerHTML; let batchBarHTML = popupContent.querySelector('.batch-download-bar').outerHTML; let progressHTML = popupContent.querySelector('.download-progress').outerHTML; popupContent.innerHTML = ` ${headerHTML}
${batchBarHTML}
${progressHTML} `; const imgContainer = popupContent.querySelector('.img-container'); // 添加一个图片计数器 let imageCount = 0; for (let i = 0; i < arr.length; i++) { let finished = false; for (let j = 0; j < done.length; j++) { if (arr[i] === done[j]) { finished = true; } } if (!finished && arr[i] !== '') { imageCount++; const imgItem = document.createElement('div'); imgItem.className = 'img-item'; // 添加复选框(批量模式使用) const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.className = 'checkbox'; checkbox.style.display = is_batch_mode ? 'block' : 'none'; checkbox.addEventListener('change', toggleImageSelection); imgItem.appendChild(checkbox); // 创建图片包装器 const imgWrapper = document.createElement('div'); imgWrapper.className = 'img-wrapper'; const img = document.createElement('img'); img.src = arr[i]; img.addEventListener('error', function() { this.src = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ij48cGF0aCBmaWxsPSIjOTk5IiBkPSJNMTMgNGg2djZoLTZ6TTMgMTJoNnY2SDN6Ii8+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgyNHYyNEgweiIvPjwvc3ZnPg=='; imgItem.style.opacity = '0.7'; }); imgWrapper.appendChild(img); imgItem.appendChild(imgWrapper); // 创建图片信息区域 const imgInfo = document.createElement('div'); imgInfo.className = 'img-info'; const imgName = document.createElement('p'); imgName.className = 'img-name'; imgName.textContent = u_arr[i] || '未命名图片'; imgInfo.appendChild(imgName); imgItem.appendChild(imgInfo); // 添加下载按钮 const downloadBtn = document.createElement('button'); downloadBtn.className = 'download-btn'; downloadBtn.innerHTML = '⬇'; downloadBtn.title = '下载此图片'; downloadBtn.addEventListener('click', function(e) { e.stopPropagation(); // 防止触发父元素点击事件 const imgSrc = this.closest('.img-item').querySelector('img').src; const nameEl = is_edit_mode ? this.closest('.img-item').querySelector('.edit-name') : this.closest('.img-item').querySelector('.img-name'); const imgName = nameEl ? nameEl.value || nameEl.textContent : '未命名图片'; download({ url: imgSrc, name: common_prefix ? `${common_prefix}_${imgName}` : imgName }); // 添加下载反馈 this.textContent = '✓'; this.style.background = '#28a745'; setTimeout(() => { this.textContent = '⬇'; this.style.background = ''; }, 1500); }); imgItem.appendChild(downloadBtn); // 点击图片项处理 imgItem.addEventListener('click', function(e) { // 如果点击的是复选框、下载按钮或编辑输入框,不处理 if (e.target.classList.contains('checkbox') || e.target.classList.contains('download-btn') || e.target.classList.contains('edit-name')) { return; } if (is_batch_mode) { // 批量模式下点击切换选中状态 const checkbox = this.querySelector('.checkbox'); checkbox.checked = !checkbox.checked; const event = new Event('change'); checkbox.dispatchEvent(event); } else if (!is_edit_mode) { // 单击模式且非编辑模式下直接打开大图预览 showImagePreview(this.querySelector('img').src, this.querySelector('.img-name').textContent); } }); imgContainer.appendChild(imgItem); done.push(arr[i]); } } // 如果没有找到图片,显示提示 if(imageCount === 0) { imgContainer.innerHTML = `
🔍

没有找到可下载的图片

请尝试右键点击具体图片或刷新页面后再试

`; } // 重新绑定事件监听器 document.getElementById('toggle-batch').addEventListener('click', toggleBatchMode); document.getElementById('toggle-edit').addEventListener('click', toggleEditMode); document.getElementById('refresh-images').addEventListener('click', refreshImages); document.getElementById('common-prefix').addEventListener('input', updateCommonPrefix); document.getElementById('download-selected').addEventListener('click', downloadSelected); // 确保帮助按钮有事件监听 const helpBtn = document.getElementById('show-help'); if (helpBtn) { helpBtn.addEventListener('click', showHelp); } // 添加关闭按钮事件监听 document.querySelector('.close-btn').addEventListener('click', function() { document.getElementById('pop').style.top = '-800px'; first_hid = true; }); // 如果是批量模式,显示批量下载栏 if (is_batch_mode) { document.querySelector('.batch-download-bar').style.display = 'flex'; document.getElementById('toggle-batch').textContent = '单个模式'; document.getElementById('toggle-batch').style.background = '#dc3545'; } else { document.querySelector('.batch-download-bar').style.display = 'none'; } // 如果是编辑模式,显示编辑输入框 if (is_edit_mode) { document.getElementById('toggle-edit').textContent = '完成编辑'; document.getElementById('toggle-edit').style.background = '#ffc107'; document.getElementById('toggle-edit').style.color = '#000'; toggleEditMode(); } // 显示弹窗在页面最左边 const popup = document.getElementById('pop'); popup.style.top = '20px'; popup.style.left = '10px'; popup.style.display = 'block'; // 确保弹窗可拖动 setTimeout(() => { makeDraggable(popup); // 确保帮助按钮有事件监听 const helpBtn = document.getElementById('show-help'); if (helpBtn) { helpBtn.addEventListener('click', showHelp); } }, 50); } // 添加非阻塞的提示toast function showToast(message, type = 'success') { // 检查是否已存在toast容器 let toastContainer = document.getElementById('img-downloader-toast-container'); if (!toastContainer) { toastContainer = document.createElement('div'); toastContainer.id = 'img-downloader-toast-container'; toastContainer.style.cssText = ` position: fixed; bottom: 15px; left: 15px; z-index: 999999; display: flex; flex-direction: column; align-items: flex-start; `; document.body.appendChild(toastContainer); } // 创建新的toast const toast = document.createElement('div'); toast.classList.add('img-downloader-toast'); // 设置toast样式 const backgroundColor = type === 'success' ? 'rgba(40, 167, 69, 0.9)' : 'rgba(220, 53, 69, 0.9)'; toast.style.backgroundColor = backgroundColor; toast.style.opacity = '0.9'; toast.style.animation = 'fadeIn 0.3s, fadeOut 0.3s 2.7s'; // 添加关闭按钮 const closeBtn = document.createElement('span'); closeBtn.innerHTML = '×'; closeBtn.style.cssText = ` margin-left: 8px; cursor: pointer; float: right; font-size: 14px; `; closeBtn.onclick = function() { toastContainer.removeChild(toast); }; // 设置消息内容 toast.innerHTML = message; toast.appendChild(closeBtn); // 添加到容器 toastContainer.appendChild(toast); // 自动消失 setTimeout(() => { if (toastContainer.contains(toast)) { toast.style.opacity = '0'; setTimeout(() => { if (toastContainer.contains(toast)) { toastContainer.removeChild(toast); } }, 300); } }, 3000); } document.oncontextmenu = (e) => { // 如果是在图片下载助手内部点击,不拦截右键事件 if (e.target.closest('.img-downloader-popup')) { return true; // 允许浏览器默认右键菜单 } console.log(e,'right click'); let target = e.target, find_element = false; if (target.nodeName === 'IMG') { let imgUrl = target.src.split('@')[0].split('"')[0]; // 处理优酷和爱奇艺的图片链接,移除特定参数 if(imgUrl.includes('youku') || imgUrl.includes('ykimg')) { imgUrl = imgUrl.split('?')[0]; } if(imgUrl.includes('iqiyi') || imgUrl.includes('qiyipic')) { imgUrl = imgUrl.split('?')[0]; } final_url = { url: imgUrl, name: get_name(target) }; // 直接下载图片,不使用confirm弹窗 download(); return false; // 阻止浏览器默认右键菜单 } find_element = get_url(target); if (!find_element) { // 显示所有图片 get_all_img(); // 强制设置位置,避免位置不正确 setTimeout(() => { const popup = document.getElementById('pop'); popup.style.top = '20px'; popup.style.left = '10px'; popup.style.display = 'block'; // 确保可见 // 再次应用拖动 makeDraggable(popup); }, 100); } else { // 直接下载图片,不使用confirm弹窗 download(); } return false; // 阻止浏览器默认右键菜单 } function get_name(ele){ let name = ""; let domain = window.location.hostname; // 根据不同网站使用不同的命名策略 if(domain.includes('qq.com')) { // 腾讯视频命名策略 name = "腾讯视频_"; try { // 尝试获取视频标题 let title = document.querySelector('.player_title') || document.querySelector('.mod_title') || document.querySelector('.video_title'); if(title) { name += title.innerText.trim(); } else { name += new Date().getTime(); } } catch(e) { name += new Date().getTime(); } } else if(domain.includes('youku.com')) { // 优酷命名策略 name = "优酷_"; try { // 尝试获取视频标题 let title = document.querySelector('.title') || document.querySelector('.video-title') || document.querySelector('.anthology-title'); if(title) { name += title.innerText.trim(); } else { name += new Date().getTime(); } } catch(e) { name += new Date().getTime(); } } else if(domain.includes('iqiyi.com')) { // 爱奇艺命名策略 name = "爱奇艺_"; try { // 尝试获取视频标题 let title = document.querySelector('.player-title') || document.querySelector('.title-wrap') || document.querySelector('.main-title'); if(title) { name += title.innerText.trim(); } else { name += new Date().getTime(); } } catch(e) { name += new Date().getTime(); } } else if(domain.includes('bilibili.com')) { // bilibili原有的命名策略 while (ele) { if(ele.classList){ switch(ele.classList.value){ case 'pop_img': name = ele.parentNode.innerText; break; case 'post-content repost': if(ele.getElementsByClassName('original-poster')[0]){ name = ele.getElementsByClassName('original-poster')[0].innerText.split('@')[1].split(':')[0]; }else{ name = ele.getElementsByClassName('username d-i-block up-info-name')[0].innerText; } break; case 'main-content': case 'card': name = ele.getElementsByClassName('user-name fs-16 ls-0 d-i-block')[0].innerText; break; case 'live-panel-item live-up': name = ele.getElementsByClassName('live-up-name tc-dark-slate fs-14 ls-0')[0].innerText; break; case 'list-item reply-wrap ': name = ele.getElementsByClassName('name')[0].innerText; break; case 'card-box': name = ele.getElementsByClassName('count up')[0].innerText; break; default: null; // still, nobody cares } } ele = ele.parentNode; } } else if(domain.includes('xiaohongshu.com')) { // 小红书命名策略 name = "小红书_"; try { // 尝试获取笔记标题 let title = document.querySelector('.title') || document.querySelector('.note-content .content') || document.querySelector('._26zd1') || document.querySelector('.note-top .title') || document.querySelector('meta[property="og:title"]'); if(title) { if(title.tagName === 'META') { name += title.getAttribute('content').trim(); } else { name += title.innerText.trim(); } } else { // 尝试获取用户名作为前缀 let username = document.querySelector('.user-nickname') || document.querySelector('.author-name') || document.querySelector('.nickname'); if(username) { name += username.innerText.trim() + "_" + new Date().getTime(); } else { name += new Date().getTime(); } } } catch(e) { name += new Date().getTime(); } } // 如果没有找到合适的名称,使用时间戳 if(!name || name === "腾讯视频_" || name === "优酷_" || name === "爱奇艺_") { name = `图片_${new Date().getTime()}`; } // 替换掉不能用作文件名的字符 name = name.replace(/[\\\/\:\*\?\"\<\>\|]/g, "_"); return name; } document.addEventListener('mouseup',(e)=>{ // 点击弹窗内部元素时保持弹窗打开 if (e.target.closest('.img-downloader-popup')) { // 确保弹窗保持显示 const popup = document.getElementById('pop'); if (popup.style.top !== '20px') { popup.style.top = '20px'; popup.style.left = '10px'; first_hid = false; } return; } // 不再自动隐藏弹窗,只点击关闭按钮时才隐藏 // document.getElementById('pop').style.top = '-800px'; // first_hid = true; }); // 给页面添加快捷键支持 document.addEventListener('keydown', (e) => { // ESC键关闭弹窗 if (e.key === 'Escape') { document.getElementById('pop').style.top = '-800px'; first_hid = true; } // 如果弹窗已显示 if (document.getElementById('pop').style.top === '10px' || parseInt(document.getElementById('pop').style.top) > 0) { // Ctrl+B - 切换批量模式 if (e.ctrlKey && e.key === 'b') { e.preventDefault(); document.getElementById('toggle-batch').click(); } // Ctrl+E - 切换编辑模式 if (e.ctrlKey && e.key === 'e') { e.preventDefault(); document.getElementById('toggle-edit').click(); } // Ctrl+S - 下载选中图片 if (e.ctrlKey && e.key === 's' && is_batch_mode) { e.preventDefault(); document.getElementById('download-selected').click(); } // Ctrl+R - 刷新图片 if (e.ctrlKey && e.key === 'r') { e.preventDefault(); document.getElementById('refresh-images').click(); } // Ctrl+A - 全选/取消全选图片 if (e.ctrlKey && e.key === 'a' && is_batch_mode) { e.preventDefault(); selectAllImages(); } } }); // 全选/取消全选图片 function selectAllImages() { const imgItems = document.querySelectorAll('.img-item'); const allSelected = selected_images.length === imgItems.length; // 如果所有图片都已选中,则取消全选 if (allSelected) { imgItems.forEach(item => { item.classList.remove('selected'); const checkbox = item.querySelector('.checkbox'); if (checkbox) checkbox.checked = false; }); selected_images = []; } else { // 否则全选 selected_images = []; imgItems.forEach(item => { item.classList.add('selected'); const checkbox = item.querySelector('.checkbox'); if (checkbox) checkbox.checked = true; const imgSrc = item.querySelector('img').src; const imgName = is_edit_mode ? item.querySelector('.edit-name').value : item.querySelector('.img-name').textContent; selected_images.push({ url: imgSrc, name: imgName }); }); } updateSelectedCounter(); } // 显示帮助信息 function showHelp() { // 创建一个模态对话框来显示帮助信息 const modal = document.createElement('div'); modal.className = 'img-downloader-help-modal'; modal.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); display: flex; justify-content: center; align-items: center; z-index: 2147483647; `; const content = document.createElement('div'); content.style.cssText = ` background-color: white; width: 80%; max-width: 500px; max-height: 80%; overflow-y: auto; padding: 20px; border-radius: 5px; box-shadow: 0 3px 10px rgba(0,0,0,0.2); position: relative; `; const closeBtn = document.createElement('button'); closeBtn.innerHTML = '×'; closeBtn.style.cssText = ` position: absolute; top: 10px; right: 10px; background: none; border: none; font-size: 24px; cursor: pointer; padding: 0; line-height: 1; `; closeBtn.onclick = function() { document.body.removeChild(modal); }; content.innerHTML = `

图片下载助手使用说明

基本功能

常用快捷键

提示

窗口标题栏可拖动调整位置

您的设置将自动保存,下次使用时会自动恢复

`; content.appendChild(closeBtn); modal.appendChild(content); // 点击模态框外部关闭 modal.addEventListener('click', function(e) { if (e.target === modal) { document.body.removeChild(modal); } }); document.body.appendChild(modal); } // 添加图片预览功能 function showImagePreview(imageSrc, imageName) { // 创建预览容器 const previewContainer = document.createElement('div'); previewContainer.className = 'img-preview-container'; previewContainer.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.85); display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 9999999; `; // 创建图片预览区域 const previewContent = document.createElement('div'); previewContent.style.cssText = ` position: relative; max-width: 85%; max-height: 75%; text-align: center; `; // 创建图片元素 const img = document.createElement('img'); img.src = imageSrc; img.style.cssText = ` max-width: 100%; max-height: 75vh; object-fit: contain; border-radius: 4px; box-shadow: 0 5px 20px rgba(0,0,0,0.5); `; // 添加文件名 const nameLabel = document.createElement('div'); nameLabel.textContent = imageName || '未命名图片'; nameLabel.style.cssText = ` color: white; padding: 8px; font-size: 14px; margin-top: 8px; `; // 添加下载按钮 const downloadBtn = document.createElement('button'); downloadBtn.textContent = '下载图片'; downloadBtn.style.cssText = ` background: #4e8df5; color: white; border: none; padding: 8px 15px; border-radius: 5px; cursor: pointer; margin-top: 10px; font-size: 13px; font-weight: 500; transition: all 0.25s; `; downloadBtn.addEventListener('click', function() { download({ url: imageSrc, name: common_prefix ? `${common_prefix}_${imageName}` : imageName }); this.textContent = '已下载'; this.style.background = '#28a745'; setTimeout(() => { this.textContent = '下载图片'; this.style.background = '#4e8df5'; }, 1500); }); // 添加关闭按钮 const closeBtn = document.createElement('button'); closeBtn.innerHTML = '×'; closeBtn.style.cssText = ` position: absolute; top: -35px; right: -35px; background: none; border: none; font-size: 25px; color: white; cursor: pointer; padding: 8px; `; closeBtn.addEventListener('click', function() { document.body.removeChild(previewContainer); }); // 点击背景关闭预览 previewContainer.addEventListener('click', function(e) { if (e.target === this) { document.body.removeChild(this); } }); // 添加ESC键关闭预览 const escHandler = function(e) { if (e.key === 'Escape') { document.body.removeChild(previewContainer); document.removeEventListener('keydown', escHandler); } }; document.addEventListener('keydown', escHandler); // 组装预览界面 previewContent.appendChild(img); previewContent.appendChild(closeBtn); previewContainer.appendChild(previewContent); previewContainer.appendChild(nameLabel); previewContainer.appendChild(downloadBtn); document.body.appendChild(previewContainer); }