Greasy Fork

画像一覧&ダウンロード

archive.todayから画像を取得し一覧の表示とダウンロードボタンを表示します。

// ==UserScript==
// @name         画像一覧&ダウンロード
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  archive.todayから画像を取得し一覧の表示とダウンロードボタンを表示します。
// @author       あるぱか
// @match        https://archive.md/*
// @exclude      https://archive.md/
// @exclude      https://archive.md/*/
// @exclude      https://archive.md/*/*
// @icon         https://archive.md/apple-touch-icon-144x144.png
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 要素の作成と追加
    function displayImageList(imageUrls) {
        // 背景の半透明黒を作成
        const overlay = document.createElement('div');
        overlay.style.position = 'fixed';
        overlay.style.top = '0';
        overlay.style.left = '0';
        overlay.style.width = '100%';
        overlay.style.height = '100%';
        overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
        overlay.style.zIndex = '9999';
        overlay.style.display = 'none';
        document.body.appendChild(overlay);

        const container = document.createElement('div');
        container.style.position = 'fixed';
        container.style.top = '50px';
        container.style.right = '80px';
        container.style.bottom = '50px';
        container.style.left = '80px';
        container.style.backgroundColor = 'white';
        container.style.border = '1px solid black';
        container.style.padding = '10px';
        container.style.zIndex = '10000';
        container.style.overflowY = 'auto';
        container.style.overflowX = 'hidden';
        container.style.display = 'none'; // 最初は表示しない

        const minimizeButton = document.createElement('button');
        minimizeButton.innerText = '×';
        minimizeButton.style.position = 'sticky';
        minimizeButton.style.top = '10px';
        minimizeButton.style.right = '10px';
        minimizeButton.style.zIndex = '10001';
        minimizeButton.style.marginLeft = '98%';
        minimizeButton.style.backgroundColor = '#c04000';
        minimizeButton.style.cursor = 'pointer';
        container.appendChild(minimizeButton);

        const title = document.createElement('h3');
        title.innerText = '画像一覧';
        title.style.textAlign = 'center';
        container.appendChild(title);

        const showButton = document.createElement('button');
        showButton.innerText = '画像一覧表示';
        showButton.style.position = 'fixed';
        showButton.style.top = '10px';
        showButton.style.right = '10px';
        showButton.style.zIndex = '10001';
        showButton.style.cursor = 'pointer';
        showButton.onclick = () => {
            container.style.display = 'block';
            overlay.style.display = 'block';
            showButton.style.display = 'none';
            document.body.style.overflow = 'hidden'; // スクロール無効
        };
        document.body.appendChild(showButton);

        const grid = document.createElement('div');
        grid.style.display = 'grid';
        grid.style.gridTemplateColumns = 'repeat(4, 1fr)';
        grid.style.gap = '10px';
        container.appendChild(grid);

        imageUrls.forEach(url => {
            const imgContainer = document.createElement('div');
            imgContainer.style.textAlign = 'center';
            imgContainer.style.display = 'flex';
            imgContainer.style.flexDirection = 'column';
            imgContainer.style.alignItems = 'center';
            imgContainer.style.justifyContent = 'space-between';
            imgContainer.style.height = '400px';
            imgContainer.style.marginBottom = '50px';

            const imgWrapper = document.createElement('div');
            imgWrapper.style.flexGrow = '1';
            imgWrapper.style.display = 'flex';
            imgWrapper.style.alignItems = 'center';
            imgWrapper.style.justifyContent = 'center';
            imgWrapper.style.maxHeight = 'calc(100% - 60px)';

            const img = document.createElement('img');
            img.src = url;
            img.style.maxWidth = '100%';
            img.style.maxHeight = '100%';
            img.style.cursor = 'pointer';
            img.onclick = () => {
                window.open(url, '_blank');
            };

            const saveButton = document.createElement('button');
            saveButton.innerText = '画像を保存';
            saveButton.style.padding = '10px 20px';
            saveButton.style.fontSize = '16px';
            saveButton.style.height = '50px';
            saveButton.style.marginTop = '10px';
            saveButton.style.cursor = 'pointer';
            saveButton.onclick = () => {
                const a = document.createElement('a');
                a.href = url;
                a.download = url.split('/').pop();
                a.click();
            };

            imgWrapper.appendChild(img);
            imgContainer.appendChild(imgWrapper);
            imgContainer.appendChild(saveButton);
            grid.appendChild(imgContainer);
        });

        document.body.appendChild(container);

        minimizeButton.onclick = () => {
            if (container.style.display === 'none') {
                container.style.display = 'block';
                overlay.style.display = 'block';
                minimizeButton.innerText = '縮小';
                document.body.style.overflow = 'hidden'; // スクロール無効
            } else {
                container.style.display = 'none';
                overlay.style.display = 'none';
                showButton.style.display = 'block';
                document.body.style.overflow = 'auto'; // スクロール有効
            }
        };
    }

    // 要素から画像URL取得
    function extractImageUrls() {
        const targetDiv = document.querySelector('#CONTENT > div.html1');
        if (!targetDiv) {
            return [];
        }

        const imageUrls = new Set();
        const imgs = targetDiv.querySelectorAll('img'); // img:not([alt])
        const anchors = targetDiv.querySelectorAll('a');

        imgs.forEach(img => {
            if (img.src && !img.src.endsWith('.svg') && img.src.startsWith('https://archive.md/') && !imageUrls.has(img.src)) {
                imageUrls.add(img.src);
            }
        });

        anchors.forEach(a => {
            if (a.href && !a.href.endsWith('.svg') && a.href.startsWith('https://archive.md/') && (a.href.endsWith('.jpg') || a.href.endsWith('.jpeg') || a.href.endsWith('.png') || a.href.endsWith('.gif') || a.href.endsWith('.mp4')) && !imageUrls.has(a.href)) {
                imageUrls.add(a.href);
            }
        });

        return Array.from(imageUrls);
    }

    function main() {
        const imageUrls = extractImageUrls();
        if (imageUrls.length > 0) {
            displayImageList(imageUrls);
        }
    }

    // 画面読み込み時に作動
    window.addEventListener('load', main);
})();