删除 mt/auto-meal-complete
This commit is contained in:
parent
bd4fa02c81
commit
984adceabe
@ -1,315 +0,0 @@
|
|||||||
// ==UserScript==
|
|
||||||
// @name 美团外卖自动出餐
|
|
||||||
// @namespace https://circlecloud.ltd/
|
|
||||||
// @version 0.0.1
|
|
||||||
// @description 自动出餐
|
|
||||||
// @author MiaoWoo
|
|
||||||
// @match https://e.waimai.meituan.com/**region_id=**®ion_version=**
|
|
||||||
// @icon https://www.google.com/s2/favicons?sz=64&domain=meituan.com
|
|
||||||
// @grant none
|
|
||||||
// ==/UserScript==
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
'use strict';
|
|
||||||
function sleep(ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
|
||||||
}
|
|
||||||
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 convertSecondsToMinutesSeconds(seconds) {
|
|
||||||
var minutes = Math.floor(seconds / 60);
|
|
||||||
var remainingSeconds = seconds % 60;
|
|
||||||
return minutes + "分" + remainingSeconds.toFixed(0) + "秒";
|
|
||||||
}
|
|
||||||
function request(path, params) {
|
|
||||||
return fetch(`https://e.waimai.meituan.com/${path}?region_id=${cookies.region_id}®ion_version=${cookies.region_version}`, {
|
|
||||||
"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/x-www-form-urlencoded",
|
|
||||||
"sec-ch-ua": "\"Microsoft Edge\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"",
|
|
||||||
"sec-ch-ua-mobile": "?0",
|
|
||||||
"sec-ch-ua-platform": "\"Windows\"",
|
|
||||||
"sec-fetch-dest": "empty",
|
|
||||||
"sec-fetch-mode": "cors",
|
|
||||||
"sec-fetch-site": "same-origin"
|
|
||||||
},
|
|
||||||
"referrer": "https://e.waimai.meituan.com/new_fe/business_gw",
|
|
||||||
"referrerPolicy": "unsafe-url",
|
|
||||||
"body": (new URLSearchParams(params)).toString(),
|
|
||||||
"method": "POST",
|
|
||||||
"mode": "cors",
|
|
||||||
"credentials": "include"
|
|
||||||
}).then(r => r.json())
|
|
||||||
}
|
|
||||||
async function requestGet(path, params) {
|
|
||||||
return await fetch(`https://e.waimai.meituan.com/gw/phf${path}?${(new URLSearchParams({
|
|
||||||
region_id: cookies.region_id,
|
|
||||||
region_version: cookies.region_version,
|
|
||||||
...params
|
|
||||||
})).toString()}`, {
|
|
||||||
"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",
|
|
||||||
"sec-ch-ua": "\"Microsoft Edge\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"",
|
|
||||||
"sec-ch-ua-mobile": "?0",
|
|
||||||
"sec-ch-ua-platform": "\"Windows\"",
|
|
||||||
"sec-fetch-dest": "empty",
|
|
||||||
"sec-fetch-mode": "cors",
|
|
||||||
"sec-fetch-site": "same-origin"
|
|
||||||
},
|
|
||||||
"referrer": "https://e.waimai.meituan.com/new_fe/business_gw",
|
|
||||||
"referrerPolicy": "unsafe-url",
|
|
||||||
"body": null,
|
|
||||||
"method": "GET",
|
|
||||||
"mode": "cors",
|
|
||||||
"credentials": "include"
|
|
||||||
}).then(r => r.json());
|
|
||||||
}
|
|
||||||
function listUnprocessedOrder() {
|
|
||||||
return request('/gw/api/order/mix/unprocessed/list/common', {
|
|
||||||
tag: "process",
|
|
||||||
pageSize: 10,
|
|
||||||
pageNum: 1,
|
|
||||||
pageGray: 1,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async function completeMealTime(order, cookTime = order.cookTime, tip = order.deliveOnShop ? '骑手已到店' : '骑手未到店') {
|
|
||||||
let wmOrderViewId = order.wmOrderViewIdStr
|
|
||||||
let daySeq = order.daySeq
|
|
||||||
let result = await request('/v2/common/w/reported/completeMealTime', {
|
|
||||||
wmPoiId: mt.wmPoiId,
|
|
||||||
wmOrderViewId: wmOrderViewId
|
|
||||||
})
|
|
||||||
debug('订单 #' + daySeq + ' 上报出餐结束.')
|
|
||||||
mt.submitOrders.push({
|
|
||||||
completeTime: new Date().toLocaleTimeString(),
|
|
||||||
daySn: daySeq, orderId: wmOrderViewId, tip, cookTime
|
|
||||||
})
|
|
||||||
if (mt.submitOrders.length > mt.maxLogOrderLength) {
|
|
||||||
mt.submitOrders = mt.submitOrders.slice(mt.submitOrders.length - mt.maxLogOrderLength)
|
|
||||||
}
|
|
||||||
localStorage.setItem(SubmitOrdersKey, JSON.stringify(mt.submitOrders))
|
|
||||||
await sleep(5)
|
|
||||||
await syncOrders()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
async function checkCooking() {
|
|
||||||
if (!mt.processOrders) return
|
|
||||||
for (const order of mt.processOrders) {
|
|
||||||
if (order.isFoodDone) continue
|
|
||||||
order.cookTime -= 5
|
|
||||||
order.leftTime -= 5
|
|
||||||
order.submitLeft -= 5
|
|
||||||
if (order.submitLeft < 0) {
|
|
||||||
if (order.cookTime < 180) {
|
|
||||||
console.log(order)
|
|
||||||
debug('订单 #' + order.daySeq + ' 出餐时间 ' + order.cookTime + 's 小于 ' + 180 + 's 取消自动上报.')
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (order.deliveOnShop) {
|
|
||||||
debug('订单 #' + order.daySeq + ' 骑手已到店.')
|
|
||||||
debug('订单 #' + order.daySeq + ' 剩余出餐时间 ' + order.leftTime + 's 小于 ' + mt.autoSubmitLeftTimeWhenOnShop + 's 模拟提交出餐.')
|
|
||||||
} else {
|
|
||||||
debug('订单 #' + order.daySeq + ' 骑手未到店.')
|
|
||||||
debug('订单 #' + order.daySeq + ' 剩余出餐时间 ' + order.leftTime + 's 小于 ' + mt.autoSubmitLeftTime + 's 模拟提交出餐.')
|
|
||||||
}
|
|
||||||
return await completeMealTime(order, order.cookTime)
|
|
||||||
}
|
|
||||||
if (order.submitLeft < 20) {
|
|
||||||
debug('订单 #' + order.daySeq + ' 还剩 ' + order.leftTime + 's 上报超时 将于 ' + order.submitLeft + 's 后自动上报.')
|
|
||||||
} else {
|
|
||||||
updateInfo()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function syncPhfOrderMeal(wmOrderViewId) {
|
|
||||||
let result = await requestGet('/v2/order/receive/processed/r/orderAsyncInfos/v3', {
|
|
||||||
orderInfos: JSON.stringify([{
|
|
||||||
"wmOrderViewId": wmOrderViewId,
|
|
||||||
"wmPoiId": cookies.wmPoiId,
|
|
||||||
"cityId": cookies.city_id
|
|
||||||
}])
|
|
||||||
})
|
|
||||||
return result.data[wmOrderViewId]
|
|
||||||
}
|
|
||||||
async function syncPhfOrderlLgistic(wmOrderViewId) {
|
|
||||||
let result = await requestGet('/v2/order/receive/processed/r/distribute/list/v2', {
|
|
||||||
orderInfos: JSON.stringify([{
|
|
||||||
"wmOrderViewId": wmOrderViewId,
|
|
||||||
"wmPoiId": cookies.wmPoiId,
|
|
||||||
"cityId": cookies.city_id
|
|
||||||
}])
|
|
||||||
})
|
|
||||||
return result.data[wmOrderViewId]
|
|
||||||
}
|
|
||||||
async function syncOrderInfo(order) {
|
|
||||||
let now = Math.floor(Date.now() / 1000)
|
|
||||||
order.wordLogo = ''
|
|
||||||
order.daySeq = order.commonInfo.wm_poi_order_dayseq
|
|
||||||
order.cookTime = now - order.commonInfo.confirmTime
|
|
||||||
order.leftTime = order.commonInfo.confirmTime + 480 - now
|
|
||||||
if (order.businessType == 1) {
|
|
||||||
// 获取订单类型 普通订单存在预订单
|
|
||||||
order.wordLogo = order.orderInfo.orderInfo.wordLogo || '普'
|
|
||||||
order.wmOrderViewIdStr = order.orderInfo.orderInfo.wmOrderViewId
|
|
||||||
order.isFoodDone = !order.orderInfo.mealInfo.foodDoneButtonVo.isShow
|
|
||||||
order.cookTime = now - order.orderInfo.mealInfo.countDownTimerVo.timerShowVo.preMealBeginTime
|
|
||||||
order.logisticsStatus = order.orderInfo.logisticsInfo.logisticsProcessVo.processDesc
|
|
||||||
// 部分数据存在长 结束备餐时间可能是0 需要计算开始时间 + 480(配置的出餐时间) - 当前时间
|
|
||||||
if (order.orderInfo.mealInfo.countDownTimerVo.timerShowVo.preMealEndTime) {
|
|
||||||
order.leftTime = order.orderInfo.mealInfo.countDownTimerVo.timerShowVo.preMealEndTime - now
|
|
||||||
} else {
|
|
||||||
order.leftTime = order.orderInfo.mealInfo.countDownTimerVo.timerShowVo.preMealBeginTime + 480 - now
|
|
||||||
}
|
|
||||||
if (order.wordLogo == '预' && !order.isFoodDone) {
|
|
||||||
// 预订单需要从提醒时间开始计算备餐时间
|
|
||||||
order.leftTime = order.orderInfo.mealInfo.foodDoneTitleVo.reminderTime + 480 - now
|
|
||||||
}
|
|
||||||
order.submitCanClickLimitTime = order.orderInfo.mealInfo.foodDoneButtonVo.buttonClickVo?.canClickLimitTime || 0
|
|
||||||
} else if (order.businessType == 2) {
|
|
||||||
order.wordLogo = '拼'
|
|
||||||
order.wmOrderViewIdStr = order.orderInfo.wm_order_id_view_str
|
|
||||||
order.mealInfo = await syncPhfOrderMeal(order.wmOrderViewIdStr)
|
|
||||||
order.logisticsInfo = await syncPhfOrderlLgistic(order.wmOrderViewIdStr)
|
|
||||||
order.isFoodDone = order.mealInfo.prepareStauts == 2 || order.phfOperationContent
|
|
||||||
order.logisticsStatus = order.logisticsInfo.latestLogisticsLogDesc.split(' ')[1]
|
|
||||||
order.submitCanClickLimitTime = order.mealInfo.buttonTimeLimit
|
|
||||||
}
|
|
||||||
order.deliveOnShop = order.logisticsStatus == '骑手已到店'
|
|
||||||
// 剩余时间取最小出餐时间和剩余出餐时间大的值
|
|
||||||
order.submitLeft = Math.max(order.submitCanClickLimitTime - now,
|
|
||||||
order.leftTime - (order.deliveOnShop ? mt.autoSubmitLeftTimeWhenOnShop : mt.autoSubmitLeftTime))
|
|
||||||
}
|
|
||||||
async function syncOrders() {
|
|
||||||
let originCount = mt.processOrders.length
|
|
||||||
let orders = await listUnprocessedOrder()
|
|
||||||
orders = orders.data.wmOrderList?.map(o => {
|
|
||||||
o.commonInfo = JSON.parse(o.commonInfo)
|
|
||||||
o.orderInfo = JSON.parse(o.orderInfo)
|
|
||||||
return o
|
|
||||||
})
|
|
||||||
await Promise.all(orders.map(syncOrderInfo))
|
|
||||||
mt.processOrders = orders || []
|
|
||||||
if (originCount != mt.processOrders.length) {
|
|
||||||
debug('更新订单数据 目前进行中订单: ' + mt.processOrders.length + '个')
|
|
||||||
} else {
|
|
||||||
updateInfo()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function printOrderInfo(order) {
|
|
||||||
let leftTime = order.submitCanClickLimitTime < Date.now() / 1000
|
|
||||||
? order.submitLeft : order.submitCanClickLimitTime - Date.now() / 1000
|
|
||||||
return `订单: #${order.daySeq} ${order.wordLogo}
|
|
||||||
出餐状态 ${order.isFoodDone ? '已出餐' : `未出餐(${leftTime.toFixed(0)}s)`}
|
|
||||||
配送状态 ${order.logisticsStatus}`
|
|
||||||
}
|
|
||||||
function debug(msg) {
|
|
||||||
mt.logs.push('[' + (new Date().toLocaleTimeString()) + '] ' + msg)
|
|
||||||
if (mt.logs.length > mt.maxLogLength) {
|
|
||||||
mt.logs = mt.logs.slice(mt.logs.length - mt.maxLogLength)
|
|
||||||
}
|
|
||||||
updateInfo()
|
|
||||||
}
|
|
||||||
function updateInfo() {
|
|
||||||
try {
|
|
||||||
let title = `${mt.title} Version: ${mt.version} By ${mt.author}`
|
|
||||||
let configInfo = `当前配置: </br>
|
|
||||||
<div class="ant-alert-content">
|
|
||||||
订单 刷新间隔: ${mt.syncInterval}s 检测间隔: ${mt.checkInterval}s</br>
|
|
||||||
出餐 最长时间: ${mt.autoSubmitMaxCookTime}s
|
|
||||||
骑手未到店: ${mt.autoSubmitLeftTime}s 骑手已到店: ${mt.autoSubmitLeftTimeWhenOnShop}s</br>
|
|
||||||
</div>`
|
|
||||||
let orderInfo = `进行中的订单信息 更新时间:${new Date().toLocaleTimeString()}</br>
|
|
||||||
${mt.processOrders.map(printOrderInfo).join('</br>')}`
|
|
||||||
let submitInfo = `已自动出餐的订单信息: </br>
|
|
||||||
<div class="ant-alert-content">
|
|
||||||
${mt.submitOrders.length
|
|
||||||
? mt.submitOrders
|
|
||||||
.map(o => '[' + o.completeTime + '] 订单: #' + o.daySn
|
|
||||||
+ ' 出餐用时 ' + convertSecondsToMinutesSeconds(o.cookTime) + ' ' + o.tip).join('</br>')
|
|
||||||
: '当前没有自动出餐的订单.'}
|
|
||||||
</div>`
|
|
||||||
let logs = `运行日志: </br>
|
|
||||||
<div class="ant-alert-content">
|
|
||||||
${mt.logs.join('</br>')}
|
|
||||||
</div>`
|
|
||||||
window.appContainerNoticeBar.innerHTML = `
|
|
||||||
<div style="
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
display: flex;"
|
|
||||||
>
|
|
||||||
<div style="flex: 1 1 0%;">
|
|
||||||
${title}
|
|
||||||
<div style="margin-top: 20px;">
|
|
||||||
${configInfo}
|
|
||||||
</div>
|
|
||||||
<div style="margin-top: 20px;">
|
|
||||||
${orderInfo}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style="flex: 1 1 0%;">
|
|
||||||
${submitInfo}
|
|
||||||
</div>
|
|
||||||
<div style="flex: 1 1 0%;">
|
|
||||||
${logs}
|
|
||||||
</div>
|
|
||||||
</div>`
|
|
||||||
} catch (error) {
|
|
||||||
console.log(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function scheduleCheck() {
|
|
||||||
await checkCooking()
|
|
||||||
await sleep(mt.checkInterval * 1000)
|
|
||||||
scheduleCheck()
|
|
||||||
}
|
|
||||||
async function main() {
|
|
||||||
while (!document.getElementById('hashframe')) {
|
|
||||||
await sleep(300)
|
|
||||||
}
|
|
||||||
console.log(`${mt.title} Version: ${mt.version} By ${mt.author}`)
|
|
||||||
window.appContainerNoticeBar = document.createElement('div')
|
|
||||||
let iframe = document.getElementById('hashframe')
|
|
||||||
iframe.parentNode.insertBefore(window.appContainerNoticeBar, iframe)
|
|
||||||
debug('页面注入成功 开始运行...')
|
|
||||||
syncOrders()
|
|
||||||
scheduleCheck()
|
|
||||||
setInterval(() => syncOrders(), mt.syncInterval * 1000)
|
|
||||||
}
|
|
||||||
let cookies = document.cookie.split('; ').map(cookie => cookie.split('=')).reduce((c, [key, value]) => {
|
|
||||||
c[key] = decodeURIComponent(value);
|
|
||||||
return c;
|
|
||||||
}, {});
|
|
||||||
var SubmitOrdersKey = 'AutoMealComplete:SubmitOrders'
|
|
||||||
let mt = {
|
|
||||||
title: '美团自动出餐',
|
|
||||||
version: '0.0.5',
|
|
||||||
author: 'MiaoWoo',
|
|
||||||
wmPoiId: localStorage.product_local_first_enter_screen,
|
|
||||||
checkInterval: 5,
|
|
||||||
syncInterval: 15,
|
|
||||||
maxLogLength: 20,
|
|
||||||
maxLogOrderLength: 20,
|
|
||||||
autoSubmitLeftTime: 260,
|
|
||||||
autoSubmitMaxCookTime: 420,
|
|
||||||
autoSubmitLeftTimeWhenOnShop: 280,
|
|
||||||
logs: [],
|
|
||||||
processOrders: [],
|
|
||||||
submitOrders: JSON.parse(localStorage.getItem(SubmitOrdersKey)) || [],
|
|
||||||
debug: debug,
|
|
||||||
syncOrders: syncOrders,
|
|
||||||
}
|
|
||||||
window.mt = mt
|
|
||||||
main()
|
|
||||||
})();
|
|
Loading…
Reference in New Issue
Block a user