Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## PowerDeleteSuite — Copilot instructions

Short, focused notes to help an AI agent be immediately productive editing this repo.

1) Big picture (what this code does)
- Single-page client-side bookmarklet / userscript that runs on old.reddit.com user overview.
- Main app is the global `pd` object in `powerdeletesuite.js`. There is no backend — all actions use Reddit JSON endpoints.
- UI markup is pulled at runtime from the subreddit wiki (`/r/PowerDeleteSuite/wiki/centralform.json`) and CSS is fetched from a raw JSON stylesheet URL.

2) Key files to read first
- `powerdeletesuite.js` — the entire app (init, settings, endpoints, UI binders, filters, deletion/edit flows).
- `bookmarklet.js` and `powerdeletesuite.user.js` — wrappers / distribution formats (bookmarklet and userscript headers).
- `README.md` — install & usage instructions and the bookmarklet snippet users copy.
- `stylesheet.json` — repository copy of stylesheet data referenced by the app.

3) Architecture & runtime patterns (concrete)
- Global object `pd` holds version (pd.version), bookmarklet version (pd.bookmarkver), config, endpoints, and runtime state.
- Uses jQuery (`$`) and `$.ajax(...).then(success, failure)` style rather than fetch/async/await.
- Reddit integration: calls to endpoints like `/user/<user>/comments/.json`, `/user/<user>/submitted/.json`, and `/search.json`.
- Settings and simple persistence: `localStorage` keys (e.g., `pd_ver`) and DOM parsing to extract Reddit modhash (`#config`).

4) Developer workflows / testing (how to verify changes)
- No build step. Edit `powerdeletesuite.js` directly.
- Typical dev checklist when changing behavior:
- bump `pd.version` (and optionally `pd.bookmarkver` if bookmarklet string changes)
- update the README bookmarklet snippet if you changed the hosted/URL behavior
- smoke test on `https://old.reddit.com/u/me/overview` and exercise: load comments, run filter, attempt an edit and a delete flow

5) Conventions and fragile/important details (do not change lightly)
- Identity check: `pd.checks.location()` compares DOM username text to header link. If you change selectors, tests will break.
- `pd.setup.applyCentral()` and `pd.setup.applyStyles()` fetch remote wiki and stylesheet JSON — UI is wiki-driven. Be aware of CORS and network failures.
- `pd.editStrings` is the in-file list of candidate edit texts; changing it affects edit behavior.
- Modhash extraction uses `#config` innerHTML parsing — this is brittle; prefer keeping the same extraction if possible.

6) Helpful code examples (copy/paste pointers)
- Where endpoints are defined: in `powerdeletesuite.js` -> `pd.setup.basicSettings()` (look for `pd.endpoints`).
- Where UI is filled from the wiki: `pd.setup.applyCentral()`.
- Where CSS is injected: `pd.setup.applyStyles()` — it expects JSON with `data.stylesheet`.

7) Common failure modes to watch for
- Empty or changed Reddit DOM selectors (username, #config) — will make the script refuse to run.
- Remote wiki or stylesheet fetch failures — script alerts on failure; add robust fallbacks if needed.
- Running on the wrong reddit domain (new reddit) — script explicitly checks for `old.reddit.com` style overview path.

8) Pull request checklist for code changes
- Update `pd.version` for user-facing changes; bump `pd.bookmarkver` only when bookmarklet install string in `README.md` must change.
- Mention in PR description how you tested on `old.reddit.com/u/me/overview` and what flows you exercised (comments, submissions, search, edit+delete order).

If anything above is unclear or you'd like me to add quick local launch scripts (or a tiny test runner that simulates Reddit JSON responses), tell me which part to expand and I will update this file.
105 changes: 87 additions & 18 deletions powerdeletesuite.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var pd = {
version: "1.4.11",
version: "1.4.12",
bookmarkver: "1.4",
editStrings: [
"I love ice cream.",
Expand Down Expand Up @@ -359,6 +359,7 @@ var pd = {
.first()
.text("Power Delete Suite v" + pd.version);
pd.setup.applySubList();
pd.setup.addSkipInteractionsUI();
pd.setup.bindUI();
pd.helpers.restoreSettings();
},
Expand Down Expand Up @@ -407,6 +408,26 @@ var pd = {
).prepend("<b class='m'>[M]</b>");
});
},
addSkipInteractionsUI: function () {
// Add the retry and skip interactions options after the remember settings checkbox
var rememberSection = $("#pd__remember").closest("div");
if (rememberSection.length > 0) {
rememberSection.after(
'<div>' +
'<input type="checkbox" name="pd__enable-retries" id="pd__enable-retries" checked />' +
'<label for="pd__enable-retries"> Enable automatic retries on failure</label>' +
'</div>' +
'<div style="margin-left: 20px;">' +
'<label for="pd__retry-count">Retry attempts: </label>' +
'<input type="number" name="pd__retry-count" id="pd__retry-count" value="3" min="1" max="10" style="width: 60px;" />' +
'</div>' +
'<div>' +
'<input type="checkbox" name="pd__skip-interactions" id="pd__skip-interactions" />' +
'<label for="pd__skip-interactions"> Skip all user interaction prompts (auto-continue after retries or immediately if retries disabled)</label>' +
'</div>'
);
}
},
createProcessStream: function () {
window.pd_processing = true;
pd.exportItems = [];
Expand Down Expand Up @@ -445,6 +466,9 @@ var pd = {
isRemovingComments: $("#pd__comments").is(":checked"),
isEditing: $("#pd__comments-edit").is(":checked"),
editText: $("#pd__comments-edit-text").val(),
skipUserInteractions: $("#pd__skip-interactions").is(":checked"),
enableRetries: $("#pd__enable-retries").is(":checked"),
retryCount: parseInt($("#pd__retry-count").val()) || 3,
Comment thread
zaxlofful marked this conversation as resolved.
Outdated
},
paths: {
sections:
Expand Down Expand Up @@ -732,6 +756,7 @@ var pd = {
} else {
pd.task.info.errors++;
if (
pd.task.config.skipUserInteractions ||
confirm(
"Reddit seems to be under heavy load. Would you like to continue processing?"
)
Expand All @@ -746,6 +771,7 @@ var pd = {
function () {
pd.task.info.errors++;
if (
pd.task.config.skipUserInteractions ||
confirm(
"Error getting " +
pd.task.paths.sections[0] +
Expand Down Expand Up @@ -872,6 +898,11 @@ var pd = {
},
},
delete: function (item) {
// Initialize retry counter if not present
if (!item.pdDeleteRetries) {
item.pdDeleteRetries = 0;
}

setTimeout(() => {
if (pd.performActions) {
$.ajax({
Expand All @@ -890,17 +921,34 @@ var pd = {
},
function () {
pd.task.info.errors++;
if (
confirm(
"Error deleting " +
(item.kind == "t3" ? "post" : "comment") +
", would you like to retry?"
)
) {
pd.actions.children.handleSingle();
} else {
item.pdDeleteRetries++;

// Check if retries are enabled and we haven't exceeded the limit
if (pd.task.config.enableRetries && item.pdDeleteRetries < pd.task.config.retryCount) {
pd.actions.delete(item);
return;
}
Comment thread
zaxlofful marked this conversation as resolved.

// After max retries (or if retries disabled), check skip interactions setting
if (pd.task.config.skipUserInteractions) {
// Skip user interaction, continue with next item
pd.actions.children.finishItem();
pd.actions.children.handleGroup();
} else {
// Show confirmation dialog
var message = "Error deleting " + (item.kind == "t3" ? "post" : "comment");
if (pd.task.config.enableRetries) {
message += " after " + pd.task.config.retryCount + " attempts";
}
message += ", would you like to continue with the next item?";
Comment thread
zaxlofful marked this conversation as resolved.

if (confirm(message)) {
pd.actions.children.finishItem();
pd.actions.children.handleGroup();
} else {
// User chose to stop processing
pd.ui.done();
}
}
}
);
Expand All @@ -912,6 +960,11 @@ var pd = {
}, 5000);
},
edit: function (item) {
// Initialize retry counter if not present
if (!item.pdEditRetries) {
item.pdEditRetries = 0;
}

setTimeout(() => {
if (pd.performActions) {
var editString = pd.task.config.editText ||
Expand All @@ -934,16 +987,32 @@ var pd = {
},
function () {
pd.task.info.errors++;
if (
!confirm(
"Error editing " +
(item.kind == "t3" ? "post" : "comment") +
", would you like to retry?"
)
) {
item.pdEditRetries++;

// Check if retries are enabled and we haven't exceeded the limit
if (pd.task.config.enableRetries && item.pdEditRetries < pd.task.config.retryCount) {
pd.actions.edit(item);
return;
}

// After max retries (or if retries disabled), check skip interactions setting
if (pd.task.config.skipUserInteractions) {
// Skip user interaction, mark as edited and continue
item.pdEdited = true;
pd.actions.children.handleSingle();
} else {
// Show confirmation dialog
var message = "Error editing " + (item.kind == "t3" ? "post" : "comment");
if (pd.task.config.enableRetries) {
message += " after " + pd.task.config.retryCount + " attempts";
}
message += ", would you like to continue with the next item?";

if (!confirm(message)) {
item.pdEdited = true;
}
pd.actions.children.handleSingle();
}
pd.actions.children.handleSingle();
}
);
} else {
Expand Down