mdcci 2.2__tar.gz → 2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mdcci
3
- Version: 2.2
3
+ Version: 2.4
4
4
  Summary: Extended LPro - MProcs simplified - A Life program by tderk, originally LPro.py and Destiny [2024]
5
5
  Author-email: tderk <usvu.tech@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mdcci"
7
- version = "2.2"
7
+ version = "2.4"
8
8
  description = "Extended LPro - MProcs simplified - A Life program by tderk, originally LPro.py and Destiny [2024]"
9
9
  requires-python = ">=3.8"
10
10
  readme = "README.md"
@@ -80,6 +80,49 @@ def change_username(provided_name=None):
80
80
 
81
81
  omit_result = False
82
82
  current_ddd = [""]
83
+ jot_log = None
84
+ jot_active = False
85
+ jot_file_path = ""
86
+
87
+ def jot(path=None):
88
+ import os
89
+ global jot_log, jot_active, jot_file_path
90
+ if not jot_active:
91
+ jot_file_path = path if path else "JOT.txt"
92
+ folder = os.path.dirname(jot_file_path)
93
+ if folder and not os.path.isdir(folder):
94
+ print(f"{ORANGE}[JOT] Folder not found: {folder}{RESET}")
95
+ return
96
+ jot_log = open(jot_file_path, "a", buffering=1)
97
+ jot_active = True
98
+ print(f"{GREEN}[JOT] Recording started -> {jot_file_path}{RESET}")
99
+ else:
100
+ jot_log.close()
101
+ jot_active = False
102
+ print(f"{ORANGE}[JOT] Recording stopped -> {jot_file_path}{RESET}")
103
+ jot_log = None
104
+ jot_file_path = ""
105
+
106
+ def jot_write(msg):
107
+ global jot_log, jot_active
108
+ if jot_active and jot_log:
109
+ jot_log.write(msg + "\n")
110
+ jot_log.flush()
111
+
112
+ print_orig = print
113
+ def jot_print(*args, **kwargs):
114
+ global jot_log, jot_active
115
+ if 'file' in kwargs and kwargs['file'] == z:
116
+ print_orig(*args, **kwargs)
117
+ return
118
+ text = " ".join(str(a) for a in args)
119
+ clean_text = re.sub(r'\x1b\[[0-9;]*m', '', text)
120
+ if jot_active and jot_log:
121
+ jot_log.write(clean_text + "\n")
122
+ jot_log.flush()
123
+ print_orig(*args, **kwargs)
124
+
125
+ print = jot_print
83
126
 
84
127
  def main():
85
128
 
@@ -695,7 +738,7 @@ def main():
695
738
  print(alert, value, random_letters, rrchar_str, kkchar_str, cchat, hchar_str, ct, file=z)
696
739
 
697
740
  def version():
698
- title = usr + "" + " " + "" + f"snowtiger >>> {ORANGE}I.S. (Incubator Studios) Outbeat Produce:{RESET} {GREEN}MProcs-9.0{RESET} {ORANGE}by tderk{RESET} - {ORANGE}Established Lpro.py (Life-pro) and Destiny [2024]{RESET}"
741
+ title = usr + "" + " " + "" + f"snowtiger >>> {ORANGE}I.S. (Incubator Studios) Outbeat Produce:{RESET} {GREEN}MProcs-9.2{RESET} {ORANGE}by tderk{RESET} - {ORANGE}Established Lpro.py (Life-pro) and Destiny [2024]{RESET}"
699
742
  title2 = f"| {BLUE}Indicative: @USVirtualUni && © Medicine, Computable (N_2025) && FNTCCI{RESET} |"
700
743
  title3 = f"{ORANGE}All Rights Reserved{RESET} - {BLUE}Medicci.ca{RESET}"
701
744
  title4 = f"- {RED}(P0cket Un1-Ver$e){RESET}"
@@ -917,7 +960,7 @@ def main():
917
960
 
918
961
  def commands():
919
962
  print()
920
- print(" version | switch/lpro-s [lx] | [blank input] for nano / 1-nano [n1/3 spaces] | morn [m] | nano characters [nanochars/nnc] | katakana [kata/b] | jamo [hangu/n] | chi [++] | ans [@@] | ruh [%%] | profile | note / journal / save | pwd / ls / cd / clear [cl] / mkdir / rm | type-text | Term-Search [tsearch] | search | scmpy / scm [social media]")
963
+ print(" version | switch/lpro-s [lx] | [blank input] for nano / 1-nano [n1/3 spaces] | morn [m] | nano characters [nanochars/nnc] | katakana [kata/b] | jamo [hangu/n] | chi [++] | ans [@@] | ruh [%%] | profile | note / journal / save | pwd / ls / cd / clear [cl] / mkdir / rm | type-text | Term-Search [tsearch] | search | scmpy / scm [social media] | jot [JOT] (record terminal to file)")
921
964
  print()
922
965
  print(" FNTCCI: tinien [single space/**], ntag, fcci-monitor [fstart/fcci] | synthesis: cbmp, cmbpc, xcbmp, xcbmpc, hbmp, hbmpc, xhbmp, xhbmpc, jbmp, jbmpc, xjbmp, xjbmpc, fbmp, xfbmp")
923
966
  print()
@@ -8662,6 +8705,7 @@ def main():
8662
8705
  print()
8663
8706
  print(file=z)
8664
8707
  choice = input(usr)
8708
+ jot_write(f"{usr}{choice}")
8665
8709
  ct = datetime.datetime.now()
8666
8710
  print(usr, choice, ct, file=z)
8667
8711
 
@@ -8676,6 +8720,15 @@ def main():
8676
8720
  scmpy.scmpy_main()
8677
8721
  return "continue"
8678
8722
 
8723
+ if choice == "jot" or choice == "JOT":
8724
+ if jot_active:
8725
+ jot()
8726
+ else:
8727
+ path = input("Path (Enter for ./JOT.txt): ").strip()
8728
+ jot(path if path else "JOT.txt")
8729
+ jot_write(f"=== JOT Session: {datetime.datetime.now()} ===")
8730
+ return "continue"
8731
+
8679
8732
  if choice == "nano chars" or choice == "nano characters" or choice == "nano-characters" or choice == "nanochars" or choice == "nano-chars" or choice == "nnc" or choice == 'NNC':
8680
8733
  select_charset()
8681
8734
 
@@ -79,6 +79,55 @@ def change_username(provided_name=None):
79
79
 
80
80
  omit_result = False
81
81
  current_ddd = [""]
82
+ jot_log = None
83
+ jot_active = False
84
+ jot_file_path = ""
85
+
86
+ def jot(path=None):
87
+ import os
88
+ global jot_log, jot_active, jot_file_path
89
+ if not jot_active:
90
+ jot_file_path = path if path else "JOT.txt"
91
+ folder = os.path.dirname(jot_file_path)
92
+ if folder and not os.path.isdir(folder):
93
+ print(f"{ORANGE}[JOT] Folder not found: {folder}{RESET}")
94
+ return
95
+ jot_log = open(jot_file_path, "a", buffering=1)
96
+ jot_active = True
97
+ print(f"{GREEN}[JOT] Recording started -> {jot_file_path}{RESET}")
98
+ else:
99
+ jot_log.close()
100
+ jot_active = False
101
+ print(f"{ORANGE}[JOT] Recording stopped -> {jot_file_path}{RESET}")
102
+ jot_log = None
103
+ jot_file_path = ""
104
+
105
+ def jot_write(msg):
106
+ global jot_log, jot_active
107
+ if jot_log and jot_active:
108
+ jot_log.write(msg + "\n")
109
+ jot_log.flush()
110
+
111
+ print_orig = print
112
+
113
+ class SkipLog:
114
+ pass
115
+
116
+ skip_log = SkipLog()
117
+
118
+ def jot_print(*args, **kwargs):
119
+ global jot_log, jot_active
120
+ f = kwargs.get('file')
121
+ if f is skip_log or (hasattr(f, 'name') and 'MProcs' in f.name):
122
+ return print_orig(*args, file=None, **kwargs)
123
+ text = " ".join(str(a) for a in args)
124
+ clean_text = re.sub(r'\x1b\[[0-9;]*m', '', text)
125
+ if jot_active and jot_log:
126
+ jot_log.write(clean_text + "\n")
127
+ jot_log.flush()
128
+ print_orig(*args, **kwargs)
129
+
130
+ print = jot_print
82
131
 
83
132
  def main():
84
133
 
@@ -692,7 +741,7 @@ def main():
692
741
  print(alert, value, random_letters, kkchar_str, cchat, hchar_str, rrchar_str, ct)
693
742
 
694
743
  def version():
695
- title = usr + "" + " " + "" + f"snowtiger >>> {ORANGE}I.S. (Incubator Studios) Outbeat Produce:{RESET} {GREEN}MProcs-9.0-s{RESET} {ORANGE}by tderk{RESET} - {ORANGE}Established Lpro.py (Life-pro) and Destiny [2024]{RESET}"
744
+ title = usr + "" + " " + "" + f"snowtiger >>> {ORANGE}I.S. (Incubator Studios) Outbeat Produce:{RESET} {GREEN}MProcs-9.2-s{RESET} {ORANGE}by tderk{RESET} - {ORANGE}Established Lpro.py (Life-pro) and Destiny [2024]{RESET}"
696
745
  title2 = f"| {BLUE}Indicative: @USVirtualUni && © Medicine, Computable (N_2025) && FNTCCI{RESET} |"
697
746
  title3 = f"{ORANGE}All Rights Reserved{RESET} - {BLUE}Medicci.ca{RESET}"
698
747
  title4 = f"- {RED}(P0cket Un1-Ver$e){RESET}"
@@ -900,7 +949,7 @@ def main():
900
949
 
901
950
  def commands():
902
951
  print()
903
- print(" version | switch/lpro [lx] | [blank input] for nano / 1-nano [n1/3 spaces] | morn [m] | nano characters [nanochars/nnc] | katakana [kata/b] | jamo [hangu/n] | chi [++] | ans [@@] | ruh [%%] | profile | pwd / ls / cd / clear [cl] / mkdir / rm | type-text | Term-Search [tsearch] | fsearch | scmpy / scm [social media]")
952
+ print(" version | switch/lpro [lx] | [blank input] for nano / 1-nano [n1/3 spaces] | morn [m] | nano characters [nanochars/nnc] | katakana [kata/b] | jamo [hangu/n] | chi [++] | ans [@@] | ruh [%%] | profile | pwd / ls / cd / clear [cl] / mkdir / rm | type-text | Term-Search [tsearch] | fsearch | scmpy / scm [social media] | jot [JOT] (record terminal to file)")
904
953
  print()
905
954
  print(" FNTCCI: tinien [single space/**], ntag, fcci-monitor [fstart/fcci] | synthesis: xcbmp, xcbmpc, xhbmp, xhbmpc, xjbmp, xjbmpc, xfbmp")
906
955
  print()
@@ -6618,6 +6667,7 @@ def main():
6618
6667
  global usr
6619
6668
  print()
6620
6669
  choice = input(usr)
6670
+ jot_write(f"{usr}{choice}")
6621
6671
  ct = datetime.datetime.now()
6622
6672
 
6623
6673
  if choice == "version" or choice == "about" or choice == "intro":
@@ -6637,6 +6687,15 @@ def main():
6637
6687
  scmpy.check_dependencies()
6638
6688
  return "continue"
6639
6689
 
6690
+ if choice == "jot" or choice == "JOT":
6691
+ if jot_active:
6692
+ jot()
6693
+ else:
6694
+ path = input("Path (Enter for ./JOT.txt): ").strip()
6695
+ jot(path if path else "JOT.txt")
6696
+ jot_write(f"=== JOT Session: {datetime.datetime.now()} ===")
6697
+ return "continue"
6698
+
6640
6699
  if choice == "nano chars" or choice == "nano characters" or choice == "nano-characters" or choice == "nanochars" or choice == "nano-chars" or choice == "nnc" or choice == "NNC":
6641
6700
  select_charset()
6642
6701
 
@@ -971,11 +971,20 @@ def display_videos():
971
971
  print(f"=== YOUTUBE RESULTS ({len(CACHED_VIDEOS)} videos) ===\n")
972
972
  for i, v in enumerate(CACHED_VIDEOS):
973
973
  title = v.get('title', 'No title')
974
- video_id = v.get('vid', '')
974
+ video_id = v.get('vid', v.get('videoId', ''))
975
975
  url_link = v.get('url', f'https://youtube.com/watch?v={video_id}')
976
976
  print(f"{i+1}. {title}")
977
977
  print(f" {url_link}")
978
978
  print()
979
+ if CACHED_VIDEOS:
980
+ num = input(f"Open video # (1-{len(CACHED_VIDEOS)}) or Enter to skip: ").strip()
981
+ if num.isdigit():
982
+ idx = int(num) - 1
983
+ if 0 <= idx < len(CACHED_VIDEOS):
984
+ video_id = CACHED_VIDEOS[idx].get('vid', CACHED_VIDEOS[idx].get('videoId', ''))
985
+ url = CACHED_VIDEOS[idx].get('url', f'https://youtube.com/watch?v={video_id}')
986
+ print(f"Opening: {url}")
987
+ open_in_browser(url)
979
988
 
980
989
  def download_file(url, filepath, show_progress=True):
981
990
  if show_progress:
@@ -1009,7 +1018,13 @@ def download_by_number(items, number, folder, is_image=False, prefix=""):
1009
1018
 
1010
1019
  os.makedirs(folder, exist_ok=True)
1011
1020
  base = f"{prefix}_{number}" if prefix else f"download_{number}"
1012
- ext = url.split('.')[-1][:4].lower() or 'jpg'
1021
+ from urllib.parse import urlparse
1022
+ parsed = urlparse(url)
1023
+ path = parsed.path
1024
+ if '.' in path and len(path.split('.')[-1]) >= 3:
1025
+ ext = path.split('.')[-1][:4].lower()
1026
+ else:
1027
+ ext = 'png'
1013
1028
  filepath = unique_filename(folder, base, ext)
1014
1029
  print(f"Downloading to {filepath}...")
1015
1030
  download_file(url, filepath)
@@ -1024,9 +1039,13 @@ def download_all_images(items, folder, prefix="img"):
1024
1039
  url = item.get('image', '')
1025
1040
  if not url:
1026
1041
  continue
1027
- ext = url.split('.')[-1][:4].lower() or 'jpg'
1028
- if len(ext) < 3:
1029
- ext = 'jpg'
1042
+ from urllib.parse import urlparse
1043
+ parsed = urlparse(url)
1044
+ path = parsed.path
1045
+ if '.' in path and len(path.split('.')[-1]) >= 3:
1046
+ ext = path.split('.')[-1][:4].lower()
1047
+ else:
1048
+ ext = 'png'
1030
1049
  base = f"{prefix}_{i+1}"
1031
1050
  filepath = unique_filename(folder, base, ext)
1032
1051
  filename = os.path.basename(filepath)
@@ -1354,13 +1373,52 @@ def ai_image(prompt):
1354
1373
  for i, url in enumerate(urls):
1355
1374
  print(f"{i+1}. {url}")
1356
1375
 
1357
- def list_images():
1376
+ def list_images(path='.', add_to_cache=True, allow_upload=True):
1358
1377
  import os
1359
- images = [f for f in os.listdir('.') if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'))]
1378
+ folder = path if path != '.' else os.getcwd()
1379
+ if not os.path.isdir(folder):
1380
+ print(f"Folder not found: {folder}")
1381
+ return
1382
+ images = [f for f in os.listdir(folder) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'))]
1360
1383
  if images:
1361
- print("Images:")
1384
+ print(f"Images in {folder}:")
1362
1385
  for i, f in enumerate(images):
1363
1386
  print(f" {i+1}. {f}")
1387
+ view_opt = input(f"\nView image # (1-{len(images)}), 'c' to cache, 'p' to post, or Enter to skip: ").strip()
1388
+ if view_opt.isdigit():
1389
+ i = int(view_opt) - 1
1390
+ if 0 <= i < len(images):
1391
+ filepath = os.path.abspath(os.path.join(folder, images[i]))
1392
+ view_with_w3m(f"file://{filepath}", images[i])
1393
+ CACHED_IMAGES.append({
1394
+ 'title': images[i],
1395
+ 'image': f"file://{filepath}",
1396
+ 'thumbnail': f"file://{filepath}"
1397
+ })
1398
+ elif view_opt.lower() == 'c':
1399
+ idx = input(f"Add to cache # (1-{len(images)}): ").strip()
1400
+ if idx.isdigit():
1401
+ i = int(idx) - 1
1402
+ if 0 <= i < len(images):
1403
+ filepath = os.path.join(folder, images[i])
1404
+ CACHED_IMAGES.append({
1405
+ 'title': images[i],
1406
+ 'image': f"file://{os.path.abspath(filepath)}",
1407
+ 'thumbnail': f"file://{os.path.abspath(filepath)}"
1408
+ })
1409
+ print(f"Added to cache: {images[i]}")
1410
+ elif view_opt.lower() == 'p' and allow_upload:
1411
+ img_idx = input(f"Image # (1-{len(images)}): ").strip()
1412
+ if img_idx.isdigit():
1413
+ i = int(img_idx) - 1
1414
+ if 0 <= i < len(images):
1415
+ msg = input("Message: ").strip()
1416
+ where = input("Post to: 1=FB, 2=Tumblr, 3=Both: ").strip() or "3"
1417
+ fp = os.path.abspath(os.path.join(folder, images[i]))
1418
+ if where in ('1', '3'):
1419
+ fb_post_image_file(fp, msg)
1420
+ if where in ('2', '3'):
1421
+ tumblr_post_photo('', msg, tags_list=None, local_file=fp)
1364
1422
  else:
1365
1423
  print("No images found.")
1366
1424
 
@@ -1371,16 +1429,112 @@ def view_image(filename):
1371
1429
  else:
1372
1430
  print(f"File not found: {filename}")
1373
1431
 
1374
- def list_videos():
1432
+ def list_videos(path='.'):
1375
1433
  import os
1376
- videos = [f for f in os.listdir('.') if f.lower().endswith(('.mp4', '.mkv', '.avi', '.webm', '.mov'))]
1434
+ folder = path if path != '.' else os.getcwd()
1435
+ if not os.path.isdir(folder):
1436
+ print(f"Folder not found: {folder}")
1437
+ return
1438
+ videos = [f for f in os.listdir(folder) if f.lower().endswith(('.mp4', '.mkv', '.avi', '.webm', '.mov'))]
1377
1439
  if videos:
1378
- print("Videos:")
1440
+ print(f"Videos in {folder}:")
1379
1441
  for i, f in enumerate(videos):
1380
1442
  print(f" {i+1}. {f}")
1443
+ idx = input(f"\nOpen video # (1-{len(videos)}) or Enter to skip: ").strip()
1444
+ if idx.isdigit():
1445
+ i = int(idx) - 1
1446
+ if 0 <= i < len(videos):
1447
+ filepath = os.path.abspath(os.path.join(folder, videos[i]))
1448
+ print(f"Opening {videos[i]}...")
1449
+ open_in_browser(f"file://{filepath}")
1450
+ CACHED_VIDEOS.append({
1451
+ 'title': videos[i],
1452
+ 'url': f"file://{filepath}"
1453
+ })
1381
1454
  else:
1382
1455
  print("No videos found.")
1383
1456
 
1457
+ def list_text_files(path='.', add_to_cache=True, allow_post=True):
1458
+ import os
1459
+ folder = path if path != '.' else os.getcwd()
1460
+ if not os.path.isdir(folder):
1461
+ print(f"Folder not found: {folder}")
1462
+ return
1463
+ texts = [f for f in os.listdir(folder) if f.lower().endswith(('.txt', '.md', '.html', '.json', '.xml'))]
1464
+ if texts:
1465
+ print(f"Text files in {folder}:")
1466
+ for i, f in enumerate(texts):
1467
+ print(f" {i+1}. {f}")
1468
+ if add_to_cache:
1469
+ idx = input(f"\nAdd to text cache # (1-{len(texts)}) or Enter to skip: ").strip()
1470
+ if idx.isdigit():
1471
+ i = int(idx) - 1
1472
+ if 0 <= i < len(texts):
1473
+ filepath = os.path.join(folder, texts[i])
1474
+ try:
1475
+ with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
1476
+ content = f.read()
1477
+ ai_texts.append({
1478
+ 'text': content,
1479
+ 'source': 'file',
1480
+ 'filename': texts[i],
1481
+ 'timestamp': time.strftime('%Y-%m-%d %H:%M:%S')
1482
+ })
1483
+ print(f"Added to text cache: {texts[i]}")
1484
+ except Exception as e:
1485
+ print(f"Error reading file: {e}")
1486
+ if allow_post:
1487
+ opt = input("Post this text? (y/n): ").strip().lower()
1488
+ if opt == 'y':
1489
+ num = input("Which # to post: ").strip()
1490
+ if num.isdigit():
1491
+ i = int(num) - 1
1492
+ if 0 <= i < len(texts):
1493
+ filepath = os.path.join(folder, texts[i])
1494
+ caption = input("Caption: ").strip()
1495
+ where = input("Post to: 1=FB, 2=Tumblr, 3=Both: ").strip() or "3"
1496
+ content = convert_text_for_upload(filepath)
1497
+ if where in ('1', '3'):
1498
+ fb_post_text(content if content else caption)
1499
+ if where in ('2', '3'):
1500
+ tumblr_post_text(texts[i], content or caption)
1501
+ else:
1502
+ print("No text files found.")
1503
+
1504
+ def convert_text_for_upload(filepath):
1505
+ import os, re
1506
+ ext = filepath.rsplit('.', 1)[-1].lower()
1507
+ ansi_escape = re.compile(r'\x1b\[[0-9;]*[A-Za-z]')
1508
+ def strip_ansi(text):
1509
+ return ansi_escape.sub('', text)
1510
+ if ext in ('html', 'htm'):
1511
+ try:
1512
+ with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
1513
+ content = f.read()
1514
+ from bs4 import BeautifulSoup
1515
+ soup = BeautifulSoup(content, 'html.parser')
1516
+ return strip_ansi(soup.get_text(separator='\n', strip=True))
1517
+ except:
1518
+ return None
1519
+ elif ext == 'json':
1520
+ try:
1521
+ import json
1522
+ with open(filepath, 'r', encoding='utf-8') as f:
1523
+ data = json.load(f)
1524
+ return json.dumps(data, indent=2)
1525
+ except:
1526
+ return None
1527
+ elif ext == 'xml':
1528
+ try:
1529
+ import xml.etree.ElementTree as ET
1530
+ tree = ET.parse(filepath)
1531
+ return strip_ansi(ET.tostring(tree.getroot(), encoding='unicode'))
1532
+ except:
1533
+ return None
1534
+ else:
1535
+ with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
1536
+ return strip_ansi(f.read())
1537
+
1384
1538
  def open_url(url):
1385
1539
  open_in_browser(url)
1386
1540
 
@@ -1528,7 +1682,12 @@ VIEW:
1528
1682
  list - List cached images
1529
1683
  open - Open link in browser
1530
1684
  view - Open image in browser
1531
- videos - List/open videos
1685
+ lv - List YouTube results (with option to open)
1686
+
1687
+ LOCAL FILES:
1688
+ li - List images from folder (add to cache/post)
1689
+ ltxt - List text files (add to cache/post)
1690
+ lvv - List local videos
1532
1691
 
1533
1692
  POSTING (Facebook):
1534
1693
  fbpost - Post text
@@ -1570,6 +1729,29 @@ OTHER:
1570
1729
  """)
1571
1730
 
1572
1731
  def scmpy_main():
1732
+ required_deps = ['requests', 'requests_oauthlib', 'beautifulsoup4', 'lxml', 'PIL']
1733
+ missing = []
1734
+ for dep in required_deps:
1735
+ try:
1736
+ __import__(dep)
1737
+ except ImportError:
1738
+ missing.append(dep)
1739
+ if missing:
1740
+ print("\n=== Missing Dependencies ===")
1741
+ for dep in missing:
1742
+ print(f" - {dep}")
1743
+ print("\nInstall now? [Y/n]: ", end='', flush=True)
1744
+ try:
1745
+ resp = input().strip().lower()
1746
+ except:
1747
+ resp = 'y'
1748
+ if resp in ['', 'y', 'yes']:
1749
+ import subprocess
1750
+ for dep in missing:
1751
+ print(f"Installing {dep}...")
1752
+ subprocess.run([sys.executable, '-m', 'pip', 'install', dep], capture_output=True)
1753
+ else:
1754
+ print("Some features may not work.")
1573
1755
  load_history()
1574
1756
  show_help = True
1575
1757
 
@@ -1696,26 +1878,23 @@ Type 'h' for help, 'x' to exit
1696
1878
  else:
1697
1879
  print("No images to view!")
1698
1880
 
1699
- elif choice in ['videos', 'vid', 'youtubes']:
1881
+ elif choice in ['li', 'limg', 'localimg']:
1882
+ path = input("Folder (default .): ").strip() or "."
1883
+ list_images(path, add_to_cache=True, allow_upload=True)
1884
+
1885
+ elif choice in ['ltxt', 'txtfiles', 'localtxt']:
1886
+ path = input("Folder (default .): ").strip() or "."
1887
+ list_text_files(path, add_to_cache=True, allow_post=True)
1888
+
1889
+ elif choice in ['lvv', 'lvid', 'localvid']:
1890
+ path = input("Folder (default .): ").strip() or "."
1891
+ list_videos(path)
1892
+
1893
+ elif choice in ['videos', 'vid', 'youtubes', 'lv']:
1700
1894
  if CACHED_VIDEOS:
1701
- print("\nVideo options:")
1702
- print(" 1. List videos")
1703
- print(" 2. Open video in browser")
1704
- opt = input("Choose (1-2): ").strip()
1705
- if opt == '1':
1706
- display_videos()
1707
- elif opt == '2':
1708
- num = input(f"Video number (1-{len(CACHED_VIDEOS)}): ").strip()
1709
- try:
1710
- idx = int(num) - 1
1711
- if 0 <= idx < len(CACHED_VIDEOS):
1712
- url = CACHED_VIDEOS[idx].get('url', '')
1713
- print(f"Opening: {url}")
1714
- open_in_browser(url)
1715
- except:
1716
- print("Invalid")
1895
+ display_videos()
1717
1896
  else:
1718
- print("No videos searched yet!")
1897
+ print("No videos searched yet! Run 'yt' first.")
1719
1898
 
1720
1899
  elif choice in ['open', 'o', 'url', 'link']:
1721
1900
  if CACHED_LINKS:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mdcci
3
- Version: 2.2
3
+ Version: 2.4
4
4
  Summary: Extended LPro - MProcs simplified - A Life program by tderk, originally LPro.py and Destiny [2024]
5
5
  Author-email: tderk <usvu.tech@gmail.com>
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes