Merge branch 'main' of github.com:xpamych/PortProton_2.0 into xpamych-main
This commit is contained in:
commit
be95574b16
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,5 @@
|
|||||||
*.log
|
*.log
|
||||||
modules/__pycache__
|
modules/__pycache__
|
||||||
|
*.idea
|
||||||
|
app.log
|
||||||
|
.gigaide
|
41
README-RU.md
Normal file
41
README-RU.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<div align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/Castro-Fidel/PortWINE/master/data_from_portwine/img/gui/portproton.svg" width="64">
|
||||||
|
<h1 align="center">PortProton 2.0 (В разработке)</h1>
|
||||||
|
<a href="https://github.com/Castro-Fidel/PortWINE/blob/master/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/Castro-Fidel/PortWine?logo=github" alt="GitHub License">
|
||||||
|
</a>
|
||||||
|
<a href="https://t.me/linux_gaming_ru">
|
||||||
|
<img src="https://img.shields.io/endpoint?&style=flat&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Flinux_gaming_ru" alt="Telegram">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.youtube.com/@linux-gaming5986">
|
||||||
|
<img src="https://img.shields.io/youtube/channel/subscribers/UCbI8OJx2D3q-4QKt4LffXTw?style=flat&logo=youtube" alt="YouTube Channel Subscribers">
|
||||||
|
</a>
|
||||||
|
<br/>
|
||||||
|
<p align="center">
|
||||||
|
Проект(реализация на python), призванный сделать запуск Windows-игр в Linux простым и удобным как для начинающих, так и для опытных пользователей.<br>
|
||||||
|
Проект стремится сделать запуск игр (и другого программного обеспечения) максимально простым, но в то же время предоставляет гибкие настройки для опытных пользователей.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
# **Язык README**
|
||||||
|
|
||||||
|
**Русский** - [English](README.md)
|
||||||
|
|
||||||
|
## Внимание
|
||||||
|
|
||||||
|
**Официальный сайт проекта** с сентября 2022 года: https://linux-gaming.ru. **Любой другой сайт - фальшивка!**
|
||||||
|
|
||||||
|
## Особенности
|
||||||
|
|
||||||
|
- Основан на версии WINE от Valve (Proton) и ее модификациях (Proton GE).
|
||||||
|
Включает набор скриптов, объединенных с самим wine-proton, контейнер Steam Runtime Sniper с добавлением портированных версий MANGOHUD (вывод полезной информации в окно игры: FPS, FrameTime, CPU, GPU и т.д.) и vkBasalt (улучшение графики в играх, очень хорош в связке с FSR, DLSS) + множество уже настроенных оптимизаций для максимальной производительности.
|
||||||
|
|
||||||
|
- Для любителей консольных игр предлагается множество эмуляторов консолей (на вкладке ЭМУЛЯТОРЫ ): PPSSPP, Citra, Cemu, ePSXe, MAME и многие другие..
|
||||||
|
|
||||||
|
**ПОЖАЛУЙСТА, НЕ СООБЩАЙТЕ О НАЙДЕННЫХ ОШИБКАХ В WINEHQ ИЛИ ПРОГРАММНОМ ОБЕСПЕЧЕНИИ VALVE!**
|
||||||
|
|
||||||
|
## **Ссылка на исходный код версий wine используемых в PortProton:**
|
||||||
|
|
||||||
|
* WINE-PROTON: https://github.com/ValveSoftware/Proton
|
||||||
|
|
||||||
|
* WINE-PROTON-GE: https://github.com/GloriousEggroll/proton-ge-custom
|
46
README.md
46
README.md
@ -1 +1,45 @@
|
|||||||
# PortProton_2.0
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/Castro-Fidel/PortWINE/master/data_from_portwine/img/gui/portproton.svg" width="64">
|
||||||
|
<h1 align="center">PortProton 2.0 (in progress)</h1>
|
||||||
|
<a href="https://github.com/Castro-Fidel/PortWINE/blob/master/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/Castro-Fidel/PortWine?logo=github" alt="GitHub License">
|
||||||
|
</a>
|
||||||
|
<a href="https://t.me/linux_gaming_ru">
|
||||||
|
<img src="https://img.shields.io/endpoint?&style=flat&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Flinux_gaming_ru" alt="Telegram">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.youtube.com/@linux-gaming5986">
|
||||||
|
<img src="https://img.shields.io/youtube/channel/subscribers/UCbI8OJx2D3q-4QKt4LffXTw?style=flat&logo=youtube" alt="YouTube Channel Subscribers">
|
||||||
|
</a>
|
||||||
|
<br/>
|
||||||
|
<p style="text-align: center;">
|
||||||
|
A project (python realisation) designed to make running Windows games on Linux easy and convenient for both beginners and advanced users.<br>
|
||||||
|
The project aims to simplify the process of launching games (and other software) while also providing flexible settings for experienced users.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
# **Readme Language**
|
||||||
|
|
||||||
|
**English** - [Русский](README-RU.md)
|
||||||
|
|
||||||
|
## Attention
|
||||||
|
|
||||||
|
The **official website of the project** since September 2022 is: https://linux-gaming.ru. **Any other site is fake!**
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Based on the version of WINE from Valve (Proton) and its modifications (Proton GE).
|
||||||
|
Includes a set of scripts combined with wine-proton itself, a Steam Runtime Sniper container with the addition of
|
||||||
|
ported mangoHud (output useful information over the game window: FPS, frametime, CPU, GPU, etc.),
|
||||||
|
vkBasalt (improvement of graphics in games, great alongside FSR or DLSS) versions,
|
||||||
|
and many already configured optimizations for maximum performance.
|
||||||
|
|
||||||
|
- For fans of console games, there are many console emulators to choose from (in the EMULATORS tab): PPSSPP, Citra, Cemu, ePSXe, MAME, and many others.
|
||||||
|
|
||||||
|
**PLEASE DON'T REPORT BUGS ENCOUNTERED WITH THIS AT WINEHQ OR VALVE SOFTWARE!**
|
||||||
|
|
||||||
|
## **Wine sources used in PortWINE:**
|
||||||
|
|
||||||
|
* WINE-PROTON: https://github.com/ValveSoftware/Proton
|
||||||
|
|
||||||
|
* WINE-PROTON-GE: https://github.com/GloriousEggroll/proton-ge-custom
|
||||||
|
@ -6,7 +6,7 @@ from .files_worker import *
|
|||||||
|
|
||||||
def try_download(url, save_path=None):
|
def try_download(url, save_path=None):
|
||||||
"""
|
"""
|
||||||
Скачивает файл по указанному URL с отображением прогресса.
|
Скачивает файл по-указанному URL с отображением прогресса.
|
||||||
|
|
||||||
:param url: URL файла для скачивания.
|
:param url: URL файла для скачивания.
|
||||||
:param save_path: Путь для сохранения файла. Если None или директория, то используется имя файла из URL.
|
:param save_path: Путь для сохранения файла. Если None или директория, то используется имя файла из URL.
|
||||||
|
@ -31,10 +31,10 @@ def try_force_link_file(source, link):
|
|||||||
|
|
||||||
os.symlink(source, link)
|
os.symlink(source, link)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"failed to create link for file: {e}")
|
log.error(f"failed to create link for file: {e}")
|
||||||
|
|
||||||
|
|
||||||
def try_remove_file(path):
|
def try_remove_file(file_path):
|
||||||
if os.path.exists(file_path) and os.path.isfile(file_path):
|
if os.path.exists(file_path) and os.path.isfile(file_path):
|
||||||
try:
|
try:
|
||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
@ -60,21 +60,55 @@ def try_force_link_dir(path, link):
|
|||||||
|
|
||||||
os.symlink(path, link)
|
os.symlink(path, link)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"failed to create link for file: {e}")
|
log.error(f"failed to create link for file: {e}")
|
||||||
|
|
||||||
|
def replace_file(file_path, file_name): # функция замены файла (сначала запись во временный файл, потом замена)
|
||||||
|
try:
|
||||||
|
if os.path.exists(file_name) and os.path.getsize(file_name) > 0:
|
||||||
|
os.replace(file_name, file_path) # Меняем местами файлы, если временный файл не пуст
|
||||||
|
log.info(f"Данные успешно обновлены в {file_path}.")
|
||||||
|
else:
|
||||||
|
log.warning(f"Временный файл {file_name} пуст, замена в {file_path} не выполнена.")
|
||||||
|
if os.path.exists(file_name):
|
||||||
|
os.remove(file_name) # Удаляем пустой временный файл
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Ошибка при замене файла: {e}")
|
||||||
|
|
||||||
|
def try_write_temp_file(file_path, file_name): # функция записи в tmp
|
||||||
|
try:
|
||||||
|
with open(file_path, 'w') as file:
|
||||||
|
file.write("\n".join(file_name)) # Записываем все имена файлов во временный файл
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Ошибка при записи во временный файл {file_path}: {e}")
|
||||||
|
|
||||||
def try_remove_dir(path):
|
def try_remove_dir(path):
|
||||||
if os.path.exist(path) and os.path.isdir(path):
|
if os.path.exists(path) and os.path.isdir(path):
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"failed to remove directory: {e}")
|
log.error(f"failed to remove directory: {e}")
|
||||||
|
|
||||||
|
def get_last_modified_time(file_path): # функция получения времени последнего изменения файла
|
||||||
|
try:
|
||||||
|
return os.path.getmtime(file_path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
log.warning(f"Файл не найден: {file_path}")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Ошибка при получении времени изменения файла {file_path}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def unpack(archive_path, extract_to=None):
|
def unpack(archive_path, extract_to=None):
|
||||||
|
# Проверяем, существует ли архив
|
||||||
|
if not os.path.isfile(archive_path):
|
||||||
|
log.error(f"Архив {archive_path} не найден.")
|
||||||
|
return False
|
||||||
try:
|
try:
|
||||||
if extract_to is None:
|
if extract_to is None:
|
||||||
# TODO: перенести распаковку по умолчанию в tmp
|
# TODO: перенести распаковку по умолчанию в tmp
|
||||||
extract_to = os.path.dirname(archive_path)
|
extract_to = os.path.dirname(archive_path)
|
||||||
elif not os.exists.isdir(extract_to):
|
elif not os.path.isdir(extract_to):
|
||||||
create_new_dir(extract_to)
|
create_new_dir(extract_to)
|
||||||
|
|
||||||
with tarfile.open(archive_path, mode="r:*") as tar:
|
with tarfile.open(archive_path, mode="r:*") as tar:
|
||||||
@ -83,8 +117,15 @@ def unpack(archive_path, extract_to=None):
|
|||||||
log.info(f"Архив {archive_path} успешно распакован в {full_path}")
|
log.info(f"Архив {archive_path} успешно распакован в {full_path}")
|
||||||
except tarfile.TarError as e:
|
except tarfile.TarError as e:
|
||||||
log.error(f"Ошибка при распаковке архива {archive_path}: {e}")
|
log.error(f"Ошибка при распаковке архива {archive_path}: {e}")
|
||||||
|
return False
|
||||||
|
except PermissionError:
|
||||||
|
log.error(f"Ошибка доступа к файлу {archive_path}. Убедитесь, что у вас есть права на чтение.")
|
||||||
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Неизвестная ошибка: {e}")
|
log.error(f"Неизвестная ошибка: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def check_hash_sum(check_file, check_sum):
|
def check_hash_sum(check_file, check_sum):
|
||||||
if check_sum and isinstance(check_sum, str):
|
if check_sum and isinstance(check_sum, str):
|
||||||
|
@ -2,8 +2,7 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
class ColoredFormatter(logging.Formatter):
|
class ColoredFormatter(logging.Formatter):
|
||||||
# ANSI escape sequences for colors
|
COLORS = { # ANSI escape sequences for colors
|
||||||
COLORS = {
|
|
||||||
'DEBUG': '\033[35m', # Purple
|
'DEBUG': '\033[35m', # Purple
|
||||||
'INFO': '\033[36m', # Green
|
'INFO': '\033[36m', # Green
|
||||||
'WARNING': '\033[33m', # Yellow
|
'WARNING': '\033[33m', # Yellow
|
||||||
@ -21,19 +20,33 @@ class ColoredFormatter(logging.Formatter):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return formatted_message
|
return formatted_message
|
||||||
|
|
||||||
# Настраиваем логирование
|
|
||||||
log = logging.getLogger()
|
|
||||||
# TODO: добавить case с переменной для управление уровнем
|
|
||||||
log.setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
# Создаем консольный обработчик
|
log = logging.getLogger() # Настраиваем логирование
|
||||||
handler = logging.StreamHandler()
|
def set_logging_level(level_string):
|
||||||
|
levels = {
|
||||||
|
'DEBUG': logging.DEBUG,
|
||||||
|
'INFO': logging.INFO,
|
||||||
|
'WARNING': logging.WARNING,
|
||||||
|
'ERROR': logging.ERROR,
|
||||||
|
'CRITICAL': logging.CRITICAL
|
||||||
|
}
|
||||||
|
|
||||||
|
level = levels.get(level_string, logging.WARNING) # Уровень по умолчанию
|
||||||
|
if level == logging.WARNING:
|
||||||
|
print(f"Неизвестный уровень логирования: {level_string}. Устанавливается уровень WARNING.")
|
||||||
|
return level
|
||||||
|
|
||||||
|
|
||||||
|
log_level_input = 'DEBUG' # Задаем уровень логирования через функцию
|
||||||
|
log.setLevel(set_logging_level(log_level_input))
|
||||||
|
|
||||||
|
handler = logging.StreamHandler() # Создаем консольный обработчик
|
||||||
handler.setFormatter(ColoredFormatter('%(levelname)s: %(message)s'))
|
handler.setFormatter(ColoredFormatter('%(levelname)s: %(message)s'))
|
||||||
|
|
||||||
# Создаем файловый обработчик
|
# TODO: добавить условие для управления переменой пути сохранения лога
|
||||||
# TODO: добавить условие для управления перемееной пути сохранения лога
|
log_file_path = 'app.log' # Это может быть переменная, установленная пользователем
|
||||||
file_handler = logging.FileHandler('app.log')
|
file_handler = logging.FileHandler(log_file_path) # Создаем файловый обработчик
|
||||||
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s: %(message)s'))
|
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s: %(message)s'))
|
||||||
log.addHandler(file_handler)
|
|
||||||
|
|
||||||
|
log.addHandler(file_handler)
|
||||||
log.addHandler(handler)
|
log.addHandler(handler)
|
||||||
|
109
modules/source_fetcher.py
Normal file
109
modules/source_fetcher.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import re
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
from modules.downloader import try_download
|
||||||
|
from modules.files_worker import *
|
||||||
|
|
||||||
|
count_wines = 25 # Количество элементов для записи в .tmp файл
|
||||||
|
repos = { # Список репозиториев для обработки и их короткие имена
|
||||||
|
"GloriousEggroll/proton-ge-custom": "proton-ge-custom",
|
||||||
|
"Kron4ek/Wine-Builds": "Kron4ek",
|
||||||
|
"GloriousEggroll/wine-ge-custom": "wine-ge-custom",
|
||||||
|
"CachyOS/proton-cachyos": "proton-cachyos",
|
||||||
|
"Castro-Fidel/wine_builds": "LG"
|
||||||
|
}
|
||||||
|
|
||||||
|
def source_list_checker(tmp_path): # Проверка наличия и обновления файлов со списками исходников
|
||||||
|
for repo, short_name in repos.items():
|
||||||
|
output_file = os.path.join(tmp_path, f"{short_name}.tmp")
|
||||||
|
|
||||||
|
if not os.path.exists(output_file):
|
||||||
|
log.info(f"Файл {output_file} не существует. Получаем данные из репозитория.")
|
||||||
|
source_list_downloader(repo, tmp_path, short_name, output_file)
|
||||||
|
continue # Переходим к следующему репозиторию
|
||||||
|
|
||||||
|
if os.path.getsize(output_file) == 0: # Проверяем, является ли файл пустым
|
||||||
|
log.info(f"Файл {output_file} пуст. Обновляем данные.")
|
||||||
|
source_list_downloader(repo, tmp_path, short_name, output_file)
|
||||||
|
continue # Переходим к следующему репозиторию
|
||||||
|
|
||||||
|
last_modified_time = get_last_modified_time(output_file) # Получаем время последнего изменения файла
|
||||||
|
if last_modified_time is None: # Если время не удалось получить, пробуем обновить файл
|
||||||
|
log.info(f"Не удалось получить время последнего изменения для {output_file}. Попытаемся обновить.")
|
||||||
|
source_list_downloader(repo, tmp_path, short_name, output_file)
|
||||||
|
continue # Переходим к следующему репозиторию
|
||||||
|
|
||||||
|
current_time = time.time()
|
||||||
|
|
||||||
|
if current_time - last_modified_time >= 10800: # 10800 секунд = 3 часа, проверяем, устарел ли файл
|
||||||
|
log.info(f"Файл {output_file} устарел. Обновляем данные.")
|
||||||
|
source_list_downloader(repo, tmp_path, short_name, output_file)
|
||||||
|
else:
|
||||||
|
log.info(f"Файл {output_file} существует и был обновлён менее 3 часов назад. Используем кэшированные данные.")
|
||||||
|
|
||||||
|
def source_list_downloader(repo, tmp_path, short_name, output_file):
|
||||||
|
url = f"https://api.github.com/repos/{repo}/releases?per_page={count_wines}"
|
||||||
|
temp_file = os.path.join(tmp_path, f"{short_name}.tmp.new") # Временный файл
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(url)
|
||||||
|
response.raise_for_status() # Возбудим исключение для ошибок HTTP
|
||||||
|
releases = response.json()
|
||||||
|
|
||||||
|
log.debug(f"Ответ API: {releases}")
|
||||||
|
tar_files = [] # Проверяем каждый релиз
|
||||||
|
for release in releases:
|
||||||
|
assets = release.get('assets', [])
|
||||||
|
for asset in assets:
|
||||||
|
asset_name = asset['name']
|
||||||
|
if (
|
||||||
|
(re.search(r'(wine|proton)', asset_name, re.IGNORECASE) or
|
||||||
|
re.search(r'^GE-Proton\d+-\d+\.tar\.gz$', asset_name) or
|
||||||
|
re.search(r'^GE-Proton\d+(-\d+)?\.tar\.xz$', asset_name)) and
|
||||||
|
(asset_name.endswith('.tar.gz') or asset_name.endswith('.tar.xz'))
|
||||||
|
):
|
||||||
|
tar_files.append(asset_name) # Собираем все подходящие файлы
|
||||||
|
log.debug(f"Найденный файл: {asset_name}")
|
||||||
|
|
||||||
|
if not tar_files:
|
||||||
|
log.warning(f"Нет подходящих файлов в репозитории {repo}.")
|
||||||
|
return # Выходим из функции, если нет файлов
|
||||||
|
|
||||||
|
with open(temp_file, 'w') as file: # Записываем найденные файлы во временный файл
|
||||||
|
file.write("\n".join(tar_files))
|
||||||
|
|
||||||
|
log.info(f"Данные успешно записаны в временный файл {temp_file}.")
|
||||||
|
|
||||||
|
if os.path.exists(temp_file): # Если запись прошла успешно, заменяем основной файл
|
||||||
|
os.replace(temp_file, output_file)
|
||||||
|
log.info(f"Файл {output_file} успешно обновлен.")
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
log.error(f"Ошибка при получении данных из {repo}: {str(e)}")
|
||||||
|
|
||||||
|
def get_sources(args, tmp_path, dist_path):
|
||||||
|
os.makedirs(tmp_path, exist_ok=True)
|
||||||
|
source_list_checker(tmp_path)
|
||||||
|
|
||||||
|
if args:
|
||||||
|
for arg in args:
|
||||||
|
for repo, short_name in repos.items(): # определяем короткое имя репозитория
|
||||||
|
tmp_file_path = os.path.join(tmp_path, f"{short_name}.tmp")
|
||||||
|
|
||||||
|
if os.path.exists(tmp_file_path): # проверяем наличие файла
|
||||||
|
with open(tmp_file_path, 'r') as file:
|
||||||
|
all_tar_gz_files = file.read().splitlines()
|
||||||
|
|
||||||
|
for file_to_download in all_tar_gz_files: # Ищем совпадение в файле
|
||||||
|
if arg in file_to_download:
|
||||||
|
log.info(f"Найдено совпадение для '{arg}': {file_to_download} в файле {tmp_file_path}")
|
||||||
|
url = f"https://github.com/{repo}/releases/latest/download/{file_to_download}" # Получаем URL файла
|
||||||
|
tmp_file = os.path.join(tmp_path, file_to_download)
|
||||||
|
if not os.path.exists(tmp_file):
|
||||||
|
try:
|
||||||
|
try_download(url, tmp_path)
|
||||||
|
unpack(tmp_file, dist_path)
|
||||||
|
try_remove_file(tmp_file)
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Ошибка при загрузке или распаковке: {str(e)}")
|
@ -8,6 +8,7 @@ from modules.env_var import *
|
|||||||
from modules.files_worker import *
|
from modules.files_worker import *
|
||||||
from modules.downloader import *
|
from modules.downloader import *
|
||||||
from modules.init_wine import *
|
from modules.init_wine import *
|
||||||
|
from modules.source_fetcher import *
|
||||||
|
|
||||||
tmp_path = tempfile.gettempdir()
|
tmp_path = tempfile.gettempdir()
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ if __name__ == "__main__":
|
|||||||
case "--get-wine":
|
case "--get-wine":
|
||||||
# без аргументов сохраняем список доступных в tmp_path/get_wine.tmp и выводим в терминал
|
# без аргументов сохраняем список доступных в tmp_path/get_wine.tmp и выводим в терминал
|
||||||
# если есть аргумент (например WINE_LG_10-1) то обновляем и парсим tmp_path/get_wine.tmp с последующим скачиванием
|
# если есть аргумент (например WINE_LG_10-1) то обновляем и парсим tmp_path/get_wine.tmp с последующим скачиванием
|
||||||
get_wine(sys.argv[2:])
|
get_sources(sys.argv[2:], tmp_path, dist_path)
|
||||||
case "--get-dxvk":
|
case "--get-dxvk":
|
||||||
# без аргументов сохраняем список доступных в tmp_path/get_dxvk.tmp и выводим в терминал
|
# без аргументов сохраняем список доступных в tmp_path/get_dxvk.tmp и выводим в терминал
|
||||||
# если есть аргумент (например 2.5.3-31) то обновляем и парсим tmp_path/get_dxvk.tmp с последующим скачиванием
|
# если есть аргумент (например 2.5.3-31) то обновляем и парсим tmp_path/get_dxvk.tmp с последующим скачиванием
|
||||||
|
Loading…
Reference in New Issue
Block a user