2025|暴力破解lurl&myptt密碼|自動帶入日期|可下載圖影片🚀|v3.0

針對lurl與myptt的圖片帶入當天日期;開放下載圖片與影片(此部分僅支援lurl)

// ==UserScript==
// @name         2025|暴力破解lurl&myptt密碼|自動帶入日期|可下載圖影片🚀|v3.0
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  針對lurl與myptt的圖片帶入當天日期;開放下載圖片與影片(此部分僅支援lurl)
// @author       You
// @match        https://lurl.cc/*
// @match        https://myppt.cc/*
// @match        https://www.dcard.tw/f/sex/*
// @match        https://www.dcard.tw/f/sex
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=lurl.cc
// @grant        none
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// ==/UserScript==

/*
================================================================================
📋 程式執行流程:

A. 初始化階段
   A1. 載入外部資源(Toast通知庫)→ 
   A2. 初始化全域樣式 →
   A3. 判斷當前網站路由

B. 路由分發
   B1. Dcard路由 → 註冊連結攔截 → 延遲執行年齡確認 → 移除登入彈窗
   B2. Myptt路由 → 取得上傳日期 → 自動填入密碼 → 重新載入頁面  
   B3. Lurl路由  → 嘗試破解密碼 → 判斷內容類型 → 載入對應處理器

C. 功能執行
   C1. 影片處理 → 建立下載按鈕 → 替換原生播放器 → 綁定下載事件
   C2. 圖片處理 → 取得預載圖片 → 建立下載按鈕 → 插入頁面DOM
   C3. 密碼處理 → 解析上傳日期 → 設定Cookie值 → 自動重新載入

================================================================================
更新紀錄:
2025/09/19 v3.0 - 重構為functional風格,採用jQuery,改善架構
2025/09/19 v2.1 - 新增myptt密碼自動帶入
2025/07/29 v2.0 - 修復lurl邏輯改變問題
================================================================================
*/

(function ($) {
  "use strict";

  // ==================== 通用工具函數 ====================
  const Utils = {
    // 從日期字串提取月日(MMDD格式)
    extractMMDD: (dateText) => {
      const pattern = /(\d{4})-(\d{2})-(\d{2})/;
      const match = dateText.match(pattern);
      return match ? match[2] + match[3] : null;
    },

    // 取得URL查詢參數
    getQueryParam: (name) => {
      const params = new URLSearchParams(window.location.search);
      return params.get(name);
    },

    // Cookie操作
    cookie: {
      get: (name) => {
        const match = document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`));
        return match ? match[2] : null;
      },
      set: (name, value) => {
        document.cookie = `${name}=${value}; path=/`;
      },
    },

    // 顯示Toast通知
    showToast: (message, type = "success") => {
      if (typeof Toastify === "undefined") return;

      Toastify({
        text: message,
        duration: 5000,
        gravity: "top",
        position: "right",
        style: {
          background: type === "success" ? "#28a745" : "#dc3545",
        },
      }).showToast();
    },

    // 下載檔案(使用Blob)
    downloadFile: async (url, filename) => {
      try {
        const response = await fetch(url);
        const blob = await response.blob();
        const blobUrl = URL.createObjectURL(blob);

        const link = document.createElement("a");
        link.href = blobUrl;
        link.download = filename;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);

        URL.revokeObjectURL(blobUrl);
      } catch (error) {
        console.error("下載失敗:", error);
      }
    },
  };

  // ==================== 資源載入器 ====================
  const ResourceLoader = {
    loadToastify: () => {
      // 載入CSS
      $("<link>", {
        rel: "stylesheet",
        href: "https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css",
      }).appendTo("head");

      // 載入JS
      $("<script>", {
        src: "https://cdn.jsdelivr.net/npm/toastify-js",
      }).appendTo("head");
    },

    loadCustomStyles: () => {
      $("<style>")
        .text(
          `
                .disabled-button {
                    background-color: #ccc !important;
                    color: #999 !important;
                    opacity: 0.5;
                    cursor: not-allowed;
                }
            `
        )
        .appendTo("head");
    },

    init: () => {
      ResourceLoader.loadToastify();
      ResourceLoader.loadCustomStyles();
    },
  };

  // ==================== Myptt處理器 ====================
  const MypttHandler = {
    getUploadDate: () => {
      const $dateSpan = $(".login_span").eq(1);
      if ($dateSpan.length === 0) return null;

      return Utils.extractMMDD($dateSpan.text());
    },

    autoFillPassword: () => {
      const date = MypttHandler.getUploadDate();
      if (!date) return;

      $("#pasahaicsword").val(date);
      $("#main_fjim60unBU").click();
      location.reload();
    },

    init: () => {
      $(document).ready(() => {
        MypttHandler.autoFillPassword();
      });
    },
  };

  // ==================== Dcard處理器 ====================
  const DcardHandler = {
    // 攔截Lurl連結點擊
    interceptLurlLinks: () => {
      $(document).on("click", 'a[href^="https://lurl.cc/"]', function (e) {
        e.preventDefault();

        const href = $(this).attr("href");
        const title = encodeURIComponent(document.title);

        window.open(`${href}?title=${title}`, "_blank");
      });
    },

    // 自動點選年齡確認
    autoConfirmAge: () => {
      const $buttons = $("button");
      if ($buttons.length !== 13) return;

      const $secondP = $("p").eq(1);
      if (!$secondP.length) return;

      const $nextElement = $secondP.next();
      if ($nextElement.prop("nodeType") === 1) {
        $nextElement.find("button").eq(1).click();
      }
    },

    // 移除登入提示並恢復捲動
    removeLoginModal: () => {
      $(".__portal").remove();
      $("body").css("overflow", "auto");
    },

    // 監聽路由變化(單頁應用)
    watchRouteChange: () => {
      if (window.location.href !== "https://www.dcard.tw/f/sex") return;

      let currentURL = window.location.href;
      $(document).on("click", () => {
        if (window.location.href !== currentURL) {
          window.location.reload();
        }
      });
    },

    init: () => {
      DcardHandler.interceptLurlLinks();
      DcardHandler.watchRouteChange();

      // 延遲執行(等待頁面載入)
      setTimeout(() => {
        DcardHandler.autoConfirmAge();
        DcardHandler.removeLoginModal();
      }, 3500);
    },
  };

  // ==================== Lurl處理器 ====================
  const LurlHandler = {
    // 密碼破解模組
    passwordCracker: {
      getCookieName: () => {
        const match = window.location.href.match(/lurl\.cc\/(\w+)/);
        return match ? `psc_${match[1]}` : null;
      },

      isPasswordCorrect: () => {
        const $statusSpan = $(
          "#back_top .container.NEWii_con section:nth-child(6) h2 span"
        );
        const text = $statusSpan.text();
        return text.includes("成功") || text.includes("錯誤");
      },

      tryTodayPassword: () => {
        if (LurlHandler.passwordCracker.isPasswordCorrect()) {
          return false;
        }

        const $dateSpan = $(".login_span").eq(1);
        if (!$dateSpan.length) return false;

        const date = Utils.extractMMDD($dateSpan.text());
        if (!date) return false;

        const cookieName = LurlHandler.passwordCracker.getCookieName();
        if (!cookieName) return false;

        Utils.cookie.set(cookieName, date);
        return true;
      },

      init: () => {
        if (LurlHandler.passwordCracker.tryTodayPassword()) {
          location.reload();
        }
      },
    },

    // 圖片下載模組
    pictureDownloader: {
      getImageUrl: () => {
        const $preloadLink = $('link[rel="preload"][as="image"]');
        return $preloadLink.attr("href") || null;
      },

      createDownloadButton: () => {
        const imageUrl = LurlHandler.pictureDownloader.getImageUrl();
        if (!imageUrl) return null;

        const $button = $("<button>", {
          text: "下載圖片",
          class: "btn btn-primary",
        });

        const $link = $("<a>", {
          href: imageUrl,
          download: "downloaded-image.jpg",
          css: { textDecoration: "none" },
        }).append($button);

        return $("<div>", { class: "col-12" }).append($link);
      },

      inject: () => {
        const $button = LurlHandler.pictureDownloader.createDownloadButton();
        if (!$button) return;

        const $targetRow = $(
          'div.row[style*="margin: 10px"][style*="border-style:solid"]'
        );
        if ($targetRow.length) {
          $targetRow.append($button);
        }
      },
    },

    // 影片下載模組
    videoDownloader: {
      getVideoUrl: () => {
        const $source = $("source").first();
        return $source.attr("src") || null;
      },

      replacePlayer: () => {
        const videoUrl = LurlHandler.videoDownloader.getVideoUrl();
        if (!videoUrl) return;

        const $newVideo = $("<video>", {
          src: videoUrl,
          controls: true,
          autoplay: true,
          width: 640,
          height: 360,
          preload: "metadata",
          class: "vjs-tech",
          id: "vjs_video_3_html5_api",
          tabIndex: -1,
          role: "application",
          "data-setup": '{"aspectRatio":"16:9"}',
        });

        $("video").replaceWith($newVideo);

        // 清理原始控制項
        $("#vjs_video_3").removeAttr("oncontextmenu controlslist");
        $(".vjs-control-bar").remove();
      },

      createDownloadButton: () => {
        const videoUrl = LurlHandler.videoDownloader.getVideoUrl();
        if (!videoUrl) return null;

        const title = Utils.getQueryParam("title") || "video";

        const $button = $("<a>", {
          href: videoUrl,
          download: `${title}.mp4`,
          text: "下載影片",
          class: "btn btn-primary",
          css: { color: "white", float: "right" },
        });

        // 綁定點擊事件
        $button.on("click", async function (e) {
          e.preventDefault();

          const $this = $(this);
          if ($this.hasClass("disabled-button")) return;

          $this.addClass("disabled-button").attr("disabled", true);

          Utils.showToast("🎉成功下載!請稍等幾秒......");
          await Utils.downloadFile(videoUrl, `${title}.mp4`);

          setTimeout(() => {
            $this.removeClass("disabled-button").removeAttr("disabled");
          }, 7000);
        });

        return $button;
      },

      inject: () => {
        const $button = LurlHandler.videoDownloader.createDownloadButton();
        if (!$button) return;

        const $h2List = $("h2");

        if ($h2List.length === 3) {
          // 建立新的標題區塊
          const $header = $("<h2>", {
            text: "✅助手啟動",
            css: {
              color: "white",
              textAlign: "center",
              marginTop: "25px",
            },
          });

          $("#vjs_video_3").before($header);
          $header.append($button);
        } else {
          // 附加到現有標題
          $h2List.first().append($button);
        }
      },
    },

    // 內容類型判斷
    detectContentType: () => {
      return $("video").length > 0 ? "video" : "picture";
    },

    init: () => {
      // 先嘗試密碼破解
      LurlHandler.passwordCracker.init();

      // 頁面載入完成後處理內容
      $(window).on("load", () => {
        const contentType = LurlHandler.detectContentType();

        if (contentType === "video") {
          LurlHandler.videoDownloader.inject();
          LurlHandler.videoDownloader.replacePlayer();
        } else {
          LurlHandler.pictureDownloader.inject();
        }
      });
    },
  };

  // ==================== 路由系統 ====================
  const Router = {
    routes: {
      "myppt.cc": MypttHandler,
      "dcard.tw/f/sex": DcardHandler,
      "lurl.cc": LurlHandler,
    },

    getCurrentRoute: () => {
      const url = window.location.href;

      for (const [pattern, handler] of Object.entries(Router.routes)) {
        if (url.includes(pattern)) {
          return handler;
        }
      }

      return null;
    },

    dispatch: () => {
      const handler = Router.getCurrentRoute();

      if (handler) {
        console.log(`路由匹配成功: ${handler.constructor?.name || "Handler"}`);
        handler.init();
      } else {
        console.log("未匹配到任何路由");
      }
    },
  };

  // ==================== 主程式入口 ====================
  const Main = {
    init: () => {
      // 載入資源
      ResourceLoader.init();

      // 分發路由
      Router.dispatch();
    },
  };

  // 啟動應用
  $(document).ready(() => {
    Main.init();
  });
})(jQuery);