Respan Dataset Explorer

Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.

5,167,182physical rows
86shards
0.00%qualified row coverage
0.00%qualified cell coverage
Random row JSON API

turns-00049.parquet:15832

73114b64819e45c874da3df2
turn 6/12gpt-4o-2024-08-06EnglishHong Kong188 words
degenerate_repetitionAbsentFinal dense release
USER
How about this?

国内写真套图秀人模特第9360期小蛮妖秀惹火身材诱惑写真
  [XiuRen秀人网] 2024.10.29 No.9360 小蛮妖Yummy 黑丝美腿 [66+1P] 模特@小蛮妖Yummy 性感写真发布,性感黑色情趣服饰搭配性感黑丝,清新视觉性感淋漓呈现,全套写真共66P,希望大家喜欢和多多支持。模特小蛮妖Yummy第79套写真作品。。摄影:摄影师 - KING。。
ASSISTANT
Using the regex pattern:

```regex
\[[^\]]+\] \d{4}\.\d{2}\.\d{2} (VOL\.|No\.)\d+ .+? \[[^\]]+P\]
```

This pattern will match and capture the following segment from your text:

```
[XiuRen秀人网] 2024.10.29 No.9360 小蛮妖Yummy 黑丝美腿 [66+1P]
```

Here's a breakdown of how it works in your example:

1. **`\[[^\]]+\]`** captures `[XiuRen秀人网]`:
   - `\[` and `\]` match literal brackets.
   - `[^\]]+` captures all characters within the brackets.

2. **`\d{4}\.\d{2}\.\d{2}`** captures `2024.10.29`:
   - Matches a typical date format with a four-digit year, two-digit month, and two-digit day separated by periods.

3. **`(VOL\.|No\.)\d+`** captures `No.9360`:
   - `(VOL\.|No\.)` matches either `VOL.` or `No.`.
   - `\d+` captures one or more digits following either descriptor.

4. **`.+?`** captures `小蛮妖Yummy 黑丝美腿 `:
   - Matches any sequence of characters, lazily, up to the next pattern component.

5. **`\[[^\]]+P\]`** captures `[66+1P]`:
   - `\[` and `\]` match the literal brackets.
   - `[^\]]+` captures any characters inside the brackets followed by `P`, indicating an ending digit-or-more followed by `P`.

This regex effectively isolates and captures the desired segment of your text, assuming consistent structure in the parts you want to match.

turns-00049.parquet:15833

bf4e7f4d283172485be67339
turn 7/12gpt-4o-2024-08-06EnglishHong Kong204 words
degenerate_repetitionAbsentFinal dense release
USER
If  2024.09.14 No.9160 叫我小猫 美臀性感  can be any alphanumeric pattern...how do I can the Regex to match it?
ASSISTANT
If the segment `2024.09.14 No.9160 叫我小猫 美臀性感` can be any alphanumeric pattern, you can adjust the regex pattern to accommodate this variability. You can use a pattern that is more flexible in matching any sequence of characters between specific known parts of the pattern. 

Here’s how you can modify the regex:

```regex
\[[^\]]+\] .+? \[[^\]]+P\]
```

Here's the breakdown of this pattern:

1. **`\[[^\]]+\]`**: Matches the opening bracket segment, such as `[XiuRen秀人网]`.
   - `\[` and `\]` match literal brackets.
   - `[^\]]+` captures all characters within the brackets.

2. **`. +?`**: Matches any character sequence non-greedily, allowing for flexibility in what it captures. This will cover everything after the initial bracketed segment up to the next known bracketed segment.

3. **`\[[^\]]+P\]`**: Matches the closing bracket segment, such as `[66+1P]`.
   - `\[` and `\]` match literal brackets.
   - `[^\]]+P` captures all characters inside the brackets that end with a digit or more followed by `P`.

This regex pattern becomes flexible enough to handle any alphanumeric sequence between your known bracketed sections, allowing it to capture the desired part of the text without restrictions on the content in between.

turns-00049.parquet:15834

b272a10100b43d5dbc7cf8d0
turn 8/12gpt-4o-2024-08-06EnglishHong Kong164 words
degenerate_repetitionAbsentFinal dense release
USER
using this new Regex pattern, what will I get from this
秀人旗下新写真[HuaYan花の颜]第070期绯月樱高叉连体衣完美诱惑写真
  [HuaYan花の颜] 2019.11.21 VOL.070 绯月樱-Cherry [55P] @绯月樱-Cherry 马尔代夫旅拍新图上架~ 全套写真共55张,两套服装,希望大家喜欢!
ASSISTANT
Using the regex pattern:

```regex
\[[^\]]+\] .+? \[[^\]]+P\]
```

Applied to the text you provided, this pattern will match and capture the following segment:

```
[HuaYan花の颜] 2019.11.21 VOL.070 绯月樱-Cherry [55P]
```

Here's how the pattern works here:

1. **`\[[^\]]+\]`** matches `[HuaYan花の颜]`:
   - The `\[` and `\]` match the literal opening and closing brackets.
   - `[^\]]+` captures everything inside the brackets.

2. **`. +?`** matches `2019.11.21 VOL.070 绯月樱-Cherry `:
   - This portion of the regex is non-greedy, capturing all characters from immediately after the initial bracketed term until it reaches the next part that resembles the end bracket pattern.

3. **`\[[^\]]+P\]`** matches `[55P]`:
   - `\[` and `\]` match the literal brackets.
   - `[^\]]+P` captures all characters inside the brackets, ensuring it ends with a 'P'.

This regex effectively captures the entire desired segment, handling any variety in the alphanumeric content between the known structured parts.

turns-00049.parquet:15835

1bba7d87529f1e6b7f345b50
turn 9/12gpt-4o-2024-08-06EnglishHong Kong2271 words
degenerate_repetitionAbsentFinal dense release
USER
// ==UserScript==
// @name         JYNGMN Image Downloader
// @namespace    http://tampermonkey.net/
// @version      1.26
// @description  Download images from specified WebURLs as a ZIP file, log image URLs, and add DOWNLOAD buttons correctly, without leaving the page. Compatible with Chrome and Edge browsers, supports multiple pages.
// @author
// @match        https://www.xinggan5.top/*
// @connect      *
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// ==/UserScript==

(function () {
    'use strict';

    // **Initialization Log**
    console.log('JYNGMN Image Downloader script initializing...');

    /**
     * Utility function to convert relative URLs to absolute URLs.
     * @param {string} url - The URL to convert.
     * @param {string} base - The base URL for conversion.
     * @returns {string} - The absolute URL.
     */
    function makeAbsoluteURL(url, base) {
        try {
            return new URL(url, base || window.location.origin).href;
        } catch (error) {
            console.error(`Invalid URL: ${url} - Error: ${error.message}`);
            return url;
        }
    }

    /**
     * Function to inject external scripts (e.g., JSZip).
     * @param {string} url - The URL of the script to inject.
     * @returns {Promise} - Resolves when the script is loaded.
     */
    async function injectScript(url) {
        return new Promise((resolve, reject) => {
            if (document.querySelector(`script[src="${url}"]`)) {
                console.log(`Script already injected: ${url}`);
                resolve();
                return;
            }

            const script = document.createElement('script');
            script.src = url;
            script.onload = () => {
                console.log(`Injected script loaded: ${url}`);
                resolve();
            };
            script.onerror = () => {
                console.error(`Failed to load script: ${url}`);
                reject(new Error(`Failed to load script: ${url}`));
            };
            document.head.appendChild(script);
        });
    }

    /**
     * Function to fetch and parse HTML from a given URL using GM_xmlhttpRequest.
     * @param {string} url - The URL to fetch.
     * @returns {Promise<Document>} - Resolves with the parsed HTML document.
     */
    function fetchHTML(url) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                onload: function (response) {
                    if (response.status >= 200 && response.status < 400) {
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(response.responseText, 'text/html');
                        resolve(doc);
                    } else {
                        reject(new Error(`Failed to fetch page: ${url} - Status: ${response.status}`));
                    }
                },
                onerror: function () {
                    reject(new Error(`Network error while fetching page: ${url}`));
                }
            });
        });
    }

    /**
     * Function to fetch an image blob from a URL using the Fetch API.
     * @param {string} url - The image URL.
     * @returns {Promise<Blob|null>} - Resolves with the image blob or null if failed.
     */
    async function fetchImage(url) {
        try {
            console.log(`Fetching image: ${url}`);
            const response = await fetch(url, { mode: 'cors', credentials: 'omit' });
            if (!response.ok) throw new Error(`Failed to fetch image: ${url} - Status: ${response.status}`);
            return await response.blob();
        } catch (error) {
            console.error(`Error fetching image: ${error.message}`);
            return null;
        }
    }

    /**
     * Utility function to extract the file extension from a URL.
     * @param {string} url - The URL to extract the extension from.
     * @returns {string} - The file extension (default: 'jpg').
     */
    function getFileExtension(url) {
        const match = url.match(/\.([a-zA-Z0-9]+)(?:\?.*)?$/);
        return match ? match[1].toLowerCase() : 'jpg';
    }

    /**
     * Function to trigger the download of a ZIP blob using an anchor element.
     * @param {string} blobUrl - The Object URL of the ZIP blob.
     * @param {string} fileName - The desired name for the downloaded ZIP file.
     */
    function downloadUsingAnchor(blobUrl, fileName) {
        const a = document.createElement('a');
        a.href = blobUrl;
        a.download = fileName;
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        console.log(`Download initiated for: ${fileName}`);
    }

    /**
     * Function to create and download the ZIP file using JSZip.
     * @param {JSZip} zip - The JSZip instance containing files.
     * @param {string} [zipName='images.zip'] - The desired name for the ZIP file.
     */
    async function createAndDownloadZip(zip, zipName = 'images.zip') {
        try {
            console.log('Generating ZIP Blob...');
            const zipBlob = await zip.generateAsync({ type: 'blob', compression: 'STORE' });
            console.log('ZIP Blob generated. Size:', zipBlob.size, 'bytes');

            const blobUrl = URL.createObjectURL(zipBlob);
            downloadUsingAnchor(blobUrl, zipName);
        } catch (error) {
            console.error(`Error creating or downloading ZIP: ${error.message}`);
            alert(`An error occurred while creating the ZIP file: ${error.message}`);
        }
    }

    /**
     * Function to add a DOWNLOAD button to a target element with an associated linkUrl.
     * @param {HTMLElement} targetElement - The element to which the button will be appended or after which it will be inserted.
     * @param {string} linkUrl - The URL to be processed when the button is clicked.
     * @param {boolean} useCurrentPage - If true, processes the current page without fetching linkUrl.
     * @param {string} insertMode - Where to insert the button: 'after' or 'append'.
     */
    function addDownloadButton(targetElement, linkUrl, useCurrentPage = false, insertMode = 'after') {
        // Check if the button already exists based on the insertMode
        if (insertMode === 'append') {
            if (targetElement.querySelector('button.download-button')) {
                return; // Button already exists inside the target
            }
        } else if (insertMode === 'after') {
            // Check the next sibling if insertMode is 'after'
            if (targetElement.nextElementSibling && targetElement.nextElementSibling.classList.contains('download-button')) {
                return; // Button already exists after the target
            }
        }

        const button = document.createElement('button');
        button.innerText = 'DOWNLOAD';
        button.classList.add('download-button');
        // **Styling the Button**
        button.style.marginLeft = '10px';
        button.style.padding = '5px 10px';
        button.style.cursor = 'pointer';
        button.style.backgroundColor = '#28a745';
        button.style.color = '#fff';
        button.style.border = 'none';
        button.style.borderRadius = '4px';
        button.style.fontSize = '14px';
        button.style.transition = 'background-color 0.3s';
        button.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';

        // **Hover Effects for the Button**
        button.addEventListener('mouseenter', () => {
            button.style.backgroundColor = '#218838';
        });
        button.addEventListener('mouseleave', () => {
            button.style.backgroundColor = '#28a745';
        });

        // **Click Event to Initiate the Download Process**
        button.addEventListener('click', async (event) => {
            event.preventDefault(); // Prevent default behavior if applicable
            button.disabled = true;
            const originalText = button.innerText;
            button.innerText = 'Processing...';
            console.log(`DOWNLOAD button clicked for URL: ${linkUrl}, useCurrentPage: ${useCurrentPage}`);

            await downloadImagesFromUrl(linkUrl, useCurrentPage);

            button.innerText = originalText;
            button.disabled = false;
        });

        // **Inserting the Button at the Correct Location**
        if (insertMode === 'append') {
            targetElement.appendChild(button);
            console.log(`DOWNLOAD button appended to`, targetElement);
        } else { // 'after'
            targetElement.insertAdjacentElement('afterend', button);
            console.log(`DOWNLOAD button added after`, targetElement);
        }
    }

    /**
     * Main function to download images from a given URL.
     * @param {string} linkUrl - The URL from which to download images.
     * @param {boolean} useCurrentPage - If true, use the current document instead of fetching linkUrl.
     */
    async function downloadImagesFromUrl(linkUrl, useCurrentPage = false) {
        try {
            console.log(`Starting image download process for URL: ${useCurrentPage ? window.location.href : linkUrl}`);
            let doc;

            if (useCurrentPage) {
                doc = document;
            } else {
                doc = await fetchHTML(linkUrl);
            }

            // **Extracting the Title for the ZIP Filename**
            const jianjieDiv = doc.querySelector('div.article-meta');
            if (!jianjieDiv) {
                throw new Error('div.article-meta not found on the target page.');
            }

            const jianjieText = jianjieDiv.textContent.trim();
            console.log(`Extracted jianjie text: ${jianjieText}`);

            const titleMatch = jianjieText.match(/\[.*?\d+P\]/);
            if (!titleMatch || !titleMatch[0]) {
                console.error('TITLE not found in extracted text.');
                alert('Title pattern not matched. Please check the page structure.');
                return;
            }

            const TITLE = titleMatch[0].trim().replace(/[\\/:*?"<>|]/g, '_');
            console.log(`Extracted TITLE for ZIP: ${TITLE}`);

            // **Collecting All Image Page URLs from div.pagination**
            const paginationDiv = doc.querySelector('div.pagination');
            let pageUrls = [];

            if (paginationDiv) {
                const pageLinks = paginationDiv.querySelectorAll('a[href]');
                pageUrls = Array.from(pageLinks)
                    .filter(link => /^\d+$/.test(link.textContent.trim()))
                    .map(link => makeAbsoluteURL(link.getAttribute('href'), linkUrl));
            } else {
                console.warn('div.pagination not found. Proceeding with the current page only.');
            }

            // **Handling Button 2 (Current Page)**
            if (useCurrentPage && pageUrls.length === 0) {
                pageUrls.push(window.location.href);
            }

            console.log(`Total related pages found: ${pageUrls.length}`);

            // **Storing Unique Image URLs**
            const images = new Set();

            /**
             * Function to process a single page and collect image URLs.
             * @param {string} pageUrl - The URL of the page to process.
             */
            async function processPage(pageUrl) {
                try {
                    console.log(`Processing page: ${pageUrl}`);
                    const pageDoc = useCurrentPage && pageUrl === window.location.href ? document : await fetchHTML(pageUrl);
                    const contentDivs = pageDoc.querySelectorAll('article.article-content p');
                    if (contentDivs.length > 0) {
                        let imagesInPage = [];
                        contentDivs.forEach(div => {
                            const imgs = div.querySelectorAll('img[src]');
                            imagesInPage.push(...imgs);
                        });
                        console.log(`Found ${imagesInPage.length} images in ${pageUrl}`);
                        imagesInPage.forEach(img => {
                            const src = img.getAttribute('src');
                            if (src) {
                                images.add(makeAbsoluteURL(src, pageUrl));
                            }
                        });
                    } else {
                        console.warn(`No article.article-content p found in ${pageUrl}`);
                    }
                } catch (e) {
                    console.warn(`Failed to process ${pageUrl}: ${e.message}`);
                }
            }

            // **Processing All Pages with Concurrency Control**
            const CONCURRENT_LIMIT = 5;
            let index = 0;

            async function processNext() {
                while (index < pageUrls.length) {
                    const currentIndex = index++;
                    const pageUrl = pageUrls[currentIndex];
                    await processPage(pageUrl);
                }
            }

            const workers = [];
            for (let i = 0; i < CONCURRENT_LIMIT; i++) {
                workers.push(processNext());
            }
            await Promise.all(workers);

            if (images.size === 0) {
                console.error('No images found.');
                alert('No images found on the target page(s).');
                return;
            }

            const imageArray = Array.from(images);
            console.log(`Total images collected: ${imageArray.length}`);

            // **Initializing JSZip**
            const zip = new JSZip();
            let counter = 0;
            const totalImages = imageArray.length;

            // **Loop Through Each Image to Add to ZIP**
            for (let i = 0; i < imageArray.length; i++) {
                const imgUrl = imageArray[i];
                const isLastImage = (i === imageArray.length - 1); // Check if it's the last image

                try {
                    const blob = await fetchImage(imgUrl);
                    if (!blob) {
                        console.warn(`Skipping image due to fetch failure: ${imgUrl}`);
                        continue;
                    }

                    const extension = getFileExtension(imgUrl);
                    const validExtensions = ['jpg', 'jpeg', 'png', 'webp', 'bmp', 'tiff'];
                    const finalExtension = validExtensions.includes(extension) ? extension : 'jpg';

                    let filename;
                    if (isLastImage) {
                        // **Rename the Last Image to '000.ext'**
                        filename = `000.${finalExtension}`;
                    } else {
                        // **Name Other Images Sequentially: '001.ext', '002.ext', etc.**
                        // Note: Counter starts at 0, so add 1 and pad with zeros
                        filename = `${String(counter + 1).padStart(3, '0')}.${finalExtension}`;
                    }

                    zip.file(filename, blob);
                    counter++;
                    console.log(`Added ${filename} to ZIP (${counter}/${totalImages})`);
                } catch (e) {
                    console.warn(`Failed to fetch/add image ${imgUrl}: ${e.message}`);
                }
            }

            if (counter === 0) {
                console.error('No images were successfully added to the ZIP.');
                alert('No images were successfully downloaded.');
                return;
            }

            console.log(`Successfully added ${counter} images to the ZIP.`);
            await createAndDownloadZip(zip, `${TITLE}.zip`);

        } catch (error) {
            console.error(`Error during image download process: ${error.message}`);
            alert('An error occurred during the image download process.');
        }
    }

    /**
     * Function to find relevant elements and add DOWNLOAD buttons accordingly.
     * Adjusted to match the provided HTML structures.
     */
    function findAndAddButtons() {
        // **Adding DOWNLOAD Button 1 to div.node p a b**
        const titleLinks = document.querySelectorAll('div.node p a b');
        titleLinks.forEach(link => {
            const aTag = link.parentElement; // Get the <a> tag

            if (aTag && !aTag.nextElementSibling?.classList.contains('download-button')) {
                const href = aTag.getAttribute('href');
                if (href) {
                    const linkUrl = makeAbsoluteURL(href, window.location.href);
                    addDownloadButton(link, linkUrl, false, 'after'); // Insert after the <b> tag
                } else {
                    console.warn('No href found for div.node p a b element.');
                }
            }
        });

        // **Adding DOWNLOAD Button 2 to div.toptip**
        const toptipDivs = document.querySelectorAll('div.toptip');
        toptipDivs.forEach(div => {
            if (!div.querySelector('button.download-button')) {
                // Button 2 processes the current page
                addDownloadButton(div, window.location.href, true, 'append'); // Insert inside div.toptip
            }
        });
    }

    /**
     * Function to initialize the script: inject JSZip and add buttons.
     */
    async function initializeScript() {
        console.log('Initializing JYNGMN Image Downloader script...');
        try {
            // **Injecting JSZip**
            await injectScript('https://cdn.jsdelivr.net/npm/jszip@3.10.0/dist/jszip.min.js');
            if (typeof JSZip === 'undefined') {
                throw new Error('JSZip failed to load after injection.');
            }
            console.log('JSZip loaded successfully. Version:', JSZip.version);

            // **Adding DOWNLOAD Buttons**
            findAndAddButtons();

            // **Setting Up MutationObserver to Handle Dynamic Content**
            const observer = new MutationObserver((mutations) => {
                for (const mutation of mutations) {
                    if (mutation.type === 'childList') {
                        findAndAddButtons();
                    }
                }
            });

            observer.observe(document.body, { childList: true, subtree: true });
            console.log('MutationObserver set to watch for new elements to add DOWNLOAD buttons.');

        } catch (error) {
            console.error('Failed to inject JSZip:', error.message);
            alert('Failed to load JSZip library. Please check the console for details.');
        }
    }

    /**
     * Ensuring the script runs after the DOM is fully loaded.
     */
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initializeScript);
    } else {
        initializeScript();
    }

})();

Can you apply this new Regex pattern to this script for finding the TITLE?
ASSISTANT
To apply the updated regex pattern `\[[^\]]+\] .+? \[[^\]]+P\]` to the script in order to find the `TITLE`, you would need to adjust the way the script extracts the title from the HTML content. The new pattern aims to match a segment of text that may include any alphanumeric pattern between known bracketed parts.

Here's how you could modify the script to use this pattern when fetching the title:

```javascript
/**
 * Main function to download images from a given URL.
 * @param {string} linkUrl - The URL from which to download images.
 * @param {boolean} useCurrentPage - If true, use the current document instead of fetching linkUrl.
 */
async function downloadImagesFromUrl(linkUrl, useCurrentPage = false) {
    try {
        console.log(`Starting image download process for URL: ${useCurrentPage ? window.location.href : linkUrl}`);
        let doc;

        if (useCurrentPage) {
            doc = document;
        } else {
            doc = await fetchHTML(linkUrl);
        }

        // **Extracting the Title for the ZIP Filename**
        const titleText = doc.body.textContent || ''; // Assuming the whole body as potential source
        console.log(`Extracted text for title matching: ${titleText.substring(0, 100)}...`); // Sample for log

        const titleMatch = titleText.match(/\[[^\]]+\] .+? \[[^\]]+P\]/);
        if (!titleMatch || !titleMatch[0]) {
            console.error('TITLE not found in extracted text.');
            alert('Title pattern not matched. Please check the page structure.');
            return;
        }

        const TITLE = titleMatch[0].trim().replace(/[\\/:*?"<>|]/g, '_');
        console.log(`Extracted TITLE for ZIP: ${TITLE}`);

        // **Collecting All Image Page URLs from div.pagination**
        const paginationDiv = doc.querySelector('div.pagination');
        let pageUrls = [];

        if (paginationDiv) {
            const pageLinks = paginationDiv.querySelectorAll('a[href]');
            pageUrls = Array.from(pageLinks)
                .filter(link => /^\d+$/.test(link.textContent.trim()))
                .map(link => makeAbsoluteURL(link.getAttribute('href'), linkUrl));
        } else {
            console.warn('div.pagination not found. Proceeding with the current page only.');
        }

        // **Handling Button 2 (Current Page)**
        if (useCurrentPage && pageUrls.length === 0) {
            pageUrls.push(window.location.href);
        }

        console.log(`Total related pages found: ${pageUrls.length}`);

        // **Storing Unique Image URLs**
        const images = new Set();

        //... (rest of the function unchanged)
    } catch (error) {
        console.error(`Error during image download process: ${error.message}`);
        alert('An error occurred during the image download process.');
    }
}
```

### Explanation:

- **Text Extraction**: I used the entire document's text (`doc.body.textContent`) to search for a potential title. This change makes sure that we're looking through as much content as feasible.
- **Regex**: The regex `\[[^\]]+\] .+? \[[^\]]+P\]` looks for text structures with known bounding brackets and includes an alphanumeric pattern in between.
- **Fallback and Alerts**: If the title is not found using this pattern, it logs an error and prompts an alert, allowing users to know something didn’t work as expected.

This approach assumes that the title would match the specified pattern somewhere in the document's text content. If more specific or varied sources for the title are necessary, this might need expanding to analyze different parts of the page structure.

turns-00049.parquet:15836

a462422d84b62bca00b47190
turn 10/12gpt-4o-2024-08-06EnglishHong Kong1961 words
degenerate_repetitionAbsentFinal dense release
USER
Please print out the entire script.
ASSISTANT
Certainly! Here is the entire script with the necessary modifications to use the new regex pattern for extracting the title, matching alphanumeric and structured text:

```javascript
// ==UserScript==
// @name         JYNGMN Image Downloader
// @namespace    http://tampermonkey.net/
// @version      1.26
// @description  Download images from specified WebURLs as a ZIP file, log image URLs, and add DOWNLOAD buttons correctly, without leaving the page. Compatible with Chrome and Edge browsers, supports multiple pages.
// @author
// @match        https://www.xinggan5.top/*
// @connect      *
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// ==/UserScript==

(function () {
    'use strict';

    // **Initialization Log**
    console.log('JYNGMN Image Downloader script initializing...');

    /**
     * Utility function to convert relative URLs to absolute URLs.
     * @param {string} url - The URL to convert.
     * @param {string} base - The base URL for conversion.
     * @returns {string} - The absolute URL.
     */
    function makeAbsoluteURL(url, base) {
        try {
            return new URL(url, base || window.location.origin).href;
        } catch (error) {
            console.error(`Invalid URL: ${url} - Error: ${error.message}`);
            return url;
        }
    }

    /**
     * Function to inject external scripts (e.g., JSZip).
     * @param {string} url - The URL of the script to inject.
     * @returns {Promise} - Resolves when the script is loaded.
     */
    async function injectScript(url) {
        return new Promise((resolve, reject) => {
            if (document.querySelector(`script[src="${url}"]`)) {
                console.log(`Script already injected: ${url}`);
                resolve();
                return;
            }

            const script = document.createElement('script');
            script.src = url;
            script.onload = () => {
                console.log(`Injected script loaded: ${url}`);
                resolve();
            };
            script.onerror = () => {
                console.error(`Failed to load script: ${url}`);
                reject(new Error(`Failed to load script: ${url}`));
            };
            document.head.appendChild(script);
        });
    }

    /**
     * Function to fetch and parse HTML from a given URL using GM_xmlhttpRequest.
     * @param {string} url - The URL to fetch.
     * @returns {Promise<Document>} - Resolves with the parsed HTML document.
     */
    function fetchHTML(url) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                onload: function (response) {
                    if (response.status >= 200 && response.status < 400) {
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(response.responseText, 'text/html');
                        resolve(doc);
                    } else {
                        reject(new Error(`Failed to fetch page: ${url} - Status: ${response.status}`));
                    }
                },
                onerror: function () {
                    reject(new Error(`Network error while fetching page: ${url}`));
                }
            });
        });
    }

    /**
     * Function to fetch an image blob from a URL using the Fetch API.
     * @param {string} url - The image URL.
     * @returns {Promise<Blob|null>} - Resolves with the image blob or null if failed.
     */
    async function fetchImage(url) {
        try {
            console.log(`Fetching image: ${url}`);
            const response = await fetch(url, { mode: 'cors', credentials: 'omit' });
            if (!response.ok) throw new Error(`Failed to fetch image: ${url} - Status: ${response.status}`);
            return await response.blob();
        } catch (error) {
            console.error(`Error fetching image: ${error.message}`);
            return null;
        }
    }

    /**
     * Utility function to extract the file extension from a URL.
     * @param {string} url - The URL to extract the extension from.
     * @returns {string} - The file extension (default: 'jpg').
     */
    function getFileExtension(url) {
        const match = url.match(/\.([a-zA-Z0-9]+)(?:\?.*)?$/);
        return match ? match[1].toLowerCase() : 'jpg';
    }

    /**
     * Function to trigger the download of a ZIP blob using an anchor element.
     * @param {string} blobUrl - The Object URL of the ZIP blob.
     * @param {string} fileName - The desired name for the downloaded ZIP file.
     */
    function downloadUsingAnchor(blobUrl, fileName) {
        const a = document.createElement('a');
        a.href = blobUrl;
        a.download = fileName;
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        console.log(`Download initiated for: ${fileName}`);
    }

    /**
     * Function to create and download the ZIP file using JSZip.
     * @param {JSZip} zip - The JSZip instance containing files.
     * @param {string} [zipName='images.zip'] - The desired name for the ZIP file.
     */
    async function createAndDownloadZip(zip, zipName = 'images.zip') {
        try {
            console.log('Generating ZIP Blob...');
            const zipBlob = await zip.generateAsync({ type: 'blob', compression: 'STORE' });
            console.log('ZIP Blob generated. Size:', zipBlob.size, 'bytes');

            const blobUrl = URL.createObjectURL(zipBlob);
            downloadUsingAnchor(blobUrl, zipName);
        } catch (error) {
            console.error(`Error creating or downloading ZIP: ${error.message}`);
            alert(`An error occurred while creating the ZIP file: ${error.message}`);
        }
    }

    /**
     * Function to add a DOWNLOAD button to a target element with an associated linkUrl.
     * @param {HTMLElement} targetElement - The element to which the button will be appended or after which it will be inserted.
     * @param {string} linkUrl - The URL to be processed when the button is clicked.
     * @param {boolean} useCurrentPage - If true, processes the current page without fetching linkUrl.
     * @param {string} insertMode - Where to insert the button: 'after' or 'append'.
     */
    function addDownloadButton(targetElement, linkUrl, useCurrentPage = false, insertMode = 'after') {
        // Check if the button already exists based on the insertMode
        if (insertMode === 'append') {
            if (targetElement.querySelector('button.download-button')) {
                return; // Button already exists inside the target
            }
        } else if (insertMode === 'after') {
            // Check the next sibling if insertMode is 'after'
            if (targetElement.nextElementSibling && targetElement.nextElementSibling.classList.contains('download-button')) {
                return; // Button already exists after the target
            }
        }

        const button = document.createElement('button');
        button.innerText = 'DOWNLOAD';
        button.classList.add('download-button');
        // **Styling the Button**
        button.style.marginLeft = '10px';
        button.style.padding = '5px 10px';
        button.style.cursor = 'pointer';
        button.style.backgroundColor = '#28a745';
        button.style.color = '#fff';
        button.style.border = 'none';
        button.style.borderRadius = '4px';
        button.style.fontSize = '14px';
        button.style.transition = 'background-color 0.3s';
        button.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';

        // **Hover Effects for the Button**
        button.addEventListener('mouseenter', () => {
            button.style.backgroundColor = '#218838';
        });
        button.addEventListener('mouseleave', () => {
            button.style.backgroundColor = '#28a745';
        });

        // **Click Event to Initiate the Download Process**
        button.addEventListener('click', async (event) => {
            event.preventDefault(); // Prevent default behavior if applicable
            button.disabled = true;
            const originalText = button.innerText;
            button.innerText = 'Processing...';
            console.log(`DOWNLOAD button clicked for URL: ${linkUrl}, useCurrentPage: ${useCurrentPage}`);

            await downloadImagesFromUrl(linkUrl, useCurrentPage);

            button.innerText = originalText;
            button.disabled = false;
        });

        // **Inserting the Button at the Correct Location**
        if (insertMode === 'append') {
            targetElement.appendChild(button);
            console.log(`DOWNLOAD button appended to`, targetElement);
        } else { // 'after'
            targetElement.insertAdjacentElement('afterend', button);
            console.log(`DOWNLOAD button added after`, targetElement);
        }
    }

    /**
     * Main function to download images from a given URL.
     * @param {string} linkUrl - The URL from which to download images.
     * @param {boolean} useCurrentPage - If true, use the current document instead of fetching linkUrl.
     */
    async function downloadImagesFromUrl(linkUrl, useCurrentPage = false) {
        try {
            console.log(`Starting image download process for URL: ${useCurrentPage ? window.location.href : linkUrl}`);
            let doc;

            if (useCurrentPage) {
                doc = document;
            } else {
                doc = await fetchHTML(linkUrl);
            }

            // **Extracting the Title for the ZIP Filename**
            const titleText = doc.body.textContent || ''; // Assuming the whole body as potential source
            console.log(`Extracted text for title matching: ${titleText.substring(0, 100)}...`); // Sample for log

            const titleMatch = titleText.match(/\[[^\]]+\] .+? \[[^\]]+P\]/);
            if (!titleMatch || !titleMatch[0]) {
                console.error('TITLE not found in extracted text.');
                alert('Title pattern not matched. Please check the page structure.');
                return;
            }

            const TITLE = titleMatch[0].trim().replace(/[\\/:*?"<>|]/g, '_');
            console.log(`Extracted TITLE for ZIP: ${TITLE}`);

            // **Collecting All Image Page URLs from div.pagination**
            const paginationDiv = doc.querySelector('div.pagination');
            let pageUrls = [];

            if (paginationDiv) {
                const pageLinks = paginationDiv.querySelectorAll('a[href]');
                pageUrls = Array.from(pageLinks)
                    .filter(link => /^\d+$/.test(link.textContent.trim()))
                    .map(link => makeAbsoluteURL(link.getAttribute('href'), linkUrl));
            } else {
                console.warn('div.pagination not found. Proceeding with the current page only.');
            }

            // **Handling Button 2 (Current Page)**
            if (useCurrentPage && pageUrls.length === 0) {
                pageUrls.push(window.location.href);
            }

            console.log(`Total related pages found: ${pageUrls.length}`);

            // **Storing Unique Image URLs**
            const images = new Set();

            /**
             * Function to process a single page and collect image URLs.
             * @param {string} pageUrl - The URL of the page to process.
             */
            async function processPage(pageUrl) {
                try {
                    console.log(`Processing page: ${pageUrl}`);
                    const pageDoc = useCurrentPage && pageUrl === window.location.href ? document : await fetchHTML(pageUrl);
                    const contentDivs = pageDoc.querySelectorAll('article.article-content p');
                    if (contentDivs.length > 0) {
                        let imagesInPage = [];
                        contentDivs.forEach(div => {
                            const imgs = div.querySelectorAll('img[src]');
                            imagesInPage.push(...imgs);
                        });
                        console.log(`Found ${imagesInPage.length} images in ${pageUrl}`);
                        imagesInPage.forEach(img => {
                            const src = img.getAttribute('src');
                            if (src) {
                                images.add(makeAbsoluteURL(src, pageUrl));
                            }
                        });
                    } else {
                        console.warn(`No article.article-content p found in ${pageUrl}`);
                    }
                } catch (e) {
                    console.warn(`Failed to process ${pageUrl}: ${e.message}`);
                }
            }

            // **Processing All Pages with Concurrency Control**
            const CONCURRENT_LIMIT = 5;
            let index = 0;

            async function processNext() {
                while (index < pageUrls.length) {
                    const currentIndex = index++;
                    const pageUrl = pageUrls[currentIndex];
                    await processPage(pageUrl);
                }
            }

            const workers = [];
            for (let i = 0; i < CONCURRENT_LIMIT; i++) {
                workers.push(processNext());
            }
            await Promise.all(workers);

            if (images.size === 0) {
                console.error('No images found.');
                alert('No images found on the target page(s).');
                return;
            }

            const imageArray = Array.from(images);
            console.log(`Total images collected: ${imageArray.length}`);

            // **Initializing JSZip**
            const zip = new JSZip();
            let counter = 0;
            const totalImages = imageArray.length;

            // **Loop Through Each Image to Add to ZIP**
            for (let i = 0; i < imageArray.length; i++) {
                const imgUrl = imageArray[i];
                const isLastImage = (i === imageArray.length - 1); // Check if it's the last image

                try {
                    const blob = await fetchImage(imgUrl);
                    if (!blob) {
                        console.warn(`Skipping image due to fetch failure: ${imgUrl}`);
                        continue;
                    }

                    const extension = getFileExtension(imgUrl);
                    const validExtensions = ['jpg', 'jpeg', 'png', 'webp', 'bmp', 'tiff'];
                    const finalExtension = validExtensions.includes(extension) ? extension : 'jpg';

                    let filename;
                    if (isLastImage) {
                        // **Rename the Last Image to '000.ext'**
                        filename = `000.${finalExtension}`;
                    } else {
                        // **Name Other Images Sequentially: '001.ext', '002.ext', etc.**
                        // Note: Counter starts at 0, so add 1 and pad with zeros
                        filename = `${String(counter + 1).padStart(3, '0')}.${finalExtension}`;
                    }

                    zip.file(filename, blob);
                    counter++;
                    console.log(`Added ${filename} to ZIP (${counter}/${totalImages})`);
                } catch (e) {
                    console.warn(`Failed to fetch/add image ${imgUrl}: ${e.message}`);
                }
            }

            if (counter === 0) {
                console.error('No images were successfully added to the ZIP.');
                alert('No images were successfully downloaded.');
                return;
            }

            console.log(`Successfully added ${counter} images to the ZIP.`);
            await createAndDownloadZip(zip, `${TITLE}.zip`);

        } catch (error) {
            console.error(`Error during image download process: ${error.message}`);
            alert('An error occurred during the image download process.');
        }
    }

    /**
     * Function to find relevant elements and add DOWNLOAD buttons accordingly.
     * Adjusted to match the provided HTML structures.
     */
    function findAndAddButtons() {
        // **Adding DOWNLOAD Button 1 to div.node p a b**
        const titleLinks = document.querySelectorAll('div.node p a b');
        titleLinks.forEach(link => {
            const aTag = link.parentElement; // Get the <a> tag

            if (aTag && !aTag.nextElementSibling?.classList.contains('download-button')) {
                const href = aTag.getAttribute('href');
                if (href) {
                    const linkUrl = makeAbsoluteURL(href, window.location.href);
                    addDownloadButton(link, linkUrl, false, 'after'); // Insert after the <b> tag
                } else {
                    console.warn('No href found for div.node p a b element.');
                }
            }
        });

        // **Adding DOWNLOAD Button 2 to div.toptip**
        const toptipDivs = document.querySelectorAll('div.toptip');
        toptipDivs.forEach(div => {
            if (!div.querySelector('button.download-button')) {
                // Button 2 processes the current page
                addDownloadButton(div, window.location.href, true, 'append'); // Insert inside div.toptip
            }
        });
    }

    /**
     * Function to initialize the script: inject JSZip and add buttons.
     */
    async function initializeScript() {
        console.log('Initializing JYNGMN Image Downloader script...');
        try {
            // **Injecting JSZip**
            await injectScript('https://cdn.jsdelivr.net/npm/jszip@3.10.0/dist/jszip.min.js');
            if (typeof JSZip === 'undefined') {
                throw new Error('JSZip failed to load after injection.');
            }
            console.log('JSZip loaded successfully. Version:', JSZip.version);

            // **Adding DOWNLOAD Buttons**
            findAndAddButtons();

            // **Setting Up MutationObserver to Handle Dynamic Content**
            const observer = new MutationObserver((mutations) => {
                for (const mutation of mutations) {
                    if (mutation.type === 'childList') {
                        findAndAddButtons();
                    }
                }
            });

            observer.observe(document.body, { childList: true, subtree: true });
            console.log('MutationObserver set to watch for new elements to add DOWNLOAD buttons.');

        } catch (error) {
            console.error('Failed to inject JSZip:', error.message);
            alert('Failed to load JSZip library. Please check the console for details.');
        }
    }

    /**
     * Ensuring the script runs after the DOM is fully loaded.
     */
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initializeScript);
    } else {
        initializeScript();
    }
})();
```

### Key Modifications:
- **Title Extraction**: I updated the part where the script extracts the title using the new regex pattern `\[[^\]]+\] .+? \[[^\]]+P\]`, scanning the entire document’s text content.
- **Logging**: Added logging to provide a sample of extracted text for debugging purposes, and to alert or log when the title pattern match fails.
- **Pre-checks**: Includes further checks and alerts to maintain robustness in scenarios where expected text patterns do not exist. 

This script should be suitable for adapting scenarios where you're trying to find sections matching the new flexible pattern in the HTML document's text. Adjustments might be needed depending on the actual HTML structure it interacts with.

turns-00049.parquet:15837

abdb0355f8d3a4f7d3770e99
turn 11/12gpt-4o-2024-08-06EnglishHong Kong1970 words
degenerate_repetitionAbsentFinal dense release
USER
In case there is no match can you use h1.article-title as the TITLE 
ASSISTANT
Certainly! You can add a fallback mechanism where if the regex pattern does not find a match for the `TITLE`, the script will try to use the content in the `<h1 class="article-title">` element as the `TITLE`. Here's how you can modify the script to incorporate this logic:

```javascript
// ==UserScript==
// @name         JYNGMN Image Downloader
// @namespace    http://tampermonkey.net/
// @version      1.26
// @description  Download images from specified WebURLs as a ZIP file, log image URLs, and add DOWNLOAD buttons correctly, without leaving the page. Compatible with Chrome and Edge browsers, supports multiple pages.
// @author
// @match        https://www.xinggan5.top/*
// @connect      *
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// ==/UserScript==

(function () {
    'use strict';

    // **Initialization Log**
    console.log('JYNGMN Image Downloader script initializing...');

    /**
     * Utility function to convert relative URLs to absolute URLs.
     * @param {string} url - The URL to convert.
     * @param {string} base - The base URL for conversion.
     * @returns {string} - The absolute URL.
     */
    function makeAbsoluteURL(url, base) {
        try {
            return new URL(url, base || window.location.origin).href;
        } catch (error) {
            console.error(`Invalid URL: ${url} - Error: ${error.message}`);
            return url;
        }
    }

    /**
     * Function to inject external scripts (e.g., JSZip).
     * @param {string} url - The URL of the script to inject.
     * @returns {Promise} - Resolves when the script is loaded.
     */
    async function injectScript(url) {
        return new Promise((resolve, reject) => {
            if (document.querySelector(`script[src="${url}"]`)) {
                console.log(`Script already injected: ${url}`);
                resolve();
                return;
            }

            const script = document.createElement('script');
            script.src = url;
            script.onload = () => {
                console.log(`Injected script loaded: ${url}`);
                resolve();
            };
            script.onerror = () => {
                console.error(`Failed to load script: ${url}`);
                reject(new Error(`Failed to load script: ${url}`));
            };
            document.head.appendChild(script);
        });
    }

    /**
     * Function to fetch and parse HTML from a given URL using GM_xmlhttpRequest.
     * @param {string} url - The URL to fetch.
     * @returns {Promise<Document>} - Resolves with the parsed HTML document.
     */
    function fetchHTML(url) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                onload: function (response) {
                    if (response.status >= 200 && response.status < 400) {
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(response.responseText, 'text/html');
                        resolve(doc);
                    } else {
                        reject(new Error(`Failed to fetch page: ${url} - Status: ${response.status}`));
                    }
                },
                onerror: function () {
                    reject(new Error(`Network error while fetching page: ${url}`));
                }
            });
        });
    }

    /**
     * Function to fetch an image blob from a URL using the Fetch API.
     * @param {string} url - The image URL.
     * @returns {Promise<Blob|null>} - Resolves with the image blob or null if failed.
     */
    async function fetchImage(url) {
        try {
            console.log(`Fetching image: ${url}`);
            const response = await fetch(url, { mode: 'cors', credentials: 'omit' });
            if (!response.ok) throw new Error(`Failed to fetch image: ${url} - Status: ${response.status}`);
            return await response.blob();
        } catch (error) {
            console.error(`Error fetching image: ${error.message}`);
            return null;
        }
    }

    /**
     * Utility function to extract the file extension from a URL.
     * @param {string} url - The URL to extract the extension from.
     * @returns {string} - The file extension (default: 'jpg').
     */
    function getFileExtension(url) {
        const match = url.match(/\.([a-zA-Z0-9]+)(?:\?.*)?$/);
        return match ? match[1].toLowerCase() : 'jpg';
    }

    /**
     * Function to trigger the download of a ZIP blob using an anchor element.
     * @param {string} blobUrl - The Object URL of the ZIP blob.
     * @param {string} fileName - The desired name for the downloaded ZIP file.
     */
    function downloadUsingAnchor(blobUrl, fileName) {
        const a = document.createElement('a');
        a.href = blobUrl;
        a.download = fileName;
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        console.log(`Download initiated for: ${fileName}`);
    }

    /**
     * Function to create and download the ZIP file using JSZip.
     * @param {JSZip} zip - The JSZip instance containing files.
     * @param {string} [zipName='images.zip'] - The desired name for the ZIP file.
     */
    async function createAndDownloadZip(zip, zipName = 'images.zip') {
        try {
            console.log('Generating ZIP Blob...');
            const zipBlob = await zip.generateAsync({ type: 'blob', compression: 'STORE' });
            console.log('ZIP Blob generated. Size:', zipBlob.size, 'bytes');

            const blobUrl = URL.createObjectURL(zipBlob);
            downloadUsingAnchor(blobUrl, zipName);
        } catch (error) {
            console.error(`Error creating or downloading ZIP: ${error.message}`);
            alert(`An error occurred while creating the ZIP file: ${error.message}`);
        }
    }

    /**
     * Function to add a DOWNLOAD button to a target element with an associated linkUrl.
     * @param {HTMLElement} targetElement - The element to which the button will be appended or after which it will be inserted.
     * @param {string} linkUrl - The URL to be processed when the button is clicked.
     * @param {boolean} useCurrentPage - If true, processes the current page without fetching linkUrl.
     * @param {string} insertMode - Where to insert the button: 'after' or 'append'.
     */
    function addDownloadButton(targetElement, linkUrl, useCurrentPage = false, insertMode = 'after') {
        // Check if the button already exists based on the insertMode
        if (insertMode === 'append') {
            if (targetElement.querySelector('button.download-button')) {
                return; // Button already exists inside the target
            }
        } else if (insertMode === 'after') {
            // Check the next sibling if insertMode is 'after'
            if (targetElement.nextElementSibling && targetElement.nextElementSibling.classList.contains('download-button')) {
                return; // Button already exists after the target
            }
        }

        const button = document.createElement('button');
        button.innerText = 'DOWNLOAD';
        button.classList.add('download-button');
        // **Styling the Button**
        button.style.marginLeft = '10px';
        button.style.padding = '5px 10px';
        button.style.cursor = 'pointer';
        button.style.backgroundColor = '#28a745';
        button.style.color = '#fff';
        button.style.border = 'none';
        button.style.borderRadius = '4px';
        button.style.fontSize = '14px';
        button.style.transition = 'background-color 0.3s';
        button.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';

        // **Hover Effects for the Button**
        button.addEventListener('mouseenter', () => {
            button.style.backgroundColor = '#218838';
        });
        button.addEventListener('mouseleave', () => {
            button.style.backgroundColor = '#28a745';
        });

        // **Click Event to Initiate the Download Process**
        button.addEventListener('click', async (event) => {
            event.preventDefault(); // Prevent default behavior if applicable
            button.disabled = true;
            const originalText = button.innerText;
            button.innerText = 'Processing...';
            console.log(`DOWNLOAD button clicked for URL: ${linkUrl}, useCurrentPage: ${useCurrentPage}`);

            await downloadImagesFromUrl(linkUrl, useCurrentPage);

            button.innerText = originalText;
            button.disabled = false;
        });

        // **Inserting the Button at the Correct Location**
        if (insertMode === 'append') {
            targetElement.appendChild(button);
            console.log(`DOWNLOAD button appended to`, targetElement);
        } else { // 'after'
            targetElement.insertAdjacentElement('afterend', button);
            console.log(`DOWNLOAD button added after`, targetElement);
        }
    }

    /**
     * Main function to download images from a given URL.
     * @param {string} linkUrl - The URL from which to download images.
     * @param {boolean} useCurrentPage - If true, use the current document instead of fetching linkUrl.
     */
    async function downloadImagesFromUrl(linkUrl, useCurrentPage = false) {
        try {
            console.log(`Starting image download process for URL: ${useCurrentPage ? window.location.href : linkUrl}`);
            let doc;

            if (useCurrentPage) {
                doc = document;
            } else {
                doc = await fetchHTML(linkUrl);
            }

            // **Extracting the Title for the ZIP Filename**
            const titleText = doc.body.textContent || ''; // Assuming the whole body as potential source
            console.log(`Extracted text for title matching: ${titleText.substring(0, 100)}...`); // Sample for log

            let titleMatch = titleText.match(/\[[^\]]+\] .+? \[[^\]]+P\]/);
            let TITLE;

            if (titleMatch && titleMatch[0]) {
                TITLE = titleMatch[0].trim().replace(/[\\/:*?"<>|]/g, '_');
                console.log(`Extracted TITLE for ZIP: ${TITLE}`);
            } else {
                console.warn('TITLE pattern not matched in the document text. Attempting to use h1.article-title.');
                const h1TitleElement = doc.querySelector('h1.article-title');
                if (h1TitleElement) {
                    TITLE = h1TitleElement.textContent.trim().replace(/[\\/:*?"<>|]/g, '_');
                    console.log(`Fallback TITLE using h1.article-title: ${TITLE}`);
                } else {
                    console.error('h1.article-title not found as a fallback.');
                    alert('Title pattern not matched and no article title available.');
                    return;
                }
            }

            // **Collecting All Image Page URLs from div.pagination**
            const paginationDiv = doc.querySelector('div.pagination');
            let pageUrls = [];

            if (paginationDiv) {
                const pageLinks = paginationDiv.querySelectorAll('a[href]');
                pageUrls = Array.from(pageLinks)
                    .filter(link => /^\d+$/.test(link.textContent.trim()))
                    .map(link => makeAbsoluteURL(link.getAttribute('href'), linkUrl));
            } else {
                console.warn('div.pagination not found. Proceeding with the current page only.');
            }

            // **Handling Button 2 (Current Page)**
            if (useCurrentPage && pageUrls.length === 0) {
                pageUrls.push(window.location.href);
            }

            console.log(`Total related pages found: ${pageUrls.length}`);

            // **Storing Unique Image URLs**
            const images = new Set();

            /**
             * Function to process a single page and collect image URLs.
             * @param {string} pageUrl - The URL of the page to process.
             */
            async function processPage(pageUrl) {
                try {
                    console.log(`Processing page: ${pageUrl}`);
                    const pageDoc = useCurrentPage && pageUrl === window.location.href ? document : await fetchHTML(pageUrl);
                    const contentDivs = pageDoc.querySelectorAll('article.article-content p');
                    if (contentDivs.length > 0) {
                        let imagesInPage = [];
                        contentDivs.forEach(div => {
                            const imgs = div.querySelectorAll('img[src]');
                            imagesInPage.push(...imgs);
                        });
                        console.log(`Found ${imagesInPage.length} images in ${pageUrl}`);
                        imagesInPage.forEach(img => {
                            const src = img.getAttribute('src');
                            if (src) {
                                images.add(makeAbsoluteURL(src, pageUrl));
                            }
                        });
                    } else {
                        console.warn(`No article.article-content p found in ${pageUrl}`);
                    }
                } catch (e) {
                    console.warn(`Failed to process ${pageUrl}: ${e.message}`);
                }
            }

            // **Processing All Pages with Concurrency Control**
            const CONCURRENT_LIMIT = 5;
            let index = 0;

            async function processNext() {
                while (index < pageUrls.length) {
                    const currentIndex = index++;
                    const pageUrl = pageUrls[currentIndex];
                    await processPage(pageUrl);
                }
            }

            const workers = [];
            for (let i = 0; i < CONCURRENT_LIMIT; i++) {
                workers.push(processNext());
            }
            await Promise.all(workers);

            if (images.size === 0) {
                console.error('No images found.');
                alert('No images found on the target page(s).');
                return;
            }

            const imageArray = Array.from(images);
            console.log(`Total images collected: ${imageArray.length}`);

            // **Initializing JSZip**
            const zip = new JSZip();
            let counter = 0;
            const totalImages = imageArray.length;

            // **Loop Through Each Image to Add to ZIP**
            for (let i = 0; i < imageArray.length; i++) {
                const imgUrl = imageArray[i];
                const isLastImage = (i === imageArray.length - 1); // Check if it's the last image

                try {
                    const blob = await fetchImage(imgUrl);
                    if (!blob) {
                        console.warn(`Skipping image due to fetch failure: ${imgUrl}`);
                        continue;
                    }

                    const extension = getFileExtension(imgUrl);
                    const validExtensions = ['jpg', 'jpeg', 'png', 'webp', 'bmp', 'tiff'];
                    const finalExtension = validExtensions.includes(extension) ? extension : 'jpg';

                    let filename;
                    if (isLastImage) {
                        // **Rename the Last Image to '000.ext'**
                        filename = `000.${finalExtension}`;
                    } else {
                        // **Name Other Images Sequentially: '001.ext', '002.ext', etc.**
                        // Note: Counter starts at 0, so add 1 and pad with zeros
                        filename = `${String(counter + 1).padStart(3, '0')}.${finalExtension}`;
                    }

                    zip.file(filename, blob);
                    counter++;
                    console.log(`Added ${filename} to ZIP (${counter}/${totalImages})`);
                } catch (e) {
                    console.warn(`Failed to fetch/add image ${imgUrl}: ${e.message}`);
                }
            }

            if (counter === 0) {
                console.error('No images were successfully added to the ZIP.');
                alert('No images were successfully downloaded.');
                return;
            }

            console.log(`Successfully added ${counter} images to the ZIP.`);
            await createAndDownloadZip(zip, `${TITLE}.zip`);

        } catch (error) {
            console.error(`Error during image download process: ${error.message}`);
            alert('An error occurred during the image download process.');
        }
    }

    /**
     * Function to find relevant elements and add DOWNLOAD buttons accordingly.
     * Adjusted to match the provided HTML structures.
     */
    function findAndAddButtons() {
        // **Adding DOWNLOAD Button 1 to div.node p a b**
        const titleLinks = document.querySelectorAll('div.node p a b');
        titleLinks.forEach(link => {
            const aTag = link.parentElement; // Get the <a> tag

            if (aTag && !aTag.nextElementSibling?.classList.contains('download-button')) {
                const href = aTag.getAttribute('href');
                if (href) {
                    const linkUrl = makeAbsoluteURL(href, window.location.href);
                    addDownloadButton(link, linkUrl, false, 'after'); // Insert after the <b> tag
                } else {
                    console.warn('No href found for div.node p a b element.');
                }
            }
        });

        // **Adding DOWNLOAD Button 2 to div.toptip**
        const toptipDivs = document.querySelectorAll('div.toptip');
        toptipDivs.forEach(div => {
            if (!div.querySelector('button.download-button')) {
                // Button 2 processes the current page
                addDownloadButton(div, window.location.href, true, 'append'); // Insert inside div.toptip
            }
        });
    }

    /**
     * Function to initialize the script: inject JSZip and add buttons.
     */
    async function initializeScript() {
        console.log('Initializing JYNGMN Image Downloader script...');
        try {
            // **Injecting JSZip**
            await injectScript('https://cdn.jsdelivr.net/npm/jszip@3.10.0/dist/jszip.min.js');
            if (typeof JSZip === 'undefined') {
                throw new Error('JSZip failed to load after injection.');
            }
            console.log('JSZip loaded successfully. Version:', JSZip.version);

            // **Adding DOWNLOAD Buttons**
            findAndAddButtons();

            // **Setting Up MutationObserver to Handle Dynamic Content**
            const observer = new MutationObserver((mutations) => {
                for (const mutation of mutations) {
                    if (mutation.type === 'childList') {
                        findAndAddButtons();
                    }
                }
            });

            observer.observe(document.body, { childList: true, subtree: true });
            console.log('MutationObserver set to watch for new elements to add DOWNLOAD buttons.');

        } catch (error) {
            console.error('Failed to inject JSZip:', error.message);
            alert('Failed to load JSZip library. Please check the console for details.');
        }
    }

    /**
     * Ensuring the script runs after the DOM is fully loaded.
     */
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initializeScript);
    } else {
        initializeScript();
    }
})();
```

### Key Additions:
- **Fallback Mechanism**: The script attempts to use the `<h1 class="article-title">` element's text as the title if the regex pattern does not find a match in the document's text.
- **Logging and Alerts**: Enhanced logging and alerts inform you when the script uses the fallback method or when it encounters any errors.

turns-00049.parquet:15838

fdf480a328ab0ac1e28e024f
turn 12/12gpt-4o-2024-08-06EnglishHong Kong262 words
degenerate_repetitionAbsentFinal dense release
USER
I would like t change the size, colour, and font size inside the button.  How do I do it?  Just should be the section needs to be change.
ASSISTANT
To customize the size, color, and font size of the button in the script, you need to modify the inline styles applied to the button. Here's the specific section that you should change:

```javascript
// **Styling the Button**
button.style.marginLeft = '10px';
button.style.padding = '5px 10px'; // Adjust this for size
button.style.cursor = 'pointer';
button.style.backgroundColor = '#28a745'; // Change this color
button.style.color = '#fff'; // Change text color
button.style.border = 'none';
button.style.borderRadius = '4px';
button.style.fontSize = '14px'; // Adjust this for font size
button.style.transition = 'background-color 0.3s';
button.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';
```

Here's a quick rundown on how to adjust:

- **Size**: Modify the `padding` property to change the button's size. It's defined as `padding: 'vertical horizontal'`, so adjust accordingly.
- **Background Color**: Change the `backgroundColor` property to the desired background color in hex code or other CSS color formats.
- **Text Color**: Change the `color` property to set the desired text color for the button.
- **Font Size**: Modify the `fontSize` property to adjust the button's font size.

For example, to make the button larger, with a blue background, white text, and a larger font size:

```javascript
button.style.padding = '10px 20px'; // Larger button
button.style.backgroundColor = '#007bff'; // Blue
button.style.color = '#ffffff'; // White text
button.style.fontSize = '16px'; // Larger font size
```

Replace these modifications in your script where the button styling is defined, and it will reflect the changes accordingly.

turns-00049.parquet:15839

b2aac03b3dcf0e8a5027c468
turn 1/2gpt-4o-2024-08-06SpanishArgentina350 words
degenerate_repetitionAbsentFinal dense release
USER
Es un buen negocio un cementerio para mascotas?
ASSISTANT
Invertir en un cementerio para mascotas puede ser una buena oportunidad de negocio, dependiendo de varios factores. Aquí hay algunas consideraciones clave para evaluar la viabilidad de este tipo de negocio:

1. **Crecimiento del Mercado de Mascotas**: La industria de las mascotas ha crecido significativamente en las últimas décadas. A medida que las personas ven a sus mascotas como miembros de la familia, aumenta la demanda de servicios que reflejen ese vínculo, incluidos los cementerios para mascotas.

2. **Demanda Local**: Es importante investigar si hay demanda en tu área geográfica. Esto puede implicar un estudio de mercado sobre cuántas personas tienen mascotas y cómo manejan actualmente la disposición final de sus cuerpos.

3. **Competencia**: Evalúa cuántos cementerios de mascotas ya existen en tu área y cómo se están desempeñando. Si el mercado ya está saturado, podría ser difícil establecerse.

4. **Regulaciones**: La operación de un cementerio para mascotas puede estar sujeta a regulaciones locales específicas en cuanto a zonificación, impacto ambiental y cuestiones sanitarias. Asegúrate de investigar y cumplir con todas las leyes aplicables.

5. **Costos de Instalación y Mantenimiento**: Considera los costos de adquirir o alquilar un terreno adecuado, así como los gastos asociados con mantener el cementerio y proporcionar servicios adicionales, como incineración o recordatorios.

6. **Servicios Adicionales**: Ofrecer servicios complementarios, como cremación, urnas personalizadas o ceremonias conmemorativas, puede aumentar los ingresos y atraer a más clientes.

7. **Sensibilidad y Empatía**: Al tratarse de un negocio relacionado con la pérdida y el duelo, es fundamental manejarlo con sensibilidad y empatía. Esto no solo es crucial para el bienestar de los clientes, sino también para construir una reputación positiva.

8. **Marketing y Educación**: Es posible que sea necesario educar al público sobre este tipo de servicios. Un esfuerzo de marketing eficaz puede ayudar a aumentar la concienciación y generar demanda.

En resumen, un cementerio para mascotas puede ser un negocio rentable si hay suficiente demanda y se gestionan bien los aspectos regulatorios, financieros y operativos. Realizar un cuidadoso análisis de viabilidad es esencial antes de invertir en este tipo de empresa.

turns-00049.parquet:15840

46ae184bb0dd45098399d16e
turn 2/2gpt-4o-2024-08-06SpanishArgentina143 words
degenerate_repetitionAbsentFinal dense release
USER
Existen cementerios de mascotas en córdoba capital
ASSISTANT
En Córdoba Capital, Argentina, existe al menos un cementerio para mascotas. Uno de los más conocidos es el Cementerio de Mascotas "El Edén", que ofrece servicios de entierro y cremación, además de contar con un espacio dedicado para el descanso final de los animales de compañía. 

Esto indica que ya hay una infraestructura y servicios establecidos en la ciudad, por lo que cualquier nueva iniciativa en este ámbito debería considerar la presencia de esta competencia y evaluar si hay suficiente demanda no cubierta o si se pueden ofrecer servicios diferenciados.

Es importante verificar toda la información disponible y actualizada, ya que pueden haber surgido nuevos servicios o cambios en los ya existentes desde mis últimos datos. Además, consultar con las autoridades locales sobre las regulaciones específicas aplicables es esencial si estás considerando ingresar en este negocio.

turns-00049.parquet:15841

052b615561cb108b809e86b7
turn 1/4gpt-4o-2024-08-06RussianRussia67 words
degenerate_repetitionAbsentFinal dense release
USER
Допиши стихотворение ниже...

В даль уходят корабли
Мы теперь с тобой одни
Мысли мои под дождем
Мы снимали нашу жизнь
Это вроде бы у всех
Наше счастье позади
Ждет меня теперь успех
Чувствую на пол пути Я
ASSISTANT
набираю новый шаг.
Пусть штормит кругом и тьма,
Светит в будущем маяк.
Я иду туда, где свет,
Оставляя грусть вдали,
Ведь на всё один ответ —
В даль уходят корабли.