From d209d39e2e1e0d3fb27ed00768f009a39c4e952b Mon Sep 17 00:00:00 2001 From: probonopd Date: Fri, 25 Apr 2025 22:51:55 +0200 Subject: [PATCH 1/4] Remove [L] if PerformanceSelectToLoad=0 (the new default) (#887) Closes #718 --- src/uimenu.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index dabea87..1475342 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1572,9 +1572,11 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) } std::string Value; - if (Event == MenuEventUpdate) + if (Event == MenuEventUpdate || Event == MenuEventUpdateParameter) { pUIMenu->m_bPerformanceDeleteMode=false; + // Ensure selected performance matches the actual loaded one + pUIMenu->m_nSelectedPerformanceID = pUIMenu->m_pMiniDexed->GetActualPerformanceID(); } if (pUIMenu->m_bSplashShow) @@ -1703,7 +1705,7 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) nPPerf = nPPerf.substr(nPPerf.length()-3,3); nPSelected += ":"+nPPerf; - if(nValue == pUIMenu->m_pMiniDexed->GetActualPerformanceID()) + if(bPerformanceSelectToLoad && nValue == pUIMenu->m_pMiniDexed->GetActualPerformanceID()) { nPSelected += " [L]"; } @@ -1791,7 +1793,7 @@ void CUIMenu::EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) nPSelected += std::to_string(nValue+1); // Convert to user-facing number rather than index nPSelected = nPSelected.substr(nPSelected.length()-3,3); - if(nValue == (unsigned)pUIMenu->m_pMiniDexed->GetParameter (CMiniDexed::ParameterPerformanceBank)) + if(bPerformanceSelectToLoad && nValue == (unsigned)pUIMenu->m_pMiniDexed->GetParameter (CMiniDexed::ParameterPerformanceBank)) { nPSelected += " [L]"; } From ce6c79adbfca2a0fe585ca4e31e7bf24c2bd6ed6 Mon Sep 17 00:00:00 2001 From: probonopd Date: Fri, 25 Apr 2025 23:06:51 +0200 Subject: [PATCH 2/4] Publish TXT record on FTP service, only show MiniDexed FTP servers in updater --- src/minidexed.cpp | 8 +++++--- updater.py | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 134d241..1e925ed 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -833,7 +833,7 @@ void CMiniDexed::SetMIDIChannel (uint8_t uchChannel, unsigned nTG) assert (nActiveTGs <= 8); static const unsigned Log2[] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; - m_nActiveTGsLog2 = Log2[nActiveTGs]; + m_nActiveTGsLog2 = Log2[nActiveTGs]; */ #endif @@ -2334,7 +2334,8 @@ void CMiniDexed::UpdateNetwork() } static constexpr const char *ServiceTypeFTP = "_ftp._tcp"; - if (!m_pmDNSPublisher->PublishService (m_pConfig->GetNetworkHostname(), ServiceTypeFTP, 21)) + static const char *ftpTxt[] = { "app=MiniDexed", nullptr }; + if (!m_pmDNSPublisher->PublishService (m_pConfig->GetNetworkHostname(), ServiceTypeFTP, 21, ftpTxt)) { LOGPANIC ("Cannot publish mdns service"); } @@ -2384,7 +2385,8 @@ void CMiniDexed::UpdateNetwork() } static constexpr const char *ServiceTypeFTP = "_ftp._tcp"; - if (!m_pmDNSPublisher->PublishService (m_pConfig->GetNetworkHostname(), ServiceTypeFTP, 21)) + static const char *ftpTxt[] = { "app=MiniDexed", nullptr }; + if (!m_pmDNSPublisher->PublishService (m_pConfig->GetNetworkHostname(), ServiceTypeFTP, 21, ftpTxt)) { LOGPANIC ("Cannot publish mdns service"); } diff --git a/updater.py b/updater.py index 3307417..311b886 100644 --- a/updater.py +++ b/updater.py @@ -36,10 +36,18 @@ class MyListener(ServiceListener): info = zc.get_service_info(type_, name) print(f"Service {name} added, service info: {info}") if info and info.addresses: - ip = socket.inet_ntoa(info.addresses[0]) - if ip not in self.ip_list: - self.ip_list.append(ip) - self.name_list.append(info.server.rstrip('.')) + # Only add if TXT record contains 'MiniDexed' + txt_records = info.properties + if txt_records: + for k, v in txt_records.items(): + # v may be bytes, decode if needed + val = v.decode() if isinstance(v, bytes) else v + if (b"MiniDexed" in k or b"MiniDexed" in v) or ("MiniDexed" in str(k) or "MiniDexed" in str(val)): + ip = socket.inet_ntoa(info.addresses[0]) + if ip not in self.ip_list: + self.ip_list.append(ip) + self.name_list.append(info.server.rstrip('.')) + break # Constants From 988f08c36da61f758c9d0bf5cf09dca16c923c80 Mon Sep 17 00:00:00 2001 From: probonopd Date: Sat, 26 Apr 2025 00:26:20 +0200 Subject: [PATCH 3/4] Suppress expected timeout after BYE [ci skip] --- updater.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/updater.py b/updater.py index 311b886..2180fb8 100644 --- a/updater.py +++ b/updater.py @@ -327,7 +327,15 @@ if __name__ == "__main__": with open(local_path, 'rb') as f: ftp.storbinary(f'STOR {remote_path}', f, 8192, callback=progress_callback) print(f"\nUploaded {file} to {selected_ip}.") + except ftplib.all_errors as e: + print(f"FTP error: {e}") + + try: ftp.sendcmd("BYE") print(f"Disconnected from {selected_ip}.") except ftplib.all_errors as e: - print(f"FTP error: {e}") + if str(e).strip().lower() == "timed out": + # Suppress expected timeout after BYE + print(f"Disconnected from {selected_ip}.") + else: + print(f"FTP error after BYE: {e}") From 778d6846be56b458f4f0254a68841eb4f2b6fb6b Mon Sep 17 00:00:00 2001 From: probonopd Date: Sat, 26 Apr 2025 01:50:13 +0200 Subject: [PATCH 4/4] Support --ip and --version command line options and -h/--help [ci skip] --- updater.py | 82 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/updater.py b/updater.py index 2180fb8..a88228c 100644 --- a/updater.py +++ b/updater.py @@ -90,6 +90,8 @@ def extract_zip(zip_path): if __name__ == "__main__": parser = argparse.ArgumentParser(description="MiniDexed Updater") parser.add_argument("-v", action="store_true", help="Enable verbose FTP debug output") + parser.add_argument("--ip", type=str, help="IP address of the device to upload to (skip mDNS discovery)") + parser.add_argument("--version", type=int, choices=[1,2,3], help="Version to upload: 1=Latest official, 2=Continuous, 3=Local build (skip prompt)") args = parser.parse_args() import time @@ -105,16 +107,24 @@ if __name__ == "__main__": ] if has_local_build: release_options.append(("Local build (from src/)", None)) - print("Which release do you want to update?") - for idx, (desc, _) in enumerate(release_options): - print(f" [{idx+1}] {desc}") - while True: - choice = input(f"Enter the number of your choice (1-{len(release_options)}): ").strip() - if choice.isdigit() and 1 <= int(choice) <= len(release_options): - selected_idx = int(choice)-1 - github_url = release_options[selected_idx][1] - break - print("Invalid selection. Please enter a valid number.") + + if args.version: + selected_idx = args.version - 1 + if selected_idx < 0 or selected_idx >= len(release_options): + print(f"Invalid version selection: {args.version}") + sys.exit(1) + github_url = release_options[selected_idx][1] + else: + print("Which release do you want to update?") + for idx, (desc, _) in enumerate(release_options): + print(f" [{idx+1}] {desc}") + while True: + choice = input(f"Enter the number of your choice (1-{len(release_options)}): ").strip() + if choice.isdigit() and 1 <= int(choice) <= len(release_options): + selected_idx = int(choice)-1 + github_url = release_options[selected_idx][1] + break + print("Invalid selection. Please enter a valid number.") # If local build is selected, skip all GitHub/zip logic and do not register cleanup use_local_build = has_local_build and selected_idx == len(release_options)-1 @@ -175,29 +185,35 @@ if __name__ == "__main__": # Using mDNS to find the IP address of the device(s) that advertise the FTP service "_ftp._tcp." ip_addresses = [] device_names = [] - zeroconf = Zeroconf() - listener = MyListener(ip_addresses, device_names) - browser = ServiceBrowser(zeroconf, "_ftp._tcp.local.", listener) - try: - print("Searching for devices...") - time.sleep(10) - if ip_addresses: - print("Devices found:") - for idx, (name, ip) in enumerate(zip(device_names, ip_addresses)): - print(f" [{idx+1}] {name} ({ip})") - while True: - selection = input(f"Enter the number of the device to upload to (1-{len(ip_addresses)}): ").strip() - if selection.isdigit() and 1 <= int(selection) <= len(ip_addresses): - selected_ip = ip_addresses[int(selection)-1] - selected_name = device_names[int(selection)-1] - break - print("Invalid selection. Please enter a valid number.") - else: - print("No devices found.") - sys.exit(1) - finally: - zeroconf.close() - print("Devices found:", list(zip(device_names, ip_addresses))) + selected_ip = None + selected_name = None + if args.ip: + selected_ip = args.ip + selected_name = args.ip + else: + zeroconf = Zeroconf() + listener = MyListener(ip_addresses, device_names) + browser = ServiceBrowser(zeroconf, "_ftp._tcp.local.", listener) + try: + print("Searching for devices...") + time.sleep(10) + if ip_addresses: + print("Devices found:") + for idx, (name, ip) in enumerate(zip(device_names, ip_addresses)): + print(f" [{idx+1}] {name} ({ip})") + while True: + selection = input(f"Enter the number of the device to upload to (1-{len(ip_addresses)}): ").strip() + if selection.isdigit() and 1 <= int(selection) <= len(ip_addresses): + selected_ip = ip_addresses[int(selection)-1] + selected_name = device_names[int(selection)-1] + break + print("Invalid selection. Please enter a valid number.") + else: + print("No devices found.") + sys.exit(1) + finally: + zeroconf.close() + print("Devices found:", list(zip(device_names, ip_addresses))) # Log into the selected device and upload the new version of MiniDexed print(f"Connecting to {selected_name} ({selected_ip})...")