Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mjishnu/alt-app-installer
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.6.8
Choose a base ref
...
head repository: mjishnu/alt-app-installer
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.6.9
Choose a head ref
  • 11 commits
  • 9 files changed
  • 3 contributors

Commits on Jan 30, 2024

  1. switched to full pypdl

    mjishnu committed Jan 30, 2024
    Copy the full SHA
    af79386 View commit details
  2. Update README.md

    mjishnu authored Jan 30, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    b6a2c91 View commit details
  3. updated requirements.txt

    mjishnu committed Jan 30, 2024
    Copy the full SHA
    cef07f1 View commit details
  4. Merge branch 'main' of https://github.com/m-jishnu/alt-app-installer

    mjishnu committed Jan 30, 2024
    Copy the full SHA
    e3882a3 View commit details

Commits on Feb 5, 2024

  1. fixed minor resource leak

    mjishnu committed Feb 5, 2024
    Copy the full SHA
    0b43247 View commit details

Commits on Feb 24, 2024

  1. update store api

    mjishnu committed Feb 24, 2024
    Copy the full SHA
    7bade08 View commit details

Commits on Mar 7, 2024

  1. update xml

    mjishnu committed Mar 7, 2024
    Copy the full SHA
    ee6a19a View commit details

Commits on Jun 6, 2024

  1. switch to async requsts

    mjishnu committed Jun 6, 2024
    Copy the full SHA
    1ddaff5 View commit details

Commits on Jun 7, 2024

  1. minor bug fix

    mjishnu committed Jun 7, 2024
    Copy the full SHA
    3934805 View commit details

Commits on Jun 8, 2024

  1. revert retries to 3

    mjishnu committed Jun 8, 2024
    Copy the full SHA
    3619afc View commit details

Commits on Jun 19, 2024

  1. improve support for arm, fix minor bugs

    mjishnu committed Jun 19, 2024
    Copy the full SHA
    fa6fb8c View commit details
Showing with 832 additions and 1,182 deletions.
  1. +2 −2 README.md
  2. +49 −33 app/core.py
  3. +15 −30 app/data/xml/FE3FileUrl.xml
  4. +11 −26 app/data/xml/GetCookie.xml
  5. +649 −678 app/data/xml/WUIDRequest.xml
  6. +0 −327 app/modules/downloader.py
  7. +89 −83 app/modules/url_gen.py
  8. +16 −3 app/utls.py
  9. +1 −0 requirements.txt
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ A program to download and install microsoft store apps
- Can install already downloaded microsoft store apps (appx,msix,appxbundle...)
- Can get microsoft store apps by providing its url
- Uses custom link generation to produce download links using API from [StoreLib](https://github.com/StoreDev/StoreLib) and [MS-Store-API](https://github.com/ThomasPe/MS-Store-API)
- Uses [concurrent/multi-part downloader](https://stackoverflow.com/questions/93642/how-do-download-accelerators-work) using a stripped version [pypdl](https://github.com/m-jishnu/pypdl) for fast downloading
- Uses [concurrent/multi-part downloader](https://stackoverflow.com/questions/93642/how-do-download-accelerators-work) using [pypdl](https://github.com/m-jishnu/pypdl) for fast downloading
- Can resume interrupted downloads
- Automatically use a new url in case current one expires
- Downloads and install app along with all dependencies
@@ -24,7 +24,7 @@ A program to download and install microsoft store apps
- System architecture of the user(x64/x32)
- Favorable type(these are decrypted file formats, which doesn't need admin privilage to install)
- Latest version
- Then it retrives the download links for the parsed data using the API and the files are downloaded using a stripped version of [pypdl](https://github.com/m-jishnu/pypdl), which allows for concurrent/multi-part downloading this makes the download faster.It also has the ability to resume interrupted downloads and can also automatically use a new url in case current download link expires.
- Then it retrives the download links for the parsed data using the API and the files are downloaded using [pypdl](https://github.com/m-jishnu/pypdl), which allows for concurrent/multi-part downloading this makes the download faster.It also has the ability to resume interrupted downloads and can also automatically use a new url in case current download link expires.
- Finally it installs the downloaded files via System.Management.Automation.dll using [pythonnet](https://pypi.org/project/pythonnet)

<img width="1060" alt="1-min" src="https://user-images.githubusercontent.com/83004520/226940878-11cfb8ca-074e-4876-8a38-142559f5116b.png">
82 changes: 49 additions & 33 deletions app/core.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import asyncio
import os
import time
from datetime import datetime
from threading import Event

import clr
from pypdl import Pypdl
from PyQt6.QtCore import QThreadPool
from PyQt6.QtGui import QIcon
from PyQt6.QtWidgets import QMessageBox

from modules.downloader import Downloader
from modules.gui import Ui_MainProgram
from modules.url_gen import url_generator
from utls import Worker
from utls import Worker, default_logger

script_dir = os.path.dirname(os.path.abspath(__file__))
clr.AddReference(rf"{script_dir}\data\System.Management.Automation.dll")


class internal_func(Ui_MainProgram):
def __init__(self):
super().__init__()
self.logger = default_logger("Downloader")

def error_msg(self, text, msg_details, title="Error", critical=False):
msg = QMessageBox()
msg.setWindowTitle(title)
@@ -204,13 +209,15 @@ def parser(self, arg):

self.url = arg # saving the url for future uses
worker = Worker(
lambda **kwargs: url_generator(
str(arg),
self.ignore_ver,
self.all_dependencies,
self.stop,
emit=True,
**kwargs,
lambda **kwargs: asyncio.run(
url_generator(
str(arg),
self.ignore_ver,
self.all_dependencies,
self.stop,
emit=True,
**kwargs,
)
)
)
worker.signals.result.connect(self.download_install)
@@ -243,50 +250,59 @@ def download_install_thread(data, progress_current, progress_main):
if not os.path.exists(dwnpath):
os.makedirs(dwnpath)
path_lst = {}
d = Downloader()
d = Pypdl(allow_reuse=True, logger=self.logger)
for f_name in final_data:
# Define the remote file to retrieve
remote_url = main_dict[f_name] # {f_name:url}
# Download remote and save locally
path = f"{dwnpath}{f_name}"
if not os.path.exists(path): # don't download if it exists already

def new_url_gen():
return url_generator(
def new_url_gen():
urls = asyncio.run(
url_generator(
self.url,
self.ignore_ver,
self.all_dependencies,
self.stop,
progress_current,
progress_main,
emit=False,
)[0][f_name]

d.start(
remote_url,
path,
20,
retries=5,
retry_func=new_url_gen,
block=False,
)
)
while d.progress != 100:
download_percentage = int(d.progress)
progress_current.emit(download_percentage)
time.sleep(0.1)
if self.stop.is_set(): # check if the stop event is triggered
d.stop()
raise Exception("Stoped By User!")
if d.Failed:
raise Exception("Download Error Occured!")

progress_main.emit(part)
return urls[0][f_name]

d.start(
remote_url,
path,
20,
retries=3,
mirror_func=new_url_gen,
block=False,
display=False,
overwrite=False,
)

while not d.completed:
download_percentage = int(d.progress)
progress_current.emit(download_percentage)
time.sleep(0.1)
if self.stop.is_set(): # check if the stop event is triggered
d.stop()
d.shutdown()
raise Exception("Stoped By User!")
if d.failed:
d.shutdown()
raise Exception("Download Error Occured!")

progress_main.emit(part)

fname_lower = (f_name.split(".")[1].split("_")[0]).lower()
if file_name in fname_lower:
path_lst[path] = 1
else:
path_lst[path] = 0

d.shutdown()
return path_lst, uwp # install the apps'

worker = Worker(lambda **kwargs: download_install_thread(arg, **kwargs))
45 changes: 15 additions & 30 deletions app/data/xml/FE3FileUrl.xml
Original file line number Diff line number Diff line change
@@ -1,29 +1,15 @@
<s:Envelope
xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetExtendedUpdateInfo2</a:Action>
<a:MessageID>urn:uuid:2cc99c2e-3b3e-4fb1-9e31-0cd30e6f43a0</a:MessageID>
<a:To s:mustUnderstand="1">https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured</a:To>
<o:Security s:mustUnderstand="1"
xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<Timestamp
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<Created>2017-08-01T00:29:01.868Z</Created>
<Expires>2017-08-01T00:34:01.868Z</Expires>
</Timestamp>
<wuws:WindowsUpdateTicketsToken wsu:id="ClientMSA"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wuws="http://schemas.microsoft.com/msus/2014/10/WindowsUpdateAuthorization">
<TicketType Name="MSA" Version="1.0" Policy="MBI_SSL">
{2}
</TicketType>
</wuws:WindowsUpdateTicketsToken>
</o:Security>
</s:Header>
<s:Body>
<GetExtendedUpdateInfo2
xmlns="http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService">
<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<Header>
<a:Action mustUnderstand="1">http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetExtendedUpdateInfo2</a:Action>
<a:To mustUnderstand="1">https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured</a:To>
<Security mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<WindowsUpdateTicketsToken xmlns="http://schemas.microsoft.com/msus/2014/10/WindowsUpdateAuthorization" u:id="ClientMSA">
<!-- <TicketType Name="MSA" Version="1.0" Policy="MBI_SSL"><User/></TicketType> -->
</WindowsUpdateTicketsToken>
</Security>
</Header>
<Body>
<GetExtendedUpdateInfo2 xmlns="http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService">
<updateIDs>
<UpdateIdentity>
<UpdateID>{0}</UpdateID>
@@ -34,7 +20,6 @@
<XmlUpdateFragmentType>FileUrl</XmlUpdateFragmentType>
<XmlUpdateFragmentType>FileDecryption</XmlUpdateFragmentType>
</infoTypes>
<deviceAttributes>BranchReadinessLevel=CB;CurrentBranch=rs_prerelease;OEMModel=Virtual Machine;FlightRing=WIS;AttrDataVer=21;SystemManufacturer=Microsoft Corporation;InstallLanguage=en-US;OSUILocale=en-US;InstallationType=Client;FlightingBranchName=external;FirmwareVersion=Hyper-V UEFI Release v2.5;SystemProductName=Virtual Machine;OSSkuId=48;FlightContent=Branch;App=WU;OEMName_Uncleaned=Microsoft Corporation;AppVer=10.0.16184.1001;OSArchitecture=AMD64;SystemSKU=None;UpdateManagementGroup=2;IsFlightingEnabled=1;IsDeviceRetailDemo=0;TelemetryLevel=3;OSVersion=10.0.16184.1001;DeviceFamily=Windows.Desktop;</deviceAttributes>
</GetExtendedUpdateInfo2>
</s:Body>
</s:Envelope>
<DeviceAttributes>FlightRing={2};</DeviceAttributes> </GetExtendedUpdateInfo2>
</Body>
</Envelope>
37 changes: 11 additions & 26 deletions app/data/xml/GetCookie.xml
Original file line number Diff line number Diff line change
@@ -1,27 +1,12 @@
<Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/2003/05/soap-envelope">
<Header>
<Action d3p1:mustUnderstand="1" xmlns:d3p1="http://www.w3.org/2003/05/soap-envelope" xmlns="http://www.w3.org/2005/08/addressing">http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetCookie</Action>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:b9b43757-2247-4d7b-ae8f-a71ba8a22386</MessageID>
<To d3p1:mustUnderstand="1" xmlns:d3p1="http://www.w3.org/2003/05/soap-envelope" xmlns="http://www.w3.org/2005/08/addressing">https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx</To>
<Security d3p1:mustUnderstand="1" xmlns:d3p1="http://www.w3.org/2003/05/soap-envelope" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<Created>2017-12-02T00:16:15.210Z</Created>
<Expires>2017-12-29T06:25:43.943Z</Expires>
</Timestamp>
<WindowsUpdateTicketsToken d4p1:id="ClientMSA" xmlns:d4p1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="http://schemas.microsoft.com/msus/2014/10/WindowsUpdateAuthorization">
<TicketType Name="MSA" Version="1.0" Policy="MBI_SSL">
<User />
</TicketType>
</WindowsUpdateTicketsToken>
</Security>
</Header>
<Body>
<GetCookie xmlns="http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService">
<oldCookie>
</oldCookie>
<lastChange>2015-10-21T17:01:07.1472913Z</lastChange>
<currentTime>2017-12-02T00:16:15.217Z</currentTime>
<protocolVersion>1.40</protocolVersion>
</GetCookie>
</Body>
<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<Header>
<a:Action mustUnderstand="1" >http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetCookie</a:Action>
<a:To mustUnderstand="1">https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx</a:To>
<Security mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<WindowsUpdateTicketsToken xmlns="http://schemas.microsoft.com/msus/2014/10/WindowsUpdateAuthorization" u:id="ClientMSA">
<!-- <TicketType Name="MSA" Version="1.0" Policy="MBI_SSL"><User/></TicketType> -->
</WindowsUpdateTicketsToken>
</Security>
</Header>
<Body></Body>
</Envelope>
1,327 changes: 649 additions & 678 deletions app/data/xml/WUIDRequest.xml

Large diffs are not rendered by default.

327 changes: 0 additions & 327 deletions app/modules/downloader.py

This file was deleted.

172 changes: 89 additions & 83 deletions app/modules/url_gen.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import asyncio
import html
import json
import os
import platform
import re
import time
import warnings
from threading import Thread
from xml.dom import minidom

import requests
import aiohttp

warnings.filterwarnings("ignore")
# parent directory for absloute path
@@ -23,57 +23,30 @@ def check(Event):


def os_arc():
if platform.machine().endswith("64"):
machine = platform.machine().lower()

if machine.endswith("arm64"):
return "arm64"
if machine.endswith("64"):
return "x64"
if platform.machine().endswith("32") or platform.machine().endswith("86"):
if machine.endswith("32") or machine.endswith("86"):
return "x86"
################################
return "arm" # not sure wheather work or not, needs testing
else:
return "arm"


# cleans My.name.1.2 -> myname


def clean_name(badname):
name = "".join(
[(i if (64 < ord(i) < 91 or 96 < ord(i) < 123) else "") for i in badname]
)
return name.lower()


def url_generator(
async def url_generator(
url, ignore_ver, all_dependencies, Event, progress_current, progress_main, emit
):
total_prog = 0
progress_current.emit(total_prog)
# geting product id from url
try:
pattern = re.compile(r".+\/([^\/\?]+)(?:\?|$)")
matches = pattern.search(str(url))
product_id = matches.group(1)
except AttributeError:
raise Exception("No Data Found: --> [You Selected Wrong Page, Try Again!]")

# getting cat_id and package name from the api
details_api = f"https://storeedgefd.dsx.mp.microsoft.com/v9.0/products/{product_id}?market=US&locale=en-us&deviceFamily=Windows.Desktop"
session = requests.Session()
r = session.get(details_api, timeout=20)
response = json.loads(
r.text,
object_hook=lambda obj: {
k: json.loads(v) if k == "FulfillmentData" else v for k, v in obj.items()
},
)

if not response.get("Payload", None):
raise Exception("No Data Found: --> [You Selected Wrong Page, Try Again!]")

response_data = response["Payload"]["Skus"][0]
data_list = response_data.get("FulfillmentData", None)
total_prog += 20
progress_current.emit(total_prog)

def uwp_gen():
async def uwp_gen(session):
nonlocal total_prog

def parse_dict(main_dict, file_name, ignore_ver, all_dependencies):
@@ -254,14 +227,14 @@ def greater_ver(arg1, arg2):
with open(rf"{parent_dir}\data\xml\GetCookie.xml", "r") as f:
cookie_content = f.read()
check(Event)
out = session.post(
"https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx",
data=cookie_content,
headers={"Content-Type": "application/soap+xml; charset=utf-8"},
verify=False,
timeout=20,
)
doc = minidom.parseString(out.text)
out = await (
await session.post(
"https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx",
data=cookie_content,
headers={"Content-Type": "application/soap+xml; charset=utf-8"},
)
).text()
doc = minidom.parseString(out)
total_prog += 20
progress_current.emit(total_prog)
# extracting the cooking from the EncryptedData tag
@@ -272,15 +245,15 @@ def greater_ver(arg1, arg2):
with open(rf"{parent_dir}\data\xml\WUIDRequest.xml", "r") as f:
cat_id_content = f.read().format(cookie, cat_id, release_type)
check(Event)
out = session.post(
"https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx",
data=cat_id_content,
headers={"Content-Type": "application/soap+xml; charset=utf-8"},
verify=False,
timeout=20,
)
out = await (
await session.post(
"https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx",
data=cat_id_content,
headers={"Content-Type": "application/soap+xml; charset=utf-8"},
)
).text()

doc = minidom.parseString(html.unescape(out.text))
doc = minidom.parseString(html.unescape(out))
total_prog += 20
progress_current.emit(total_prog)
filenames = {} # {ID: filename}
@@ -335,15 +308,15 @@ def greater_ver(arg1, arg2):
progress_current.emit(total_prog)
part = int(30 / len(final_dict))

def geturl(updateid, revisionnumber, file_name, total_prog):
out = session.post(
"https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured",
data=file_content.format(updateid, revisionnumber, release_type),
headers={"Content-Type": "application/soap+xml; charset=utf-8"},
verify=False,
timeout=20,
)
doc = minidom.parseString(out.text)
async def geturl(updateid, revisionnumber, file_name, total_prog):
out = await (
await session.post(
"https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured",
data=file_content.format(updateid, revisionnumber, release_type),
headers={"Content-Type": "application/soap+xml; charset=utf-8"},
)
).text()
doc = minidom.parseString(out)
# checks for all the tags which have name "filelocation" and extracts the url from it
for i in doc.getElementsByTagName("FileLocation"):
url = i.getElementsByTagName("Url")[0].firstChild.nodeValue
@@ -353,37 +326,38 @@ def geturl(updateid, revisionnumber, file_name, total_prog):
total_prog += part
progress_current.emit(total_prog)

# using threading to concurrently get the download url for all the files
threads = []
# creating a list of tasks to be executed
tasks = []
for key, value in final_dict.items():
check(Event)
file_name = key
updateid, revisionnumber = value
th = Thread(
target=geturl, args=(updateid, revisionnumber, file_name, total_prog)
tasks.append(
asyncio.create_task(
geturl(updateid, revisionnumber, file_name, total_prog)
)
)
th.daemon = True
threads.append(th)
th.start()

# waiting for all threads to complete
while len(file_dict) != len(final_dict):
check(Event)
time.sleep(0.2)
await asyncio.gather(*tasks)

# # waiting for all threads to complete
if len(file_dict) != len(final_dict):
raise Exception("server returned a incomplete list")

if emit is True:
progress_current.emit(100)
time.sleep(0.2)
progress_main.emit(20)
# uwp = True
return file_dict, parse_names, main_file_name, True

def non_uwp_gen():
async def non_uwp_gen(session):
nonlocal total_prog
api = f"https://storeedgefd.dsx.mp.microsoft.com/v9.0/packageManifests//{product_id}?market=US&locale=en-us&deviceFamily=Windows.Desktop"
check(Event)

r = session.get(api, timeout=20)
datas = json.loads(r.text)
data = await (await session.get(api)).text()
datas = json.loads(data)

if not datas.get("Data", None):
raise Exception("server returned a empty list")
@@ -444,8 +418,40 @@ def non_uwp_gen():
# uwp = False
return file_dict, [main_file_name], main_file_name, False

# check and see if the app is ump or not, return --> func_output,(ump or not)
if data_list:
return uwp_gen()
else:
return non_uwp_gen()
total_prog = 0
progress_current.emit(total_prog)
# geting product id from url
try:
pattern = re.compile(r".+\/([^\/\?]+)(?:\?|$)")
matches = pattern.search(str(url))
product_id = matches.group(1)
except AttributeError:
raise Exception("No Data Found: --> [You Selected Wrong Page, Try Again!]")

async with aiohttp.ClientSession(
timeout=aiohttp.ClientTimeout(total=60), raise_for_status=True
) as session:
# getting cat_id and package name from the api
details_api = f"https://storeedgefd.dsx.mp.microsoft.com/v9.0/products/{product_id}?market=US&locale=en-us&deviceFamily=Windows.Desktop"
data = await (await session.get(details_api)).text()
response = json.loads(
data,
object_hook=lambda obj: {
k: json.loads(v) if k == "FulfillmentData" else v
for k, v in obj.items()
},
)

if not response.get("Payload", None):
raise Exception("No Data Found: --> [You Selected Wrong Page, Try Again!]")

response_data = response["Payload"]["Skus"][0]
data_list = response_data.get("FulfillmentData", None)
total_prog += 20
progress_current.emit(total_prog)

# check and see if the app is ump or not, return --> func_output,(ump or not)
if data_list:
return await uwp_gen(session)
else:
return await non_uwp_gen(session)
19 changes: 16 additions & 3 deletions app/utls.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
import logging
import os
import sys
import traceback
import webbrowser

from PyQt6 import QtCore, QtWidgets
from PyQt6.QtCore import QObject, QRunnable, pyqtSignal, pyqtSlot
from PyQt6.QtGui import QIcon, QPixmap, QFont
from PyQt6.QtGui import QFont, QIcon, QPixmap
from PyQt6.QtWidgets import QDialog
import os

curr_dir = os.path.dirname(os.path.abspath(__file__))


def default_logger(name: str) -> logging.Logger:
"""Creates a default debugging logger."""
logger = logging.getLogger(name)
handler = logging.FileHandler(f"{curr_dir}/log.txt", mode="a", delay=True)
custom_format = (
f"[{name} logs] \n[%(asctime)s]\n\n %(levelname)s: %(message)s\n{82*"-"}\n"
)
handler.setFormatter(logging.Formatter(custom_format, datefmt="%d-%m-%Y %H:%M:%S"))
logger.addHandler(handler)
return logger


class UrlBox(QDialog):
closed = QtCore.pyqtSignal(object)

@@ -265,7 +278,7 @@ def setupUi(self, about):
QtWidgets.QSizePolicy.Policy.Expanding,
)
self.gridLayout.addItem(spacerItem9, 0, 1, 1, 1)
self.label.setText("Alt App Installer 2.6.8")
self.label.setText("Alt App Installer 2.6.9")
self.label_2.setText("© 2022 - 2024 Jishnu M")
urlLink = '<a href="http://github.com/m-jishnu/alt-app-installer" style="text-decoration: none; color: black;">github.com/m-jishnu/alt-app-installer</a>'
self.label_3.setText(urlLink)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pypdl
pythonnet
requests
pyqt6