copyparty-sfx.py is an SFX (self-extracting archive).
because copyparty is made to be as portable and flexible as possible, and because copyparty is really just a small and simple python module, there's many ways to obtain and run it depending on your circumstances:
uv tool run copyparty is niceWhich brings us to copyparty-sfx.py, in many ways the best option;
python copyparty-sfx.py and you have a partybut maybe the wall of binary garbage in the file looks a bit funny, so:
There's a tiny bit of python-code at the start (the unpacker) followed by a completely normal tar.gz archive (basically a .zip file) which contains a few python modules; everything necessary to run copyparty. That is, everything except for a python installation, which you probably already have.
In other words, this is not a form of obfuscation, just efficient packaging. If you want to manually extract the archive without running the python code at all, here's how:
# eof line\n (byte 0x0a / linefeed)# at start of each line?0 with \0 (byte 0x00 / nullbyte)?n with \n (byte 0x0a / linefeed)?r with \r (byte 0x0d / carriage-return)?? with ? (byte 0x3f / questionmark)tar -zvt or tar -zvxTrivia: The reason for the quirky questionmark escaping is that python doesn't allow nullbytes in comments, and comments have a max-length on older versions.
And here's a simple awk script which does just that; taking copyparty-sfx.py as input, streaming out the tar.gz within, and listing (zvt) the contents of that archive (replace zvt with zvx to extract):
cat copyparty-sfx.py | LC_ALL=C gawk '
/^# eof$/{o=1;next}
o{for(a=2;a<=length($0);a++){
c=substr($0,a,1)
if(c!="?"){printf"%s",c;continue}
switch(substr($0,++a,1)){
case"0":c=0;break
case"r":c=13;break
case"n":c=10;break
default:c=63;break
}printf"%c",c}}' | tar -zvt
(and before someone tries to give me a UUoC award, it's there to make it obvious what's going on)
the above explains how to extract copyparty-sfx.py as the simple tar.gz that it is, but if you want to know how it was made, then docs/devnotes.md tells the whole story, starting from the completely normal source code in the git-repo (to the extent that we can call any of it "completely normal")
there's more info and better explanations in github issues #270 and #345 which haven't been added here yet