feat: add 2048 minigame
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
package minigame
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
hc "neo/context"
|
||||
"neo/core"
|
||||
)
|
||||
|
||||
func init() { core.Default.Register(Game2048) }
|
||||
|
||||
var Game2048 = &core.Command{
|
||||
Name: "2048",
|
||||
Aliases: []string{"2048"},
|
||||
Category: "minigame",
|
||||
Description: "Play 2048 in WhatsApp",
|
||||
Run: func(ctx *hc.Ctx) {
|
||||
htmlBytes, err := os.ReadFile("cmds/minigame/2048.html")
|
||||
if err != nil {
|
||||
ctx.Reply(fmt.Sprintf("Failed to read HTML file: %v", err))
|
||||
return
|
||||
}
|
||||
_, err = ctx.SendInteractiveHTML(string(htmlBytes))
|
||||
if err != nil {
|
||||
ctx.Reply(fmt.Sprintf("Failed to send game: %v", err))
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<title>2048</title>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background: #faf8ef;
|
||||
font-family: 'Clear Sans', 'Helvetica Neue', Arial, sans-serif;
|
||||
color: #776e65;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
.game-wrapper {
|
||||
width: 100%;
|
||||
max-width: 450px;
|
||||
margin: auto;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 36px;
|
||||
}
|
||||
.score-container {
|
||||
background: #bbada0;
|
||||
padding: 8px 15px;
|
||||
border-radius: 5px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
.btn-reset {
|
||||
background: #8f7a66;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
padding: 8px 15px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.btn-reset:active {
|
||||
background: #776e65;
|
||||
}
|
||||
#game-container {
|
||||
background: #bbada0;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
padding: 1%;
|
||||
}
|
||||
.cell-bg, .tile {
|
||||
width: 25%;
|
||||
height: 25%;
|
||||
position: absolute;
|
||||
padding: 1.5%;
|
||||
box-sizing: border-box;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.cell-bg-inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(238, 228, 218, 0.35);
|
||||
border-radius: 5px;
|
||||
}
|
||||
.tile {
|
||||
z-index: 10;
|
||||
}
|
||||
.tile.new .tile-inner {
|
||||
animation: appear 0.2s;
|
||||
}
|
||||
.tile.merged .tile-inner {
|
||||
animation: pop 0.2s;
|
||||
}
|
||||
@keyframes appear {
|
||||
0% { opacity: 0; transform: scale(0); }
|
||||
100% { opacity: 1; transform: scale(1); }
|
||||
}
|
||||
@keyframes pop {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.2); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
.tile-inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.tile-2 .tile-inner { background: #eee4da; color: #776e65; }
|
||||
.tile-4 .tile-inner { background: #ede0c8; color: #776e65; }
|
||||
.tile-8 .tile-inner { background: #f2b179; color: #f9f6f2; }
|
||||
.tile-16 .tile-inner { background: #f59563; color: #f9f6f2; }
|
||||
.tile-32 .tile-inner { background: #f67c5f; color: #f9f6f2; }
|
||||
.tile-64 .tile-inner { background: #f65e3b; color: #f9f6f2; }
|
||||
.tile-128 .tile-inner { background: #edcf72; color: #f9f6f2; font-size: 24px; }
|
||||
.tile-256 .tile-inner { background: #edcc61; color: #f9f6f2; font-size: 24px; }
|
||||
.tile-512 .tile-inner { background: #edc850; color: #f9f6f2; font-size: 24px; }
|
||||
.tile-1024 .tile-inner { background: #edc53f; color: #f9f6f2; font-size: 20px; }
|
||||
.tile-2048 .tile-inner { background: #edc22e; color: #f9f6f2; font-size: 20px; }
|
||||
|
||||
#game-over {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(238, 228, 218, 0.73);
|
||||
border-radius: 10px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 100;
|
||||
}
|
||||
#game-over button {
|
||||
margin-top: 20px;
|
||||
padding: 10px 20px;
|
||||
background: #8f7a66;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.controls {
|
||||
width: 100%;
|
||||
max-width: 250px;
|
||||
margin: 30px auto 20px auto;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-rows: 60px 60px;
|
||||
gap: 15px;
|
||||
flex-grow: 1;
|
||||
align-content: end;
|
||||
}
|
||||
.controls button {
|
||||
background: #8f7a66;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
user-select: none;
|
||||
}
|
||||
.controls button:active {
|
||||
background: #776e65;
|
||||
}
|
||||
.btn-up { grid-column: 2; grid-row: 1; }
|
||||
.btn-left { grid-column: 1; grid-row: 2; }
|
||||
.btn-down { grid-column: 2; grid-row: 2; }
|
||||
.btn-right { grid-column: 3; grid-row: 2; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="game-wrapper">
|
||||
<div class="header">
|
||||
<div>
|
||||
<h1>2048</h1>
|
||||
<button class="btn-reset" onclick="confirmReset()">Reset</button>
|
||||
</div>
|
||||
<div class="score-container">
|
||||
<div>Score</div>
|
||||
<div id="score">0</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="game-container">
|
||||
<div id="grid-bg"></div>
|
||||
<div id="tile-container"></div>
|
||||
<div id="game-over">
|
||||
<h2 style="margin:0; font-size: 36px;">Game Over!</h2>
|
||||
<button onclick="startGame()">Try Again</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button class="btn-up" onclick="move('Up')">↑</button>
|
||||
<button class="btn-left" onclick="move('Left')">←</button>
|
||||
<button class="btn-down" onclick="move('Down')">↓</button>
|
||||
<button class="btn-right" onclick="move('Right')">→</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const gridBg = document.getElementById('grid-bg');
|
||||
const tileContainer = document.getElementById('tile-container');
|
||||
const scoreEl = document.getElementById('score');
|
||||
const gameOverEl = document.getElementById('game-over');
|
||||
|
||||
let board = [];
|
||||
let score = 0;
|
||||
let tiles = {}; // id -> { value, el, r, c }
|
||||
let tileIdCounter = 0;
|
||||
|
||||
function initGrid() {
|
||||
gridBg.innerHTML = '';
|
||||
for (let r = 0; r < 4; r++) {
|
||||
for (let c = 0; c < 4; c++) {
|
||||
const bg = document.createElement('div');
|
||||
bg.className = 'cell-bg';
|
||||
bg.style.transform = `translate(${c * 100}%, ${r * 100}%)`;
|
||||
bg.innerHTML = '<div class="cell-bg-inner"></div>';
|
||||
gridBg.appendChild(bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function confirmReset() {
|
||||
if (confirm("Are you sure you want to reset the game?")) {
|
||||
startGame();
|
||||
}
|
||||
}
|
||||
|
||||
function startGame() {
|
||||
board = Array(4).fill(null).map(() => Array(4).fill(null));
|
||||
tiles = {};
|
||||
score = 0;
|
||||
scoreEl.innerText = score;
|
||||
gameOverEl.style.display = 'none';
|
||||
tileContainer.innerHTML = '';
|
||||
addRandomTile();
|
||||
addRandomTile();
|
||||
}
|
||||
|
||||
function addRandomTile() {
|
||||
let empty = [];
|
||||
for (let r = 0; r < 4; r++) {
|
||||
for (let c = 0; c < 4; c++) {
|
||||
if (!board[r][c]) empty.push({r, c});
|
||||
}
|
||||
}
|
||||
if (empty.length > 0) {
|
||||
let {r, c} = empty[Math.floor(Math.random() * empty.length)];
|
||||
let value = Math.random() < 0.9 ? 2 : 4;
|
||||
createTile(r, c, value);
|
||||
}
|
||||
}
|
||||
|
||||
function createTile(r, c, value) {
|
||||
let id = ++tileIdCounter;
|
||||
let el = document.createElement('div');
|
||||
el.className = `tile tile-${value} new`;
|
||||
el.style.transition = 'none';
|
||||
el.style.transform = `translate(${c * 100}%, ${r * 100}%)`;
|
||||
el.innerHTML = `<div class="tile-inner">${value}</div>`;
|
||||
tileContainer.appendChild(el);
|
||||
|
||||
let tile = { id, value, el, r, c };
|
||||
tiles[id] = tile;
|
||||
board[r][c] = tile;
|
||||
|
||||
// Remove 'new' class after animation
|
||||
setTimeout(() => {
|
||||
el.classList.remove('new');
|
||||
}, 200);
|
||||
}
|
||||
|
||||
function updateTilePos(tile, r, c) {
|
||||
tile.r = r;
|
||||
tile.c = c;
|
||||
tile.el.style.transition = 'transform 0.15s ease-in-out';
|
||||
tile.el.style.transform = `translate(${c * 100}%, ${r * 100}%)`;
|
||||
}
|
||||
|
||||
function move(direction) {
|
||||
let moved = false;
|
||||
let scoreInc = 0;
|
||||
|
||||
// Remove merged class from all tiles
|
||||
Object.values(tiles).forEach(t => t.el.classList.remove('merged'));
|
||||
|
||||
const traverse = (r, c, dr, dc) => {
|
||||
let curr = board[r][c];
|
||||
if (!curr) return;
|
||||
|
||||
let nr = r + dr, nc = c + dc;
|
||||
let lastEmpty = null;
|
||||
|
||||
while (nr >= 0 && nr < 4 && nc >= 0 && nc < 4) {
|
||||
if (board[nr][nc]) {
|
||||
if (board[nr][nc].value === curr.value && !board[nr][nc].mergedThisTurn) {
|
||||
// Merge
|
||||
let target = board[nr][nc];
|
||||
board[r][c] = null;
|
||||
updateTilePos(curr, nr, nc);
|
||||
|
||||
// Animate removal of old tile and update target
|
||||
setTimeout(() => {
|
||||
curr.el.remove();
|
||||
delete tiles[curr.id];
|
||||
|
||||
target.value *= 2;
|
||||
scoreInc += target.value;
|
||||
target.el.className = `tile tile-${target.value} merged`;
|
||||
target.el.style.transform = `translate(${target.c * 100}%, ${target.r * 100}%)`;
|
||||
target.el.innerHTML = `<div class="tile-inner">${target.value}</div>`;
|
||||
scoreEl.innerText = score + scoreInc;
|
||||
}, 150);
|
||||
|
||||
target.mergedThisTurn = true;
|
||||
moved = true;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
lastEmpty = {r: nr, c: nc};
|
||||
nr += dr; nc += dc;
|
||||
}
|
||||
|
||||
if (lastEmpty) {
|
||||
board[r][c] = null;
|
||||
board[lastEmpty.r][lastEmpty.c] = curr;
|
||||
updateTilePos(curr, lastEmpty.r, lastEmpty.c);
|
||||
moved = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (direction === 'Left') {
|
||||
for(let r=0; r<4; r++) for(let c=1; c<4; c++) traverse(r, c, 0, -1);
|
||||
} else if (direction === 'Right') {
|
||||
for(let r=0; r<4; r++) for(let c=2; c>=0; c--) traverse(r, c, 0, 1);
|
||||
} else if (direction === 'Up') {
|
||||
for(let c=0; c<4; c++) for(let r=1; r<4; r++) traverse(r, c, -1, 0);
|
||||
} else if (direction === 'Down') {
|
||||
for(let c=0; c<4; c++) for(let r=2; r>=0; r--) traverse(r, c, 1, 0);
|
||||
}
|
||||
|
||||
if (moved) {
|
||||
// Clear merge flags
|
||||
for(let r=0; r<4; r++) for(let c=0; c<4; c++) {
|
||||
if (board[r][c]) board[r][c].mergedThisTurn = false;
|
||||
}
|
||||
score += scoreInc;
|
||||
setTimeout(() => {
|
||||
addRandomTile();
|
||||
if (checkGameOver()) gameOverEl.style.display = 'flex';
|
||||
}, 150);
|
||||
}
|
||||
}
|
||||
|
||||
function checkGameOver() {
|
||||
for (let r = 0; r < 4; r++) {
|
||||
for (let c = 0; c < 4; c++) {
|
||||
if (!board[r][c]) return false;
|
||||
if (r !== 3 && board[r+1][c] && board[r][c].value === board[r+1][c].value) return false;
|
||||
if (c !== 3 && board[r][c+1] && board[r][c].value === board[r][c+1].value) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
|
||||
e.preventDefault();
|
||||
move(e.key.replace('Arrow', ''));
|
||||
}
|
||||
});
|
||||
|
||||
initGrid();
|
||||
startGame();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,5 +5,6 @@ import (
|
||||
_ "neo/cmds/general"
|
||||
_ "neo/cmds/group"
|
||||
_ "neo/cmds/media"
|
||||
_ "neo/cmds/minigame"
|
||||
_ "neo/cmds/misc"
|
||||
)
|
||||
|
||||
+62
-2
@@ -2,7 +2,12 @@ package context
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.mau.fi/whatsmeow"
|
||||
"go.mau.fi/whatsmeow/proto/waAICommon"
|
||||
"go.mau.fi/whatsmeow/proto/waAICommonDeprecated"
|
||||
waCommon "go.mau.fi/whatsmeow/proto/waCommon"
|
||||
waE2E "go.mau.fi/whatsmeow/proto/waE2E"
|
||||
waTypes "go.mau.fi/whatsmeow/types"
|
||||
@@ -32,8 +37,8 @@ func (c *Ctx) Send(text string) {
|
||||
c.client.SendMessage(stdctx.Background(), c.event.Info.Chat, msg)
|
||||
}
|
||||
|
||||
func (c *Ctx) SendMessage(msg *waE2E.Message) {
|
||||
c.client.SendMessage(stdctx.Background(), c.event.Info.Chat, msg)
|
||||
func (c *Ctx) SendMessage(msg *waE2E.Message, extra ...whatsmeow.SendRequestExtra) {
|
||||
c.client.SendMessage(stdctx.Background(), c.event.Info.Chat, msg, extra...)
|
||||
}
|
||||
|
||||
func (c *Ctx) React(emoji string) {
|
||||
@@ -104,3 +109,58 @@ func (c *Ctx) SendPresence(composing bool) {
|
||||
_ = c.client.SubscribePresence(stdctx.Background(), c.event.Info.Chat)
|
||||
_ = c.client.SendChatPresence(stdctx.Background(), c.event.Info.Chat, state, waTypes.ChatPresenceMediaText)
|
||||
}
|
||||
|
||||
func (c *Ctx) SendInteractiveHTML(htmlContent string) (whatsmeow.SendResponse, error) {
|
||||
responseID := uuid.New().String()
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"response_id": responseID,
|
||||
"sections": []map[string]interface{}{
|
||||
{
|
||||
"view_model": map[string]interface{}{
|
||||
"primitive": map[string]interface{}{
|
||||
"__typename": "GenAIaeacdsnwHtmlPrimitive",
|
||||
"payload": htmlContent,
|
||||
"trusted_sources": []string{},
|
||||
},
|
||||
"__typename": "GenAISingleLayoutViewModel",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
data, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return whatsmeow.SendResponse{}, err
|
||||
}
|
||||
|
||||
msg := &waE2E.Message{
|
||||
BotForwardedMessage: &waE2E.FutureProofMessage{
|
||||
Message: &waE2E.Message{
|
||||
RichResponseMessage: &waE2E.AIRichResponseMessage{
|
||||
MessageType: waAICommonDeprecated.AIRichResponseMessageType(1).Enum(),
|
||||
Submessages: []*waAICommonDeprecated.AIRichResponseSubMessage{
|
||||
{
|
||||
MessageType: waAICommonDeprecated.AIRichResponseSubMessageType(2).Enum(),
|
||||
MessageText: proto.String("Game Center"),
|
||||
},
|
||||
},
|
||||
UnifiedResponse: &waAICommon.AIRichResponseUnifiedResponse{
|
||||
Data: data,
|
||||
},
|
||||
ContextInfo: &waE2E.ContextInfo{
|
||||
ForwardingScore: proto.Uint32(1),
|
||||
IsForwarded: proto.Bool(true),
|
||||
ForwardedAiBotMessageInfo: &waAICommon.ForwardedAIBotMessageInfo{
|
||||
BotJID: proto.String("867051314767696@bot"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return c.client.SendMessage(stdctx.Background(), c.event.Info.Chat, msg, whatsmeow.SendRequestExtra{
|
||||
ID: responseID,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
module neo
|
||||
|
||||
go 1.25.5
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
github.com/davidbyttow/govips/v2 v2.18.0
|
||||
github.com/gabriel-vasile/mimetype v1.4.13
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/mattn/go-sqlite3 v1.14.48
|
||||
github.com/mattn/go-sqlite3 v1.14.49
|
||||
github.com/mdp/qrterminal/v3 v3.2.1
|
||||
go.mau.fi/whatsmeow v0.0.0-20260630180629-b572e5bcb92b
|
||||
google.golang.org/protobuf v1.36.11
|
||||
go.mau.fi/whatsmeow v0.0.0-20260828224850-0fadda796019
|
||||
google.golang.org/protobuf v1.36.12
|
||||
gorm.io/driver/sqlite v1.6.0
|
||||
gorm.io/gorm v1.31.2
|
||||
)
|
||||
@@ -18,24 +18,25 @@ require (
|
||||
filippo.io/edwards25519 v1.2.0 // indirect
|
||||
github.com/beeper/argo-go v1.1.2 // indirect
|
||||
github.com/coder/websocket v1.8.15 // indirect
|
||||
github.com/elliotchance/orderedmap/v3 v3.1.0 // indirect
|
||||
github.com/elliotchance/orderedmap/v3 v3.1.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 // indirect
|
||||
github.com/mattn/go-colorable v0.1.15 // indirect
|
||||
github.com/mattn/go-isatty v0.0.24 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20260816044145-ed329add6b1b // indirect
|
||||
github.com/rs/zerolog v1.35.1 // indirect
|
||||
github.com/vektah/gqlparser/v2 v2.5.27 // indirect
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||
github.com/vektah/gqlparser/v2 v2.5.37 // indirect
|
||||
go.mau.fi/libsignal v0.2.2 // indirect
|
||||
go.mau.fi/util v0.9.10 // indirect
|
||||
golang.org/x/crypto v0.54.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20260611194520-c48552f49976 // indirect
|
||||
go.mau.fi/util v0.10.1-0.20260820140024-eb612d936fde // indirect
|
||||
golang.org/x/crypto v0.56.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20260813180055-c1d0aacb2297 // indirect
|
||||
golang.org/x/image v0.44.0 // indirect
|
||||
golang.org/x/net v0.57.0 // indirect
|
||||
golang.org/x/net v0.58.0 // indirect
|
||||
golang.org/x/sync v0.22.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/term v0.45.0 // indirect
|
||||
golang.org/x/text v0.40.0 // indirect
|
||||
golang.org/x/text v0.41.0 // indirect
|
||||
rsc.io/qr v0.2.0 // indirect
|
||||
)
|
||||
|
||||
@@ -16,6 +16,8 @@ github.com/davidbyttow/govips/v2 v2.18.0 h1:pZRshWVYvewP/TZx3yZ7YeC42WyLXg53tHy5
|
||||
github.com/davidbyttow/govips/v2 v2.18.0/go.mod h1:8+nst5zfMoats12PgmmAPh6p5OfjDaXK0BXMFl/vOcM=
|
||||
github.com/elliotchance/orderedmap/v3 v3.1.0 h1:j4DJ5ObEmMBt/lcwIecKcoRxIQUEnw0L804lXYDt/pg=
|
||||
github.com/elliotchance/orderedmap/v3 v3.1.0/go.mod h1:G+Hc2RwaZvJMcS4JpGCOyViCnGeKf0bTYCGTO4uhjSo=
|
||||
github.com/elliotchance/orderedmap/v3 v3.1.1 h1:eV7lfZ5fVL8d36b8Wogqi/eqm7R/kZcftA9Yiyj+63M=
|
||||
github.com/elliotchance/orderedmap/v3 v3.1.1/go.mod h1:G+Hc2RwaZvJMcS4JpGCOyViCnGeKf0bTYCGTO4uhjSo=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
@@ -30,38 +32,61 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
|
||||
github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI=
|
||||
github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
|
||||
github.com/mattn/go-sqlite3 v1.14.48 h1:7XHIgl0a8HwOaiK4E47ozLkST78rR9+OtNGx27D/TFs=
|
||||
github.com/mattn/go-sqlite3 v1.14.48/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
|
||||
github.com/mattn/go-sqlite3 v1.14.49 h1:B8jBHC3xhxZgxztrgruTuLucebnULQnx4W7cF7SAE9w=
|
||||
github.com/mattn/go-sqlite3 v1.14.49/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
|
||||
github.com/mdp/qrterminal/v3 v3.2.1 h1:6+yQjiiOsSuXT5n9/m60E54vdgFsw0zhADHhHLrFet4=
|
||||
github.com/mdp/qrterminal/v3 v3.2.1/go.mod h1:jOTmXvnBsMy5xqLniO0R++Jmjs2sTm9dFSuQ5kpz/SU=
|
||||
github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 h1:WDsQxOJDy0N1VRAjXLpi8sCEZRSGarLWQevDxpTBRrM=
|
||||
github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||
github.com/petermattis/goid v0.0.0-20260816044145-ed329add6b1b h1:sS7HLzwS+dO+gxATgQfeZDEdUZe2pKAB3nGoUwP5zU0=
|
||||
github.com/petermattis/goid v0.0.0-20260816044145-ed329add6b1b/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
|
||||
github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
|
||||
github.com/vektah/gqlparser/v2 v2.5.27 h1:RHPD3JOplpk5mP5JGX8RKZkt2/Vwj/PZv0HxTdwFp0s=
|
||||
github.com/vektah/gqlparser/v2 v2.5.27/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
|
||||
github.com/vektah/gqlparser/v2 v2.5.37 h1:jbb1Ilv+xBklV6653tKb4oVUupPNTLb5LmrnBKVI12Y=
|
||||
github.com/vektah/gqlparser/v2 v2.5.37/go.mod h1:9O4Ox6Ngd3Y12bMD3w6i3CRQXh8W1oC1q0m6olCymDM=
|
||||
go.mau.fi/libsignal v0.2.2 h1:QV+XdzQkm3x3aSG7FcqfGSZuFXz83pRZPBFaPygHbOU=
|
||||
go.mau.fi/libsignal v0.2.2/go.mod h1:CRlIQg2J8uYTfDFvNoO8/KcZjs5cey0vbc6oj/bssY0=
|
||||
go.mau.fi/util v0.9.10 h1:wzvz5iDHyqDXB8vgisD4d3SzucLXNM3iNY+1O1RoHtg=
|
||||
go.mau.fi/util v0.9.10/go.mod h1:YQOxySn+ZE3qSYqNxvyX7Yi3suA8YK17PS6QqBREW7A=
|
||||
go.mau.fi/util v0.10.1-0.20260820140024-eb612d936fde h1:eMHY9dMDkNuDMWhfTbMZHbbsxj7G6mfujjKei1HaFQM=
|
||||
go.mau.fi/util v0.10.1-0.20260820140024-eb612d936fde/go.mod h1:z0ZZNt4hq3FZbUKnunexE/QscCx7VkLvQSvtggc/aE8=
|
||||
go.mau.fi/whatsmeow v0.0.0-20260630180629-b572e5bcb92b h1:ZUk1ErarDNpnbosXR/MeOz2gkqA4S1bh8zjaSRj7N+Y=
|
||||
go.mau.fi/whatsmeow v0.0.0-20260630180629-b572e5bcb92b/go.mod h1:9dmNTYZ/1pHjPw/bz+azBsGjAkcrZbqzMrKcvG5bJ8U=
|
||||
go.mau.fi/whatsmeow v0.0.0-20260828224850-0fadda796019 h1:vUX4rgZhobwtMYH6tkYOSyfd2ufTysNEDWVpTSVPjmc=
|
||||
go.mau.fi/whatsmeow v0.0.0-20260828224850-0fadda796019/go.mod h1:aMd13H2xFFGH9cskcvxo4Aae+TmyFN38yw+HvsrpwVg=
|
||||
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
|
||||
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
|
||||
golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y=
|
||||
golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I=
|
||||
golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M=
|
||||
golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY=
|
||||
golang.org/x/exp v0.0.0-20260813180055-c1d0aacb2297 h1:YXnL44eJ77R+ji4/ooy8UsXIhz+lbi2Qgdlc8iRN0gY=
|
||||
golang.org/x/exp v0.0.0-20260813180055-c1d0aacb2297/go.mod h1:Mkmymgv+uMpSQ/XxJ/7GpdrdYoqm3u72jEbpCLiJmNk=
|
||||
golang.org/x/image v0.44.0 h1:+tDekMZED9+LrtB3G5xzRggpVh9CARjZqROla3R3R+I=
|
||||
golang.org/x/image v0.44.0/go.mod h1:V8K3KE9KKKE+pLpQDOeN18w9oacNSvy1tDOirTu4xtY=
|
||||
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
|
||||
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
|
||||
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
|
||||
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
|
||||
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
|
||||
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -71,8 +96,12 @@ golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
|
||||
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
|
||||
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
||||
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
|
||||
|
||||
Reference in New Issue
Block a user