tis-av1-video-extension icon

AV1 Video Extension

Paquet d’installation silencieuse pour AV1 Video Extension

2.0.4.0-63

  • package: tis-av1-video-extension
  • name: AV1 Video Extension
  • version: 2.0.4.0-63
  • categories: Media,Extension
  • maintainer: WAPT Team,Tranquil IT,Jimmy PELÉ,Pierre COSSON
  • licence: proprietary_free,wapt_public
  • locale: all
  • target_os: windows
  • architecture: all
  • signature_date:
  • size: 5.52 Mo
  • installed_size: 3.98 Mo

package           : tis-av1-video-extension
version           : 2.0.4.0-63
architecture      : all
section           : base
priority          : optional
name              : AV1 Video Extension
categories        : Media,Extension
maintainer        : WAPT Team,Tranquil IT,Jimmy PELÉ,Pierre COSSON
description       : Play AV1 videos in your favorite video app on your Windows device. This extension helps video apps installed on Windows play videos that have been encoded using the AV1 video coding standard developed by the Alliance for Open Media
depends           : 
conflicts         : 
maturity          : PROD
locale            : all
target_os         : windows
min_wapt_version  : 2.3
sources           : https://apps.microsoft.com/store/detail/9MVZQVXJBQ9V
installed_size    : 3979089
impacted_process  : 
description_fr    : Lisez les vidéos AV1 dans votre application vidéo préférée sur votre appareil Windows. Cette extension permet aux applications vidéo installées sur Windows de lire les vidéos encodées à l'aide de la norme de codage vidéo AV1 développée par l'Alliance for Open Media
description_pl    : Odtwarzanie filmów AV1 w ulubionej aplikacji wideo na urządzeniu z systemem Windows. To rozszerzenie pomaga aplikacjom wideo zainstalowanym w systemie Windows odtwarzać filmy, które zostały zakodowane przy użyciu standardu kodowania wideo AV1 opracowanego przez Alliance for Open Media
description_de    : Spielen Sie AV1-Videos in Ihrer Lieblingsvideoanwendung auf Ihrem Windows-Gerät ab. Mit dieser Erweiterung können auf Windows installierte Videoanwendungen Videos wiedergeben, die mit dem von der Alliance for Open Media entwickelten AV1-Videocodierungsstandard kodiert wurden
description_es    : Reproduzca vídeos AV1 en su aplicación de vídeo favorita en su dispositivo Windows. Esta extensión ayuda a las aplicaciones de vídeo instaladas en Windows a reproducir vídeos codificados con el estándar de codificación de vídeo AV1 desarrollado por la Alliance for Open Media
description_pt    : Reproduza vídeos AV1 na sua aplicação de vídeo favorita no seu dispositivo Windows. Esta extensão ajuda as aplicações de vídeo instaladas no Windows a reproduzir vídeos que foram codificados utilizando a norma de codificação de vídeo AV1 desenvolvida pela Alliance for Open Media
description_it    : Riproducete i video AV1 nella vostra applicazione video preferita sul vostro dispositivo Windows. Questa estensione aiuta le app video installate su Windows a riprodurre i video codificati con lo standard di codifica video AV1 sviluppato da Alliance for Open Media
description_nl    : Speel AV1-video's af in je favoriete video-app op je Windows-apparaat. Deze extensie helpt video-apps die op Windows zijn geïnstalleerd video's af te spelen die zijn gecodeerd met de AV1-videocoderingsstandaard, ontwikkeld door de Alliance for Open Media
description_ru    : Воспроизведение видеороликов AV1 в любимом видеоприложении на устройстве Windows. Это расширение помогает видеоприложениям, установленным на Windows, воспроизводить видео, закодированное с использованием стандарта кодирования видео AV1, разработанного Альянсом за открытые медиа
audit_schedule    : 
editor            : 
keywords          : 
licence           : proprietary_free,wapt_public
homepage          : 
package_uuid      : 9f78dfe2-e7a1-42f7-a308-84c11636ed45
valid_from        : 
valid_until       : 
forced_install_on : 
changelog         : 
min_os_version    : 10.0.17763
max_os_version    : 
icon_sha256sum    : 5cd06abee4d9bc5102f5bf44b601bf5ee747193df5321c6e1fa2f0bd4ad83699
signer            : Tranquil IT
signer_fingerprint: 8c5127a75392be9cc9afd0dbae1222a673072c308c14d88ab246e23832e8c6bb
signature_date    : 2025-09-16T16:00:18.000000
signed_attributes : package,version,architecture,section,priority,name,categories,maintainer,description,depends,conflicts,maturity,locale,target_os,min_wapt_version,sources,installed_size,impacted_process,description_fr,description_pl,description_de,description_es,description_pt,description_it,description_nl,description_ru,audit_schedule,editor,keywords,licence,homepage,package_uuid,valid_from,valid_until,forced_install_on,changelog,min_os_version,max_os_version,icon_sha256sum,signer,signer_fingerprint,signature_date,signed_attributes
signature         : JWi1r5a6SQoiH4Y2ga6ArLwIwNeV25m9L/lhiU0frnVCJWEaR3Q0DyXcIQ4XnqqVwwph/uyiJ3odQY5YpAUKgghn1Tvr/Jq5huNEzx4RSMu9zh7R2ARl38sYSx4oZh6LXLi2mQ6EvL9h0bbGl3Rgw6Ya+VagSQanm7ejW62Evfwud4sGUEeUt9ToSPE3HgzAR/Y7MTmCa8+4slo1vdadj8QxPQUiINIe44Vb42BHM7n29y1y2lqhQA3ZYUi1//12WloVqFaty5SVFYdfyOuS1llgcMG7OXk8bswZZvlcC0ohsOufHx023TQXH+xaZzVqwyVU78fFNGueMjtkonzbtg==

# -*- coding: utf-8 -*-
from setuphelpers import *


appx_package_name = "Microsoft.AV1VideoExtension"
appx_dir = makepath(programfiles, "WindowsAppsInstallers")


def install():
    # Declare local variables
    bins_dir = control.package.split("-", 1)[1]
    old_appx_bins_dir = makepath(appx_dir, bins_dir)
    appx_bins_dir = makepath(os.getcwd(), bins_dir)

    # Removing sources because they are no longer needed
    if isdir(old_appx_bins_dir):
        print("Removing: %s" % (old_appx_bins_dir))
        remove_tree(old_appx_bins_dir)
    if dir_is_empty(appx_dir):
        print("Removing: %s since it is empty" % (appx_dir))
        remove_tree(appx_dir)

    # Removing binaries of different architectures
    for f in glob.glob(appx_bins_dir + "/*"):
        fname = f.split(os.sep)[-1]
        if control.architecture == "all":
            if "x86" in glob.glob(makepath(appx_bins_dir, f"{appx_package_name}_*"))[0].split(os.sep)[-1]:
                if not "x86" in fname and not "neutral" in fname:
                    remove_file(f)
            else:
                if not get_host_architecture() in fname and not "neutral" in fname:
                    remove_file(f)
        else:
            if not get_host_architecture() in fname and not "neutral" in fname:
                remove_file(f)
    bin_path = glob.glob(makepath(appx_bins_dir, f"{appx_package_name}_*"))[0]
    dependencies_pathes = ",".join([f'"{a}"' for a in glob.glob(makepath(appx_bins_dir, "*")) if not appx_package_name in a])
    add_appx_cmd = f'Add-AppxProvisionedPackage -Online -PackagePath "{bin_path}" -SkipLicense'
    if dependencies_pathes:
        add_appx_cmd += f" -DependencyPackagePath {dependencies_pathes}"

    # Installing the UWP application if needed
    appxprovisionedpackage = run_powershell(f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like "{appx_package_name}"')
    if appxprovisionedpackage is None:
        appxprovisionedpackage = {"Version": "0"}

    if Version(appxprovisionedpackage["Version"], 4) < Version(control.get_software_version(), 4) or force:
        print(f"Installing: {bin_path.split(os.sep)[-1]} ({control.get_software_version()})")
        killalltasks(ensure_list(control.impacted_process))
        run_powershell(add_appx_cmd, output_format="text")
    else:
        print(f'{appxprovisionedpackage["PackageName"]} is already installed and up-to-date.')


def uninstall():
    # Declare local variables
    bins_dir = control.package.split("-", 1)[1]
    appx_bins_dir = makepath(appx_dir, bins_dir)

    print(f"Removing AppX: {appx_package_name}")
    remove_appx(appx_package_name)


def audit():
    # Declaring local variables
    audit_result = "OK"
    audit_version = True
    appxprovisionedpackage = run_powershell(f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like "{appx_package_name}"')

    # Auditing software
    if appxprovisionedpackage is None:
        print(f"{appx_package_name} is not installed.")
        audit_result = "ERROR"
    elif audit_version:
        if Version(appxprovisionedpackage.get("Version", "0"), 4) < Version(control.get_software_version(), 4):
            print(
                f'{appxprovisionedpackage["PackageName"]} is installed in version: {appxprovisionedpackage["Version"]} instead of: {control.get_software_version()}.'
            )
            audit_result = "WARNING"
        else:
            print(f'{appxprovisionedpackage["PackageName"]} is installed and up-to-date.')
    else:
        print(f'{appxprovisionedpackage["PackageName"]} is installed.')

    return audit_result


def remove_appx(package, default_user=True):
    """Remove Windows AppX package from the computer environment, excluding NonRemovable packages.

    Args:
        package (str): AppX package name. You can use an asterisk (*) as a wildcard.
        default_user (bool): Remove AppX package from the Windows image to prevent installation for new users.

    .. versionadded:: 2.2

    .. versionchanged:: 2.5
        No longer try to remove NonRemovable AppX package

    """
    if running_as_admin() or running_as_system():
        if default_user:
            run_powershell(
                f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like "{package}" | Remove-AppxProvisionedPackage -Online -AllUsers',
                output_format="text",
            )
        run_powershell(
            r'Get-AppxPackage -Name "%s" -AllUsers | Where-Object {{ -not ($_.NonRemovable) }} | Remove-AppxPackage -AllUsers' % package,
            output_format="text",
        )
    else:
        run_powershell(r'Get-AppxPackage -Name "%s" | Where-Object {{ -not ($_.NonRemovable) }} | Remove-AppxPackage' % package, output_format="text")

# -*- coding: utf-8 -*-
from setuphelpers import *

try:
    from setupdevhelpers import *

except:
    from bs4 import BeautifulSoup
import json
import waptguihelper
import html
from xml.dom import minidom
import requests
import json
import re

release_name_map = {"retail": "Retail", "RP": "Release Preview", "WIS": "Insider Slow", "WIF": "Insider Fast"}
release_type = "retail"
release_name = release_name_map[release_type]
arch = "x64"

sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
import xmltodict

#For debug mode, set as True
debug_mode = False

#To make 5 api requests, set as True / Only use if retrieve binary is bad
loop_enable = False

def update_package():
    # Declaring local variables
    package_updated = False
    proxies = get_proxies()
    
    if not proxies:
        proxies = get_proxies_from_wapt_console()
    store_url = control.sources
    
    if not store_url:
        store_id = waptguihelper.input_dialog(
            "Choice of app", "Enter the windows store app id (foundable in package url: https://apps.microsoft.com/store/apps)", store_url
        ).split("/")[-1]
    else:
        store_id = store_url.split("/")[-1]
    store_id = store_id.split("?")[0]

    url_ms = "https://apps.microsoft.com/store/detail/%s" % store_id
    control.sources = url_ms
    control.save_control_to_wapt()

    package_json = get_json(store_id)

    # Updating package.json ignored_versions list
    if isfile("package.json"):
        package_infos = json_load_file("package.json")
    else:
        package_infos = {"version_prefix": None, "ignored_versions": []}

    ignored_versions = package_infos["ignored_versions"]
    version_prefix = package_infos.get("version_prefix", None)
    
    #Debug print package.json informations
    if debug_mode:
        print("\n\n=== CAREFUL : DEBUG MODE IS ACTIVE ===\n")
        print(f"version prefix : {version_prefix}")
        print(f"ignored versions : {ignored_versions}\n")
    
    #Get files from Microsoft Store API
    print("Retrieving informations from Microsoft Store API, please wait\n")
    all_files_dict = get_all_files(url_ms,proxies)
    
    #Debug print all_files_dict, contains all files from a Store url API request
    if debug_mode:
        all_files_dict_json = json.dumps(all_files_dict,indent=4)
        print("*** Pretty return from get_all_files() ***")
        print(f"all_files_dict : {all_files_dict_json}\n")

	# check setup.py incase the package name doesnt match the installer file
    with open("setup.py", "r") as f:
        for line in f.readlines():
            if line.startswith("appx_package"):
                store_package_name = line.split("=")[1].split('"')[1]
                break
    
    #Find the last binaries or the one matching prefix inside all_files_dict
    bin_selected_dict = ask_app_filename(all_files_dict, store_package_name,ignored_versions=ignored_versions,version_prefix=version_prefix)
    
    #Debug print post filtering to see which files have been selected
    if debug_mode:
        bin_selected_dict_json = json.dumps(bin_selected_dict,indent=4)
        print("*** Selected file from ask_app_file_name() ***")
        print(f"bin_selected_dict : {bin_selected_dict_json}\n")

    #Define binarie variables
    appx_package = bin_selected_dict[0]["bin_name"].split("_")[0]
    bin_selected = bin_selected_dict[0]
    latest_bin = bin_selected["bin_name"]
    version = bin_selected["version"]
    download_url = bin_selected["download_url"]
    package_name = bin_selected["package_name"]
    software_name = bin_selected["software_name"]
    package_arch = bin_selected["package_arch"]
    
    #Download binarie file
    if download_url.split("/")[2].endswith("microsoft.com"):
        if not isfile(latest_bin):
            print("Downloading: %s" % latest_bin)
            wget(download_url, latest_bin, proxies=proxies)
        else:
            print("Binary file version corresponds to online version")
    else:
        print("ERROR: The retrieved url will not download from microsoft's servers")

    # Asking pkg infos if needed and not running as luti
    if not params.get("running_as_luti"):
        if package_arch == "all":
            ask_control_architecture(package_arch)
        ask_control_categories()
        ask_control_package(package_name, "template-microsoft-store", remove_base_files=True)
        ask_control_name(software_name, "Template Microsoft Store")
        # description from microsoft website
        ask_control_description("update_package", get_description(package_json))

    # Changing setup.py appx_package variable
    new_lines = []
    with open("setup.py", "r") as f:
        for line in f.readlines():
            if line.startswith("appx_package"):
                line = 'appx_package_name = "%s"\n' % latest_bin.split("_")[0]
            new_lines.append(line)
    with open("setup.py", "w") as f:
        f.writelines(new_lines)

	#Making dependency dict from downloaded binary
    uwp_app_dict = make_dependency_dict(appx_package)

    if not uwp_app_dict:
        # error(f'{appx_package_name} not found in "uwp_app_dict".\n\n{list(set([ua["bin_name"].split("_")[0] for ua in all_files]))}')
        error(f'"{appx_package}" not found in "uwp_app_dict". This is probably caused by "package_json" filters:\n{package_json}')
    
    #Download each dependency
    newer_uwp_app = download_uwp_dependency(uwp_app_dict,all_files_dict,proxies)
    
    #To make things pretty
    if debug_mode:
        print("\n")
    
    # Changing version of the package
    if Version(version) > Version(control.get_software_version()):
        print("Software version updated (from: %s to: %s)" % (control.get_software_version(), Version(version)))
        package_updated = True
    else:
        print("Software version up-to-date (%s)" % Version(version))

    if debug_mode:
        print("Deleting binary files and exiting")
        for uwp_file in glob.glob(f'{newer_uwp_app["Name"]}*{newer_uwp_app["Version"]}*.*'):
            remove_file(uwp_file)
            return

    control.set_software_version(version)
    control.save_control_to_wapt()

    # Placing binaries in a dir ["appxbundle", "msixbundle", "appx", "msix]
    for f in glob.glob("*.part"):
        remove_file(f)
    bins_dir = control.package.split("-", 1)[1]
    if isdir(bins_dir):
        remove_tree(bins_dir)
    mkdirs(bins_dir)
    for uwp_file in glob.glob(f'{newer_uwp_app["Name"]}*{newer_uwp_app["Version"]}*.*'):
        if not isfile(makepath(bins_dir, uwp_file)):
            shutil.move(uwp_file, bins_dir)
    if uwp_app_dict[newer_uwp_app["FileName"]]["Dependencies"] is not None:
        for l in [glob.glob(a["Name"] + "_*") for a in uwp_app_dict[newer_uwp_app["FileName"]]["Dependencies"]]:
            for f in l:
                if not isfile(makepath(bins_dir, f)):
                    shutil.move(f, bins_dir)

    # Deleting outdated binaries
    remove_outdated_binaries(version, ["appxbundle", "msixbundle", "appx", "msix", "part"], latest_bin)

    # Validating or not update-package-sources
    return package_updated

def get_json(app_id):
    # download json from url and return it as dict
    url = "https://storeedgefd.dsx.mp.microsoft.com/v9.0/products/%s?market=US&locale=en-us&deviceFamily=Windows.Desktop" % app_id
    dict = json.loads(requests.get(url).text)
    return dict

def get_all_files(store_id,proxies):
    all_files = url_generator(
        store_id,
        proxies=proxies
    )

    #Debug print raw dict directly from API
    if debug_mode:
        all_files_json = json.dumps(all_files,indent=4)
        print("*** Raw return from url_generator() ***")
        print(f"all_files : {all_files_json}\n")

    all_files_dict = []
    
    # parse every file name and url in all_files and make a dict:
    for i,download_url in all_files[0].items():
        version = i.split("_")[1]
        bin_name = i.replace("~", "_")
        pkg_splitted = re.split(r"_\d+\.", bin_name)[0]
        package_prefix = control.package.split("-")[0]
        package_name = package_prefix + "-" + pkg_splitted.split("_")[0].replace(".", "-").lower()
        software_name = bin_name.split("_")[0].replace("-", " ").replace(".", " ")
        if "arm64" in bin_name:
            package_arch = "arm64"
        elif "arm" in bin_name:
            package_arch = "arm"
        elif "x64" in bin_name:
            package_arch = "x64"
        # elif "x86" in bin_name:
        #     package_arch = "all"  # not x86 since it may be required for x64
        else:
            package_arch = "all"

        file_dict = {
            "version": version,
            "bin_name": bin_name,
            "package_name": package_name,
            "software_name": software_name,
            "package_arch": control.architecture,
            "package_arch": package_arch,
            "download_url": download_url,
        }
        all_files_dict.append(file_dict)
    return all_files_dict

def url_generator(url,proxies):
    def uwp_gen(data_list):

        cat_id = data_list["WuCategoryId"]
        main_file_name = data_list["PackageFamilyName"].split("_")[0]
        release_type = "Retail"

        #Ask Microsoft API for a cookie
        with open(rf"{basedir}\data\xml\GetCookie.xml", "r") as f:
            cookie_content = f.read()

        out = requests.post(
            "https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx",
            data=cookie_content,
            headers={"Content-Type": "application/soap+xml; charset=utf-8"},
            proxies=proxies,
            verify=False
        ).text
        doc = minidom.parseString(out)

        cookie = doc.getElementsByTagName("EncryptedData")[0].firstChild.nodeValue

        with open(rf"{basedir}\data\xml\WUIDRequest.xml", "r") as f:
            cat_id_content = f.read().format(cookie, cat_id, release_type)

        out = requests.post(
            "https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx",
            data=cat_id_content,
            headers={"Content-Type": "application/soap+xml; charset=utf-8"},proxies=proxies,verify=False).text

        doc = minidom.parseString(html.unescape(out))
        
        if loop_enable:
            #To avoid picking wrong miror, make 5 requests and merge responses
            req = 0
            for req in range(4):
                out2 = requests.post(
                    "https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx",
                    data=cat_id_content,
                    headers={"Content-Type": "application/soap+xml; charset=utf-8"},proxies=proxies,verify=False).text

                doc2 = minidom.parseString(html.unescape(out2))
                imp = doc.importNode(doc2.childNodes[0],True)
                doc.childNodes[0].appendChild(imp)
                req += 1
            
        filenames = {}
        for node in doc.getElementsByTagName("Files"):
            try:
                filenames[
                    node.parentNode.parentNode.getElementsByTagName("ID")[0].firstChild.nodeValue
                ] = (
                    f"{node.firstChild.attributes['InstallerSpecificIdentifier'].value}_{node.firstChild.attributes['FileName'].value}",
                    node.firstChild.attributes["Modified"].value,
                )
            except KeyError:
                continue
        if not filenames:
            raise Exception("server returned an empty list")

        identities = {}
        name_modified = {}
        for node in doc.getElementsByTagName("SecuredFragment"):
            try:
                file_name, modifed = filenames[
                    node.parentNode.parentNode.parentNode.getElementsByTagName("ID")[0].firstChild.nodeValue
                ]
                update_identity = node.parentNode.parentNode.firstChild
                name_modified[file_name] = modifed
                identities[file_name] = (
                    update_identity.attributes["UpdateID"].value,
                    update_identity.attributes["RevisionNumber"].value,
                )
            except KeyError:
                continue
        
        api_dict = {value: identities[value] for value in name_modified}
        
        #Debug print raw dict directly from API
        if debug_mode:
            api_dict_json = json.dumps(api_dict,indent=4)
            print("*** First API Return from url_generator() ***")
            print(f"api_dict : {api_dict_json}\n")

        with open(rf"{basedir}\data\xml\FE3FileUrl.xml", "r") as f:
            file_content = f.read()

        file_dict = {}

        for file_name, (updateid, revisionnumber) in api_dict.items():

            out = requests.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"},
                proxies=proxies,
                verify=False
            ).text
            doc = minidom.parseString(out)
            for i in doc.getElementsByTagName("FileLocation"):
                url = i.getElementsByTagName("Url")[0].firstChild.nodeValue
                if len(url) != 99:
                    file_dict[file_name] = url


        if len(file_dict) != len(api_dict):
            raise Exception("server returned an incomplete list")

        return file_dict, main_file_name

    def non_uwp_gen(product_id):

        api = f"https://storeedgefd.dsx.mp.microsoft.com/v9.0/packageManifests//{product_id}?market=US&locale=en-us&deviceFamily=Windows.Desktop"

        data = requests.get(api,proxies=proxies).text
        datas = json.loads(data)

        if not datas.get("Data"):
            raise Exception("server returned an empty list")

        file_name = datas["Data"]["Versions"][0]["DefaultLocale"]["PackageName"]
        installer_list = datas["Data"]["Versions"][0]["Installers"]

        download_data = set((d["Architecture"], d["InstallerLocale"], d["InstallerType"], d["InstallerUrl"]) for d in installer_list)
        curr_arch = os_arc()
        download_data = list(download_data)

        arch, locale, installer_type, url = download_data[0]
        if len(download_data) > 1:
            for data in download_data[1:]:
                if arch not in ("neutral", curr_arch) and data[0] in ("neutral", curr_arch):
                    arch, locale, installer_type, url = data
                elif data[0] == arch and data[1] != locale and ("us" in data[1] or "en" in data[1]):
                    locale, installer_type, url = data[1], data[2], data[3]
                    break

        main_file_name = clean_name(file_name) + "." + installer_type
        file_dict = {main_file_name: url}
        return file_dict, [main_file_name], main_file_name, False

    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()

    pattern = re.compile(r".+\/([^\/\?]+)(?:\?|$)")
    matches = pattern.search(str(url))
    if not matches:
        raise Exception("No Data Found: --> [You Selected Wrong Page, Try Again!]")

    product_id = matches.group(1)
    details_api = f"https://storeedgefd.dsx.mp.microsoft.com/v9.0/products/{product_id}?market=US&locale=en-us&deviceFamily=Windows.Desktop"
    data = requests.get(details_api,proxies=proxies).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"):
        raise Exception("No Data Found: --> [You Selected Wrong Page, Try Again!]")

    response_data = response["Payload"]["Skus"][0]
    data_list = response_data.get("FulfillmentData")

    if data_list:
        return uwp_gen(data_list)
    else:
        return non_uwp_gen(product_id)

def ask_app_filename(all_files_dict, store_package_name, ignored_versions=[], version_prefix=None):
    # input files dict and a  store packa_name if it exist, if empty selct automatically the proper file if not ask user to select it
    if "template-microsoft-store" in control.package:
        selected = waptguihelper.grid_dialog(
            "Please select the proper file",
            json.dumps(all_files_dict),
            waptguihelper.GRT_SELECTED,
            '{"columns":[{"propertyname":"version","datatype":"String","required":false,"readonly":false,"width":130},{"propertyname":"bin_name","datatype":"String","required":false,"readonly":false,"width":420},{"propertyname":"package_name","datatype":"String","required":false,"readonly":false,"width":190},{"propertyname":"software_name","datatype":"String","required":false,"readonly":false,"width":172},{"propertyname":"package_arch","datatype":"String","required":false,"readonly":false,"width":88},{"propertyname":"download_url","datatype":"String","required":false,"readonly":false,"width":1472}]}',
        )
    else:
        selected = [a for a in all_files_dict if (a["package_arch"] in ensure_list(control.architecture) or control.architecture == "all" or a["package_arch"] == "all")]
        if len(selected) > 1:
            if version_prefix:
                target_version = None
                for app_file in all_files_dict:
                    latest_bin = app_file["bin_name"]
                    if not latest_bin.startswith(f"{store_package_name}_"):  # ignore other files
                        continue
                    if latest_bin.split(".")[-1].lower().startswith("e"):  # ignore encrypted UWP apps
                        continue
                    if version_prefix is not None and Version(app_file["version"], len(version_prefix.split("."))) == Version(
                        version_prefix, len(version_prefix.split(".")) and target_version < Version(app_file["version"]) #Find the file matching version_prefix
                    ):
                        target_version=app_file["version"]
                        break
                selected = [a for a in selected if target_version == a["version"] and store_package_name in a["bin_name"]]
            else:
                higher_version = "0"
                for a in all_files_dict:
                    if any(
                        Version(a["version"], len(ignored_version.split("."))) == Version(ignored_version, len(ignored_version.split(".")))
                        for ignored_version in ignored_versions #ignore files in ignored_versions
                    ):
                        continue
                    if Version(higher_version) < Version(a["version"]) and store_package_name in a["bin_name"]: # Select the higher version
                        higher_version = a["version"]
                        continue
                selected = [a for a in selected if higher_version == a["version"] and store_package_name in a["bin_name"]]

    return selected

def ask_control_categories():
    """Requesting that the user supply package categories for the control.categories field if empty or Template is selected"""

    if control.categories == "Template":
        categories = waptguihelper.grid_dialog(
            "Select package categories",
            [
                "Internet",
                "Utilities",
                "Messaging",
                "Security",
                "System and network",
                "Media",
                "Development",
                "Office",
                "Drivers",
                "Education",
                "Configuration",
                "CAD",
                "Template",
                "Dependencies",
                "Extensions",
            ],
            waptguihelper.GRT_SELECTED,
        )
        if categories:
            control.categories = ",".join([a["unknown"] for a in categories])
        else:
            control.categories = ""
        control.save_control_to_wapt()
    return control.categories

def ask_control_architecture(package_arch):
    """Requesting that the user supply package architecture for the control.architecture field if empty or Template is selected"""

    if control.categories == "Template":
        architecture = waptguihelper.grid_dialog(
            f"Package Architecture available : {package_arch}",
            [
                "all",
                "x64",
                "x86",
                "arm",
                "arm64",
            ],
            waptguihelper.GRT_SELECTED,
        )
        if architecture:
            control.architecture = ",".join([a["unknown"] for a in architecture])
        else:
            control.architecture = package_arch
        control.save_control_to_wapt()
    return control.architecture

def ask_control_package(control_package, conditionnal_package_name=None, remove_base_files=False):
    """Requesting that the user provide a package name to be entered into the control.package field, and offering the possibility of removing the base files (icon.png and changelog.txt) for template package usage

    Args:
        control_package             (str)   : prefilled control_package (default: actual control_package)
        conditionnal_package_name   (str)   : only ask when the control.package contains conditionnal_package_name (default: always ask for control_package)
        remove_base_files           (bool)  : removes base files if parameter is True and conditionnal_package_name is provided (default: False)
    """
    if conditionnal_package_name is None or conditionnal_package_name in control.package:
        control.package = waptguihelper.input_dialog(control.package, "You can redefine the package name", control_package)
        control.save_control_to_wapt()

    # Removing template files
    if conditionnal_package_name in control.package and remove_base_files:
        if isfile("WAPT\\changelog.txt"):
            remove_file("WAPT\\changelog.txt")
        if isfile("WAPT\\icon.png"):
            remove_file("WAPT\\icon.png")
    return control.package

def ask_control_name(control_name, conditionnal_package_name=None):
    """Requesting that the user provide a package name to be entered into control.name field

    Args:
        control_name                (str)   : prefilled control_name (default: control.name)
        conditionnal_package_name   (str)   : only ask when the control.name contains conditionnal_package_name (default: always ask for control_name)
    """
    if conditionnal_package_name is None or conditionnal_package_name in control.name:
        control.name = waptguihelper.input_dialog(control.name, "You can redefine the name for the self-service", control_name)
        control.save_control_to_wapt()
    return control.name

def ask_control_description(blank_str=None, description_from_store=""):
    """Requesting that the user supply package description for the control.description field

    Args:
        blank_str   (str): The description will be cleared if it includes the specified string to avoid using the template description (default: do not clear description)
    """
    if not control.description:
        control.description = ask_dialog("Description", "Please fill the description", description_from_store)
        control.save_control_to_wapt()
    if blank_str is not None and blank_str in control.description:
        control.description = ""
        control.save_control_to_wapt()
    return control.description

def ask_dialog(title, text, default="", stay_on_top=False):
    """This function opens a dialog box with a action input"""
    # - Title: the title for the dialog
    # - Text: indicates which value the user should type
    # - Default: the default value, if the user do not want to type any
    # Optional:
    # - StayOnTop: indicates if the form will always stay on top - default is False
    return waptguihelper.input_dialog(title, text, default, stay_on_top)

def get_description(dict):
    # get the description from the dict
    return dict["Payload"]["Skus"][0]["Description"]

def make_dependency_dict(appx_package_name):

    #Make dependendy dict directly from binary file
    ms_app_db = {}

    for ms_app_file in (
        glob.glob(f"{appx_package_name}*.appxbundle")
        + glob.glob(f"{appx_package_name}*.msixbundle")
        + glob.glob(f"{appx_package_name}*.appx")
        + glob.glob(f"{appx_package_name}*.msix")
    ):
        data_dict = {}
        before_dependencies = []
        sub_dependencies = []
        dependency_data_dict = None

        manifest = None
        bundle_manifest = None

        manifest_path = makepath(basedir,"AppxManifest.xml")
        # Get AppxManifest, contains dependencies list
        unzip_with_7zip(ms_app_file, ".", "AppxManifest.xml", False)
        
        if isfile(manifest_path):
            manifest = manifest_path
        
        bundle_manifest_path = makepath(basedir,"AppxBundleManifest.xml")
        # Get AppxBundleManifest, contains dependencies list
        unzip_with_7zip(ms_app_file, ".", "AppxMetadata\\AppxBundleManifest.xml", False)
        
        if isfile(bundle_manifest_path):
            bundle_manifest = bundle_manifest_path
        
        ms_app_info = {
            "FileName": ms_app_file,
        }

        if not manifest:
            if bundle_manifest:
                with open(bundle_manifest, encoding="utf8") as xml_file:
                    data_dict = xmltodict.parse(xml_file.read(), attr_prefix="")

                if type(data_dict["Bundle"]["Packages"]["Package"]) == dict:
                    data_dict["Bundle"]["Packages"]["Package"] = [dict(data_dict["Bundle"]["Packages"]["Package"])]

                for app_pkg in list(data_dict["Bundle"]["Packages"]["Package"]):
                    if app_pkg["Type"] == "application":
                        before_dependency_info = {
                            "FileName": app_pkg["FileName"],
                            "Version": app_pkg["Version"],
                            "Architecture": app_pkg["Architecture"],
                        }
                        before_dependencies.append(before_dependency_info)

                if before_dependencies:
                    for dependency in before_dependencies:
                        unzip(
                            ms_app_file,
                            ".",
                            makepath(
                                dependency["FileName"],
                            ),
                            False,
                        )
                        unzip(dependency["FileName"], ".", makepath("AppxManifest.xml"), False)
                        manifest = manifest_path = makepath(basedir,"AppxManifest.xml")
                        if isfile(dependency["FileName"]):
                            remove_file(dependency["FileName"])
                        with open(manifest, encoding="utf8") as xml_file:
                            dependency_data_dict = xmltodict.parse(xml_file.read(), attr_prefix="")

                    if dependency_data_dict["Package"].get("Dependencies"):
                        if dependency_data_dict["Package"]["Dependencies"].get("PackageDependency"):
                            sub_dependencies = list(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])
                            if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == dict:
                                sub_dependencies = [dict(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])]
                            if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == list:
                                sub_dependencies = dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]
                        if dependency_data_dict["Package"]["Dependencies"].get("TargetDeviceFamily"):
                            if not "TargetDeviceFamily" in ms_app_info:
                                if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == dict:
                                    ms_app_info["TargetDeviceFamily"] = [dict(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"])]
                                if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == list:
                                    ms_app_info["TargetDeviceFamily"] = dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]
            else:
                error("nothing to parse")
        else:
            unzip_with_7zip(ms_app_file, ".", makepath("AppxManifest.xml"), False)
            manifest = manifest_path = makepath(basedir,"AppxManifest.xml")
            with open(manifest, encoding="utf8") as xml_file:
                dependency_data_dict = xmltodict.parse(xml_file.read(), attr_prefix="")

        if dependency_data_dict["Package"].get("Dependencies"):
            if "PackageDependency" in dependency_data_dict["Package"]["Dependencies"]:
                sub_dependencies = list(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])
                if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == dict:
                    sub_dependencies = [dict(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])]
                if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == list:
                    sub_dependencies = dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]
            if "TargetDeviceFamily" in dependency_data_dict["Package"]["Dependencies"]:
                if not "TargetDeviceFamily" in ms_app_info:
                    if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == dict:
                        ms_app_info["TargetDeviceFamily"] = [dict(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"])]
                    if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == list:
                        ms_app_info["TargetDeviceFamily"] = dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]
        else:
            ms_app_info.update({"Dependencies": None})

        if ms_app_info.get("TargetDeviceFamily"):
            ms_app_info.update(
                {
                    "MinVersion": ms_app_info["TargetDeviceFamily"][0]["MinVersion"],
                    "MaxVersionTested": ms_app_info["TargetDeviceFamily"][0]["MaxVersionTested"],
                }
            )
        elif dependency_data_dict is not None and dependency_data_dict["Package"].get("Prerequisites"):
            ms_app_info.update(
                {
                    "MinVersion": dependency_data_dict["Package"]["Prerequisites"]["OSMinVersion"],
                    "MaxVersionTested": dependency_data_dict["Package"]["Prerequisites"]["OSMaxVersionTested"],
                }
            )
        else:
            ms_app_info.update({"TargetDeviceFamily": None})

        if data_dict:
            ms_app_info.update(data_dict["Bundle"]["Identity"])
        else:
            ms_app_info.update(dependency_data_dict["Package"]["Identity"])
        if "ProcessorArchitecture" in ms_app_info:
            ms_app_info.update({"Architecture": ms_app_info["ProcessorArchitecture"]})
        if before_dependencies:
            ms_app_info["b4:Dependencies"] = before_dependencies
        else:
            ms_app_info.update({"b4:Dependencies": None})

        if sub_dependencies:
            ms_app_info["Dependencies"] = sub_dependencies
        else:
            ms_app_info.update({"Dependencies": None})

        ms_app_db[ms_app_file] = ms_app_info

        for xml_file in glob.glob("AppxManifest.xml") + glob.glob("AppxBundleManifest.xml"):
            remove_file(xml_file)

    return ms_app_db

def get_newer_uwp_depency(dependency_dict, all_files_dict, version_prefix=None, min_version=None):
    """Returns a list of the bin_name of the latest required dependencies"""
    newer_version = "0"

    for uwp_app in all_files_dict:
        if not uwp_app["bin_name"].startswith(f'{dependency_dict["Name"]}_'):
            continue
        if version_prefix is not None and Version(uwp_app["version"], len(version_prefix.split("."))) != Version(
            version_prefix, len(version_prefix.split("."))
        ):
            continue

        if Version(newer_version) < Version(uwp_app["version"]):
            newer_uwp_depency = uwp_app
            newer_version = uwp_app["version"]

    return newer_uwp_depency["bin_name"].split(newer_version + "_")[0] + newer_version + "_"

def download_uwp_dependency(uwp_app_dict,all_files_dict,proxies):

    #Return first dict from list of dict
    newer_uwp_app = next(iter(uwp_app_dict.values()))

    # Downloading dependency files
    dependencies_to_download = []
    if newer_uwp_app["Dependencies"]:
        for dependency in newer_uwp_app["Dependencies"]:
            #Find in all_files_dict, dependency needed in binary
            dependencies_to_download.append(get_newer_uwp_depency(dependency, all_files_dict, min_version=dependency["MinVersion"]))
    if dependencies_to_download:
        
        #Trigger warning that nothing will be download
        if debug_mode:
            print("\nNO DOWNLOADED DEPENDENCY - ONLY PRINTING\n")
        
        for dependency_file in all_files_dict:
            latest_bin = dependency_file["bin_name"]
            if not True in [d in latest_bin for d in dependencies_to_download]:  # ignore unecessary dependencies
                continue
            if not "all" in ensure_list(control.architecture):
                if not get_uwp_filename_arch(latest_bin) in ensure_list(control.architecture) and not "neutral" in latest_bin:
                    if isfile(latest_bin):
                        remove_file(latest_bin)
                    continue
            if latest_bin.split(".")[-1].lower().startswith("e"):  # ignore encrypted uwp apps
                continue

            #Only printing the dependencie without downloading
            if debug_mode:
                print(f"Dependencie to download : {latest_bin}")
                continue
            
            download_url = dependency_file["download_url"]
            if download_url.split("/")[2].endswith("microsoft.com"):
                if not isfile(latest_bin):
                    print("Downloading: %s" % latest_bin)
                    wget(download_url, latest_bin, proxies=proxies)
                else:
                    print("Binary is present: %s" % latest_bin)
            else:
                error("ERROR: The retrieved URL will not download from microsoft's servers")
    
    return newer_uwp_app

def get_uwp_filename_arch(appx_filename, appx_package_name=None):
    """
    Returns the architecture of a Universal Windows Platform (UWP) app based on the provided 'appx_filename'
    and optionally, the 'appx_package_name'.

    Args:
        appx_filename (str): The filename of the UWP app package.
        appx_package_name (str, optional): The package name of the UWP app. Defaults to None.

    Returns:
        str: The architecture of the UWP app, which can be "x64", "arm64", "x86", or "all" (if no specific
        architecture is detected).
    """
    if not appx_package_name:
        appx_package_name = None
    if len(glob.glob(f'{appx_package_name}*{appx_filename.split("_")[1]}*')) > 1:
        pass
    elif "arm64" in appx_filename:
        return "arm64"
    elif "arm" in appx_filename:
        return "arm"
    elif "x64" in appx_filename:
        return "x64"
    if appx_filename is not None and "x86" in appx_filename and (appx_package_name is None or not appx_package_name in appx_filename):
        return "x86"

    return "all"

38d056ab130f7bf7c481c12636a4e9959de36561d3dfcbe54c6e3571bc0c1dc3 : WAPT/certificate.crt
a1a0c1081c3e31784d1e3d00accd3887d2080556d101d79365afd9a21b6de3e3 : WAPT/control
5cd06abee4d9bc5102f5bf44b601bf5ee747193df5321c6e1fa2f0bd4ad83699 : WAPT/icon.png
a8a19f84f19654e4add3285303945d8f69fbe9f80236f13f29216951e41b6a17 : av1-video-extension/Microsoft.AV1VideoExtension_2.0.4.0_neutral___8wekyb3d8bbwe_7039500a-0900-4615-8f34-6781bcf47114.appxbundle
87370426807b83b7916c4f43942cd9bf71b1eeaf3b44728d241efe107927e3a2 : data/xml/FE3FileUrl.xml
2d3dd983c9d83c2464afaa85ab49ad5c78a537a131ec61e0c32f6b446bed4f55 : data/xml/GetCookie.xml
f8a4681fbeafb4ddcaac37b406374143900d8885b59ba7a7a0ec782d79bacd9b : data/xml/WUIDRequest.xml
d3eb736ef1a7c3c9580d815f509a845007081d63519954e46b7d9e58999769cb : luti.json
27903ed717f85f26e2825a8ad66c92ca32f76abc3c2f5a1783bbe3de430b8409 : package.json
83a72f609cc6cde447eb7f10a6333d1fc6f8d20279be9240afe6cafa3ba57acc : setup.py
f31bb903630e71ceeff68ce1e3058f3b120008d9beb2d9fda7491cfe67b49662 : setupdevhelpers.py
a4d71f3c52cdbec3ddded73e6ea0c31e5ea228b7466179272ab8ffae2e0ce0a9 : update_package.py
364e01205533a0c6907fb9e8a8f70353985ae81ead35b71aade9a4253184f847 : xmltodict.py