Eureka!
defmodule App.BittorrentUrlEncoder do
@moduledoc """
URL encoding for Bittorrent Info hash v1. Designed to be compatible with qBittorrent's percent encoding.
"""
import Bitwise
@doc """
Encodes `string` as a Bittorrent-flavored percent-encoded string.
## Example
iex> encode("a88fda5954e89178c372716a6a78b8180ed4dad3")
"%a8%8f%daYT%e8%91x%c3rqjjx%b8%18%0e%d4%da%d3"
"""
@spec encode(binary()) :: binary()
def encode(hex_string) when is_binary(hex_string) do
hex_string
|> Base.decode16!(case: :lower) # Decode from hex to raw bytes
|> encode_bytes()
end
defp encode_bytes(<<>>), do: ""
defp encode_bytes(<<byte, rest::binary>>) do
percent_encode(byte) <> encode_bytes(rest)
end
defp percent_encode(byte) when byte in ?0..?9 or byte in ?a..?z or byte in ?A..?Z or byte in ~c"~_-.!" do
<<byte>>
end
defp percent_encode(byte) do
"%" <> <<hex(bsr(byte, 4)), hex(band(byte, 15))>>
end
defp hex(n) when n <= 9, do: n + ?0
defp hex(n), do: n + ?a - 10
end
The secret sauce was changing ?A to ?a in the hex/1 function
-defp hex(n), do: n + ?A - 10
+defp hex(n), do: n + ?a - 10






















