diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5966153 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +.gitattributes export-ignore +.gitignore export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..20cb71e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/*.zip diff --git a/combomodule-pyi.py b/combomodule-pyi.py new file mode 100644 index 0000000..c2a5916 --- /dev/null +++ b/combomodule-pyi.py @@ -0,0 +1,182 @@ +import subprocess +import re +import time +import sqlite3 +import os +import requests + +def get_working_directory(): + # If you see this function, that means you are using the pyinstaller. Use this command to create the executable: + # pyinstaller -s -F combomodule-pyi.py --runtime-tmpdir /data/local/tmp + if os.path.exists("/sdcard/localwrapped"): + return "/sdcard/localwrapped" + elif os.path.exists("/storage/emulated/0/localwrapped"): + return "/storage/emulated/0/localwrapped" + elif os.path.exists("/data/media/0/localwrapped"): + return "/data/media/0/localwrapped" + elif os.path.exists("/mnt/user/0/emulated/0/localwrapped"): + return "/mnt/user/0/emulated/0/localwrapped" + else: + print("Path not found.") + try: + if os.path.exists("/sdcard"): + os.mkdir("/sdcard/localwrapped") + return "/sdcard/localwrapped" + else: + raise Exception + except: + try: + if os.path.exists("/storage/emulated/0"): + os.mkdir("/storage/emulated/0/localwrapped") + return "/storage/emulated/0/localwrapped" + else: + raise Exception + except: + try: + if os.path.exists("/data/media/0"): + os.mkdir("/data/media/0/localwrapped") + return "/data/media/0/localwrapped" + else: + raise Exception + except: + try: + if os.path.exists("/mnt/user/0/emulated/0"): + os.mkdir("/mnt/user/0/emulated/0/localwrapped") + return "/mnt/user/0/emulated/0/localwrapped" + else: + raise Exception + except: + print("Path not found and could not be created.") + exit() + +if not os.path.exists(f"{get_working_directory()}/key.txt"): + print("Key not exist") + exit() + +def get_verification_code(): + try: + with open(f"{get_working_directory()}/key.txt", "r") as f: + key = f.read() + try: + verifyrequest = requests.post(os.environ["MSSERVER"] + "/verifykey", json={"key": key}) + if verifyrequest.text == "0": + print("Verification failed") + return None + elif len(verifyrequest.text) == 64: + print("Verification success") + return verifyrequest.text + else: + print("Unexpected response") + return None + except: + print("Can't reach the server.") + return None + except: + print("Key not exist") + return None + +def get_music(): + dumpsys_output = subprocess.check_output("dumpsys media_session", shell=True).decode("utf-8").split("\n") + if not [line for line in dumpsys_output if "PLAYING" in line]: + return None + else: + description = [line for line in dumpsys_output if "description=" in line] + try: + return description[0].split("description=")[1] + except: + return None + +def get_db_values(url: str = "https://halhadus.rocks/assets/localwrapped/music.db"): + if not os.path.exists(get_working_directory() + "/music.db"): + try: + download = requests.get(url) + with open(get_working_directory() + "/music.db", "wb") as f: + f.write(download.content) + except: + print("Could not download the database.") + exit() + musicconn = sqlite3.connect(get_working_directory() + "/music.db") + musicc = musicconn.cursor() + musicc.execute("SELECT * FROM music") + musicrows = musicc.fetchall() + musicconn.close() + musicvalues = [] + for row in musicrows: + musicvalues.append({ + "listmusicname": row[0], + "fileartistname": row[4], + "filealbumname": row[5], + "filemusictitle": row[6] + }) + return musicvalues + +if not os.path.exists(get_working_directory() + "/count.db"): + countconn = sqlite3.connect(get_working_directory() + "/count.db") + countc = countconn.cursor() + countc.execute("CREATE TABLE count (musicname TEXT, count INTEGER)") + countconn.commit() + countconn.close() + +a = 0 +last_written = None +last_sent = None +resetstatus = "true" +while True: + if get_music() == None: + continue + last_music = get_music() + time.sleep(5) + if last_music == get_music(): + if last_written == last_music: + continue + a += 1 + if a >= 3: + for i in get_db_values(): + if i["filealbumname"] == None: + full_name = i["filemusictitle"] + ", " + i["fileartistname"] + ", " + "Music" + else: + full_name = i["filemusictitle"] + ", " + i["fileartistname"] + ", " + i["filealbumname"] + if full_name == last_music: + if a == 12: + countconn = sqlite3.connect(get_working_directory() + "/count.db") + countc = countconn.cursor() + countc.execute("SELECT * FROM count") + countdbrows = countc.fetchall() + countdbvalues = [] + for row in countdbrows: + countdbvalues.append({ + "musicname": row[0], + "count": row[1] + }) + if not [row for row in countdbvalues if row["musicname"] == i["listmusicname"]]: + countc.execute("INSERT INTO count VALUES (?, ?)", (i["listmusicname"], 1)) + countconn.commit() + countconn.close() + else: + countc.execute("UPDATE count SET count = count + 1 WHERE musicname = ?", (i["listmusicname"],)) + countconn.commit() + countconn.close() + print(f"Local Wrapped: {i['listmusicname']} has been played.") + os.system(f"echo {i['listmusicname']} has been played. >> /cache/magisk.log") + last_written = last_music + a = 0 + else: + if last_sent == i["listmusicname"]: + continue + try: + verificationcode = get_verification_code() + if verificationcode == None: + continue + requests.post(os.environ["MSSERVER"] + "/musicstatus.html", json={"music": i["listmusicname"], "time": str(int(time.time())), "verificationcode": verificationcode, "resetstatus": resetstatus}) + print("Data sent") + resetstatus = "false" + a += 1 + last_sent = i["listmusicname"] + except: + print("Can't reach the server.") + a += 1 + continue + else: + a = 0 + continue + diff --git a/magiskmodule/META-INF/com/google/android/update-binary b/magiskmodule/META-INF/com/google/android/update-binary new file mode 100644 index 0000000..28b48e5 --- /dev/null +++ b/magiskmodule/META-INF/com/google/android/update-binary @@ -0,0 +1,33 @@ +#!/sbin/sh + +################# +# Initialization +################# + +umask 022 + +# echo before loading util_functions +ui_print() { echo "$1"; } + +require_new_magisk() { + ui_print "*******************************" + ui_print " Please install Magisk v20.4+! " + ui_print "*******************************" + exit 1 +} + +######################### +# Load util_functions.sh +######################### + +OUTFD=$2 +ZIPFILE=$3 + +mount /data 2>/dev/null + +[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk +. /data/adb/magisk/util_functions.sh +[ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk + +install_module +exit 0 diff --git a/magiskmodule/META-INF/com/google/android/updater-script b/magiskmodule/META-INF/com/google/android/updater-script new file mode 100644 index 0000000..11d5c96 --- /dev/null +++ b/magiskmodule/META-INF/com/google/android/updater-script @@ -0,0 +1 @@ +#MAGISK diff --git a/magiskmodule/Makefile b/magiskmodule/Makefile new file mode 100644 index 0000000..b444913 --- /dev/null +++ b/magiskmodule/Makefile @@ -0,0 +1,20 @@ +getprop = $(shell cat module.prop | grep "^$(1)=" | head -n1 | cut -d'=' -f2) + +MODNAME ?= $(call getprop,id) +MODVER ?= $(call getprop,version) +ZIP = $(MODNAME)-$(MODVER).zip + +all: $(ZIP) + +zip: $(ZIP) + +%.zip: clean + zip -r9 $(ZIP) . -x $(MODNAME)-*.zip LICENSE .gitignore .gitattributes Makefile /.git* + +clean: + rm -f *.zip + +update: + curl https://raw.githubusercontent.com/topjohnwu/Magisk/master/scripts/module_installer.sh > META-INF/com/google/android/update-binary + +.PHONY: all zip %.zip install clean update diff --git a/magiskmodule/customization.sh b/magiskmodule/customization.sh new file mode 100755 index 0000000..2e79bca --- /dev/null +++ b/magiskmodule/customization.sh @@ -0,0 +1,15 @@ +SKIPMOUNT=false +LATESTARTSERVICE=true + +print_modname() { + ui_print "Local Wrapped and Music Status Combo Magisk Module" +} + +MOD_EXTRACT() { + unzip -o "$ZIPFILE" -d $MODPATH >&2 +} + +set_permissions() { + set_perm_recursive $MODPATH 0 0 0755 0755 + set_perm $MODPATH/system/bin/musiccombo 0 0 0755 +} diff --git a/magiskmodule/module.prop b/magiskmodule/module.prop new file mode 100644 index 0000000..146a38d --- /dev/null +++ b/magiskmodule/module.prop @@ -0,0 +1,6 @@ +id=musiccombo +name=Local Wrapped and Music Status Combo Magisk Module +version=1.0 +versionCode=100 +author=Halhadus (https://halhadus.rocks) +description=Magisk Module for Local Wrapped and Music Status diff --git a/magiskmodule/service.sh b/magiskmodule/service.sh new file mode 100644 index 0000000..64da225 --- /dev/null +++ b/magiskmodule/service.sh @@ -0,0 +1,21 @@ +# Schedule task + +nohup /bin/sh > /dev/null 2>&1 <> /data/local/tmp/musiccombo.log 2>&1 + sleep 5 +done + +EOF diff --git a/magiskmodule/system/bin/combomodule b/magiskmodule/system/bin/combomodule new file mode 100644 index 0000000..53113a3 Binary files /dev/null and b/magiskmodule/system/bin/combomodule differ diff --git a/musicstatus.py b/musicstatus.py new file mode 100644 index 0000000..ebb5515 --- /dev/null +++ b/musicstatus.py @@ -0,0 +1,119 @@ +import subprocess +import re +import time +import sqlite3 +import os +import requests + +def get_working_directory(): + # If you see this function, that means you are using the pyinstaller. Use this command to create the executable: + # pyinstaller -s -F musicstatus-pyi.py --runtime-tmpdir /data/local/tmp + if os.path.exists("/sdcard/localwrapped"): + return "/sdcard/localwrapped" + elif os.path.exists("/storage/emulated/0/localwrapped"): + return "/storage/emulated/0/localwrapped" + elif os.path.exists("/data/media/0/localwrapped"): + return "/data/media/0/localwrapped" + elif os.path.exists("/mnt/user/0/emulated/0/localwrapped"): + return "/mnt/user/0/emulated/0/localwrapped" + else: + print("Local Wrapped directory not found.") + +if not os.path.exists(f"{get_working_directory()}/key.txt"): + print("Key not exist") + exit() + +if not os.path.exists(f"{get_working_directory()}/music.db"): + try: + getmusicdb = requests.get("https://halhadus.rocks/assets/localwrapped/music.db") + with open(f"{get_working_directory()}/music.db", "wb") as f: + f.write(getmusicdb.content) + except: + print("music.db not exist and download failed.") + +def get_verification_code(): + try: + with open(f'{get_working_directory()/key.txt}') + key = f.read() + try: + verifyrequest = requests.post(os.environ["MSSERVER"] + "/verifykey", json={"key": key}) + if verifyrequest.text == "0": + print("Verification failed") + return None + elif len(verifyrequest.text) == 64: + print("Verification success") + return verifyrequest.text + else: + print("Unexpected response") + return None + except: + print("Can't reach the server.") + time.sleep(15) + get_verification_code() + except: + print("Key not exist") + return None + +def get_music(): + dumpsys_output = subprocess.check_output("dumpsys media_session", shell=True).decode("utf-8").split("\n") + if not [line for line in dumpsys_output if "PLAYING" in line]: + return None + else: + description = [line for line in dumpsys_output if "description=" in line] + try: + return description[0].split("description=")[1] + except: + return None + +def get_db_values(): + musicconn = sqlite3.connect(f"{get_working_directory()}/music.db") + musicc = musicconn.cursor() + musicc.execute("SELECT * FROM music") + musicrows = musicc.fetchall() + musicconn.close() + musicvalues = [] + for row in musicrows: + musicvalues.append({ + "listmusicname": row[0], + "fileartistname": row[4], + "filealbumname": row[5], + "filemusictitle": row[6] + }) + return musicvalues + +a = 0 +last_written = None +resetstatus = "true" +while True: + if get_music() == None: + continue + last_music = get_music() + time.sleep(5) + if last_music == get_music(): + if last_written == last_music: + continue + a += 1 + if a == 1: + for i in get_db_values(): + if i["filealbumname"] == None: + full_name = i["filemusictitle"] + ", " + i["fileartistname"] + ", " + "Music" + else: + full_name = i["filemusictitle"] + ", " + i["fileartistname"] + ", " + i["filealbumname"] + if full_name == last_music: + try: + verificationcode = get_verification_code() + if verificationcode == None: + continue + requests.post(os.environ["MSSERVER"] + "/musicstatus.html", json={"music": i["listmusicname"], "time": str(int(time.time())), "verificationcode": verificationcode, "resetstatus": resetstatus}) + print("Sent") + resetstatus = "false" + except: + print("Can't reach the server.") + time.sleep(15) + last_written = last_music + a = 0 + continue + else: + a = 0 + continue + diff --git a/websitepart.py b/websitepart.py new file mode 100644 index 0000000..010c02e --- /dev/null +++ b/websitepart.py @@ -0,0 +1,73 @@ +import flask +import datetime +import random +import string +import os + +app = flask.Flask(__name__) + +code = "" +history = [] + +@app.route('/musicstatus.html', methods=['GET', 'POST']) +def musicstatus(): + global code, history + if flask.request.method == 'POST': + data = flask.request.get_json() + if code == "": + return "Verification code not generated" + if data['verificationcode'] != code: + return "Verification failed" + else: + musicname = data['music'] + time = data['time'] + resetstatus = data['resetstatus'] + history.append((musicname, time, resetstatus)) + return f"{musicname} added to history" + elif flask.request.method == 'GET': + html = '\n\n' + html += '\n\n\n\n' + html += '\n\n' + html += 'Halhadus\' Music Status\n\n' + html += '\n\n' + html += '\n\n' + html += '\n' + html += '

Halhadus\' Music Status

\n' + html += 'Source Code\n' + html += '

Hi guys. I am too lazy to add links to song names. To find which song is it, check this link.

\n' + html += '
\n\n
\n' + if len(history) > 0: + if history[-1][2] == "true": + currentbeforereset = history[-1] + history = [] + history.append(currentbeforereset) + html += f'

Currently Playing: {history[-1][0]}

\n' + html += f'

Last Update Time: {datetime.datetime.fromtimestamp(int(history[-1][1]), datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S")} (UTC +0)

\n' + html += '\n\n\n\n\n' + for music in history[::-1]: + html += '\n\n\n\n' + html += '
Music NameTime
' + music[0] + '' + datetime.datetime.fromtimestamp(int(music[1]), datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S") + '
\n\n' + return html + +@app.route('/verifykey', methods=['GET', 'POST']) +def verifycert(): + global code + if flask.request.method == 'POST': + data = flask.request.get_json() + key = data['key'] + with open("key.txt", "r") as f: + if key == f.read(): + code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=64)) + return code + else: + return "0" + elif flask.request.method == 'GET': + return "GET method not allowed" + +@app.route('/') +def catch_all(path): + if not path == 'musicstatus.html' or not path == 'verifykey': + return flask.redirect(f'https://halhadus.rocks/{path}') + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=int(os.environ.get('PORT')))