diff --git a/ele/auto-meal-complete.user.js b/ele/auto-meal-complete.user.js new file mode 100644 index 0000000..c21590f --- /dev/null +++ b/ele/auto-meal-complete.user.js @@ -0,0 +1,187 @@ +// ==UserScript== +// @name 饿了么自动出餐 +// @namespace https://circlecloud.ltd/ +// @version 0.1 +// @description 自动出餐 +// @author MiaoWoo +// @match https://melody.shop.ele.me/app/shop/**/order__processing +// @icon https://www.google.com/s2/favicons?sz=64&domain=ele.me +// @updateURL https://git.yumc.pw/502647092/UserScript/raw/branch/master/ele/auto-meal-complete.user.js +// @downloadURL https://git.yumc.pw/502647092/UserScript/raw/branch/master/ele/auto-meal-complete.user.js +// @grant none +// ==/UserScript== + +(function () { + 'use strict'; + function generateRandomString(length) { + var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + var result = ''; + var charactersLength = characters.length; + for (var i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; + } + function getRequestId() { + return generateRandomString(32) + "|" + Date.now() + } + function convertSecondsToMinutesSeconds(seconds) { + var minutes = Math.floor(seconds / 60); + var remainingSeconds = seconds % 60; + return minutes + "分" + remainingSeconds + "秒"; + } + function getShopId() { + return parseInt(localStorage.shopId) + } + function getShopMeta() { + return { + "appVersion": "1.0.0", + "appName": "melody", + "ksid": localStorage.ksid, + "shopId": getShopId() + } + } + function request(service, method, params) { + let payload = { + "service": service, + "method": method, + "params": params, + "id": getRequestId(), + "metas": getShopMeta(), + "ncp": "2.0.0" + } + return fetch("https://app-api.shop.ele.me/fulfill/weborder/" + method + "/?method=" + service + "." + method, { + "headers": { + "accept": "application/json, text/plain, */*", + "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", + "content-type": "application/json;charset=UTF-8", + "sec-ch-ua": "\"Microsoft Edge\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"", + "sec-ch-ua-platform": "\"Windows\"", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-site", + "x-eleme-requestid": payload.id, + "x-shard": "shopid=" + payload.metas.shopId + }, + "referrer": "https://napos-order-pc.faas.ele.me/", + "referrerPolicy": "strict-origin-when-cross-origin", + "body": JSON.stringify(payload), + "method": "POST", + "mode": "cors", + "credentials": "omit" + }).then(r => r.json()) + } + + function queryInProcessOrders() { + return request('OrderWebService', 'queryInProcessOrders', { + "shopId": getShopId(), + "queryType": "ALL", + // "queryType": "COOKING" + }) + } + async function mealComplete(orderId, cookTime) { + let result = await request('ShipmentService', 'mealComplete', { + "shopId": getShopId(), + "orderId": orderId + }) + debug('订单 ' + orderId + ' 上报出餐结束.') + ele.submitOrders.push({ orderId, cookTime }) + if (ele.submitOrders.length > ele.maxLogOrderLength) + ele.submitOrders = ele.submitOrders.slice(ele.submitOrders.length - ele.maxLogOrderLength) + await updateOrders() + return result + } + async function checkCooking() { + if (!ele.processOrders) return + for (const cook of ele.processOrders) { + let orderId = cook.id + if (!cook.mealPreparationInfo || cook.mealPreparationInfo.mealComplete) continue + // 骑手到店 并且大于最小上报时长 直接上报出餐 + let cookTime = (Date.now() - new Date(cook.activeTime).getTime()) / 1000 + let leftTime = cook.mealPreparationInfo.commonShowTime + if (cook.deliveryInfo.distTraceView.traceView.status == '骑士已到店' + && cook.mealPreparationInfo.minMealCompleteTimeCount < 0 + && leftTime < ele.autoSubmitLeftTimeWhenOnShop) { + debug('订单 ' + orderId + ' 骑手到店 且剩余时间 ' + leftTime + 's 小于 ' + ele.autoSubmitLeftTimeWhenOnShop + 's 模拟提交出餐.') + return mealComplete(orderId, cookTime) + } + if (leftTime < ele.autoSubmitLeftTime) { + // 大于最小上报时长 并且距离上报超时不足120秒 直接上报出餐 + debug('订单 ' + orderId + ' 骑手未到店 且剩余时间 ' + leftTime + 's 小于 ' + ele.autoSubmitLeftTimeWhenOnShop + 's 模拟提交出餐.') + return mealComplete(orderId, cookTime) + } + debug('订单 ' + orderId + ' 还剩 ' + cook.mealPreparationInfo.commonShowTime + 's 上报超时.') + cook.mealPreparationInfo.minMealCompleteTimeCount -= 5 + cook.mealPreparationInfo.commonShowTime -= 5 + } + } + async function updateOrders() { + let orders = await queryInProcessOrders() + ele.autoCheckTime = Date.now() / 1000 + ele.processOrders = orders.result || [] + debug('更新订单数据 目前进行中订单: ' + ele.processOrders.length + '个') + } + function debug(msg) { + try { + ele.logs.push('[' + (new Date().toLocaleTimeString()) + '] ' + msg) + if (ele.logs.length > ele.maxLogLength) + ele.logs = ele.logs.slice(ele.logs.length - ele.maxLogLength) + let title = '饿了么自动出餐 By MiaoWoo
' + let configInfo = '当前配置:
' + + '骑手到店 提前 ' + ele.autoSubmitLeftTimeWhenOnShop + 's 出餐 ' + + '骑手未到店 提前 ' + ele.autoSubmitLeftTime + 's 出餐
' + + '
' + let submitInfo = '已自动出餐的订单信息:
' + + (ele.submitOrders.length + ? ele.submitOrders.map(o => '订单: ' + o.orderId + ' 出餐用时 ' + convertSecondsToMinutesSeconds(o.cookTime)).join('
') + : '当前没有自动出餐的订单.') + + '
' + let orderInfo = '进行中的订单信息:
' + + (ele.processOrders.length + ? ele.processOrders.map(o => '订单: ' + o.id + ' 出餐状态 ' + (o.mealPreparationInfo.mealComplete ? '已出餐' : '未出餐') + ' 配送状态 ' + o.deliveryInfo.distTraceView.traceView.status).join('
') + : '当前没有进行中的订单.') + + '
' + let logs = '运行日志:
' + + ele.logs.join('
') + + '
' + window.appContainerNoticeBar.innerHTML = '
' + + title + '
' + + configInfo + '
' + + submitInfo + '
' + + orderInfo + '
' + + '
' + + '
' + + logs + + '
' + } catch (error) { + console.log(msg) + } + } + async function main() { + setTimeout(() => { + window.appContainerNoticeBar = document.getElementById('app-container-notice-bar') + window.appContainerNoticeBar.style.marginLeft = '35px' + window.appContainerNoticeBar.style.marginTop = '20px' + window.appContainerNoticeBar.style.display = 'flex' + updateOrders() + }, 5000) + setInterval(() => { checkCooking() }, 5000) + setInterval(() => { updateOrders() }, 30000) + } + var ele = { + logs: [], + maxLogLength: 15, + maxLogOrderLength: 5, + orderStatus: {}, + processOrders: [], + submitOrders: [], + autoCheckTask: undefined, + autoSubmitLeftTime: 180, + autoSubmitLeftTimeWhenOnShop: 300, + debug: debug, + updateOrders: updateOrders, + checkCooking: checkCooking, + mealComplete: mealComplete, + } + window.ele = ele + main() +})();