重磅!python获取同步输出的桌面网易云音乐歌词(内存偏移获取)

重磅!python获取同步输出的桌面网易云音乐歌词(内存偏移获取)

最喜欢研究跟音乐相关的东西了,就像有的人爱喝酒吗,我离不开音乐,撸代码的时候,来点音乐,状态飙升,就跟晚上有人喜欢自己买点花生米小酌一下。

一直想做一个歌词输出的屏幕,心里暗暗合计了好一阵了,无非大致有如下几种思路:

一、买个副屏,显卡可识别的那种,然后把显示歌词的小窗拖过去即可,这种方法最简单,但是成本较高;

二、自己做个音乐播放器,就可以随便想怎么输出歌词了,这种方法工作量太大,需要自己用pyqt写个音乐播放器,我又有强迫症,界面太丑不干,得花费好一阵;

三、想办法获取电脑桌面歌词,输出到单片机,这种方法比较好,但是技术要求高一些,还是想采用这种方法。

如何获取电脑屏幕上的歌词呢?

最先想到的,截图,然后获取直接OCR。。。太笨而且费资源,然后看到python其实可以操作内存,有人用python写了植物大战僵尸的修改器,受到启发,直接通过查找内存找到歌词,然后随便怎么输出都行了。

奥里给,开始干,没想到网上有用的资料太少,然后自己汇编、内存了解的比较少,这一做就是一整天,好在终于搞定了。

首先,任何数据都在内存里,最直观的就是游戏数据,血量,金钱之类的,小时候应该很多人都用过金山游侠修改数据,就是那套原理,那么歌词作为文本,也是数据,为啥我不找找呢,于是搞了个CE打法,先显示英文的歌词,一直查找第一位字母的ASCII码,果然找到了,歌词不是什么敏感数据,一般也不会加密之类的,所以很典型很顺畅的找到了。

然后,网上教程说用OD去找偏移量,其实CE也可以搞定,一顿顺腾摸瓜,最最最重要的偏移量他来了,上图:

可以很清楚看到实时显示歌词的地址是怎么来的,从cloudmusic.dll的基址开始,经过三次偏移得道,当然最后一次是0,可以不用算。

原理知道了,愣着干嘛,一顿操作如虎,搞定了,这里,网易云音乐歌词的规则也被我看出来了,每个字,不管是英文还是中文,都占用两个bytes,中文用的是unicode编码,两个字符高低位反过来,如原来是\x34\x12就变成u1234,就行了,这里网上居然没找到现成的转换方式,网上找点有点的东西是真的费劲。。。于是自己手动写了坨屎山,转换了。英文就是\x00接ascii吗,如果遇到连续两个\x00\x00视为词句歌词结束,现在规则全看不透了,搞定。

这样就做好了,感觉干了件大事,网上没有相关资料代码,全靠自己摸索哦

上代码:

#2022-10-15 by jd3096 vx:jd3096

import pymem

import time

import socket

import win32process

from win32con import PROCESS_ALL_ACCESS

import win32api

import ctypes

from win32gui import FindWindow

def GetProcssID(address,bufflength):

pid = ctypes.c_ulong()

kernel32 = ctypes.windll.LoadLibrary("kernel32.dll")

hwnd = FindWindow("DesktopLyrics", u"桌面歌词")#获取窗口句柄

hpid, pid = win32process.GetWindowThreadProcessId(hwnd)#获取窗口ID

hProcess = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid)#获取进程句柄

ReadProcessMemory = kernel32.ReadProcessMemory

addr = ctypes.c_ulong()

ReadProcessMemory(int(hProcess), address, ctypes.byref(addr), bufflength, None)#读内存

win32api.CloseHandle(hProcess)#关闭句柄

return addr.value

def Get_moduladdr(dll): #找到dll的内存基址

modules = list(Game.list_modules())

for module in modules:

if module.name == dll:

Moduladdr = module.lpBaseOfDll

return Moduladdr

def get_add(): #从基址加偏移量反复三次得到实际内存地址

Char_Modlue = Get_moduladdr("cloudmusic.dll")

addr = GetProcssID((Char_Modlue + 0xAF7C44),4)

ret = addr + 0xc8

ret2 = GetProcssID(ret, 4)

ret3 = ret2 + 0x14

ret4 = GetProcssID(ret3, 4)

print (hex(ret4))

return ret4

Game = pymem.Pymem("cloudmusic.exe")

lyrics_addr=get_add()#实际内存地址

lyrics_len=200

last_lyrics=b''

def B2Q(uchar):

"""单个字符 半角转全角"""

inside_code = ord(uchar)

if inside_code < 0x0020 or inside_code > 0x7e: # 不是半角字符就返回原来的字符

return uchar

if inside_code == 0x0020: # 除了空格其他的全角半角的公式为: 半角 = 全角 - 0xfee0

inside_code = 0x3000

else:

inside_code += 0xfee0

return chr(inside_code)

def stringB2Q(ustring):

"""把字符串强行全角"""

return "".join([B2Q(uchar) for uchar in ustring])

def b2u(b): #bytes转unicode方法 我感觉应该有现成的函数,就是找不到好气,只能写了坨屎山凑合用

length=len(b)

sr=''

for i in range(0,length,2):

b0=hex(b[i])

b1=hex(b[i+1])

if b0=='0x0': #第一位如果是0说明不是中文,中文占2bytes

s1=chr(b[i+1])

sr+=s1

else:

if len(b0)==4:

s0=str(b0[2:4])

else:

s0='0'+str(b0[3])

if len(b1)==4:

s1=str(b1[2:4])

else:

s1='0'+str(b1[2])

s=s0+s1

result=b'\x5c\x75'

for ss in s:

bb=ss.encode()

result+=bb

sr+=result.decode("unicode_escape")

return sr

def get_lyrics():

global last_lyrics

raw_bytes=Game.read_bytes(lyrics_addr,lyrics_len)

use_bytes=raw_bytes.split(b'\x00\x00')[0]

if len(use_bytes)%2==1:

use_bytes+=b'\x00'

lyrics_bytes=b''

for i in range(0,lyrics_len,2): #构建bytes 这里高低位需要调换一下顺序

b1=use_bytes[i:i+1]

b2=use_bytes[i+1:i+2]

lyrics_bytes+=b2+b1

if last_lyrics!=lyrics_bytes: #检查看词是否变化

last_lyrics=lyrics_bytes

return b2u(lyrics_bytes)

else:

return None

def sendto(lyric):

quan=stringB2Q(lyric)

data=quan.encode('gbk')

return data

# tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

# tcp_server.bind(("", 30960))

# tcp_server.listen(5)

# tcp_client, tcp_client_address= tcp_server.accept()

while True:

lyrics=get_lyrics()

if lyrics!=None:

print(lyrics)

data_send=sendto(lyrics)

#tcp_client.send(data_send)

time.sleep(0.1)

中间注释的部分就是可以通过tcp发送歌词数据到任意单片机上,老本行回归,也可以用串口,随便发挥,上俩做好的图:

K210 FFT加歌词输出

之前提到的中景园oled带字库那个屏幕,用TCP实现。

这次真的是爽爆了,完全实时同步,随便切歌,拉进度,歌词永远同步。

不过没有彻底完善,比如遇到日文韩文等显示不了,英文强行被我转GBK,很占地方,这个看心情再说吧哈哈哈,懂原理了什么时候解决都不急。

💫 相关推荐

走在全面失守边缘,“方便面鼻祖”做错了什么?
完美体育365平台官网

走在全面失守边缘,“方便面鼻祖”做错了什么?

📅 07-14 👀 2527
十大九游游戏排行榜2024
365不给提款怎么办

十大九游游戏排行榜2024

📅 07-13 👀 6313
UC所有历史版本大全
365bet手机投注

UC所有历史版本大全

📅 06-29 👀 1805
怎么卸载IE浏览器?强制卸载IE9/10/11实用方法(四种)
1 、关于 youtube-dl
365不给提款怎么办

1 、关于 youtube-dl

📅 07-11 👀 8403
周易第23卦详解
365不给提款怎么办

周易第23卦详解

📅 07-10 👀 5069
来吧,兄弟
完美体育365平台官网

来吧,兄弟

📅 07-11 👀 8487
电动车鼓刹片型号如何看?从没想到用卷尺也能知道刹车片型号
京东一起下单可以单独退一个吗?如何操作?2025最新退货操作指南