pip is a software package management system written in the Python computer programming language. It can install and manage software packages, with a simple command “pip”, you can get access to more then one hundred thousand of cool libraries, here I am going to show you how to upload your own code to PyPi and able to download with pip.
There are few step for you to develop your own package.
Prepare your code.
Create a PyPi account.
Prepare the files PyPi needs.
upload it to PyPi
pip install your package.
Upload it to github
Code
In here, I want to upload the class I wrote for research in the institute, If you are interested, It is a code for calculate the limit of TASEH(Taiwan Axion Search Experiment Haloscope).
Now, I wish my classes are all in a same package call ou_Axion_limit
# my expectation
from ou_Axion_limit import Glimit
from ou_Axion_limit import analyse
so first create a folder (Glimit), this folder will content every thing PyPi needs, and next create a floder name with your package name (ou_Axion_limit ), inside the folder you just created, and throw you python code inside.
__init__.py
Creata a file __init__.py inside the ou_Axion_limit
This file allows you to determine the classes that users can directly call and use, so in my cases, I can just import my class with following way.
# my expectation
from ou_Axion_limit import Glimit
from ou_Axion_limit import analyse
setup.py
The setup.py file contains the information that PyPi needed , such as its name, description, current version, etc. Copy and paste the following code and replace the string with the matching content:
CHANGELOG.txt
The changelog of you package
LICENSE.txt
Use this file to define all license details, you can use your own license, however, I will use MIT license
MANIFEST.in
Just a file use to include everything
README.md
A markdown file can make people understand your package better.
Upload it to PyPi
Everything is prepared, we can now upload it to PyPi.
First, goto you folder open cmd and tpye:
python setup.py sdist
If you see UserWarning: Unknown distribution option: ‘install_requires’, just ignore it.
It should create a file in dist folder
Next, we need twine for upload the package
pip install twine
Then, run the following command:
twine upload dist/{Generated_file}
You will be asked to provide your username and password. Provide your credentials you used to register with PyPi.
Congratulations, you successfully upload your packge to the PyPi, goto the website it gives you to see your package online.
Install your package
pip install YOURPACKAGENAME
Upload to github
For the fist time using git, we need to create a ssh-key to connect to github
Recently, youtube kill’s some of the most used music robots on discord, and other public ones may also be asked to be shut down, so today let us make our discord bot!!!
If you create the bot successfully, you should see it appear on your main page, just click it.
Go and copy your APPLICATION ID, and fill in this link:
https://discordapp.com/oauth2/authorize?&client_id=xxxxxxxxxxxxx&scope=bot&permissions=8 # replace xxxxx with you Id
with this link, you can invite it to your channel.
Step 2 : authorization token
Go to the “bot” and click “copy”, this will give you your Token
Step 3 : Start coding
Here, I’m will build the bot with python in windows, so you will need python on your computer
open cmd and download discord’s API
pip install discord.py
Open sublime and paste the following code to start a simple bot
save and open with cmd.
we know this is not enough…, we need a music bot, not a ping-pong idiot…, next, I will speed up and point out the difficulties and solutions I encountered.
Step 4 : A music bot
A normal music bot should be able to play youtube music and have the following functions.
play : Add a song or a playlist to the Queqe and invite the bot to the voice channel
pause : pause
skip : skip current song
list : show the playlist
clear : clear the playlist
loop : loop the playlist
leave : leave the voice channel
we define severals function that we want our music bot have.
Step 5 : Play a music
Let’s see how others play music
with this code we can understand how everything works, first, we need FFmpeg.
when a user types a play command, the code will get its message channel (ctx), and get the Author’s voice channel (channel), then with “channel.connect()” to connect the bot to the voice channel.
channel = ctx.message.author.voice.channel #this line will get the user's voice channel
voice = await channel.connect() # connect to the user's voice channel
voice.play(discord.FFmpegPCMAudio(song_path), after = lambda e: somefuciton())
# play the music , 'after' will run when the song is finish.
Step 6 : Create a class
you may ask: why do we need a class?
If our robot is to serve different servers, it means that there will be different ctx, channel, and voice, we also need to queue the songs of each channel, so the best choice is to create a class, each class serves a server.
class MusicBot:
def __init__(self,channel, voice , ctx):
self.music_msg = None # The message for current music
self.loop = False # Enable loop or not
self.live = True # Kill this Musicbot if self.live = False
self.channel = channel # Voice channel
self.channelid = channel.id # This Music serves channel Id
self.floder = "music" # Folder to store music
self.ctx = ctx # ctx
self.voice = voice # voice client
self.queqed = [] # music queqed for play
self.passed = [] # Played music
self.state = 0 # 0:not playing , 1:playing , 2:pause
self.rejoin_c = 0 # rejoin every 20 songs
self.dont_stop = 0 # will play untill dont_stop = 3 to check again
so I define a class that needs channel, voice, and ctx as input.
Step 7 : Download youtube music
we know we can use youtube_dl to download the music.
pip install youtube-dl
self.ytl = {
'format': '249/250/251',
"outtmpl" : f"{self.floder}/{this_song_name}",
'noplaylist': False
}
with youtube_dl.YoutubeDL(self.ytl) as ydl:
ydl.download([this_song_url])
But I think it is difficult to manage which songs the user has queued and youtube_dl will download the entire playlist before I play the music, of course, I can use a thread, But it is too complex.
So, I will use a youtube data API to grab the playlist’s songs and download one at a time and play it. the following is the youtube API code, however, I will not explain this code since our main character is a discord music bot.
with this API, I can write a function to add music to the queue
def add_thread(self,url):
print("[*] Adding rest in this thread ... ")
output = grab_playlist(url,50)
for each in output[10:50]:
self.queqed.append(each)
print("[*] Adding Thread done.")
print(f"[*] Qeuqed {len(self.queqed)} songs ->",self.channelid)
async def add(self,url):
print("[*]", url)
if ("list" in url):
print("[*] Adding a play list in", self.channelid)
output = grab_playlist(url,10)
for each in output[0:10]:
self.queqed.append(each)
threading.Thread(target = self.add_thread, args=(url,)).start()
else:
print("[*] Adding a single video in", self.channelid)
self.queqed.append((get_title(url),url))
print("\n[*]",self.channelid,"-> Enqueued :",len(self.queqed), "the remaining songs will continue add in the background")
if (self.state ==0):
self._next() # the play music function
add function can handle a video or a playlist, if it is a video, just add it directly, but if it is a playlist, I will first grab the first 10 videos, the rest will throw in a thread to continue, this is to speed up the time to start the song, otherwise, the user will feel impatient.
Play command
Users_class = {}
@client.command(brief="Play music (My wonderful singing )")
async def play(ctx, url : str):
if not ctx.message.author.voice:
await ctx.send('you are not connected to a voice channel')
return
else:
channel = ctx.message.author.voice.channel
if (channel.id in Users_class):
if ctx.guild.voice_client not in client.voice_clients:
await Users_class[channel.id].kill() # kill the music player
del Users_class[channel.id]
print("[*] rejoin the voice channel")
voice = await channel.connect()
MB = MusicBot(channel, voice , ctx)
Users_class[channel.id] = MB
await Users_class[channel.id].add(url)
else:
voice = await channel.connect()
MB = MusicBot(channel, voice , ctx)
print(f"[*] creating Class id : {id(MB)} for serving channel",channel.id)
Users_class[channel.id] = MB
await MB.add(url)
In play command, I will create the music bot class and save the class to a dictionary by using channel id as the key.
# play next music
async def _next(self):
if (len(self.queqed) == 0):
if (self.loop): # refill the music queqed for play with Played music
self.queqed = self.passed
self.passed = []
else:
self.state = 0
return
self.state = 1 # State = 1 -> start playing
self.this_song = self.queqed.pop(0) # get the song
self.passed.append(self.this_song) # Store in history music
print("[*] playing :", self.this_song[0],"in", self.channelid)
this_song_url = self.this_song[1]
this_song_name = self.this_song[0]
# This for is beacuse the youtube_dl will change the filename
# when handling special char
for each_char in ['"', "'", ":", "|"]:
if (each_char in this_song_name):
this_song_name = this_song_name.replace(each_char,"#")
# youtube_dl will create a floder for \ and /
for each_char in ["\\", "/"]:
if (each_char in this_song_name):
this_song_name = this_song_name.replace(each_char,"")
song_path = os.path.join(self.floder , this_song_name)
# download youtube music
if ( not os.path.isfile(song_path)):
self.ytl = {
'format': '249/250/251',
"outtmpl" : f"{self.floder}/{this_song_name}",
'noplaylist': False,
}
self.dowloading = await self.ctx.send(f'... Downloading {this_song_name}')
print("[*] downloading ->", this_song_name,"\n")
with youtube_dl.YoutubeDL(self.ytl) as ydl:
ydl.download([this_song_url])
print("\n[*] ------------ download successful ------------")
# Check if bot is in the voice channel
if self.ctx.guild.voice_client not in client.voice_clients:
print("[*] get kicked from",self.channelid)
return
# send currently playing music
self.music_msg = await self.ctx.send(f':musical_note: Now playing ({len(self.passed)}/{len(self.queqed)+len(self.passed)}) : {this_song_name} :musical_note:')
###################### I will explian this later
FFMPEG_OPTS = {
'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
'options': '-vn'
}
self.rejoin_c += 1
if (self.rejoin_c == 10):
self.voice.play(
discord.FFmpegPCMAudio(song_path, **FFMPEG_OPTS),
after=lambda e: print("[*] reconnecting the ffmpeg , error : ",e)
)
self.rejoin_c = 0
await asyncio.sleep(5)
######################
# play the music, call _endsong when the song finish
self.voice.play(
discord.FFmpegPCMAudio(song_path),
after = lambda e: asyncio.run_coroutine_threadsafe(self._endsong(e), client.loop)
)
# check every three song
self.dont_stop +=1
if (self.dont_stop > 3):
client.loop.create_task(self.check())
This is a quite long function, but most of them are actually pretty easy to understand, except the FFMPEG_OPTS part, this part is to solve a known problem.
why python? Python is a programming language that lets you work more quickly and integrate your systems more effectively. <– (Introduction on the official website), and also my favorite language.
Here, I will show how to download python and run with Jupiter and Sublime
Lyto-Different-Color It’s basically a simple color recognition game, when I saw this game for the first time, I had the idea of using python and opencv to write this game assistant.
so first we need python, If you don’t know how to download python, you can go to this page
# select screen range
mon = {'top': 179, 'left': 706, 'width': 1214-706, 'height': 1080-179}
sct = mss()
sct.get_pixels(mon)
while True:
# transform the screen information to numpy array
img = np.array(Image.frombytes('RGB', (sct.width, sct.height), sct.image))
# show the screen via opencv
cv2.imshow('test', np.array(img))
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
I want the program to find the ball in the screen first, and then get the color of the center of the ball, so that it can find the ball with a different color, there is a funcction in opencv, call HoughCircles, it can help us to find the circle in the image.
The usage is very simple, just throw the image into the function, well… and some parameters
# transform the image into gray scale to speed up the calculation
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Houghcircles
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT,1.2,10)
# circles will be something likes
# [(x1, y1, r1),(x1, y1, r1) ...]
# where x1 y1 is the position of circle's center and r is the radius
with circle’s center, we can get correspondging color
color = []
# loop every circle
for (x, y, r) in circles:
# store the circle's center color into 'colors'
colors.append(list(img[y,x,:]))
I write a function to find the different one, (there must be a better way of writing, but I only use a very dumb way)
def find_different(arr):
for num,i in enumerate(arr):
if (arr.count(i)==1):
return num
else:
return 0
At this point, we are done. All we need is to put them all together and draw the balls of different colors.