MCPcopy Create free account
hub / github.com/Dispatcharr/Dispatcharr / bulk_regex_rename

Method bulk_regex_rename

apps/channels/api_views.py:1417–1495  ·  view source on GitHub ↗

Efficiently apply a regex find/replace to the `name` field of multiple channels.

(self, request)

Source from the content-addressed store, hash-verified

1415 )
1416 @action(detail=False, methods=["post"], url_path="edit/bulk-regex")
1417 def bulk_regex_rename(self, request):
1418 """
1419 Efficiently apply a regex find/replace to the `name` field of multiple channels.
1420 """
1421 import regex as re
1422
1423 channel_ids = request.data.get("channel_ids", [])
1424 pattern = request.data.get("find", "")
1425 replace = request.data.get("replace", "")
1426 flags_str = request.data.get("flags", "") or ""
1427
1428 if not isinstance(channel_ids, list) or len(channel_ids) == 0:
1429 return Response({"error": "channel_ids must be a non-empty list"}, status=status.HTTP_400_BAD_REQUEST)
1430 if not isinstance(pattern, str) or pattern.strip() == "":
1431 return Response({"error": "find (regex pattern) is required"}, status=status.HTTP_400_BAD_REQUEST)
1432 if not isinstance(replace, str):
1433 return Response({"error": "replace must be a string"}, status=status.HTTP_400_BAD_REQUEST)
1434
1435 # Convert JS-style named groups to Python (?<name>...) -> (?P<name>...)
1436 try:
1437 converted_pattern = re.sub(r"\(\?<([^>]+)>", r"(?P<\1>", pattern)
1438 except Exception as e:
1439 return Response({"error": f"Failed to normalize pattern: {e}"}, status=status.HTTP_400_BAD_REQUEST)
1440
1441 # Compile flags
1442 re_flags = 0
1443 if "i" in flags_str:
1444 re_flags |= re.IGNORECASE
1445 # Note: 'g' (global) is the default behavior of re.sub; no action needed.
1446
1447 # Translate common JS replacement tokens to Python
1448 def translate_js_replacement(rep: str) -> str:
1449 # $$ -> $
1450 rep = rep.replace("$$", "$")
1451 # $& -> \g<0>
1452 rep = rep.replace("$&", r"\g<0>")
1453 # $<name> -> \g<name>
1454 rep = re.sub(r"\$<([A-Za-z_][A-Za-z0-9_]*)>", r"\\g<\1>", rep)
1455 # $1 -> \g<1>, $2 -> \g<2>, etc.
1456 rep = re.sub(r"\$(\d+)", r"\\g<\1>", rep)
1457 return rep
1458
1459 try:
1460 replacement_py = translate_js_replacement(replace)
1461 compiled = re.compile(converted_pattern, flags=re_flags)
1462 except Exception as e:
1463 return Response({"error": f"Invalid regex pattern: {e}"}, status=status.HTTP_400_BAD_REQUEST)
1464
1465 # Fetch channels in one query
1466 channels = list(Channel.objects.filter(id__in=channel_ids))
1467 if not channels:
1468 return Response({"error": "No matching channels found for provided IDs"}, status=status.HTTP_404_NOT_FOUND)
1469
1470 changed = []
1471 for ch in channels:
1472 current = ch.name or ""
1473 try:
1474 new_name = compiled.sub(replacement_py, current)

Callers

nothing calls this directly

Calls 2

getMethod · 0.45
filterMethod · 0.45

Tested by

no test coverage detected