- // ==UserScript==
- // @name 22k4已购游戏搜索
- // @namespace http://tampermonkey.net/
- // @version 2024-10-07
- // @description 已购买游戏详情页添加搜索功能
- // @author 口吃者
- // @match https://22k4.com/member/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=22k4.com
- // @grant none
- // @license MIT
- // ==/UserScript==
- /*
- 1. 多次快速点击分页按钮造成卡死
- 2. 可以增加保存配置功能,在没有购买新游戏时,可以保存配置,下次直接加载
- */
- class ProductCatalog {
- constructor() {
- this.pages = []; // 存储每页的商品列表
- this.productByName = new Map(); // 存储商品名称到商品对象的映射
- }
-
- // 添加商品到指定页
- addProductToPage(pageIndex, product) {
- if (!this.pages[pageIndex]) {
- this.pages[pageIndex] = [];
- }
-
- // 检查商品名称是否已存在
- const existingProduct = this.productByName.get(product.name.toLowerCase());
- if (existingProduct) {
- console.log(`Product with name "${product.name}" already exists.`);
- return; // 商品名称已存在,不添加
- }
-
- // 添加商品到对应页,并更新映射
- this.pages[pageIndex].push(product);
- this.productByName.set(product.name.toLowerCase(), product);
- }
-
- // 根据商品名称查询商品
- findProductByName(name) {
- const lowerCaseName = name.toLowerCase();
- return this.productByName.get(lowerCaseName);
- }
- // 模糊查询商品
- searchProductsByPartialName(query) {
- const results = [];
-
- // 遍历所有商品
- this.productByName.forEach((product, name) => {
- if (name.includes(query.toLowerCase())) {
- results.push(product);
- }
- });
-
- return results;
- }
-
- // 获取所有商品
- getAllProducts() {
- return this.productByName.values();
- }
-
- // 获取某一页的所有商品
- getProductsOnPage(pageIndex) {
- return this.pages[pageIndex] || [];
- }
- }
- const catalog = new ProductCatalog();
- var requestsCompleted = false;
- var pickUpGameHref = '#';
- var searchGameHref = '#';
- (function() {
- 'use strict';
- addPanel();
- // Your code here...
- })();
- window.onload = function() {
- // 示例:检查请求是否全部完成
- let btnSwitch = document.querySelector('#btnSwitch');
- checkTimer = setTimeout(() => {
- btnSwitch.textContent = "正在获取游戏中..."
- }, 1000); // 这只是一个示例,实际应用中应该根据实际场景决定何时检查
-
- //获取总页数
- let pageCount = document.querySelector("#PageCount").value;
- let pageSize = document.querySelector("#PageSize").value;
- let totalPages = getTotalPages(pageCount, pageSize);
- console.log(totalPages);
- const urls = Array.from({ length: totalPages }, (_, i) =>
- `https://22k4.com/member/product.php?page=${i + 1}`
- );
-
- // 创建一个 Promise 数组
- const fetchPromises = urls.map(url =>
- fetch(url, {
- method: 'GET',
- credentials: 'include', // 使得请求会发送 Cookie
- headers: {
- 'Content-Type': 'text/html;charset=utf-8',
- }
- }).then(response => {
- if (!response.ok) {
- throw new Error("HTTP error " + response.status);
- }
- return response.text(); // 读取为文本
- })
- );
-
- // 使用 Promise.all 来等待所有请求完成
- Promise.all(fetchPromises)
- .then(htmlTexts => {
- // 处理每个 HTML 文档
- htmlTexts.forEach((htmlText, index) => {
- // 创建一个范围较小的虚拟文档环境
- const parser = new DOMParser();
- const doc = parser.parseFromString(htmlText, "text/html");
- getAllItemDetails(doc, index + 1);
- requestsCompleted = true;
- clearTimeout(checkTimer);
- btnSwitch.textContent = "面板"
- });
- })
- .catch(error => {
- console.error('There was a problem with one of the fetch operations:', error);
- });
-
- //输入框
- document.getElementById('iptName').addEventListener('input', function(event) {
- let input = event.target.value;
- // 显示建议列表
- displaySuggestions(input, 1);
- })
- // 初始化分页图标
- updatePaginationIcons(1, 1); // 假设初始页码为1,总页数为1(待更新)
- var cssText = `
- #input_suggestion li {
- color: aliceblue;
- cursor: pointer;
- }
- #input_suggestion li:hover {
- color: cadetblue;
- background-color: #f0f0f0;
- }
- #pagination span {
- display: inline-block;
- width: 25px;
- height: 25px;
- line-height: 25px;
- text-align: center;
- border: 1px solid #ccc;
- cursor: pointer;
- background: azure;
- margin-inline-end: 5px;
- margin-inline-start: 5px;
- }
- `
- GMaddStyle(cssText);
-
- }
- function addPanel(){
- function genDiv(cls, id){
- let d = document.createElement('div');
- d.style.cssText = 'vertical-align:middle;';
- if(cls){ d.className = cls };
- if(id){ d.id = id };
- return d;
- }
- //创建一个可以自由弹出的面板
- function genPanel(name, visiable){
- let panel = genDiv(name, name);
- panel.style.cssText = 'background: rgba(58, 58, 58, 0.8);position: fixed;top: 50%;right: 0px;';
- panel.style.cssText += 'text-align: center;transform: translate(0px, -50%);z-index: 100;';
- panel.style.cssText += 'border: 1px solid rgb(83, 83, 83);padding: 5px;border-radius: 10px 0 0 10px;';
- panel.style.cssText += 'transition:right 0.8s;right:-300px;'
- return panel;
- }
- function genButton(test, foo, id, fooParams = {}){
- let b = document.createElement('button');
- b.textContent = test;
- b.style.verticalAlign = 'inherit';
- // 使用箭头函数创建闭包来保存 fooParams 并传递给 foo
- b.addEventListener('click', () => {
- foo.call(b, ...Object.values(fooParams)); // 使用 call 方法确保 this 指向按钮对象
- });
- if(id){ b.id = id };
- return b;
- }
- function genInput(id, value, tips, number) {
- let i = document.createElement('input');
- i.id = id;
- i.style.cssText = 'border:none;border-radius:0;margin:0px 5px;width:60%;text-align:center;';
- i.style.cssText += 'color:#000;background:#fff;vertical-align:inherit;';
- if (value) { i.value = value; }
- if (tips) { i.placeholder = tips; }
- if (number) {
- i.type = 'number';
- i.step = 0.01;
- i.min = 0;
- }
- return i;
- }
- function genUl(items, id) {
- // 创建一个新的<ul>元素
- let ul = document.createElement('ul');
-
- // 如果提供了类名,添加到<ul>元素上
- if (id) {
- ul.id = id;
- }
-
- // // 遍历items数组,为每个项目创建一个<li>元素并添加到<ul>中
- // items.forEach(function(item) {
- // let li = document.createElement('li');
-
- // // 这里简单地将item的值设置为<li>的文本内容
- // // 根据实际需求,这里可以进一步定制化,比如添加事件监听器等
- // li.textContent = item;
-
- // // 将<li>添加到<ul>中
- // ul.appendChild(li);
- // });
-
- return ul;
- }
- function genSpan(id, textContentSpan) {
- let s = document.createElement('span');
- s.id = id;
- s.textContent = textContentSpan;
- return s;
- }
- //展开指定面板
- function showPanel(panelId){
- let panel = document.getElementById(panelId);
- if (panel.style.right == '-300px') {
- panel.style.right = '0';
- } else {
- panel.style.right = '-300px';
- }
- }
- let btnSwitch = genButton('面板', showPanel, 'btnSwitch', {param1: 'autoSell'});
- let panelFunc = genPanel('autoSell', false); //初始隐藏
- //加入位置
- let lBtnArea = document.querySelector('body > div.page > div.container.m_top_30 > div');
- lBtnArea.insertBefore(btnSwitch, lBtnArea.children[0]);
- lBtnArea.insertBefore(panelFunc, lBtnArea.children[0]);
- //自动出售(加入到面板中) 搜索
- let divName = genDiv();
- let divPagination = genDiv(null, 'pagination');
- let button01 = genButton('搜索', searchGame, 'searchGame');
- let button02 = genButton('提货', pickUpGame, 'pickUpGame');
- let iptName = genInput('iptName', '', ' 游戏名称', false);
- let inputSuggestion = genUl(['无'], 'input_suggestion');
- let prePageSpan = genSpan('prePageSpan', '<');
- let nextPageSpan = genSpan('nextPageSpan', '>');
-
- divName.appendChild(button01);
- divName.appendChild(button02);
- divName.appendChild(iptName);
- divName.appendChild(inputSuggestion);
-
- divPagination.append(prePageSpan);
- divPagination.append(nextPageSpan);
-
- panelFunc.appendChild(divName);
- panelFunc.appendChild(divPagination);
- //todo 可优化成bilibili增强的样式表写法
- let h5Element = document.querySelector("body > div.page > div.container.m_top_30 > div > h5");
- btnSwitch.style.cssText += 'display: inline-block; margin-right: 10px;'
- btnSwitch.style.cssText += 'font-weight: bold;font-size: 16px;'
- h5Element.style.cssText += 'display: inline-block; margin-right: 10px;'
- }
- function searchGame(){
- // 使用 window.open 方法打开链接
- var url = this.getAttribute('data-url');// 链接动态变化,添加格外属性,每次点击重新获取
- window.open(url, '_blank'); // '_blank' 表示在一个新的浏览器标签页中打开
- }
- function pickUpGame(event){
- // 使用 window.open 方法打开链接
- var url = this.getAttribute('data-url');// 链接动态变化,添加格外属性,每次点击重新获取
- window.open(url, '_blank'); // '_blank' 表示在一个新的浏览器标签页中打开
- }
- function getTotalPages(input, eachPage) {
- // 将字符串转换为整数,如果是数字类型则直接使用
- let num = typeof input === 'string' ? parseInt(input, 10) : input;
- let eachPage01 = typeof eachPage === 'string' ? parseInt(eachPage, 10) : eachPage;
-
- // 检查转换后的值是否为 NaN 或者小于等于 0
- if (isNaN(num) || num <= 0 || isNaN(eachPage01) || eachPage01 <= 0) {
- throw new Error('getTotalPages error:Invalid input: input must be a positive integer.');
- }
-
- // 计算总页数
- // Math.ceil() 用于向上取整
- const totalPages = Math.ceil(num / eachPage01);
-
- return totalPages;
- }
- function getAllItemDetails(pageDocument, page){
- let itemList = pageDocument.querySelectorAll('tbody > tr');
- itemList.forEach(item => {
- let itemId = item.id;
- let itemImg = item.querySelector('img').src;
- let itemName = item.querySelector('a').textContent;
- let itemPrice = item.querySelector('span').textContent;
- let itemOrderNo = item.querySelector('td:nth-child(3) > p:nth-child(1)').textContent;
- let itemOrderTime = item.querySelector('td:nth-child(3) > p:nth-child(2)').textContent;
- let itemPickup = item.querySelector('td:nth-child(4) > p > a').href;
- let itemSearch = item.querySelector('td:nth-child(2) > p:nth-child(1) > b > a').href;
- // 创建一个新的 product 对象
- const product = {
- id: itemId, // 假设这是一个生成唯一 ID 的方法
- name: itemName,
- imageUrl: itemImg,
- price: itemPrice,
- orderNo: itemOrderNo,
- orderTime: itemOrderTime,
- pickUp: itemPickup,
- searchGame: itemSearch
- };
- catalog.addProductToPage(page - 1, product);
- })
- }
- function displaySuggestions(input, page) {
- const suggestions = catalog.searchProductsByPartialName(input).map(product => product.name);
-
- let suggestionsList = document.getElementById('input_suggestion');
- suggestionsList.innerHTML = ''; // 清空现有建议
-
- // 根据输入过滤建议
- let filteredSuggestions = suggestions;
-
- const itemsPerPage = 7; // 每页显示的建议数
- var totalPages = Math.ceil(filteredSuggestions.length / itemsPerPage);
- const start = (page - 1) * itemsPerPage;
- const end = Math.min(start + itemsPerPage, filteredSuggestions.length);
-
- // 显示过滤后的建议
- if (filteredSuggestions.length > 0 && filteredSuggestions.length >= start) {
- suggestionsList.style.display = 'block';
- // 获取输入框元素
- const iptName = document.getElementById('iptName');
-
- // 显示当前页的建议
- for (let i = start; i < end; i++) {
- let item = document.createElement('li');
- item.textContent = filteredSuggestions[i];
-
- if(item._clickHandler){
- item.removeEventListener('click', handler);
- delete item._clickHandler; // 清理保存的引用
- }
- // 创建一个通用的事件处理函数,并保存其引用
- const handler = () => handleSuggestionClick(item);
- item._clickHandler = handler; // 保存函数引用
- item.addEventListener('click', handler);
- suggestionsList.appendChild(item);
- }
- } else {
- suggestionsList.style.display = 'none'; // 如果没有建议则隐藏列表
- }
-
- // 更新分页图标的状态
- updatePaginationIcons(page, totalPages);
- }
-
- function updatePaginationIcons(currentPage, totalPages) {
- const prevPageIcon = document.getElementById('prePageSpan');
- const nextPageIcon = document.getElementById('nextPageSpan');
-
- if(currentPage === -1 && totalPages === -1){
- prevPageIcon.style.display = 'none';
- nextPageIcon.style.display = 'none';
- return;
- }
-
- prevPageIcon.style.display = currentPage === 1 ? 'none' : 'inline-block';
- nextPageIcon.style.display = currentPage === totalPages ? 'none' : 'inline-block';
- if(prevPageIcon._clickHandler){
- prevPageIcon.removeEventListener('click', prevPageIcon._clickHandler);
- delete prevPageIcon._clickHandler;
- }
- if(nextPageIcon._clickHandler){
- nextPageIcon.removeEventListener('click', nextPageIcon._clickHandler);
- delete nextPageIcon._clickHandler;
- }
- const preHandler = () => displaySuggestions(document.getElementById('iptName').value, currentPage - 1);
- const nextHandler = () => displaySuggestions(document.getElementById('iptName').value, currentPage + 1);
- prevPageIcon._clickHandler = preHandler;
- nextPageIcon._clickHandler = nextHandler;
- prevPageIcon.addEventListener('click', preHandler);
- nextPageIcon.addEventListener('click', nextHandler);
- }
- function GMaddStyle(css){
- var myStyle = document.createElement('style');
- myStyle.textContent = css;
- var doc = document.head || document.documentElement;
- doc.appendChild(myStyle);
- }
- function handleSuggestionClick(suggestion) {
- const iptName = document.getElementById('iptName');
- iptName.value = suggestion.textContent;
-
- pickUpGameHref = catalog.findProductByName(suggestion.textContent).pickUp;
- searchGameHref = catalog.findProductByName(suggestion.textContent).searchGame;
-
- document.querySelector('#pickUpGame').setAttribute('data-url', pickUpGameHref);
- document.querySelector('#searchGame').setAttribute('data-url', searchGameHref);
-
- // 防止点击建议后再点击分页卡死
- const prevPageIcon = document.getElementById('prePageSpan');
- const nextPageIcon = document.getElementById('nextPageSpan');
- prevPageIcon.style.display = 'none';
- nextPageIcon.style.display = 'none';
-
- const suggestionsList = document.getElementById('input_suggestion');
- suggestionsList.style.display = 'none'; // 关闭建议列表
- }