diff --git a/README.RU.md b/README.RU.md index ab5b1c5..9e27571 100644 --- a/README.RU.md +++ b/README.RU.md @@ -1,19 +1,53 @@ [![EN](https://user-images.githubusercontent.com/9499881/33184537-7be87e86-d096-11e7-89bb-f3286f752bc6.png)](https://github.com/r57zone/ProtonShell/blob/master/README.md) [![RU](https://user-images.githubusercontent.com/9499881/27683795-5b0fbac6-5cd8-11e7-929c-057833e01fb1.png)](https://github.com/r57zone/ProtonShell/blob/master/README.RU.md) # ProtonShell -Легковесная оболочка для веб-сайтов, простых веб-приложений, работающая на базе системного браузера Microsoft Edge. На её основе можно сделать отдельное окно для Google Docs, ChatGPT, чата Twitch, клиента инстаграмма для ПК, с пользовательским js скриптом или какое-то веб-приложение в своём окне. +Легковесная оболочка для веб-сайтов, простых веб-приложений, работающая на базе системного браузера Microsoft Edge. На её основе можно сделать отдельное окно для сайтов, например, для: YouTube (TV), Google Docs, ChatGPT, чата Twitch, Инстаграмма, с пользовательским js скриптом или какое-то веб-приложение в своём окне. В папке `Apps` можно найти готовые параметры запуска для YouTube TV, ChatGPT, Discord, Instagram, чата Twitch, клиента X, а также простую оболочку для запуска других приложений. ## Скриншоты ![](https://github.com/user-attachments/assets/902b2e58-664d-460f-abfd-37de3c8c920b) +[![](https://github.com/user-attachments/assets/3fb00a8e-e835-45fe-9fa6-46657f4c1e0b)](https://github.com/user-attachments/assets/08b09024-ff66-4e07-837c-5b4d918862d7) [![](https://github.com/user-attachments/assets/c5f0d903-e7d4-42f3-91ad-38f7b6f08d4b)](https://github.com/user-attachments/assets/22419527-2937-4bdc-a7b8-95097cf25de7) [![](https://github-production-user-asset-6210df.s3.amazonaws.com/9499881/258204596-0de84193-e560-4165-b104-69c5a0b63d34.jpg)](https://github.com/r57zone/ProtonShell/assets/9499881/6a2701eb-869e-480a-8548-628daec17fe7) [![](https://github-production-user-asset-6210df.s3.amazonaws.com/9499881/258204442-90eb9ab6-d54b-4131-a8e8-12735213935f.jpg)](https://github.com/r57zone/ProtonShell/assets/9499881/e1ff8392-ba8b-4373-a20b-0d1a29773c10) +[![](https://github.com/user-attachments/assets/773978d5-e43c-4733-b05c-58fcad6c6a40)](https://github.com/user-attachments/assets/a4e77acb-1bfd-4fff-8e31-7415cd8b853a) +[![](https://github.com/user-attachments/assets/1c1a5637-6383-428a-8331-84656150f294)](https://github.com/user-attachments/assets/325c1c6d-8125-4f0a-beab-696e5fe7f19f) ## Настройка 1. Установите [Edge WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/). 2. Поместите файл `index.html` в папку с приложением или введите URL адрес, в конфигурационный файл. -3. Измените название, параметры окна, иконку, прокси, UserAgent и так далее, в конфигурационном файле `Config.ini`. -4. При необходимости измените иконку `exe`, с помощью [Resource Hacker](http://www.angusj.com/resourcehacker/). +3. Измените название, параметры окна, иконку, прокси, UserAgent и другие настройки, в конфигурационном файле `Config.ini`. +4. При необходимости измените иконку `exe`, с помощью [Resource Hacker](http://www.angusj.com/resourcehacker/) или укажите иконку в конфигурационном файле. + +## Параметры запуска +`-f index.html` - путь до html файла (относительный или полный). + +`-a "https://youtube.com/tv"` - адрес веб-сайта. + +`-n "My app"` - заголовок приложения. + +`-i MyIcon.ico` - путь до иконки. + +`-u Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0` - пользовательский агент (user agent). + +`-s 1.js` - пользовательский скрипт (userscript). + +`-w` - ширина приложения. + +`-h` - высота приложения. + +`-fullscreen` - полноэкранный режим. + +`-p` - изменение системной прокси на заданную (формат: IP:PORT). + +`-rp` - возврат прошлой системной прокси, для случаев изменения прокси на другую. + +`-b 3` - стиль рамок (None = `0`, Sizeable = `1`, Single = `2`, Dialog = 3, SizeToolWin = `4`, ToolWindow = `5`). + +`-t 50` - отступ сверху. + +`-l 50` - отступ справа. + +`-d` - включение режима отладки. ## Режим отладки Для быстрой отладки можно включить специальный режим, в котором доступно: изменение размеров, изменение User agent, очистка всех данных. Для включения измените параметр `Debug` на `1`. diff --git a/README.md b/README.md index 8de1da6..7031ac9 100644 --- a/README.md +++ b/README.md @@ -3,19 +3,53 @@ ← Choose language | Выберите язык # ProtonShell -Lightweight shell for websites, simple web applications, built on the Microsoft Edge system browser. Based on it you can make a self window for Google Docs, ChatGPT, Twitch chat, Instagram client for PC, with js userscript or some web application in its own window. +A lightweight shell for websites, simple web applications, based on the Microsoft Edge system browser. Based on it, you can make a separate window for websites such as: YouTube (TV), Google Docs, ChatGPT, Twitch chat, Instagram, with custom js script or some web application in its own window. In the `Apps` folder you can find ready-made startup options for YouTube TV, ChatGPT, Discord, Instagram, Twitch chat, X client, and a simple shell to run other applications. ## Screenshots ![](https://github.com/user-attachments/assets/902b2e58-664d-460f-abfd-37de3c8c920b) +[![](https://github.com/user-attachments/assets/3fb00a8e-e835-45fe-9fa6-46657f4c1e0b)](https://github.com/user-attachments/assets/08b09024-ff66-4e07-837c-5b4d918862d7) [![](https://github.com/user-attachments/assets/c5f0d903-e7d4-42f3-91ad-38f7b6f08d4b)](https://github.com/user-attachments/assets/22419527-2937-4bdc-a7b8-95097cf25de7) [![](https://github-production-user-asset-6210df.s3.amazonaws.com/9499881/258204596-0de84193-e560-4165-b104-69c5a0b63d34.jpg)](https://github.com/r57zone/ProtonShell/assets/9499881/6a2701eb-869e-480a-8548-628daec17fe7) [![](https://github-production-user-asset-6210df.s3.amazonaws.com/9499881/258204442-90eb9ab6-d54b-4131-a8e8-12735213935f.jpg)](https://github.com/r57zone/ProtonShell/assets/9499881/e1ff8392-ba8b-4373-a20b-0d1a29773c10) +[![](https://github.com/user-attachments/assets/773978d5-e43c-4733-b05c-58fcad6c6a40)](https://github.com/user-attachments/assets/a4e77acb-1bfd-4fff-8e31-7415cd8b853a) +[![](https://github.com/user-attachments/assets/1c1a5637-6383-428a-8331-84656150f294)](https://github.com/user-attachments/assets/325c1c6d-8125-4f0a-beab-696e5fe7f19f) ## Setup 1. Install [Edge WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/). 2. Place the `index.html` file in the application folder or enter the URL address, in the configuration file. -3. Change the name, window parameters, icon, proxy, UserAgent and so on, in the `Config.ini` configuration file. -4. If necessary, change the `exe` icon, using [Resource Hacker](http://www.angusj.com/resourcehacker/). +3. Change the name, window parameters, icon, proxy, UserAgent and other settings, in the `Config.ini` configuration file. +4. If necessary, change the `exe` icon, using [Resource Hacker](http://www.angusj.com/resourcehacker/) or specify the icon in the configuration file. + +## Launch options +`-f index.html` - the path to the html file (relative or full). + +`-a “https://youtube.com/tv”` - the web site address. + +`-n “My app”` - the title of the application. + +`-i MyIcon.ico` - path to the icon. + +`-u Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0` - user agent. + +`-s 1.js` - user script (userscript). + +`-w` - width of the application. + +`-h` - height of the application. + +`-fullscreen` - fullscreen mode. + +`-p` - change system proxy to the specified one (format: IP:PORT). + +`-rp` - return past system proxy, for cases of changing proxy to another one. + +`-b 3` - frame style (None = `0`, Sizeable = `1`, Single = `2`, Dialog = 3, SizeToolWin = `4`, ToolWindow = `5`). + +`-t 50` - indent from the top. + +`-l 50` - indent to the right. + +`-d` - enable debugging mode. ## Debug mode For fast debugging you can enable a special mode in which the following is available: resizing, changing User agent, clearing all data. To enable it, change the `Debug` parameter to `1`. diff --git a/Source/Apps/Apple Notes.bat b/Source/Apps/Apple Notes.bat new file mode 100644 index 0000000..592f4bc --- /dev/null +++ b/Source/Apps/Apple Notes.bat @@ -0,0 +1 @@ +cmd /d /c start "" /B "..\ProtonShell.exe" -a "https://www.icloud.com/notes/" -n "Notes" -w 720 -h 480 -b 2" diff --git a/Source/Apps/ChatGPT.bat b/Source/Apps/ChatGPT.bat new file mode 100644 index 0000000..0c63959 --- /dev/null +++ b/Source/Apps/ChatGPT.bat @@ -0,0 +1 @@ +cmd /d /c start "" /B "..\ProtonShell.exe" -a "https://chatgpt.com" -n "ChatGPT"" diff --git a/Source/Apps/Debug mode.bat b/Source/Apps/Debug mode.bat new file mode 100644 index 0000000..a5aa338 --- /dev/null +++ b/Source/Apps/Debug mode.bat @@ -0,0 +1 @@ +cmd /d /c start "" /B "..\ProtonShell.exe" -a "https://google.com" -n "Google" -d" diff --git a/Source/Apps/Discord.bat b/Source/Apps/Discord.bat new file mode 100644 index 0000000..3fd1929 --- /dev/null +++ b/Source/Apps/Discord.bat @@ -0,0 +1 @@ +cmd /d /c start "" /B "..\ProtonShell.exe" -a "https://discord.com" -n "Discord" -iw" diff --git a/Source/Apps/Instagram.bat b/Source/Apps/Instagram.bat new file mode 100644 index 0000000..ef1aae6 --- /dev/null +++ b/Source/Apps/Instagram.bat @@ -0,0 +1 @@ +cmd /d /c start "" /B "..\ProtonShell.exe" -a "https://instagram.com" -n "Instagram" -w 360 -h 640 -u "Instagram 343.0.0.33.101 Android (34/14; 383dpi; 1080x2145; samsung; SM-A156M; a15x; mt6835; pt_BR; 629710169)"" diff --git a/Source/Apps/TV.bat b/Source/Apps/TV.bat new file mode 100644 index 0000000..7307b2e --- /dev/null +++ b/Source/Apps/TV.bat @@ -0,0 +1 @@ +cmd /d /c start "" /B "..\ProtonShell.exe" -f "Apps\tv.html" -n "TV UI" -fullscreen" diff --git a/Source/Apps/Twitch chat.bat b/Source/Apps/Twitch chat.bat new file mode 100644 index 0000000..be5628e --- /dev/null +++ b/Source/Apps/Twitch chat.bat @@ -0,0 +1 @@ +cmd /d /c start "" /B "..\ProtonShell.exe" -a "https://www.twitch.tv/popout/residentevil/chat" -n "Twitch chat" -w 360 -h 640 -iw" diff --git a/Source/Apps/X.bat b/Source/Apps/X.bat new file mode 100644 index 0000000..b6ac87f --- /dev/null +++ b/Source/Apps/X.bat @@ -0,0 +1 @@ +cmd /d /c start "" /B "..\ProtonShell.exe" -a "https://x.com" -n "X" -w 480 -h 640" diff --git a/Source/Apps/YouTube.bat b/Source/Apps/YouTube.bat new file mode 100644 index 0000000..e8def58 --- /dev/null +++ b/Source/Apps/YouTube.bat @@ -0,0 +1 @@ +cmd /d /c start "" /B "..\ProtonShell.exe" -a "https://youtube.com/tv" -u "Roku/DVP-14.0 (14.0.4.12221-CG)" -n "YouTube on TV" -fullscreen -s "YouTube.js"" diff --git a/Source/Apps/YouTube.js b/Source/Apps/YouTube.js new file mode 100644 index 0000000..259ac7e --- /dev/null +++ b/Source/Apps/YouTube.js @@ -0,0 +1,57 @@ +// Функция для поиска кнопки и добавления слушателя событий +function trackButton() { + // Получаем все кнопки с указанным классом + const buttons = document.querySelectorAll('.ytlr-button--large-shape'); + + if (buttons.length > 1) { // Проверяем, есть ли хотя бы две кнопки + const button = buttons[1]; // Выбираем вторую кнопку (индекс 1) + + //console.log('Вторая кнопка найдена, создаем дубликат.'); + + // Создаем дубликат кнопки + const newButton = button.cloneNode(true); // Клонируем кнопку, включая ее содержимое и атрибуты + + // Удаляем оригинальную кнопку + const parent = button.parentNode; // Получаем родительский элемент + if (parent) { + parent.removeChild(button); // Удаляем оригинальную кнопку + + // Убираем aria-hidden у новой кнопки, чтобы она была доступна + newButton.removeAttribute('aria-hidden'); // Удаляем атрибут aria-hidden + newButton.setAttribute('tabindex', '0'); // Добавляем tabindex, чтобы кнопка могла получать фокус + + // Добавляем новый элемент на место оригинала + newButton.addEventListener('click', function(event) { + window.chrome.webview.postMessage('close'); + //alert('Кнопка нажата!'); // Показываем алерт + //console.log('Кнопка нажата:', event); + //console.dir(event.target); + }); + + // Вставляем дубликат в то же место + parent.insertBefore(newButton, button.nextSibling); // Вставляем новый элемент после оригинала + //console.log('Дубликат второй кнопки добавлен с обработчиком клика.'); + + // Устанавливаем флаг, чтобы избежать повторной обработки + // buttonProcessed = true; // Убираем этот флаг, чтобы кнопка могла заменяться повторно + + // Проверяем доступность новой кнопки + //console.log('Новая кнопка:', newButton); + } else { + //console.error('Родительский элемент не найден.'); // Если родителя нет, выводим сообщение об ошибке + } + } else { + //console.log('Недостаточно кнопок. Попробуем снова через 1 секунду.'); + } +} + +// Дожидаемся полной загрузки документа +//console.log('Документ загружен, ищем кнопки...'); + +// Пробуем сразу найти кнопки +trackButton(); + +// Если кнопки не найдены сразу, ищем их периодически +const interval = setInterval(() => { + trackButton(); // Теперь просто вызываем функцию +}, 1000); // Проверяем каждые 1000 миллисекунд (1 секунда) diff --git a/Source/Apps/tv.html b/Source/Apps/tv.html new file mode 100644 index 0000000..035ed2e --- /dev/null +++ b/Source/Apps/tv.html @@ -0,0 +1,145 @@ + + + + + +TV UI + + + + +
+ + diff --git a/Source/Config.ini b/Source/Config.ini index 90e63df..08ebb3d 100644 --- a/Source/Config.ini +++ b/Source/Config.ini @@ -29,6 +29,7 @@ HideMaximize=0 # Normal = 0, Maximized = 1, FullScreen = 2 WindowState=0 +SaveState=0 StayOnTop=0 # Position diff --git a/Source/Unit1.dfm b/Source/Unit1.dfm index 051725c..f898df2 100644 --- a/Source/Unit1.dfm +++ b/Source/Unit1.dfm @@ -27,9 +27,9 @@ object Main: TMain OnCreateWebViewCompleted = EdgeBrowserCreateWebViewCompleted OnNavigationCompleted = EdgeBrowserNavigationCompleted OnNewWindowRequested = EdgeBrowserNewWindowRequested - ExplicitTop = 0 + OnWebMessageReceived = EdgeBrowserWebMessageReceived ExplicitWidth = 636 - ExplicitHeight = 479 + ExplicitHeight = 366 end object DebugPanel: TPanel Left = 0 @@ -39,168 +39,177 @@ object Main: TMain Align = alTop TabOrder = 1 Visible = False - object ResolutionLbl: TLabel - Left = 9 - Top = 93 - Width = 75 - Height = 13 - Caption = 'Resolution: 0x0' - end - object LeftBtn: TButton - Left = 7 - Top = 7 - Width = 25 - Height = 25 - Caption = #8592 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False + ExplicitWidth = 636 + object PanelTools: TPanel + Left = 183 + Top = 0 + Width = 288 + Height = 113 + BevelOuter = bvNone TabOrder = 0 - OnClick = LeftBtnClick - end - object RightBtn: TButton - Left = 37 - Top = 7 - Width = 25 - Height = 25 - Caption = #8594 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - TabOrder = 1 - OnClick = RightBtnClick - end - object RefreshBtn: TButton - Left = 67 - Top = 7 - Width = 25 - Height = 25 - Caption = #8635 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - TabOrder = 2 - OnClick = RefreshBtnClick - end - object ClearBtn: TButton - Left = 127 - Top = 7 - Width = 25 - Height = 25 - Caption = #55357#56785#65039 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 4 - OnClick = ClearBtnClick - end - object HomeBtn: TButton - Left = 97 - Top = 7 - Width = 25 - Height = 25 - Caption = #55356#57312 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - ParentShowHint = False - ShowHint = False - TabOrder = 3 - OnClick = HomeBtnClick - end - object DevicesCB: TComboBox - Left = 8 - Top = 38 - Width = 212 - Height = 21 - Style = csDropDownList - ParentShowHint = False - ShowHint = True - TabOrder = 5 - OnChange = DevicesCBChange - end - object SetDeviceBtn: TButton - Left = 226 - Top = 7 - Width = 25 - Height = 25 - Caption = #55357#56561 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 6 - OnClick = SetDeviceBtnClick - end - object RotateDeviceBtn: TButton - Left = 256 - Top = 7 - Width = 25 - Height = 25 - Caption = #8634 - ParentShowHint = False - ShowHint = True - TabOrder = 7 - OnClick = RotateDeviceBtnClick - end - object UserAgentsCB: TComboBox - Left = 8 - Top = 66 - Width = 272 - Height = 21 - Style = csDropDownList - ItemIndex = 0 - ParentShowHint = False - ShowHint = True - TabOrder = 8 - Text = 'Default User Agent' - OnChange = UserAgentsCBChange - Items.Strings = ( - 'Default User Agent') - end - object ZoomCB: TComboBox - Left = 227 - Top = 38 - Width = 53 - Height = 21 - Style = csDropDownList - ItemIndex = 7 - TabOrder = 9 - Text = '100%' - Items.Strings = ( - '30%' - '40%' - '50%' - '60%' - '70%' - '80%' - '90%' - '100%' - '125%' - '150%' - '175%' - '200%') + object ResolutionLbl: TLabel + Left = 9 + Top = 93 + Width = 75 + Height = 13 + Caption = 'Resolution: 0x0' + end + object LeftBtn: TButton + Left = 7 + Top = 7 + Width = 25 + Height = 25 + Caption = #8592 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 0 + OnClick = LeftBtnClick + end + object RightBtn: TButton + Left = 37 + Top = 7 + Width = 25 + Height = 25 + Caption = #8594 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 1 + OnClick = RightBtnClick + end + object RefreshBtn: TButton + Left = 67 + Top = 7 + Width = 25 + Height = 25 + Caption = #8635 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 2 + OnClick = RefreshBtnClick + end + object HomeBtn: TButton + Left = 97 + Top = 7 + Width = 25 + Height = 25 + Caption = #55356#57312 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + ParentShowHint = False + ShowHint = False + TabOrder = 3 + OnClick = HomeBtnClick + end + object ClearBtn: TButton + Left = 127 + Top = 7 + Width = 25 + Height = 25 + Caption = #55357#56785#65039 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 4 + OnClick = ClearBtnClick + end + object SetDeviceBtn: TButton + Left = 226 + Top = 7 + Width = 25 + Height = 25 + Caption = #55357#56561 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 5 + OnClick = SetDeviceBtnClick + end + object RotateDeviceBtn: TButton + Left = 256 + Top = 7 + Width = 25 + Height = 25 + Caption = #8634 + ParentShowHint = False + ShowHint = True + TabOrder = 6 + OnClick = RotateDeviceBtnClick + end + object DevicesCB: TComboBox + Left = 8 + Top = 38 + Width = 212 + Height = 21 + Style = csDropDownList + ParentShowHint = False + ShowHint = True + TabOrder = 7 + OnChange = DevicesCBChange + end + object ZoomCB: TComboBox + Left = 227 + Top = 38 + Width = 53 + Height = 21 + Style = csDropDownList + ItemIndex = 7 + TabOrder = 8 + Text = '100%' + Items.Strings = ( + '30%' + '40%' + '50%' + '60%' + '70%' + '80%' + '90%' + '100%' + '125%' + '150%' + '175%' + '200%') + end + object UserAgentsCB: TComboBox + Left = 8 + Top = 66 + Width = 272 + Height = 21 + Style = csDropDownList + ItemIndex = 0 + ParentShowHint = False + ShowHint = True + TabOrder = 9 + Text = 'Default User Agent' + OnChange = UserAgentsCBChange + Items.Strings = ( + 'Default User Agent') + end end end end diff --git a/Source/Unit1.pas b/Source/Unit1.pas index a16a534..9a6712d 100644 --- a/Source/Unit1.pas +++ b/Source/Unit1.pas @@ -21,17 +21,18 @@ interface TMain = class(TForm) EdgeBrowser: TEdgeBrowser; DebugPanel: TPanel; + PanelTools: TPanel; LeftBtn: TButton; RightBtn: TButton; RefreshBtn: TButton; - ClearBtn: TButton; HomeBtn: TButton; - DevicesCB: TComboBox; + ClearBtn: TButton; SetDeviceBtn: TButton; - ResolutionLbl: TLabel; RotateDeviceBtn: TButton; - UserAgentsCB: TComboBox; + DevicesCB: TComboBox; ZoomCB: TComboBox; + UserAgentsCB: TComboBox; + ResolutionLbl: TLabel; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure EdgeBrowserCreateWebViewCompleted(Sender: TCustomEdgeBrowser; @@ -51,6 +52,8 @@ TMain = class(TForm) procedure RotateDeviceBtnClick(Sender: TObject); procedure UserAgentsCBChange(Sender: TObject); procedure DevicesCBChange(Sender: TObject); + procedure EdgeBrowserWebMessageReceived(Sender: TCustomEdgeBrowser; + Args: TWebMessageReceivedEventArgs); private { Private declarations } public @@ -59,9 +62,9 @@ TMain = class(TForm) var Main: TMain; - WinOldWidth, WinOldHeight, WinOldTop, WinOldLeft: integer; - WinSaveSize, WinSavePos, ReturnPrevSystemProxy, UserAgentsCBChanged: boolean; - MainURL, EdgeUserAgent, NewUserAgent, SystemProxy, PrevSystemProxy: string; + WinOldWidth, WinOldHeight, WinOldTop, WinOldLeft, WinOldState: integer; + WinSaveSize, WinSavePos, WinSaveState, ReturnPrevSystemProxy, UserAgentsCBChanged: boolean; + FullPath, MainURL, EdgeUserAgent, NewUserAgent, SystemProxy, PrevSystemProxy, ConfigFile: string; OpenExternalLinks, LoadUserScript: boolean; UserScriptFile: TStringList; @@ -71,6 +74,17 @@ implementation {$R *.dfm} +function FixPath(Path: string): string; +begin + if (Length(Path) > 0) and (Path[2] <> ':') then + Path:=FullPath + Path; + + if (Length(Path) > 2) and (Path[Length(Path)] = '\') and (Path[Length(Path) - 1] = '\') then + Path:=Copy(Path, 1, Length(Path) - 1); + + Result:=Path; +end; + procedure TMain.ClearBtnClick(Sender: TObject); var ScriptStr: string; @@ -82,21 +96,17 @@ procedure TMain.ClearBtnClick(Sender: TObject); ScriptStr:= 'localStorage.clear();' + sLineBreak + - 'sessionStorage.clear();' + sLineBreak + - // Cookie 'document.cookie.split(";").forEach(function(cookie) {' + sLineBreak + ' document.cookie = cookie.split("=")[0] + "=;expires=" + new Date(0).toUTCString() + ";path=/";' + sLineBreak + '});' + sLineBreak + - // IndexedDB 'indexedDB.databases().then(function(databases) {' + sLineBreak + ' databases.forEach(function(db) {' + sLineBreak + ' indexedDB.deleteDatabase(db.name);' + sLineBreak + ' });' + sLineBreak + '});' + sLineBreak + - // PWA 'caches.keys().then(function(names) {' + sLineBreak + ' for (let name of names) caches.delete(name);' + sLineBreak + @@ -140,7 +150,7 @@ procedure TMain.EdgeBrowserNavigationCompleted(Sender: TCustomEdgeBrowser; if UserScriptFile.Text <> '' then EdgeBrowser.ExecuteScript(UserScriptFile.Text); - // Debuge mode User Agents + // Debug mode User Agents if (DebugPanel.Visible = false) or (UserAgentsCBChanged = false) then Exit; UserAgentsCBChanged:=false; @@ -184,6 +194,79 @@ procedure TMain.EdgeBrowserNewWindowRequested(Sender: TCustomEdgeBrowser; end; end; +procedure TMain.EdgeBrowserWebMessageReceived(Sender: TCustomEdgeBrowser; + Args: TWebMessageReceivedEventArgs); +var + CommandP: PChar; CommandStr: string; FilePath, FileParams, FolderPath: string; + ResponseList: TStringList; SR: TSearchRec; +begin + Args.ArgsInterface.TryGetWebMessageAsString(CommandP); + CommandStr:=CommandP; + //Args.ArgsInterface.Get_webMessageAsJson(); + //ShowMessage(CommandStr); Exit; + + if CommandStr = 'close' then + Close + + else if Copy(CommandStr, 1, 5) = 'open ' then begin + if (Length(CommandStr) > 5) and (CommandStr[6] = '"') then begin + FilePath:=Copy(CommandStr, 7, Length(CommandStr) - 6); + + FileParams:=Trim(Copy(FilePath, Pos('"', FilePath) + 1, Length(FilePath))); + FilePath:=Copy(FilePath, 1, Pos('"', FilePath) - 1); + + //ShowMessage(FilePath); + //ShowMessage('"' + FileParams + '"'); + + FilePath:=FixPath(FilePath); + end else begin + FilePath:=FixPath(Copy(CommandStr, 6, Length(CommandStr) - 5)); + FileParams:=''; + end; + + ShellExecute(0, 'open', PChar(FilePath), PChar(FileParams), nil, SW_SHOWNORMAL); + + end else if Copy(CommandStr, 1, 4) = 'del ' then begin + FilePath:=Copy(CommandStr, 5, Length(CommandStr) - 4); + DeleteFile(FilePath); + + end else if Copy(CommandStr, 1, 7) = 'folder ' then begin + + FolderPath:=Copy(CommandStr, 8, Length(CommandStr) - 7); + + + // If the path is relative, then add the full path + if (FolderPath <> '') then begin + + FolderPath:=FixPath(FolderPath); + + //ShowMessage(FolderPath); + + ResponseList:=TStringList.Create; + + if FindFirst(FolderPath + '*.*', faAnyFile, SR) = 0 then begin + repeat + if (SR.Name = '.') or (SR.Name = '..') then Continue; + if (SR.Attr <> faDirectory) then + ResponseList.Add(SR.Name) + else + ResponseList.Add(SR.Name + '\\'); + until FindNext(SR) <> 0; + FindClose(SR); + end; + + ResponseList.Text:=StringReplace(Trim(ResponseList.Text), #13#10, '\n', [rfReplaceAll]); + + //ShowMessage(ResponseList.Text); + + EdgeBrowser.ExecuteScript('handleMessageFromHost("' + Trim(ResponseList.Text) + '");'); + + ResponseList.Free; + end; + end; + +end; + procedure ProxyActivate(Enable: boolean); var Reg: TRegistry; @@ -211,7 +294,6 @@ procedure SetProxy(const Server: String); PrevSystemProxy:=Reg.ReadString('ProxyServer') else PrevSystemProxy:=''; - ShowMessage(PrevSystemProxy); end; Reg.WriteString('ProxyServer', Server); Reg.CloseKey; @@ -222,11 +304,11 @@ procedure SetProxy(const Server: String); procedure TMain.FormClose(Sender: TObject; var Action: TCloseAction); var - Ini: TIniFile; + Ini: TIniFile; WinNewState: integer; begin if (WinSaveSize) and (WindowState <> wsMaximized) then if (WinOldWidth <> ClientWidth) or (WinOldHeight <> ClientHeight) then begin - Ini:=TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'Config.ini'); + Ini:=TIniFile.Create(ExtractFilePath(ParamStr(0)) + ConfigFile); Ini.WriteInteger('Window', 'Width', ClientWidth); Ini.WriteInteger('Window', 'Height', ClientHeight); Ini.Free; @@ -234,11 +316,30 @@ procedure TMain.FormClose(Sender: TObject; var Action: TCloseAction); if (WinSavePos) and (WindowState <> wsMaximized) then if (WinOldTop <> Top) or (WinOldLeft <> Left) then begin - Ini:=TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'Config.ini'); + Ini:=TIniFile.Create(ExtractFilePath(ParamStr(0)) + ConfigFile); Ini.WriteInteger('Window', 'Top', Top); Ini.WriteInteger('Window', 'Left', Left); Ini.Free; end; + + if (WinSaveState) then begin + if WindowState = wsMaximized then begin + if BorderStyle <> bsNone then + WinNewState:=1 + else + WinNewState:=2; + end else if WindowState = wsMinimized then + WinNewState:=3 + else // wsNormal + WinNewState:=0; + + if WinOldState <> WinNewState then begin + Ini:=TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'Config.ini'); + Ini.WriteInteger('Window', 'WindowState', WinNewState); + Ini.Free; + end; + end; + UserScriptFile.Free; end; @@ -269,122 +370,203 @@ function GetLocaleInformation(Flag: integer): string; procedure TMain.FormCreate(Sender: TObject); var - Ini: TIniFile; LocalFile, FulllPath, UserScriptPath, IconPath: string; + Ini: TIniFile; + LocalFile, WebAddress, UserScriptPath, IconPath, AppTitle, IconCachePath, ParamStrLower: string; + i, WindowTop, WindowLeft, WindowBorderStyle: integer; + CustomConfig, ChangePosition, DebugeMode, IsFullscreen: boolean; begin - FulllPath:=ExtractFilePath(ParamStr(0)); + EdgeUserAgent:='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0'; + FullPath:=ExtractFilePath(ParamStr(0)); + WindowBorderStyle:=1; + IsFullscreen:=false; + WinSavePos:=false; + WinSaveState:=false; + + EdgeBrowser.UserDataFolder:=FullPath + 'Data'; + + // Translations + if GetLocaleInformation(LOCALE_SENGLANGUAGE) = 'Russian' then begin + IDS_CONFIRM_DELETE_ALL_DATA:=' ?'; + IDS_RESOLUTION:=': '; + ClearBtn.Hint:=' '; + SetDeviceBtn.Hint:=' '; + RotateDeviceBtn.Hint:=' '; + end else begin + IDS_CONFIRM_DELETE_ALL_DATA:='Are you sure you want to delete all data?'; + IDS_RESOLUTION:='Resolution: '; + ClearBtn.Hint:='Deleting all data'; + SetDeviceBtn.Hint:='Change device'; + RotateDeviceBtn.Hint:='Rotate the device'; + end; - EdgeBrowser.UserDataFolder:=FulllPath + 'Data'; + // Custom config + ConfigFile:='Config.ini'; + CustomConfig:=false; + for i:=0 to ParamCount - 1 do + if (AnsiLowerCase(ParamStr(i)) = '-c') and (Trim(ParamStr(i + 1)) <> '') and (FileExists(ParamStr(i + 1))) then begin + ConfigFile:=ParamStr(i + 1); + CustomConfig:=true; + end; - Ini:=TIniFile.Create(FulllPath + 'Config.ini'); - LocalFile:=Trim(Ini.ReadString('Main', 'File', '')); + if (ParamCount = 0) or (CustomConfig) then begin + + // Config parameters + Ini:=TIniFile.Create(FullPath + ConfigFile); + LocalFile:=Trim(Ini.ReadString('Main', 'File', '')); + WebAddress:=Ini.ReadString('Main', 'URL', ''); + + NewUserAgent:=Ini.ReadString('Main', 'UserAgent', ''); + OpenExternalLinks:=Ini.ReadBool('Main', 'OpenExternalLinks', false); + UserScriptPath:=Ini.ReadString('Main', 'UserScript', ''); + + // Windows sizes + ClientWidth:=Ini.ReadInteger('Window', 'Width', ClientWidth); + ClientHeight:=Ini.ReadInteger('Window', 'Height', ClientHeight); + WinSaveSize:=Ini.ReadBool('Window', 'SaveSize', false); + WinOldWidth:=ClientWidth; + WinOldHeight:=ClientHeight; + + // Windows position + ChangePosition:=not ((Trim(Ini.ReadString('Window', 'Top', '')) = '') or (Trim(Ini.ReadString('Window', 'Left', '')) = '')); + if ChangePosition then begin + WindowTop:=Ini.ReadInteger('Window', 'Top', Top); + WindowLeft:=Ini.ReadInteger('Window', 'Left', Left); + end; + WinSavePos:=Ini.ReadBool('Window', 'SavePos', false); - // If the path is relative, then add the full path - if (LocalFile <> '') and (Length(LocalFile) > 1) and (LocalFile[2] <> ':') then - LocalFile:=FulllPath + LocalFile; + // Windows params + AppTitle:=UTF8ToAnsi(Ini.ReadString('Window', 'Title', '')); - NewUserAgent:=Ini.ReadString('Main', 'UserAgent', ''); - OpenExternalLinks:=Ini.ReadBool('Main', 'OpenExternalLinks', false); - UserScriptPath:=Ini.ReadString('Main', 'UserScript', ''); - UserScriptFile:=TStringList.Create; - if FileExists(UserScriptPath) then - UserScriptFile.LoadFromFile(UserScriptPath, TEncoding.UTF8); + IconPath:=Trim(Ini.ReadString('Window', 'IconPath', '')); - if LocalFile <> '' then - MainURL:=LocalFile - else - MainURL:=Ini.ReadString('Main', 'URL', ''); + if Ini.ReadBool('Window', 'HideMaximize', false) then + BorderIcons:=Main.BorderIcons-[biMaximize]; - EdgeBrowser.Navigate(MainURL); + WindowBorderStyle:=Ini.ReadInteger('Window', 'BorderStyle', 1); - // Windows sizes - ClientWidth:=Ini.ReadInteger('Window', 'Width', ClientWidth); - ClientHeight:=Ini.ReadInteger('Window', 'Height', ClientHeight); - WinSaveSize:=Ini.ReadBool('Window', 'SaveSize', false); - WinOldWidth:=ClientWidth; - WinOldHeight:=ClientHeight; - - // Windows position - if (Trim(Ini.ReadString('Window', 'Top', '')) <> '') and (Trim(Ini.ReadString('Window', 'Left', '')) <> '') then begin - Main.Top:=Ini.ReadInteger('Window', 'Top', Top); - Main.Left:=Ini.ReadInteger('Window', 'Left', Left); - end else// begin - WindowToCenter; - //Main.Top:=Screen.Height div 2 - Height div 2; // Main.Position - Some problems with Edge - //Main.Left:=Screen.Width div 2 - Width div 2; - //end; - WinSavePos:=Ini.ReadBool('Window', 'SavePos', false); - WinOldTop:=Top; - WinOldLeft:=Left; + WinOldState:=Ini.ReadInteger('Window', 'WindowState', 0); + case WinOldState of // 0: default + 1: WindowState:=wsMaximized; + 2: begin BorderStyle:=bsNone; WindowState:=wsMaximized; IsFullscreen:=true; end; + 3: WindowState:=wsMinimized; + end; + WinSaveState:=Ini.ReadBool('Window', 'SaveState', false); + + if Ini.ReadBool('Window', 'StayOnTop', false) then + FormStyle:=fsStayOnTop; + + // System proxy + ReturnPrevSystemProxy:=Ini.ReadBool('Main', 'ReturnPreviousProxy', false); + SystemProxy:=Trim(Ini.ReadString('Main', 'SystemProxy', '')); + + // Debug mode + DebugeMode:=Ini.ReadBool('Main', 'Debug', false); + + Ini.Free; + + end else + for i:=0 to ParamCount do begin + ParamStrLower:=ParamStr(i); + if ParamStrLower = '-d' then DebugeMode:=true; + if ParamStrLower = '-fullscreen' then begin BorderStyle:=bsNone; WindowState:=wsMaximized; IsFullscreen:=true; end; + {if (ParamStr(i) = '-iw') and (WebAddress <> '') then begin + if not DirectoryExists(FullPath + 'Icons') then + CreateDir(FullPath + 'Icons'); + IconCachePath:=FullPath + 'Icons\' + ConvertUrlToIdentifier(WebAddress) + '.ico'; + if not FileExists(IconCachePath) then + HTTPDownloadFile(GetBaseUrl(WebAddress) + '/favicon.ico', IconCachePath); + //ShowMessage(GetBaseUrl(WebAddress) + '/favicon.ico'); + IconPath:=IconCachePath; // SVG/PNG instead of ICO prevents this from being implemented + end;} + + if i + 1 > ParamCount then Continue; + if ParamStrLower = '-f' then LocalFile:=ParamStr(i + 1); + if ParamStrLower = '-a' then WebAddress:=ParamStr(i + 1); + if ParamStrLower = '-n' then AppTitle:=ParamStr(i + 1); + if ParamStrLower = '-i' then IconPath:=ParamStr(i + 1); + if ParamStrLower = '-p' then SystemProxy:=ParamStr(i + 1); + if ParamStrLower = '-u' then NewUserAgent:=ParamStr(i + 1); + if ParamStrLower = '-s' then UserScriptPath:=ParamStr(i + 1); + if ParamStrLower = '-b' then WindowBorderStyle:=StrToIntDef(ParamStr(i + 1), 1); + if ParamStrLower = '-rp' then ReturnPrevSystemProxy:=true; + if ParamStrLower = '-t' then WindowTop:=StrToIntDef(ParamStr(i + 1), 0); + if ParamStrLower = '-l' then WindowLeft:=StrToIntDef(ParamStr(i + 1), 0); + if ParamStrLower = '-w' then ClientWidth:=StrToIntDef(ParamStr(i + 1), ClientWidth); + if ParamStrLower = '-h' then ClientHeight:=StrToIntDef(ParamStr(i + 1), ClientHeight) + end; // Windows params - Main.Caption:=UTF8ToAnsi(Ini.ReadString('Window', 'Title', '')); + Main.Caption:=AppTitle; - IconPath:=Trim(Ini.ReadString('Window', 'IconPath', '')); + // Icon if (IconPath <> '') and (FileExists(IconPath)) then - Main.Icon.LoadFromFile(IconPath); - - if Ini.ReadBool('Window', 'HideMaximize', false) then - BorderIcons:=Main.BorderIcons-[biMaximize]; - - case Ini.ReadInteger('Window', 'BorderStyle', 0) of - 0: BorderStyle:=bsNone; - 1: BorderStyle:=bsSizeable; - 2: BorderStyle:=bsSingle; - 3: BorderStyle:=bsDialog; - 4: BorderStyle:=bsSizeToolWin; - 5: BorderStyle:=bsToolWindow; - end; + try + Main.Icon.LoadFromFile(IconPath); + except + DeleteFile(IconPath); + end; - case Ini.ReadInteger('Window', 'WindowState', 0) of - 1: WindowState:=wsMaximized; - 2: begin BorderStyle:=bsNone; WindowState:=wsMaximized; end; - 3: WindowState:=wsMinimized; - end; + // Window + if ChangePosition then begin + Main.Top:=WindowTop; + Main.Left:=WindowLeft; + end else + WindowToCenter; + //Main.Top:=Screen.Height div 2 - Height div 2; // Main.Position - Some problems with Edge + //Main.Left:=Screen.Width div 2 - Width div 2; + WinOldTop:=Main.Top; + WinOldLeft:=Main.Left; + + if IsFullscreen = false then + case WindowBorderStyle of + 0: BorderStyle:=bsNone; + 1: BorderStyle:=bsSizeable; + 2: BorderStyle:=bsSingle; + 3: BorderStyle:=bsDialog; + 4: BorderStyle:=bsSizeToolWin; + 5: BorderStyle:=bsToolWindow; + end; + + // If the path is relative, then add the full path + if (LocalFile <> '') and (Length(LocalFile) > 1) and (LocalFile[2] <> ':') then + LocalFile:=FullPath + LocalFile; - if Ini.ReadBool('Window', 'StayOnTop', false) then - FormStyle:=fsStayOnTop; + // Applying parameters + // Address + if LocalFile <> '' then + MainURL:=LocalFile + else + MainURL:=WebAddress; + EdgeBrowser.Navigate(MainURL); // System proxy - ReturnPrevSystemProxy:=Ini.ReadBool('Main', 'ReturnPreviousProxy', false); - SystemProxy:=Trim(Ini.ReadString('Main', 'SystemProxy', '')); if SystemProxy <> '' then begin SetProxy(SystemProxy); ProxyActivate(true); end; - if Ini.ReadBool('Main', 'Debug', false) then begin + // User scripts + UserScriptFile:=TStringList.Create; + if FileExists(UserScriptPath) then + UserScriptFile.LoadFromFile(UserScriptPath, TEncoding.UTF8); + + // Debug mode + if DebugeMode then begin DebugPanel.Visible:=true; ClientHeight:=ClientHeight + DebugPanel.Height; Top:=Top - DebugPanel.Height div 2; - if FileExists(FulllPath + 'DevicesList.txt') then begin - DevicesCB.Items.LoadFromFile(FulllPath + 'DevicesList.txt', TEncoding.UTF8); + if FileExists(FullPath + 'DevicesList.txt') then begin + DevicesCB.Items.LoadFromFile(FullPath + 'DevicesList.txt', TEncoding.UTF8); if DevicesCB.Items.Count > 0 then DevicesCB.ItemIndex:=0; end; - if FileExists(FulllPath + 'UserAgentsList.txt') then begin - UserAgentsCB.Items.LoadFromFile(FulllPath + 'UserAgentsList.txt', TEncoding.UTF8); + + if FileExists(FullPath + 'UserAgentsList.txt') then begin + UserAgentsCB.Items.LoadFromFile(FullPath + 'UserAgentsList.txt', TEncoding.UTF8); if UserAgentsCB.Items.Count > 0 then UserAgentsCB.ItemIndex:=0; end; end; - - Ini.Free; - - if GetLocaleInformation(LOCALE_SENGLANGUAGE) = 'Russian' then begin - IDS_CONFIRM_DELETE_ALL_DATA:=' ?'; - IDS_RESOLUTION:=': '; - ClearBtn.Hint:=' '; - SetDeviceBtn.Hint:=' '; - RotateDeviceBtn.Hint:=' '; - end else begin - IDS_CONFIRM_DELETE_ALL_DATA:='Are you sure you want to delete all data?'; - IDS_RESOLUTION:='Resolution: '; - ClearBtn.Hint:='Deleting all data'; - SetDeviceBtn.Hint:='Change device'; - RotateDeviceBtn.Hint:='Rotate the device'; - end; - - EdgeUserAgent:='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0'; end; procedure TMain.FormDestroy(Sender: TObject); @@ -399,6 +581,7 @@ procedure TMain.FormDestroy(Sender: TObject); procedure TMain.FormResize(Sender: TObject); begin ResolutionLbl.Caption:=IDS_RESOLUTION + IntToStr(EdgeBrowser.Width) + 'x' + IntToStr(EdgeBrowser.Height); + PanelTools.Left:=DebugPanel.Width div 2 - PanelTools.Width div 2; end; procedure TMain.HomeBtnClick(Sender: TObject); @@ -442,6 +625,8 @@ procedure TMain.SetDeviceBtnClick(Sender: TObject); WindowState:=wsNormal; ZoomValue:=StrToIntDef(Copy(ZoomCB.Items.Strings[ZoomCB.ItemIndex], 1, Length(ZoomCB.Items.Strings[ZoomCB.ItemIndex]) - 1), 100) * 0.01; + EdgeBrowser.ExecuteScript('document.body.style.transform = "scale(' + StringReplace(FloatToStr(ZoomValue), ',', '.', []) + ')";' + + 'document.body.style.transformOrigin = "0 0";'); ResolutionStr:=DevicesCB.Items[DevicesCB.ItemIndex]; ResolutionStr:=Copy(ResolutionStr, Pos('(', ResolutionStr) + 1, Length(ResolutionStr));