mirror of
https://github.com/zhaarey/AppleMusicDecrypt.git
synced 2025-10-23 15:11:06 +00:00
feat: use device to get m3u8
This commit is contained in:
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
poetry run python -m pip install nuitka
|
poetry run python -m pip install nuitka
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
poetry run python -m nuitka main.py --assume-yes-for-downloads --standalone --follow-imports --include-data-dir=assets=assets --include-data-files=config.example.toml=config.toml --include-data-files=agent.js=agent.js --include-module=mitmproxy_windows --include-module=winloop
|
poetry run python -m nuitka main.py --assume-yes-for-downloads --standalone --follow-imports --include-data-dir=assets=assets --include-data-files=config.example.toml=config.toml --include-data-files=agent.js=agent.js --include-data-files=m3u8.js=m3u8.js --include-module=mitmproxy_windows --include-module=winloop
|
||||||
- name: Rename
|
- name: Rename
|
||||||
run: |
|
run: |
|
||||||
ren main.dist AppleMusicDecrypt
|
ren main.dist AppleMusicDecrypt
|
||||||
|
|||||||
25
m3u8.js
Normal file
25
m3u8.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
setTimeout(function () {
|
||||||
|
Java.performNow(function () {
|
||||||
|
var C3282k = Java.use("c.a.a.e.o.k");
|
||||||
|
var m7125s = C3282k.a().s();
|
||||||
|
var PurchaseRequest$PurchaseRequestPtr = Java.use("com.apple.android.storeservices.javanative.account.PurchaseRequest$PurchaseRequestPtr");
|
||||||
|
function getM3U8(adamID) {
|
||||||
|
var c3249t = Java.cast(m7125s, Java.use("c.a.a.e.k.t"));
|
||||||
|
var create = PurchaseRequest$PurchaseRequestPtr.create(c3249t.n.value)
|
||||||
|
create.get().setProcessDialogActions(true)
|
||||||
|
create.get().setURLBagKey("subDownload")
|
||||||
|
create.get().setBuyParameters(`salableAdamId=${adamID}&price=0&pricingParameters=SUBS&productType=S`)
|
||||||
|
create.get().run()
|
||||||
|
var response = create.get().getResponse()
|
||||||
|
if (response.get().getError().get() == null){
|
||||||
|
var item = response.get().getItems().get(0)
|
||||||
|
var assets = item.get().getAssets()
|
||||||
|
var size = assets.size()
|
||||||
|
return assets.get(size - 1).get().getURL()
|
||||||
|
} else {
|
||||||
|
return response.get().getError().get().errorCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rpc.exports = {"getm3u8": getM3U8}
|
||||||
|
})
|
||||||
|
}, 8000)
|
||||||
21
src/adb.py
21
src/adb.py
@@ -42,6 +42,7 @@ class Device:
|
|||||||
suMethod: str
|
suMethod: str
|
||||||
decryptLock: asyncio.Lock
|
decryptLock: asyncio.Lock
|
||||||
hyperDecryptDevices: list[HyperDecryptDevice] = []
|
hyperDecryptDevices: list[HyperDecryptDevice] = []
|
||||||
|
m3u8Script: frida.core.Script
|
||||||
|
|
||||||
def __init__(self, host="127.0.0.1", port=5037, su_method: str = "su -c"):
|
def __init__(self, host="127.0.0.1", port=5037, su_method: str = "su -c"):
|
||||||
self.client = AdbClient(host, port)
|
self.client = AdbClient(host, port)
|
||||||
@@ -49,6 +50,18 @@ class Device:
|
|||||||
self.host = host
|
self.host = host
|
||||||
self.decryptLock = asyncio.Lock()
|
self.decryptLock = asyncio.Lock()
|
||||||
|
|
||||||
|
async def get_m3u8(self, adam_id: str):
|
||||||
|
try:
|
||||||
|
result: str = await self.m3u8Script.exports_async.getm3u8(adam_id)
|
||||||
|
except frida.core.RPCException:
|
||||||
|
# The script takes 8 seconds to start.
|
||||||
|
# If the script does not start when the function is called, wait 8 seconds and call again.
|
||||||
|
await asyncio.sleep(8)
|
||||||
|
result: str = await self.m3u8Script.exports_async.getm3u8(adam_id)
|
||||||
|
if result.isdigit():
|
||||||
|
return None
|
||||||
|
return result
|
||||||
|
|
||||||
def connect(self, host: str, port: int):
|
def connect(self, host: str, port: int):
|
||||||
try:
|
try:
|
||||||
status = self.client.remote_connect(host, port)
|
status = self.client.remote_connect(host, port)
|
||||||
@@ -96,6 +109,10 @@ class Device:
|
|||||||
self.fridaDevice = frida.get_device_manager().get_device(self.device.serial)
|
self.fridaDevice = frida.get_device_manager().get_device(self.device.serial)
|
||||||
self.pid = self.fridaDevice.spawn("com.apple.android.music")
|
self.pid = self.fridaDevice.spawn("com.apple.android.music")
|
||||||
self.fridaSession = self.fridaDevice.attach(self.pid)
|
self.fridaSession = self.fridaDevice.attach(self.pid)
|
||||||
|
with open("m3u8.js", "r") as f:
|
||||||
|
m3u8_script = f.read()
|
||||||
|
self.m3u8Script = self.fridaSession.create_script(m3u8_script)
|
||||||
|
self.m3u8Script.load()
|
||||||
script: frida.core.Script = self.fridaSession.create_script(agent)
|
script: frida.core.Script = self.fridaSession.create_script(agent)
|
||||||
script.load()
|
script.load()
|
||||||
self.fridaDevice.resume(self.pid)
|
self.fridaDevice.resume(self.pid)
|
||||||
@@ -172,6 +189,10 @@ class Device:
|
|||||||
self.fridaDevice = frida.get_device_manager().get_device(self.device.serial)
|
self.fridaDevice = frida.get_device_manager().get_device(self.device.serial)
|
||||||
self.pid = self.fridaDevice.spawn("com.apple.android.music")
|
self.pid = self.fridaDevice.spawn("com.apple.android.music")
|
||||||
self.fridaSession = self.fridaDevice.attach(self.pid)
|
self.fridaSession = self.fridaDevice.attach(self.pid)
|
||||||
|
with open("m3u8.js", "r") as f:
|
||||||
|
m3u8_script = f.read()
|
||||||
|
self.m3u8Script = self.fridaSession.create_script(m3u8_script)
|
||||||
|
self.m3u8Script.load()
|
||||||
for port in ports:
|
for port in ports:
|
||||||
self._start_forward(port, port)
|
self._start_forward(port, port)
|
||||||
with open("agent.js", "r") as f:
|
with open("agent.js", "r") as f:
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ async def rip_song(song: Song, auth_params: GlobalAuthParams, codec: str, config
|
|||||||
if not specified_m3u8 and not song_data.attributes.extendedAssetUrls.enhancedHls:
|
if not specified_m3u8 and not song_data.attributes.extendedAssetUrls.enhancedHls:
|
||||||
logger.error(f"Failed to download song: {song_metadata.artist} - {song_metadata.title}. Lossless audio does not exist")
|
logger.error(f"Failed to download song: {song_metadata.artist} - {song_metadata.title}. Lossless audio does not exist")
|
||||||
return
|
return
|
||||||
|
if not specified_m3u8:
|
||||||
|
device_m3u8 = await device.get_m3u8(song.id)
|
||||||
|
if device_m3u8:
|
||||||
|
specified_m3u8 = device_m3u8
|
||||||
|
logger.info(f"Use m3u8 from device for song: {song_metadata.artist} - {song_metadata.title}")
|
||||||
if specified_m3u8:
|
if specified_m3u8:
|
||||||
song_uri, keys, codec_id = await extract_media(specified_m3u8, codec, song_metadata,
|
song_uri, keys, codec_id = await extract_media(specified_m3u8, codec, song_metadata,
|
||||||
config.download.codecPriority,
|
config.download.codecPriority,
|
||||||
|
|||||||
Reference in New Issue
Block a user