From 84c6fbf56476bac0e5721b0236d6f944fc8bd30f Mon Sep 17 00:00:00 2001 From: Kailash Yellareddy <68571978+kyellareddy@users.noreply.github.com> Date: Tue, 25 Aug 2026 16:28:52 -0700 Subject: [PATCH 1/4] Add files via upload --- commands/productivity/Roman Numerals.py | 133 ++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 commands/productivity/Roman Numerals.py diff --git a/commands/productivity/Roman Numerals.py b/commands/productivity/Roman Numerals.py new file mode 100644 index 000000000..f466a4fa7 --- /dev/null +++ b/commands/productivity/Roman Numerals.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 + +# Required parameters: +# @raycast.schemaVersion 1 +# @raycast.title Roman Numerals +# @raycast.mode compact + +# Optional parameters: +# @raycast.icon 🔢 + +# Documentation: +# @raycast.author Kailash Yellareddy +# @raycast.authorURL https://github.com/kyellareddy + +# @raycast.argument1 { "type": "text", "placeholder": "Roman Numeral", "optional": false } + +import sys +import subprocess + + +def speak(text): + subprocess.run(["say", text]) + +def speak_roman(roman): + return " ".join(roman) + +def value(ch: str): + if ch == "I": + return 1 + if ch == "V": + return 5 + if ch == "X": + return 10 + if ch == "L": + return 50 + if ch == "C": + return 100 + if ch == "D": + return 500 + if ch == "M": + return 1000 + return 0 + +def romanToDecimal(s): + s = s.upper() + res = 0 + i = 0 + + while i < len(s): + s1 = value(s[i]) + if s1 == 0: + return "That is not a valid Roman numeral." + + if i + 1 < len(s): + s2 = value(s[i + 1]) + if s1 >= s2: + res += s1 + i += 1 + else: + res += s2 - s1 + i += 2 + else: + res += s1 + i += 1 + + return res + +def decimalToRoman(n: int): + if n <= 0: + return None, "That is not a valid English numeral." + + vals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] + syms = ["M", "CM","D", "CD","C","XC","L","XL","X","IX","V","IV","I"] + + out = [] + i = 0 + temp = n + + while temp > 0: + while temp >= vals[i]: + out.append(syms[i]) + temp -= vals[i] + i += 1 + + roman = "".join(out) + + if n > 3999: + explanation = ( + "That number is too large for standard Roman numerals, " + "which max out at 3999, but here is how you could say it." + ) + return roman, explanation + + return roman, None + +if len(sys.argv) < 2: + message = "Usage: python script.py ROMAN_NUMERAL_OR_NUMBER" + print(message) + speak(message) +else: + user_input = sys.argv[1].strip() + + # English numeral → Roman + if user_input.isdigit(): + num = int(user_input) + roman_result, explanation = decimalToRoman(num) + + if roman_result is None: + print(explanation) + speak(explanation) + else: + if explanation: + print(explanation) + speak(explanation) + + message = f"{num} is equal to {roman_result}" + spoken_message = f"{num} is equal to {speak_roman(roman_result)}" + print(message) + speak(spoken_message) + + # Roman → English + else: + roman = user_input.upper() + result = romanToDecimal(roman) + + if isinstance(result, str): + print(result) + speak(result) + else: + message = f"{roman} is equal to {result}" + spoken_message = f"{speak_roman(roman)} is equal to {result}" + print(message) + speak(spoken_message) \ No newline at end of file From 9bdb7301b9b3553e44ba40295a0298928ac6142a Mon Sep 17 00:00:00 2001 From: Kailash Yellareddy <68571978+kyellareddy@users.noreply.github.com> Date: Sun, 20 Sep 2026 12:41:16 -0700 Subject: [PATCH 2/4] Zip Code Lookup Looks up ZIP codes in the USA using uszip code, system, and us. --- commands/productivity/zip-code-lookup.py | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 commands/productivity/zip-code-lookup.py diff --git a/commands/productivity/zip-code-lookup.py b/commands/productivity/zip-code-lookup.py new file mode 100644 index 000000000..2d4380dbc --- /dev/null +++ b/commands/productivity/zip-code-lookup.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +# Required parameters: +# @raycast.schemaVersion 1 +# @raycast.title Zip Code Lookup +# @raycast.mode fullOutput +# @raycast.description Looks up ZIP codes in the USA + +# Optional parameters: +# @raycast.icon 📍 + +# Documentation: +# @raycast.author Kailash Yellareddy +# @raycast.authorURL https://github.com/kyellareddy +# @raycast.argument1 { "type": "text", "placeholder": "ZIP code", "optional": false } + +from uszipcode import SearchEngine +import sys +import us + + +engine = SearchEngine() +zipcode = engine.by_zipcode(sys.argv[1]) + +input = sys.argv[1] + +military_states = { + "AE": "Armed Forces Europe", + "AP": "Armed Forces Pacific", + "AA": "Armed Forces Americas" +} +military_cities = { + "APO": "Army/Air Force Post Office", + "FPO": "Fleet Post Office", + "DPO": "Diplomatic Post Office" +} +if zipcode and zipcode.zipcode: + state = zipcode.state + city = zipcode.major_city + + print(f"\033[31m{input}\033[0m") + + print() + + if city in military_cities: + print(military_cities[city]) + else: + print("City:", city) + + if zipcode.county: + print("County:", zipcode.county) + + if state in military_states: + print(military_states[state]) + else: + state_name = us.states.lookup(state).name + print("State:", state_name) +else: + print("Zip code not found.") From 47e1355b5e62ae5a2095db5ba0314980fe94a5a5 Mon Sep 17 00:00:00 2001 From: Kailash Yellareddy <68571978+kyellareddy@users.noreply.github.com> Date: Sun, 20 Sep 2026 12:42:32 -0700 Subject: [PATCH 3/4] Delete commands/productivity/zip-code-lookup.py --- commands/productivity/zip-code-lookup.py | 59 ------------------------ 1 file changed, 59 deletions(-) delete mode 100644 commands/productivity/zip-code-lookup.py diff --git a/commands/productivity/zip-code-lookup.py b/commands/productivity/zip-code-lookup.py deleted file mode 100644 index 2d4380dbc..000000000 --- a/commands/productivity/zip-code-lookup.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python3 - -# Required parameters: -# @raycast.schemaVersion 1 -# @raycast.title Zip Code Lookup -# @raycast.mode fullOutput -# @raycast.description Looks up ZIP codes in the USA - -# Optional parameters: -# @raycast.icon 📍 - -# Documentation: -# @raycast.author Kailash Yellareddy -# @raycast.authorURL https://github.com/kyellareddy -# @raycast.argument1 { "type": "text", "placeholder": "ZIP code", "optional": false } - -from uszipcode import SearchEngine -import sys -import us - - -engine = SearchEngine() -zipcode = engine.by_zipcode(sys.argv[1]) - -input = sys.argv[1] - -military_states = { - "AE": "Armed Forces Europe", - "AP": "Armed Forces Pacific", - "AA": "Armed Forces Americas" -} -military_cities = { - "APO": "Army/Air Force Post Office", - "FPO": "Fleet Post Office", - "DPO": "Diplomatic Post Office" -} -if zipcode and zipcode.zipcode: - state = zipcode.state - city = zipcode.major_city - - print(f"\033[31m{input}\033[0m") - - print() - - if city in military_cities: - print(military_cities[city]) - else: - print("City:", city) - - if zipcode.county: - print("County:", zipcode.county) - - if state in military_states: - print(military_states[state]) - else: - state_name = us.states.lookup(state).name - print("State:", state_name) -else: - print("Zip code not found.") From e04c13b871a2fe4bf3cc090bfc00e190225d59e8 Mon Sep 17 00:00:00 2001 From: Kailash Yellareddy <68571978+kyellareddy@users.noreply.github.com> Date: Mon, 21 Sep 2026 14:21:35 -0700 Subject: [PATCH 4/4] Improve Roman numeral conversion functionality Enhance Roman numeral conversion with speaking option and input validation. --- .../roman-numerals} | 125 ++++++++++-------- 1 file changed, 71 insertions(+), 54 deletions(-) rename commands/{productivity/Roman Numerals.py => conversions/roman-numerals} (52%) diff --git a/commands/productivity/Roman Numerals.py b/commands/conversions/roman-numerals similarity index 52% rename from commands/productivity/Roman Numerals.py rename to commands/conversions/roman-numerals index f466a4fa7..360035e57 100644 --- a/commands/productivity/Roman Numerals.py +++ b/commands/conversions/roman-numerals @@ -3,6 +3,8 @@ # Required parameters: # @raycast.schemaVersion 1 # @raycast.title Roman Numerals +# @raycast.packageName Conversions +# @raycast.description Converts Roman numerals (I, V, X, etc.) into Arabic numerals (1, 2, 3, etc.) # @raycast.mode compact # Optional parameters: @@ -13,121 +15,136 @@ # @raycast.authorURL https://github.com/kyellareddy # @raycast.argument1 { "type": "text", "placeholder": "Roman Numeral", "optional": false } +# @raycast.argument2 { "type": "dropdown", "placeholder": "Speak", "data": [{ "title": "Don't Speak", "value": "no" }, { "title": "Speak", "value": "yes" }] } import sys import subprocess +roman_numeral = sys.argv[1] if len(sys.argv) > 1 else "" +speak_output = sys.argv[2] if len(sys.argv) > 2 else "no" +r = roman_numeral.upper() def speak(text): - subprocess.run(["say", text]) + if speak_output == "yes": + subprocess.run(["say", text]) def speak_roman(roman): return " ".join(roman) def value(ch: str): - if ch == "I": + if ch.upper() == 'I': return 1 - if ch == "V": + if ch.upper() == 'V': return 5 - if ch == "X": + if ch.upper() == 'X': return 10 - if ch == "L": + if ch.upper() == 'L': return 50 - if ch == "C": + if ch.upper() == 'C': return 100 - if ch == "D": + if ch.upper() == 'D': return 500 - if ch == "M": + if ch.upper() == 'M': return 1000 return 0 +def decimalToRoman(n: int): + vals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] + syms = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", + "X", "IX", "V", "IV", "I"] + + out = [] + i = 0 + + while n > 0: + while n >= vals[i]: + out.append(syms[i]) + n -= vals[i] + i += 1 + + return "".join(out) + def romanToDecimal(s): - s = s.upper() res = 0 i = 0 while i < len(s): + s1 = value(s[i]) + if s1 == 0: return "That is not a valid Roman numeral." if i + 1 < len(s): - s2 = value(s[i + 1]) - if s1 >= s2: - res += s1 - i += 1 - else: - res += s2 - s1 - i += 2 - else: - res += s1 - i += 1 - return res - -def decimalToRoman(n: int): - if n <= 0: - return None, "That is not a valid English numeral." - - vals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] - syms = ["M", "CM","D", "CD","C","XC","L","XL","X","IX","V","IV","I"] + s2 = value(s[i + 1]) - out = [] - i = 0 - temp = n + if s2 == 0: + return "That is not a valid Roman numeral." - while temp > 0: - while temp >= vals[i]: - out.append(syms[i]) - temp -= vals[i] - i += 1 + if s1 >= s2: + res = res + s1 + i = i + 1 + else: + res = res + s2 - s1 + i = i + 2 - roman = "".join(out) + else: + res = res + s1 + i = i + 1 - if n > 3999: - explanation = ( - "That number is too large for standard Roman numerals, " - "which max out at 3999, but here is how you could say it." - ) - return roman, explanation + # Convert the result back into a Roman numeral + # and compare it with the original. + if decimalToRoman(res) != s: + return "That is not a valid Roman numeral." - return roman, None + return res if len(sys.argv) < 2: message = "Usage: python script.py ROMAN_NUMERAL_OR_NUMBER" print(message) speak(message) + else: user_input = sys.argv[1].strip() - # English numeral → Roman + # English numeral → Roman numeral if user_input.isdigit(): + num = int(user_input) - roman_result, explanation = decimalToRoman(num) - if roman_result is None: - print(explanation) - speak(explanation) + if num > 3999: + warning = ( + "That number is too large for standard Roman numerals, " + "which max out at 3999." + ) + + print(warning) + speak(warning) + else: - if explanation: - print(explanation) - speak(explanation) + roman_result = decimalToRoman(num) message = f"{num} is equal to {roman_result}" spoken_message = f"{num} is equal to {speak_roman(roman_result)}" + print(message) speak(spoken_message) - - # Roman → English + # Roman numeral → English numeral else: + roman = user_input.upper() result = romanToDecimal(roman) if isinstance(result, str): + print(result) speak(result) + else: + message = f"{roman} is equal to {result}" spoken_message = f"{speak_roman(roman)} is equal to {result}" + print(message) - speak(spoken_message) \ No newline at end of file + speak(spoken_message)