File size: 9,388 Bytes
3d599a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
const { ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
const { Octokit } = require('@octokit/rest');
const { createEmbed } = require('../utils/embeds');
const { Colors } = require('../config');

/**
 * Scans a channel for old drop embeds with broken GitHub Link buttons
 * and replaces them with new interactive download buttons (dl_<assetId>).
 *
 * Usage: fix downloads <channel_id>
 */
module.exports = {
    async execute(client, message, args) {
        const channelId = args[0]?.replace(/[<#>]/g, '');
        if (!channelId) {
            return message.reply({ content: '❌ Usage: `fix downloads <channel_id>`' });
        }

        const guild = client.guilds.cache.first();
        const channel = await guild.channels.fetch(channelId).catch(() => null);
        if (!channel) {
            return message.reply({ content: '❌ Channel not found.' });
        }

        const statusMsg = await message.reply({
            embeds: [createEmbed({
                title: 'πŸ”§ Fixing Downloads',
                description: `Scanning <#${channelId}> for broken GitHub links...`,
                color: Colors.INFO
            })]
        });

        try {
            const octokit = new Octokit({ auth: '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' });
            const [owner, repo] = 'APRK01/WSB-Storage'.split('/');

            // 1. Build a lookup map of all release assets: { "tag/filename" -> assetId }
            const assetMap = new Map();
            let page = 1;
            let hasMore = true;

            while (hasMore) {
                const { data: releases } = await octokit.rest.repos.listReleases({
                    owner,
                    repo,
                    per_page: 100,
                    page
                });

                if (releases.length === 0) {
                    hasMore = false;
                    break;
                }

                for (const release of releases) {
                    for (const asset of release.assets) {
                        // Map by tag_name/filename for lookup
                        assetMap.set(`${release.tag_name}/${asset.name}`, asset.id);
                        // Also map by just the browser_download_url for direct matching
                        assetMap.set(asset.browser_download_url, asset.id);
                    }
                }

                page++;
            }

            await statusMsg.edit({
                embeds: [createEmbed({
                    title: 'πŸ”§ Fixing Downloads',
                    description: `Found **${assetMap.size}** GitHub assets. Now scanning messages in <#${channelId}>...`,
                    color: Colors.INFO
                })]
            });

            // 2. Fetch all messages in the channel and find ones with GitHub Link buttons
            let fixedCount = 0;
            let skippedCount = 0;
            let lastId = null;
            let scannedCount = 0;

            while (true) {
                const options = { limit: 100 };
                if (lastId) options.before = lastId;

                const messages = await channel.messages.fetch(options);
                if (messages.size === 0) break;

                for (const [, msg] of messages) {
                    scannedCount++;

                    // Only process bot messages with components
                    if (msg.author.id !== client.user.id) continue;
                    if (!msg.components || msg.components.length === 0) continue;

                    // Check if any component row has a Link button pointing to WSB-Storage
                    let needsFix = false;
                    const newRows = [];

                    for (const row of msg.components) {
                        const newComponents = [];

                        for (const component of row.components) {
                            // Check if it's a Link button pointing to our GitHub repo
                            if (component.type === 2 && component.style === ButtonStyle.Link &&
                                component.url && component.url.includes('APRK01/WSB-Storage')) {

                                // Try to find the asset ID from the URL
                                const assetId = assetMap.get(component.url);

                                if (assetId) {
                                    // Replace with interactive button
                                    newComponents.push(
                                        new ButtonBuilder()
                                            .setCustomId(`dl_${assetId}`)
                                            .setLabel(component.label || 'πŸ“₯ Download Drop')
                                            .setStyle(ButtonStyle.Success)
                                    );
                                    needsFix = true;
                                } else {
                                    // Can't find asset ID β€” try parsing from URL
                                    // URL format: https://github.com/APRK01/WSB-Storage/releases/download/TAG/FILENAME
                                    const urlMatch = component.url.match(/\/releases\/download\/([^/]+)\/(.+)$/);
                                    if (urlMatch) {
                                        const lookupKey = `${decodeURIComponent(urlMatch[1])}/${decodeURIComponent(urlMatch[2])}`;
                                        const foundId = assetMap.get(lookupKey);

                                        if (foundId) {
                                            newComponents.push(
                                                new ButtonBuilder()
                                                    .setCustomId(`dl_${foundId}`)
                                                    .setLabel(component.label || 'πŸ“₯ Download Drop')
                                                    .setStyle(ButtonStyle.Success)
                                            );
                                            needsFix = true;
                                        } else {
                                            // Keep original if we can't resolve
                                            newComponents.push(ButtonBuilder.from(component));
                                            skippedCount++;
                                        }
                                    } else {
                                        newComponents.push(ButtonBuilder.from(component));
                                        skippedCount++;
                                    }
                                }
                            } else if (component.type === 2 && component.style !== ButtonStyle.Link) {
                                // Already an interactive button (already fixed or dl_ button)
                                newComponents.push(ButtonBuilder.from(component));
                            } else {
                                newComponents.push(ButtonBuilder.from(component));
                            }
                        }

                        newRows.push(new ActionRowBuilder().addComponents(newComponents));
                    }

                    if (needsFix) {
                        try {
                            await msg.edit({ components: newRows });
                            fixedCount++;
                        } catch (editErr) {
                            console.error(`[Fix Downloads] Failed to edit message ${msg.id}:`, editErr.message);
                            skippedCount++;
                        }
                    }
                }

                lastId = messages.last().id;

                // Update status periodically
                if (scannedCount % 200 === 0) {
                    await statusMsg.edit({
                        embeds: [createEmbed({
                            title: 'πŸ”§ Fixing Downloads',
                            description: `Scanned **${scannedCount}** messages... Fixed **${fixedCount}** so far.`,
                            color: Colors.INFO
                        })]
                    }).catch(() => { });
                }
            }

            await statusMsg.edit({
                embeds: [createEmbed({
                    title: 'βœ… Downloads Fixed!',
                    description: [
                        `**Channel:** <#${channelId}>`,
                        `**Messages scanned:** ${scannedCount}`,
                        `**Buttons fixed:** ${fixedCount}`,
                        skippedCount > 0 ? `**Skipped (no match):** ${skippedCount}` : '',
                        '',
                        fixedCount > 0
                            ? '> All download buttons now use the private ephemeral system. πŸ”’'
                            : '> No broken buttons found β€” everything looks good!',
                    ].filter(Boolean).join('\n'),
                    color: Colors.SUCCESS
                })]
            });

        } catch (err) {
            console.error('[Fix Downloads Error]', err);
            await statusMsg.edit({
                embeds: [createEmbed({
                    title: '❌ Fix Failed',
                    description: `Error: ${err.message}`,
                    color: Colors.ACCENT
                })]
            });
        }
    }
};