File size: 51,498 Bytes
f3e8aa7
 
 
65eb2e7
 
f3e8aa7
 
 
84d6f3d
cf419e6
12ab85e
f3e8aa7
 
 
 
 
 
 
 
a704170
aa1cbf0
a704170
 
aa1cbf0
 
 
 
 
 
 
 
 
 
 
 
 
 
a704170
 
aa1cbf0
a704170
 
84d6f3d
 
 
 
 
 
 
f3e8aa7
84d6f3d
f3e8aa7
a704170
84d6f3d
 
6406b22
 
84d6f3d
 
 
 
 
aa1cbf0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bcb2dcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6406b22
 
bcb2dcb
84d6f3d
 
aa1cbf0
84d6f3d
cf419e6
aa1cbf0
 
 
 
 
cf419e6
aa1cbf0
cf419e6
aa1cbf0
 
 
cf419e6
aa1cbf0
 
 
 
cf419e6
 
aa1cbf0
cf419e6
aa1cbf0
6406b22
84d6f3d
cf419e6
6406b22
84d6f3d
bcb2dcb
 
 
 
 
6406b22
 
 
 
 
 
 
 
 
84d6f3d
f3e8aa7
bcb2dcb
 
 
 
 
 
 
 
 
6406b22
bcb2dcb
 
 
 
84d6f3d
f3e8aa7
bcb2dcb
 
 
 
 
 
 
 
 
 
6406b22
 
 
 
cf419e6
6406b22
bcb2dcb
cf419e6
6406b22
 
 
 
 
 
cf419e6
6406b22
cf419e6
6406b22
bcb2dcb
cf419e6
6406b22
bcb2dcb
 
 
 
 
6406b22
aa1cbf0
6406b22
 
 
 
cf419e6
6406b22
cf419e6
6406b22
bcb2dcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aa1cbf0
bcb2dcb
 
 
cf419e6
aa1cbf0
cf419e6
aa1cbf0
6406b22
 
 
 
 
c913b5e
 
 
6406b22
f3e8aa7
6406b22
 
bcb2dcb
 
 
 
 
 
 
 
 
 
 
 
cf419e6
bcb2dcb
6406b22
 
 
 
 
cf419e6
6406b22
bcb2dcb
cf419e6
c913b5e
aa1cbf0
6406b22
aa1cbf0
 
 
cf419e6
aa1cbf0
cf419e6
aa1cbf0
bcb2dcb
 
 
 
aa1cbf0
 
 
 
 
 
 
 
 
 
 
6406b22
cf419e6
aa1cbf0
 
 
cf419e6
aa1cbf0
6406b22
aa1cbf0
 
 
cf419e6
aa1cbf0
 
 
 
 
cf419e6
aa1cbf0
12ab85e
 
 
 
 
 
 
 
 
 
 
cf419e6
12ab85e
 
 
cf419e6
12ab85e
 
 
 
 
cf419e6
12ab85e
 
 
 
 
cf419e6
12ab85e
bcb2dcb
cf419e6
bcb2dcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf419e6
12ab85e
 
 
 
 
 
cf419e6
12ab85e
cf419e6
12ab85e
 
 
 
 
 
 
 
 
 
 
 
 
cf419e6
12ab85e
 
 
cf419e6
12ab85e
 
 
 
 
cf419e6
12ab85e
 
 
 
 
cf419e6
12ab85e
bcb2dcb
cf419e6
bcb2dcb
 
 
 
 
 
 
12ab85e
bcb2dcb
cf419e6
bcb2dcb
 
12ab85e
 
 
 
 
 
cf419e6
12ab85e
cf419e6
12ab85e
bcb2dcb
 
 
 
12ab85e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf419e6
12ab85e
cf419e6
12ab85e
 
cf419e6
12ab85e
cf419e6
12ab85e
 
 
bcb2dcb
12ab85e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf419e6
12ab85e
 
 
bcb2dcb
 
 
12ab85e
 
 
 
 
 
bcb2dcb
 
 
 
 
 
 
cf419e6
bcb2dcb
12ab85e
 
 
 
 
 
 
cf419e6
12ab85e
cf419e6
12ab85e
cf419e6
12ab85e
 
 
 
 
 
cf419e6
12ab85e
cf419e6
12ab85e
 
 
bcb2dcb
12ab85e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf419e6
12ab85e
 
 
bcb2dcb
 
 
12ab85e
 
 
 
 
 
bcb2dcb
 
 
 
 
 
 
cf419e6
bcb2dcb
12ab85e
 
 
 
 
 
 
cf419e6
12ab85e
cf419e6
12ab85e
cf419e6
12ab85e
 
 
 
 
 
cf419e6
12ab85e
cf419e6
12ab85e
bcb2dcb
 
 
 
cf419e6
12ab85e
bcb2dcb
 
 
12ab85e
 
 
 
bcb2dcb
12ab85e
cf419e6
bcb2dcb
 
 
f1e56c7
bcb2dcb
 
 
cf419e6
bcb2dcb
 
cf419e6
 
 
bcb2dcb
 
 
cf419e6
f1e56c7
bcb2dcb
 
 
 
 
 
 
 
 
 
cf419e6
bcb2dcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf419e6
 
 
 
bcb2dcb
 
 
cf419e6
 
f1e56c7
cf419e6
f1e56c7
bcb2dcb
cf419e6
 
bcb2dcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12ab85e
bcb2dcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf419e6
bcb2dcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf419e6
bcb2dcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1e56c7
bcb2dcb
 
 
 
 
 
12ab85e
bcb2dcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf419e6
bcb2dcb
 
 
cf419e6
bcb2dcb
 
 
 
 
 
cf419e6
bcb2dcb
 
 
 
 
cf419e6
bcb2dcb
 
 
 
f1e56c7
 
bcb2dcb
cf419e6
 
 
 
 
 
 
 
bcb2dcb
 
12ab85e
cf419e6
12ab85e
cf419e6
12ab85e
 
 
 
 
 
cf419e6
12ab85e
cf419e6
84d6f3d
6406b22
 
cf419e6
f3e8aa7
 
cf419e6
aa1cbf0
 
cf419e6
12ab85e
 
 
 
cf419e6
12ab85e
 
84d6f3d
f3e8aa7
6406b22
f3e8aa7
cf419e6
aa1cbf0
55bb25a
cf419e6
f3e8aa7
cf419e6
f3e8aa7
 
bcb2dcb
6406b22
 
 
 
 
 
f3e8aa7
 
 
 
 
bcb2dcb
f3e8aa7
 
 
 
cf419e6
f3e8aa7
 
cf419e6
f3e8aa7
cf419e6
f3e8aa7
 
 
 
6406b22
65eb2e7
aa1cbf0
 
 
a704170
aa1cbf0
 
 
 
 
a704170
84d6f3d
 
f3e8aa7
6406b22
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
import gradio as gr
import time
import os
import subprocess
import sys
from PIL import Image
import io
import logging
import traceback
import random
from pathlib import Path

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# Create screenshots directory if it doesn't exist
os.makedirs('screenshots', exist_ok=True)

def download_playwright_browsers():
    """Make sure Playwright and its browsers are installed properly"""
    try:
        logger.info("Installing Playwright browsers...")
        # First ensure the package is installed
        subprocess.run(
            [sys.executable, "-m", "pip", "install", "playwright==1.39.0"], 
            check=True
        )
        
        # Then install browsers with output printed directly to console
        logger.info("Running browser installation (this may take a while)...")
        process = subprocess.run(
            [sys.executable, "-m", "playwright", "install", "chromium"],
            check=True
        )
        
        logger.info("Playwright installation completed successfully")
        return True
    except Exception as e:
        logger.error(f"Error installing Playwright browsers: {e}")
        return False

def save_placeholder_image(name):
    """Create a placeholder image when no screenshot is available"""
    timestamp = int(time.time())
    filename = f"screenshots/{name}_{timestamp}.png"
    
    # Create a simple colored image
    img = Image.new('RGB', (400, 300), color=(73, 109, 137))
    
    # Add some text if possible
    try:
        from PIL import ImageDraw
        draw = ImageDraw.Draw(img)
        draw.text((10, 150), f"Instagram Auto-Liker - {name}", fill=(255, 255, 255))
    except Exception as e:
        logger.warning(f"Couldn't add text to image: {str(e)}")
    
    img.save(filename)
    logger.info(f"Saved placeholder image: {filename}")
    return filename

def verify_playwright_installation():
    """Verify that Playwright is properly installed by checking for browser binary"""
    from pathlib import Path
    import os
    
    # Check common installation paths
    potential_paths = [
        Path.home() / ".cache" / "ms-playwright" / "chromium-1084" / "chrome-linux" / "chrome",
        Path("/home/user/.cache/ms-playwright/chromium-1084/chrome-linux/chrome")  
    ]
    
    for path in potential_paths:
        if path.exists():
            logger.info(f"Found Playwright browser at: {path}")
            return True
    
    logger.warning("Playwright browser not found in expected locations")
    return False

def human_delay(min_seconds=1, max_seconds=5):
    """Wait for a random amount of time to simulate human behavior"""
    delay = min_seconds + random.random() * (max_seconds - min_seconds)
    time.sleep(delay)
    return delay

def human_scroll(page, min_pixels=100, max_pixels=800):
    """Scroll a random amount in a human-like manner"""
    # Decide scroll direction (occasionally scroll up to look more human)
    direction = 1 if random.random() < 0.9 else -1
    
    # Decide scroll amount
    scroll_amount = direction * random.randint(min_pixels, max_pixels)
    
    # Sometimes do a smooth scroll, sometimes do a quick scroll
    if random.random() < 0.7:
        # Smooth scroll
        page.evaluate(f"""() => {{
            window.scrollBy({{
                top: {scroll_amount},
                left: 0,
                behavior: 'smooth'
            }});
        }}""")
    else:
        # Quick scroll
        page.evaluate(f"window.scrollBy(0, {scroll_amount});")
    
    # Sometimes perform multiple small scrolls instead of one big one
    if random.random() < 0.3 and direction > 0:
        human_delay(0.5, 1.5)
        second_amount = random.randint(50, 200)
        page.evaluate(f"window.scrollBy(0, {second_amount});")
    
    return scroll_amount

def human_click(page, x, y, click_type="normal"):
    """Perform a more human-like click with mouse movement and occasional double-clicks"""
    
    # Move to a random position first (sometimes)
    if random.random() < 0.6:
        random_x = random.randint(100, 1000)
        random_y = random.randint(100, 600)
        page.mouse.move(random_x, random_y)
        human_delay(0.1, 0.5)
    
    # Move to target with slight randomness
    jitter_x = x + random.randint(-5, 5)
    jitter_y = y + random.randint(-3, 3)
    page.mouse.move(jitter_x, jitter_y)
    human_delay(0.1, 0.3)
    
    # Click behavior
    if click_type == "double" or (click_type == "normal" and random.random() < 0.1):
        # Double click (rarely)
        page.mouse.dblclick(jitter_x, jitter_y)
    elif click_type == "slow" or (click_type == "normal" and random.random() < 0.2):
        # Slow click (sometimes)
        page.mouse.down()
        human_delay(0.1, 0.4)
        page.mouse.up()
    else:
        # Normal click
        page.mouse.click(jitter_x, jitter_y)
    
    # Sometimes move mouse after clicking
    if random.random() < 0.4:
        human_delay(0.2, 0.6)
        after_x = jitter_x + random.randint(-100, 100)
        after_y = jitter_y + random.randint(-80, 80)
        page.mouse.move(after_x, after_y)

def handle_automation_warning(page, status_updates):
    """Handle Instagram's automation warning dialog"""
    try:
        # Check for the warning dialog
        automation_warning_selectors = [
            "text=We suspect automated behavior",
            "text=automated behavior on your account",
            "button:has-text('Dismiss')",
            "button:has-text('Ok')",
            "button:has-text('Close')"
        ]
        
        for selector in automation_warning_selectors:
            if page.query_selector(selector):
                status_updates.append("Detected automation warning dialog")
                
                # Take a screenshot of the warning
                try:
                    warning_screenshot = f"screenshots/automation_warning_{int(time.time())}.png"
                    page.screenshot(path=warning_screenshot)
                    status_updates.append("Automation warning screenshot saved")
                except Exception as e:
                    status_updates.append(f"Error taking warning screenshot: {str(e)}")
                
                # Try to find the dismiss button using various selectors
                dismiss_selectors = [
                    "button:has-text('Dismiss')",
                    "button:has-text('Ok')",
                    "button:has-text('Close')",
                    "button[type='button']"
                ]
                
                for dismiss_selector in dismiss_selectors:
                    try:
                        dismiss_button = page.query_selector(dismiss_selector)
                        if dismiss_button:
                            # Get button coordinates
                            coords = dismiss_button.bounding_box()
                            x = coords['x'] + coords['width'] / 2
                            y = coords['y'] + coords['height'] / 2
                            
                            # Click using human-like behavior
                            human_delay(1, 3)  # Think before dismissing
                            human_click(page, x, y)
                            status_updates.append(f"Dismissed automation warning using: {dismiss_selector}")
                            
                            # Wait after dismissing
                            human_delay(2, 4)
                            return True
                    except Exception as e:
                        logger.debug(f"Dismiss button {dismiss_selector} failed: {str(e)}")
                
                # If no buttons found, try clicking in the middle of the screen
                if random.random() < 0.5:
                    human_delay(1, 2)
                    human_click(page, 640, 360)  # Click in middle of screen
                    status_updates.append("Attempted to dismiss by clicking middle of screen")
                    human_delay(2, 3)
                
                return True
        
        return False  # No warning detected
    except Exception as e:
        status_updates.append(f"Error handling automation warning: {str(e)}")
        return False

def run_instagram_liker(username, password, max_likes):
    """Run the Instagram auto-liker with Playwright"""
    status_updates = ["Starting Instagram Auto-Liker with human-like behavior..."]
    image_path = save_placeholder_image("start")
    
    # Check if browsers are installed, if not install them
    try:
        status_updates.append("Verifying Playwright installation...")
        
        # First try to import
        try:
            from playwright.sync_api import sync_playwright
        except ImportError:
            status_updates.append("Playwright not installed. Installing now...")
            download_playwright_browsers()
            status_updates.append("Playwright installation completed.")

        # Then verify browser binary exists
        if not verify_playwright_installation():
            status_updates.append("Browser binary not found. Installing browsers...")
            download_playwright_browsers()
            
            # Double check installation worked
            if not verify_playwright_installation():
                status_updates.append("Failed to install browser binary. Please try running the script again.")
                return "\n".join(status_updates), image_path
        
        status_updates.append("Playwright installation verified.")
            
        from playwright.sync_api import sync_playwright
        
        status_updates.append("Launching Playwright browser...")
        with sync_playwright() as p:
            try:
                # Use random viewport size to look less like automation
                viewport_width = random.choice([1280, 1366, 1440, 1536, 1600, 1920])
                viewport_height = random.choice([720, 768, 800, 864, 900, 1080])
                
                # Launch chromium with specific arguments
                browser = p.chromium.launch(
                    headless=True,
                    args=[
                        '--no-sandbox',
                        '--disable-dev-shm-usage',
                        '--disable-gpu',
                        '--disable-software-rasterizer',
                        '--disable-setuid-sandbox'
                    ]
                )
                
                # Create a browser context with random user agent
                user_agents = [
                    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15',
                    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
                    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0'
                ]
                user_agent = random.choice(user_agents)
                
                context = browser.new_context(
                    user_agent=user_agent,
                    viewport={'width': viewport_width, 'height': viewport_height},
                    locale=random.choice(['en-US', 'en-GB', 'en-CA']),
                    timezone_id=random.choice(['America/New_York', 'America/Los_Angeles', 'Europe/London', 'Asia/Tokyo'])
                )
                
                # Set random geolocation (if allowed)
                if random.random() < 0.5:
                    try:
                        context.set_geolocation({
                            'latitude': random.uniform(30, 50),
                            'longitude': random.uniform(-120, -70)
                        })
                    except:
                        pass
                
                # Open a new page
                page = context.new_page()
                
                # Test browser by visiting Google
                status_updates.append("Testing browser connection...")
                page.goto("https://www.google.com")
                human_delay(1, 3)  # Wait like a human
                status_updates.append(f"Browser working. Title: {page.title()}")
                
                # Take a screenshot
                try:
                    test_screenshot = f"screenshots/test_pw_{int(time.time())}.png"
                    page.screenshot(path=test_screenshot)
                    image_path = test_screenshot
                    status_updates.append("Browser screenshot saved")
                except Exception as e:
                    status_updates.append(f"Error taking screenshot: {str(e)}")
                
                # Navigate to Instagram with delay
                status_updates.append("Navigating to Instagram...")
                page.goto("https://www.instagram.com/")
                
                # Wait for load with natural variation
                wait_strategy = random.choice(['domcontentloaded', 'networkidle', 'load'])
                page.wait_for_load_state(wait_strategy)
                human_delay(2, 5)  # Additional human-like wait
                
                # Take a screenshot to see what's happening
                try:
                    landing_screenshot = f"screenshots/landing_pw_{int(time.time())}.png"
                    page.screenshot(path=landing_screenshot)
                    image_path = landing_screenshot
                    status_updates.append("Instagram page loaded, screenshot saved")
                except Exception as e:
                    status_updates.append(f"Error taking screenshot: {str(e)}")
                
                # Random initial interactions (to look human)
                if random.random() < 0.7:
                    # Maybe move mouse randomly on the page
                    for _ in range(random.randint(1, 3)):
                        random_x = random.randint(100, viewport_width - 100)
                        random_y = random.randint(100, viewport_height - 100)
                        page.mouse.move(random_x, random_y)
                        human_delay(0.3, 1.5)
                
                # Maybe scroll a bit before doing anything
                if random.random() < 0.5:
                    human_scroll(page, 100, 300)
                    human_delay(1, 3)
                
                # Click outside any potential popups (more natural location)
                try:
                    random_x = random.randint(50, 150)
                    random_y = random.randint(50, 100)
                    human_click(page, random_x, random_y)
                    status_updates.append("Clicked to dismiss any initial popups")
                except Exception as e:
                    status_updates.append(f"Click error: {str(e)}")
                
                # Handle cookie dialog if present
                try:
                    cookie_buttons = [
                        "text=Accept",
                        "text=Allow",
                        "text=Only allow essential cookies",
                        "button:has-text('Accept All')",
                        "button:has-text('Allow essential and optional cookies')"
                    ]
                    
                    for button_selector in cookie_buttons:
                        try:
                            button = page.query_selector(button_selector)
                            if button:
                                # Get coordinates
                                coords = button.bounding_box()
                                x = coords['x'] + coords['width'] / 2
                                y = coords['y'] + coords['height'] / 2
                                
                                # Human-like delay before clicking
                                human_delay(0.8, 2)
                                
                                # Human-like click
                                human_click(page, x, y)
                                status_updates.append(f"Clicked cookie consent button: {button_selector}")
                                human_delay(1, 3)
                                break
                        except Exception as e:
                            logger.debug(f"Button {button_selector} not found: {str(e)}")
                            continue
                except Exception as e:
                    status_updates.append(f"Cookie dialog handling: {str(e)}")
                
                # Interact with login form like a human
                status_updates.append("Looking for login form...")
                
                # Take a screenshot to see what we're working with
                try:
                    form_screenshot = f"screenshots/login_form_{int(time.time())}.png"
                    page.screenshot(path=form_screenshot)
                    image_path = form_screenshot
                    status_updates.append("Login form screenshot saved")
                except Exception as e:
                    status_updates.append(f"Error taking screenshot: {str(e)}")
                
                # Check for automation warning (might appear right away)
                if handle_automation_warning(page, status_updates):
                    status_updates.append("Handled initial automation warning")
                
                # Try multiple selectors for username input
                username_selectors = [
                    "input[name='username']",
                    "input[aria-label='Phone number, username, or email']",
                    "input[placeholder='Phone number, username, or email']",
                    "input[placeholder='Mobile number, username or email']",
                    "input[type='text']"
                ]
                
                username_field = None
                for selector in username_selectors:
                    try:
                        status_updates.append(f"Trying to find username field with selector: {selector}")
                        field = page.query_selector(selector)
                        if field:
                            username_field = field
                            status_updates.append(f"Found username field with selector: {selector}")
                            break
                    except Exception as e:
                        logger.debug(f"Selector {selector} failed: {str(e)}")
                
                if not username_field:
                    status_updates.append("Could not find username field. Instagram may have changed their interface.")
                    # Take final screenshot before closing
                    final_screenshot = f"screenshots/final_error_{int(time.time())}.png"
                    page.screenshot(path=final_screenshot)
                    image_path = final_screenshot
                    browser.close()
                    return "\n".join(status_updates), image_path
                
                # Try multiple selectors for password input
                password_selectors = [
                    "input[name='password']",
                    "input[aria-label='Password']",
                    "input[placeholder='Password']",
                    "input[type='password']"
                ]
                
                password_field = None
                for selector in password_selectors:
                    try:
                        status_updates.append(f"Trying to find password field with selector: {selector}")
                        field = page.query_selector(selector)
                        if field:
                            password_field = field
                            status_updates.append(f"Found password field with selector: {selector}")
                            break
                    except Exception as e:
                        logger.debug(f"Selector {selector} failed: {str(e)}")
                
                if not password_field:
                    status_updates.append("Could not find password field. Instagram may have changed their interface.")
                    # Take final screenshot before closing
                    final_screenshot = f"screenshots/final_error_{int(time.time())}.png"
                    page.screenshot(path=final_screenshot)
                    image_path = final_screenshot
                    browser.close()
                    return "\n".join(status_updates), image_path
                
                # Enter credentials like a human would
                status_updates.append(f"Entering username: {username}")
                
                # Click the username field first (human behavior)
                username_coords = username_field.bounding_box()
                username_x = username_coords['x'] + username_coords['width'] / 2
                username_y = username_coords['y'] + username_coords['height'] / 2
                human_click(page, username_x, username_y)
                
                # Type username with human-like timing
                for char in username:
                    username_field.type(char, delay=random.randint(100, 300))
                    time.sleep(random.uniform(0.01, 0.15))
                
                # Sometimes humans pause after entering username
                human_delay(0.5, 2)
                
                # Now click password field
                password_coords = password_field.bounding_box()
                password_x = password_coords['x'] + password_coords['width'] / 2
                password_y = password_coords['y'] + password_coords['height'] / 2
                human_click(page, password_x, password_y)
                
                # Type password with human-like timing
                for char in password:
                    password_field.type(char, delay=random.randint(100, 300))
                    time.sleep(random.uniform(0.01, 0.15))
                
                status_updates.append("Credentials entered")
                
                # Take a screenshot of filled form
                try:
                    creds_screenshot = f"screenshots/credentials_pw_{int(time.time())}.png"
                    page.screenshot(path=creds_screenshot)
                    image_path = creds_screenshot
                    status_updates.append("Credentials screenshot saved")
                except Exception as e:
                    status_updates.append(f"Error taking screenshot: {str(e)}")
                
                # Find login button
                login_button_selectors = [
                    "button[type='submit']",
                    "button:has-text('Log in')",
                    "button:has-text('Sign in')",
                    "button:has-text('Log In')",
                    "form button"
                ]
                
                login_button = None
                for selector in login_button_selectors:
                    try:
                        status_updates.append(f"Trying to find login button with selector: {selector}")
                        button = page.query_selector(selector)
                        if button:
                            login_button = button
                            status_updates.append(f"Found login button with selector: {selector}")
                            break
                    except Exception as e:
                        logger.debug(f"Selector {selector} failed: {str(e)}")
                
                if not login_button:
                    status_updates.append("Could not find login button. Instagram may have changed their interface.")
                    # Take final screenshot before closing
                    final_screenshot = f"screenshots/final_error_{int(time.time())}.png"
                    page.screenshot(path=final_screenshot)
                    image_path = final_screenshot
                    browser.close()
                    return "\n".join(status_updates), image_path
                
                # Click login button like a human
                status_updates.append("Clicking login button...")
                button_coords = login_button.bounding_box()
                button_x = button_coords['x'] + button_coords['width'] / 2
                button_y = button_coords['y'] + button_coords['height'] / 2
                
                # Pause briefly before clicking (human behavior)
                human_delay(0.5, 1.5)
                human_click(page, button_x, button_y)
                
                # Wait for navigation to complete with human-like variation
                status_updates.append("Waiting for login process...")
                wait_time = random.uniform(3, 7)
                time.sleep(wait_time)
                
                # Take post-login screenshot
                try:
                    post_login_screenshot = f"screenshots/post_login_pw_{int(time.time())}.png"
                    page.screenshot(path=post_login_screenshot)
                    image_path = post_login_screenshot
                    status_updates.append("Post-login screenshot saved")
                except Exception as e:
                    status_updates.append(f"Error taking screenshot: {str(e)}")
                
                # Check for automation warning after login
                if handle_automation_warning(page, status_updates):
                    status_updates.append("Handled post-login automation warning")
                
                # Check if login was successful
                current_url = page.url
                if "/accounts/login" in current_url or "/login" in current_url:
                    # Still on login page - check for error messages
                    error_selectors = [
                        "#slfErrorAlert",
                        "p[data-testid='login-error-message']",
                        "div[role='alert']",
                        "p.sIKKJ",
                        ".coreSpriteAccessUpsell + div"
                    ]
                    
                    error_message = ""
                    for selector in error_selectors:
                        try:
                            el = page.query_selector(selector)
                            if el:
                                error_message = el.text_content()
                                break
                        except:
                            pass
                    
                    if error_message:
                        status_updates.append(f"Login failed: {error_message}")
                    else:
                        status_updates.append("Login failed: Reason unknown. Check your credentials.")
                    
                    browser.close()
                    return "\n".join(status_updates), image_path
                
                status_updates.append("Login successful! Now handling post-login dialogs...")
                
                # Handle "Save Login Info" popup if it appears
                try:
                    human_delay(1, 3)  # Wait like a human for popup to appear
                    
                    save_info_selectors = [
                        "text=Save Login Info",
                        "text=Save Your Login Info",
                        "text=Save Info"
                    ]
                    not_now_selectors = [
                        "text=Not Now",
                        "button:has-text('Not Now')",
                        "button.sqdOP.yWX7d",
                        "button:not(:has-text('Save'))"
                    ]
                    
                    # Check if any save info dialog appears
                    dialog_found = False
                    for selector in save_info_selectors:
                        if page.query_selector(selector):
                            dialog_found = True
                            status_updates.append(f"Save Login Info dialog found with: {selector}")
                            break
                    
                    if dialog_found:
                        # Wait like a human would before deciding
                        human_delay(1, 4)
                        
                        # Try to click "Not Now"
                        dismissed = False
                        for not_now in not_now_selectors:
                            try:
                                button = page.query_selector(not_now)
                                if button:
                                    # Get button coordinates
                                    coords = button.bounding_box()
                                    x = coords['x'] + coords['width'] / 2
                                    y = coords['y'] + coords['height'] / 2
                                    
                                    # Click like a human
                                    human_click(page, x, y)
                                    status_updates.append(f"Dismissed 'Save Login Info' popup using: {not_now}")
                                    human_delay(1, 3)
                                    dismissed = True
                                    break
                            except Exception as e:
                                logger.debug(f"Not Now button {not_now} failed: {str(e)}")
                                continue
                        
                        if not dismissed:
                            status_updates.append("Found Save Login dialog but couldn't dismiss it")
                    else:
                        status_updates.append("No 'Save Login Info' popup detected")
                except Exception as e:
                    status_updates.append(f"Error handling Save Login dialog: {str(e)}")
                
                # Take a screenshot after handling first dialog
                try:
                    after_save_screenshot = f"screenshots/after_save_dialog_{int(time.time())}.png"
                    page.screenshot(path=after_save_screenshot)
                    image_path = after_save_screenshot
                    status_updates.append("Screenshot after Save Info dialog")
                except Exception as e:
                    status_updates.append(f"Error taking screenshot: {str(e)}")
                
                # Handle notifications popup if it appears
                try:
                    human_delay(1, 3)  # Wait like a human
                    
                    notifications_selectors = [
                        "text=Turn on Notifications",
                        "text=Enable Notifications",
                        "h2:has-text('Notifications')"
                    ]
                    not_now_selectors = [
                        "text=Not Now",
                        "button:has-text('Not Now')",
                        "button.sqdOP.yWX7d",
                        "button:not(:has-text('Allow'))"
                    ]
                    
                    # Check if any notifications dialog appears
                    dialog_found = False
                    for selector in notifications_selectors:
                        if page.query_selector(selector):
                            dialog_found = True
                            status_updates.append(f"Notifications dialog found with: {selector}")
                            break
                    
                    if dialog_found:
                        # Wait like a human before deciding
                        human_delay(1, 4)
                        
                        # Try to click "Not Now"
                        dismissed = False
                        for not_now in not_now_selectors:
                            try:
                                button = page.query_selector(not_now)
                                if button:
                                    # Get button coordinates
                                    coords = button.bounding_box()
                                    x = coords['x'] + coords['width'] / 2
                                    y = coords['y'] + coords['height'] / 2
                                    
                                    # Click like a human
                                    human_click(page, x, y)
                                    status_updates.append(f"Dismissed notifications popup using: {not_now}")
                                    human_delay(1, 3)
                                    dismissed = True
                                    break
                            except Exception as e:
                                logger.debug(f"Not Now button {not_now} failed: {str(e)}")
                                continue
                        
                        if not dismissed:
                            status_updates.append("Found Notifications dialog but couldn't dismiss it")
                    else:
                        status_updates.append("No notifications popup detected")
                except Exception as e:
                    status_updates.append(f"Error handling Notifications dialog: {str(e)}")
                
                # Take feed screenshot
                try:
                    feed_screenshot = f"screenshots/feed_pw_{int(time.time())}.png"
                    page.screenshot(path=feed_screenshot)
                    image_path = feed_screenshot
                    status_updates.append("Feed screenshot saved")
                except Exception as e:
                    status_updates.append(f"Error taking screenshot: {str(e)}")
                
                # Check for automation warning again
                if handle_automation_warning(page, status_updates):
                    status_updates.append("Handled feed automation warning")
                
                status_updates.append("Successfully navigated to Instagram feed!")
                
                # Start liking posts with human-like behavior
                likes_goal = min(max_likes, random.randint(max_likes - 3, max_likes + 3))
                status_updates.append(f"Starting to like posts (target: {likes_goal})...")
                
                # Like posts
                likes_count = 0
                scroll_count = 0
                max_scrolls = random.randint(25, 35)
                
                # Wait for the feed to load fully before looking for posts
                # Function to find and like posts with human-like behavior
                def find_and_like_post():
                    """Find and like a single post with human-like behavior"""
                    try:
                        # Use JavaScript to find like buttons directly in the DOM
                        like_button_info = page.evaluate("""() => {
                            // Try different selectors for like buttons (not already liked)
                            const selectors = [
                                // Generic selectors for Instagram's like buttons
                                "article svg[aria-label='Like']",  
                                "article section svg[aria-label='Like']",
                                "svg[aria-label='Like']",
                                "span[class*='_aamw'] svg[aria-label='Like']",
                                "button svg[aria-label='Like']",
                                // Looser selector that might catch more
                                "article button[type='button']:not([aria-pressed='true'])"
                            ];
                            
                            // Shuffle the selectors to add randomness
                            const shuffled = selectors.sort(() => 0.5 - Math.random());
                            
                            // Try each selector
                            for (const selector of shuffled) {
                                const elements = Array.from(document.querySelectorAll(selector));
                                
                                if (elements.length > 0) {
                                    // Shuffle the elements to add randomness
                                    const shuffledElements = elements.sort(() => 0.5 - Math.random());
                                    
                                    // Choose a random element from the first few found
                                    const randomIndex = Math.floor(Math.random() * Math.min(3, shuffledElements.length));
                                    const element = shuffledElements[randomIndex];
                                    
                                    // Find the actual clickable button (might be a parent)
                                    let button = element;
                                    if (element.tagName.toLowerCase() === 'svg') {
                                        button = element.closest('button') || element;
                                    }
                                    
                                    // Get element position
                                    const rect = button.getBoundingClientRect();
                                    
                                    // Check if it's visible in viewport
                                    if (rect.top >= 0 && rect.left >= 0 && 
                                        rect.bottom <= window.innerHeight && 
                                        rect.right <= window.innerWidth) {
                                        
                                        return {
                                            found: true,
                                            x: rect.x + rect.width / 2,
                                            y: rect.y + rect.height / 2,
                                            selector: selector,
                                            totalFound: elements.length
                                        };
                                    }
                                }
                            }
                            
                            return { found: false };
                        }""")
                        
                        if like_button_info['found']:
                            # Wait a bit before clicking (as if examining the post)
                            human_delay(1, 4)
                            
                            # Sometimes explore the post before liking
                            if random.random() < 0.3:
                                # Move mouse around post area
                                explore_x = like_button_info['x'] + random.randint(-100, 100)
                                explore_y = like_button_info['y'] + random.randint(-100, 100)
                                page.mouse.move(explore_x, explore_y)
                                human_delay(0.5, 2)
                            
                            # Take screenshot before click
                            try:
                                before_like_screenshot = f"screenshots/before_like_{likes_count+1}_{int(time.time())}.png"
                                page.screenshot(path=before_like_screenshot)
                            except:
                                pass
                            
                            # Click with human-like behavior
                            like_x = like_button_info['x']
                            like_y = like_button_info['y']
                            
                            # Add slight randomness to click position
                            human_click(page, like_x, like_y)
                            
                            # Wait for the like to register
                            human_delay(0.5, 2)
                            
                            return True
                        
                        return False
                    except Exception as e:
                        status_updates.append(f"Error finding/clicking like button: {str(e)}")
                        return False
                
                # Variable to track consecutive failures
                consecutive_failures = 0
                last_successful_like_time = time.time()
                
                # Main loop for scrolling and liking
                while likes_count < likes_goal and scroll_count < max_scrolls:
                    try:
                        # Take screenshot occasionally to track progress
                        if scroll_count % 5 == 0:
                            try:
                                progress_screenshot = f"screenshots/progress_{scroll_count}_{int(time.time())}.png"
                                page.screenshot(path=progress_screenshot)
                                image_path = progress_screenshot
                            except:
                                pass
                        
                        # First check for automation warnings
                        if handle_automation_warning(page, status_updates):
                            status_updates.append(f"Handled automation warning during scrolling (#{scroll_count})")
                            human_delay(3, 6)  # Longer wait after handling warning
                        
                        # Try to like a post with human-like behavior
                        if find_and_like_post():
                            likes_count += 1
                            consecutive_failures = 0
                            last_successful_like_time = time.time()
                            status_updates.append(f"Liked post {likes_count}/{likes_goal}")
                            
                            # Take post-like screenshot occasionally
                            if random.random() < 0.3:
                                try:
                                    after_like_screenshot = f"screenshots/after_like_{likes_count}_{int(time.time())}.png"
                                    page.screenshot(path=after_like_screenshot)
                                    image_path = after_like_screenshot
                                except:
                                    pass
                            
                            # Calculate a random human-like delay between likes
                            # Occasionally take longer breaks to seem more human
                            if random.random() < 0.15:  # 15% chance of a longer break
                                wait_time = random.uniform(5, 15)
                                status_updates.append(f"Taking a short break ({wait_time:.1f}s)")
                                time.sleep(wait_time)
                            else:
                                # Normal delay between likes (variable)
                                human_delay(2, 7)
                            
                            # Occasionally interact with the feed in other ways to seem human
                            if random.random() < 0.25:  # 25% chance after liking
                                random_action = random.choice([
                                    "move_mouse_random",
                                    "small_scroll_up",
                                    "pause",
                                    "long_hover"
                                ])
                                
                                if random_action == "move_mouse_random":
                                    # Move mouse to random position
                                    random_x = random.randint(100, viewport_width - 100)
                                    random_y = random.randint(100, viewport_height - 100)
                                    page.mouse.move(random_x, random_y)
                                    human_delay(0.5, 2)
                                
                                elif random_action == "small_scroll_up":
                                    # Sometimes scroll back up a bit
                                    page.evaluate("window.scrollBy(0, -100);")
                                    human_delay(0.5, 2)
                                    
                                elif random_action == "pause":
                                    # Just pause for a moment
                                    human_delay(1, 3)
                                    
                                elif random_action == "long_hover":
                                    # Hover over something for a bit
                                    random_x = random.randint(200, viewport_width - 200)
                                    random_y = random.randint(200, viewport_height - 200)
                                    page.mouse.move(random_x, random_y)
                                    human_delay(2, 4)
                        else:
                            consecutive_failures += 1
                            status_updates.append(f"No new like buttons found on scroll {scroll_count}")
                            
                            # If we haven't found anything to like in a while, check if we need to scroll
                            if consecutive_failures >= 3 or (time.time() - last_successful_like_time > 20):
                                # Scroll down to load more content
                                scroll_amount = human_scroll(page, 
                                    min_pixels=random.randint(200, 400), 
                                    max_pixels=random.randint(500, 800)
                                )
                                status_updates.append(f"Scrolled down {scroll_amount} pixels to load more posts")
                                
                                # Wait for new content with variable timing
                                wait_time = random.uniform(2, 5)
                                time.sleep(wait_time)
                                
                                # Reset failure counter after scrolling
                                consecutive_failures = 0
                                scroll_count += 1
                            else:
                                # Small wait before trying again
                                human_delay(1, 3)
                        
                        # Occasionally take a longer break to seem more human
                        if likes_count > 0 and likes_count % 5 == 0 and random.random() < 0.7:
                            break_time = random.uniform(8, 20)
                            status_updates.append(f"Taking a longer break after {likes_count} likes ({break_time:.1f}s)")
                            time.sleep(break_time)
                        
                        # Verify we haven't exceeded the target
                        if likes_count >= likes_goal:
                            status_updates.append(f"Reached target of {likes_goal} likes")
                            break
                        
                    except Exception as e:
                        status_updates.append(f"Error during like cycle: {str(e)}")
                        # Take error screenshot
                        try:
                            error_screenshot = f"screenshots/error_{int(time.time())}.png"
                            page.screenshot(path=error_screenshot)
                            image_path = error_screenshot
                        except:
                            pass
                        
                        # Continue despite errors after a pause
                        human_delay(3, 6)
                
                # Final status
                final_message = f"Finished! Liked {likes_count} posts."
                status_updates.append(final_message)
                
                # Final screenshot
                try:
                    final_screenshot = f"screenshots/final_{int(time.time())}.png"
                    page.screenshot(path=final_screenshot)
                    image_path = final_screenshot
                    status_updates.append("Final screenshot saved")
                except Exception as e:
                    status_updates.append(f"Error taking final screenshot: {str(e)}")
                
                # Close the browser
                browser.close()
                status_updates.append("Browser closed")
                
            except Exception as e:
                status_updates.append(f"Error during browser interaction: {str(e)}")
                traceback_msg = traceback.format_exc()
                logger.error(traceback_msg)
                status_updates.append("See logs for detailed error information")
                
                # Try to close browser in case of error
                try:
                    browser.close()
                    status_updates.append("Browser closed after error")
                except:
                    pass
        
    except Exception as e:
        error_message = f"Error with Playwright: {str(e)}"
        logger.error(error_message)
        status_updates.append(error_message)
        logger.error(traceback.format_exc())
    
    return "\n".join(status_updates), image_path

# Gradio Interface
def create_interface():
    with gr.Blocks(title="Instagram Auto-Liker") as app:
        gr.Markdown("# Instagram Auto-Liker (Human-like)")
        gr.Markdown("""
        Enter your Instagram credentials and the number of posts to like.
        
        **Note:** This tool is for educational purposes only. Using automation tools with Instagram
        may violate their terms of service. Use at your own risk.
        """)
        
        with gr.Row():
            with gr.Column(scale=1):
                username = gr.Textbox(label="Instagram Username")
                password = gr.Textbox(label="Instagram Password", type="password")
                max_likes = gr.Slider(minimum=1, maximum=50, value=10, step=1, label="Number of Posts to Like")
                submit_btn = gr.Button("Start Liking Posts")
            
            with gr.Column(scale=2):
                status_output = gr.Textbox(label="Status Log", lines=15)
                image_output = gr.Image(label="Latest Screenshot", type="filepath")
        
        submit_btn.click(
            fn=run_instagram_liker,
            inputs=[username, password, max_likes],
            outputs=[status_output, image_output]
        )
    
    return app

# Main entry point
if __name__ == "__main__":
    print(f"===== Application Startup at {time.strftime('%Y-%m-%d %H:%M:%S')} =====")
    
    # Make sure all dependencies are installed before starting the application
    print("Installing dependencies...")
    success = download_playwright_browsers()
    
    if not success:
        print("Failed to install Playwright browsers. Please check your connection and try again.")
        sys.exit(1)
    
    # Start the app
    print("Starting the application...")
    app = create_interface()
    app.launch()