// ==UserScript== // @name Weidian to Basetao // @namespace https://www.reddit.com/user/RobotOilInc // @version 1.0.2 // @description Add a Weidian order straight into BaseTao // @author RobotOilInc // @match https://weidian.com/item.html* // @match https://*.weidian.com/item.html* // @grant GM_xmlhttpRequest // @license MIT // @homepageURL https://greasyfork.org/en/scripts/427774-weidian-to-basetao // @supportURL https://greasyfork.org/en/scripts/427774-weidian-to-basetao // @require https://unpkg.com/js-logger@1.6.1/src/logger.min.js // @require https://unpkg.com/jquery@3.6.0/dist/jquery.min.js // @require https://greasyfork.org/scripts/401399-gm-xhr/code/GM%20XHR.js?version=938754 // @connect basetao.com // @run-at document-end // @icon https://assets.geilicdn.com/fxxxx/favicon.ico // @downloadURL none // ==/UserScript== /** * Creates a SKU toast, which is shown because of Weidians CSS * * @param toast {string} */ const Snackbar = function (toast) { const $toast = $(`
${toast}
`).css('font-size', '20px'); // Append the toast to the body $('.sku-body').append($toast); // Set a timeout to remove it setTimeout(() => $toast.fadeOut('slow', () => { $toast.remove(); }), 2000); }; // Chinese SKU names for colors const chineseForColors = ['颜色']; // Chinese SKU names for sizing const chineseForSizing = ['尺寸']; /** * Waits for an element satisfying selector to exist, then resolves promise with the element. * Useful for resolving race conditions. * * @param selector {string} * @returns {Promise} */ const elementReady = function (selector) { return new Promise((resolve) => { const el = document.querySelector(selector); if (el) { resolve(el); } new MutationObserver((mutationRecords, observer) => { // Query for elements matching the specified selector Array.from(document.querySelectorAll(selector)).forEach((element) => { resolve(element); // Once we have resolved we don't need the observer anymore. observer.disconnect(); }); }).observe(document.documentElement, { childList: true, subtree: true, }); }); }; /** * Trims the input text and removes all inbetween spaces as well. * * @param string {string} */ const removeWhitespaces = (string) => string.trim().replace(/\s(?=\s)/g, ''); // eslint-disable-next-line func-names (async function () { // Setup the logger. Logger.useDefaults(); // Log the start of the script. Logger.info(`Starting extension '${GM_info.script.name}', version ${GM_info.script.version}`); // Setup GM_XHR $.ajaxSetup({ xhr() { return new GM_XHR(); } }); // Build the basic buttons const $button = $('').css('background', '#f29800').css('font-size', '15px').css('color', '#FFFFFF') .css('text-align', 'center') .css('padding', '15px 0') .css('width', '100%') .css('height', '100%'); // Attach click handler $button.on('click', async () => { // Disable button to prevent double clicks and show clear message $button.attr('disabled', true).text('Processing...'); // Grab data required to add the order const data = await $.get('https://www.basetao.com/index/selfhelporder.html'); // Check if user is actually logged in if (data.indexOf('long time no operation ,please sign in again') !== -1) { Snackbar('You need to be logged in on BaseTao to use this extension (CSRF).'); return; } // Convert into jQuery object const $data = $(data); // Get the username const username = $data.find('#dropdownMenu1').text(); if (typeof username === 'undefined' || username == null || username === '') { Snackbar('You need to be logged in on BaseTao to use this extension (CSRF).'); return; } // Build items from Basetao const csrf = $data.find('input[name=csrf_test_name]').first().val(); // Items from Weidian const price = Number(removeWhitespaces($('.sku-cur-price').text()).replace(/(\D+)/, '')); const shopName = removeWhitespaces($('.shop-toggle-header-name').text()); const itemName = removeWhitespaces($('.item-title').text()); const imageUrl = $('img#skuPic').attr('src'); // Create dynamic items let selectedColor = null; let selectedSize = null; let canContinue = true; // Try and find the proper SKU rows $('.sku-content .sku-row').each((key, value) => { const rowTitle = $(value).find('.row-title').text(); // Check if this is color if (chineseForColors.includes(rowTitle)) { const selectedItem = $(value).find('.sku-item.selected'); if (selectedItem.length === 0) { canContinue = false; return; } selectedColor = removeWhitespaces(selectedItem.text()); } // Check if this is size if (chineseForSizing.includes(rowTitle)) { const selectedItem = $(value).find('.sku-item.selected'); if (selectedItem.length === 0) { canContinue = false; return; } selectedSize = removeWhitespaces(selectedItem.text()); } }); // Check if anything was missed if (canContinue === false) { Snackbar('You are missing a required option (color/size)'); $button.attr('disabled', false).text('Add to BaseTao'); return; } // Build the data we will send const baseTaoData = { csrf_test_name: csrf, color: selectedColor, size: selectedSize, number: 1, pric: price, shipping: 10, totalpric: price + 10, t_title: itemName, t_seller: shopName, t_img: imageUrl, t_href: window.location.href, s_url: window.location.href, buyyourself: 1, site: null, note: null, }; Logger.info('Sending order to BaseTao...', baseTaoData); $.ajax({ url: 'https://www.basetao.com/index/Ajax_data/buyonecart', type: 'POST', headers: { origin: 'https://www.basetao.com', referer: 'https://www.basetao.com/index/selfhelporder.html', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36', 'x-requested-with': 'XMLHttpRequest', }, data: baseTaoData, }).then((response) => { if (removeWhitespaces(response) !== '1') { Logger.error('Item could not be added', response); Snackbar('Item could not be added, make sure you are logged in'); return; } Snackbar('Item has been added, be sure to double check it'); // Remove button once done $button.fadeOut('slow', () => { $button.remove(); }); }).catch((err) => { Logger.error('An error happened when uploading the image', err); Snackbar('An error happened when adding the order'); }); }); // Setup for when someone presses the buy button elementReady('.sku-footer').then((element) => { $(element).before($button); }); }());