У меня есть обфускатор JS кода, написанный на питоне, однако при запуске в IDLE Shell у меня появляется ошибка в области функции комментирования. После кода напишу ошибку.

Код обфускатора:

import random
import string
import re



# Функция удаления комментариев
def remove_comments(js_code):
    # Регулярное выражение для удаления многострочных комментариев
    multiline_comment_pattern = r'/*[\s\S]?*/'
    # Регулярное выражение для удаления однострочных комментариев
    singleline_comment_pattern = r'//.(?=\n|\r|$)'
    
    # Удаление многострочных комментариев
    js_code = re.sub(multiline_comment_pattern, '', js_code, flags=re.DOTALL)
    # Удаление однострочных комментариев
    js_code = re.sub(singleline_comment_pattern, '', js_code, flags=re.MULTILINE)
    
    return js_code.strip();

# Функция минимизации пробелов
def minimize_spaces(js_code):
    lines = js_code.split('\n')
    return ''.join(line.strip() for line in lines)


# Функция для генерации случайного имени переменной
def generate_random_name(length=10):
    letters = string.ascii_letters
    return ''.join(random.choice(letters) for i in range(length))

# Функция обфускации переменных
def obfuscate_variables(js_code):
    var_map = {}
    
    # Найти все объявления переменных (после ключевого слова var)
    for var_name in re.findall(r'\bvar\s+(\w+)', js_code):
        obfuscated_name = generate_random_name()
        var_map[var_name] = obfuscated_name

    # Заменить все экземпляры оригинальных имен переменных на обфусцированные имена
    for original_name, obfuscated_name in var_map.items():
        js_code = re.sub(r'\b' + original_name + r'\b', obfuscated_name, js_code)

    return js_code

# Добавление “мертвого” кода
def add_dead_code(js_code):
    dead_code = f"function {generate_random_name()}(){{console.log(’{generate_random_name()}');}}\n"
    return dead_code + js_code

def obfuscate_js(js_code):
    #js_code = remove_comments(js_code)
    js_code = obfuscate_variables(js_code)
    js_code = minimize_spaces(js_code)
    #js_code = add_dead_code(js_code)
    return js_code

# Исходный код javascript
original_js = """
//var cvs = document.getElementById("canvas");
var cvs = document.querySelector("canvas"); 
var ctx = cvs.getContext("2d"); //указывает вид игры - 2D;

// добавляем картинки и звуки в канвас

var background = new Image(); background.src="images/backgroundd.png";
var frontground = new Image(); frontground.src="images/fg.jpg";
var player = new Image(); player.src="images/playerr.png";
var upper_stalactite = new Image(); upper_stalactite.src = "images/upper_stalactitee.png";
var bottom_stalactite = new Image(); bottom_stalactite.src = "images/bottom_stalactitee.png";
var star = new Image(); star.src = "images/starr.png";
var flying = new Audio(); flying.src = "sounds/flight.mp3";
var game_over = new Audio(); game_over.src = "sounds/end.wav";
var point1 = new Audio(); point1.src = "sounds/1point.mp3";
var point2 = new Audio(); point2.src = "sounds/2points.mp3";
var point3 = new Audio(); point3.src = "sounds/3points.mp3"; 
var point4 = new Audio(); point4.src = "sounds/4points.mp3"; 

var safe_zone=180;
var xPos=45;
var yPos=225;
var score=0;

function fly() {
    yPos -= 50;
    flying.play();
}

document.addEventListener('keydown', function(event) {
    if (event.code == 'ArrowUp'|| event.code == 'Space' || event.code=='KeyW') {
        fly();
    }
});

//созданием массив для препятствий и первое препятствие 

var obstacle = [];
obstacle[0]= {
    x: cvs.width,
    y: -200
}

function draw () {
    ctx.drawImage(background, 0, 0);
    for (var i=0; i<obstacle.length; i++) {
    ctx.drawImage(upper_stalactite, obstacle[i].x, obstacle[i].y);
    ctx.drawImage(bottom_stalactite, obstacle[i].x, obstacle[i].y+upper_stalactite.height + safe_zone);
    obstacle[i].x-=2;
    if (obstacle[i].x==350) {
        obstacle.push({x:cvs.width, y:Math.floor(Math.random()*upper_stalactite.height)-upper_stalactite.height-50})
    }

    if (xPos+player.width >= obstacle[i].x && xPos <= obstacle[i].x+ upper_stalactite.width && (yPos <= obstacle[i].y+upper_stalactite.height || yPos + player.height >= obstacle[i].y+upper_stalactite.height + safe_zone) || yPos + player.height >= cvs.height || yPos  <= 0) {
        game_over.play();
        var x=0;
        var ln=0;
        var num=score;
        if (num==0) {ln++;}
        while(num>=1){
            num/=10;
            ln++;
        }
        function draw_timer () { //создал таймер через многократное использование requestAnimationFrame(draw_timer);
            ctx.drawImage(background, 0, 0);
            ctx.fillStyle = "#ff0000";
            ctx.font = "28px Verdana";
            ctx.fillText("[" + "Game Over" + "]", cvs.width/2-79, cvs.height/2-60);
            ctx.fillStyle = "#DB5720";
            ctx.font = "24px Verdana";
            ctx.drawImage(star, cvs.width/2-25-8*ln, cvs.height/2-25);
            ctx.fillText("(" + score + ")", cvs.width/2+25-8*ln, cvs.height/2+7);
            x++; if (x>=100) { //через 100 проходов можно перезапускать игру
            ctx.fillStyle = "#ff0000";
            ctx.font = "16px Verdana";
            ctx.fillText("Press any key to restart", cvs.width/2-79, 475);
            document.addEventListener ("keydown", restart);
            function restart (){
                location.reload();
            }return 0;}
            requestAnimationFrame(draw_timer);
        }
        draw_timer();
        return 0;
    }

    if (obstacle[i].x==0) {
    if (obstacle[i].y<=-459) {
       score+=4;
       point4.play();
    } else if (obstacle[i].y<=-451||obstacle[i].y>=-53)  {
        score+=3;
        point3.play();
    } else if (obstacle[i].y<=-436||obstacle[i].y>=-62) {
        score+=2;
        point2.play();
    } else {
        score++;
        point1.play();
    }}

    if (obstacle[i].x%200==0) {
    console.log (obstacle[i].y); }}
    ctx.drawImage(player, xPos, yPos);
    yPos+=4;
    ctx.fillStyle = "#DB5720";;
    ctx.font = "24px Verdana";
    ctx.drawImage(star, 590, 452);
    ctx.fillText("(" + score + ")", 640, 485);

    requestAnimationFrame(draw);
    if (obstacle.length > 2){  // удаляем из массива уже преодоленные препятствия
        obstacle.shift();
    }
}

bottom_stalactite.onload = draw;
"""



# Выполнение обфускации и печать результата
obfuscated_js = obfuscate_js(original_js)
print(obfuscated_js)

Ошибка:

Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.

= RESTART: E:\Programms\Python\Python312\Obfuscator3.py
Traceback (most recent call last):
  File "E:\Programms\Python\Python312\Obfuscator3.py", line 183, in <module>
    obfuscated_js = obfuscate_js(original_js)
  File "E:\Programms\Python\Python312\Obfuscator3.py", line 53, in obfuscate_js
    js_code = remove_comments(js_code)
  File "E:\Programms\Python\Python312\Obfuscator3.py", line 15, in remove_comments
    js_code = re.sub(multiline_comment_pattern, '', js_code, flags=re.DOTALL)
  File "E:\Programms\Python\Python312\Lib\re\__init__.py", line 186, in sub
    return _compile(pattern, flags).sub(repl, string, count)
  File "E:\Programms\Python\Python312\Lib\re\__init__.py", line 307, in _compile
    p = _compiler.compile(pattern, flags)
  File "E:\Programms\Python\Python312\Lib\re\_compiler.py", line 745, in compile
    p = _parser.parse(p, flags)
  File "E:\Programms\Python\Python312\Lib\re\_parser.py", line 979, in parse
    p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
  File "E:\Programms\Python\Python312\Lib\re\_parser.py", line 460, in _parse_sub
    itemsappend(_parse(source, state, verbose, nested + 1,
  File "E:\Programms\Python\Python312\Lib\re\_parser.py", line 690, in _parse
    raise source.error("multiple repeat",
re.error: multiple repeat at position 9

Обрати внимание на 
  File "E:\Programms\Python\Python312\Obfuscator3.py", line 15, in remove_comments
    js_code = re.sub(multiline_comment_pattern, '', js_code, flags=re.DOTALL)