mirror of
				https://github.com/smartfrigde/armcord.git
				synced 2024-08-14 23:56:58 +00:00 
			
		
		
		
	Initial source code upload
This commit is contained in:
		
							parent
							
								
									3fd237446f
								
							
						
					
					
						commit
						101bc63651
					
				
					 41 changed files with 1117 additions and 6272 deletions
				
			
		
							
								
								
									
										85
									
								
								src/content/css/setup.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/content/css/setup.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | |||
| /*CSS ONLY FOR INTERNAL USE (setup and loading)*/ | ||||
| @import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); | ||||
| 
 | ||||
| :root { | ||||
|   background-color: #2c2f33; | ||||
|   --header-secondary: #b9bbbe; | ||||
|   --header-primary: #fff; | ||||
|   --background-tertiary: #202225; | ||||
| } | ||||
| 
 | ||||
| body { | ||||
|   color: white; | ||||
| } | ||||
| 
 | ||||
| p { | ||||
|   color: #8e9297; | ||||
|   text-align: center; | ||||
|   font-weight: 100; | ||||
|   transform: translateY(-185%); | ||||
|   font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif; | ||||
|   text-rendering: optimizeLegibility; | ||||
|   font-style: italic; | ||||
| } | ||||
| 
 | ||||
| .logo { | ||||
|   font-size: 0px; | ||||
|   text-align: center; | ||||
|   transform: translateY(-105%); | ||||
| } | ||||
| 
 | ||||
| .logo:before { | ||||
|   content: "ARM"; | ||||
|   color: #7289da; | ||||
|   font-weight: normal; | ||||
|   font-family: Helvetica, sans-serif; | ||||
|   font-size: 32px; | ||||
| } | ||||
| 
 | ||||
| .logo:after { | ||||
|   content: "Cord"; | ||||
|   color: #ffffff; | ||||
|   font-weight: normal; | ||||
|   font-family: Discordinated; | ||||
|   font-size: 32px; | ||||
| } | ||||
| 
 | ||||
| span { | ||||
|   text-align: center; | ||||
| } | ||||
| 
 | ||||
| .logo { | ||||
|   display: block; | ||||
|   margin-left: auto; | ||||
|   margin-right: auto; | ||||
|   max-height: 204px; | ||||
|   max-width: 204px; | ||||
|   transform: translateY(5%); | ||||
| } | ||||
| 
 | ||||
| .container { | ||||
|   position: fixed; | ||||
|   top: 50%; | ||||
|   left: 50%; | ||||
|   color: #fff; | ||||
|   transform: translate(-50%, -50%); | ||||
| } | ||||
| 
 | ||||
| button { | ||||
|     background-color: #7289da; | ||||
|     font-family: Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif; | ||||
|     color: #ffffff; | ||||
|     padding: 4px; | ||||
|     border-radius: 5px; | ||||
|     left: 0; | ||||
|     text-align: center; | ||||
|     border-style: none; | ||||
|     outline: none; | ||||
| } | ||||
| 
 | ||||
| button:hover { | ||||
|     background-color: #687dc6; | ||||
|     border-style: none; | ||||
|     outline: none; | ||||
|     cursor: pointer; | ||||
| } | ||||
							
								
								
									
										114
									
								
								src/content/css/splash.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/content/css/splash.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,114 @@ | |||
| /*MIT License | ||||
| 
 | ||||
| Copyright (c) 2021 GooseMod | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE.*/ | ||||
| :root { | ||||
|   --background-primary: #282b30; | ||||
|   --background-secondary: rgba(255, 255, 255, 0.1); | ||||
|   --brand-experiment: #5865f2; | ||||
|   --header-primary: #fff; | ||||
|   --text-muted: #72767d; | ||||
| } | ||||
| 
 | ||||
| @font-face { | ||||
|   font-family: Whitney; | ||||
|   font-weight: 400; | ||||
|   font-style: normal; | ||||
|   src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff"); | ||||
| } | ||||
| 
 | ||||
| html, | ||||
| body { | ||||
|   -webkit-app-region: drag; | ||||
|   overflow: hidden; | ||||
| 
 | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
| 
 | ||||
|   background: var(--background-primary); | ||||
| 
 | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
| } | ||||
| 
 | ||||
| * { | ||||
|   font-family: "Whitney", sans-serif; | ||||
| 
 | ||||
|   box-sizing: border-box; | ||||
|   -webkit-user-select: none; | ||||
|   cursor: default; | ||||
| } | ||||
| 
 | ||||
| video { | ||||
|   width: 200px; | ||||
|   height: 150px; | ||||
|   object-fit: cover; | ||||
| } | ||||
| 
 | ||||
| #text { | ||||
|   font-size: 7vw; | ||||
|   text-align: center; | ||||
| 
 | ||||
|   color: var(--header-primary); | ||||
|   font-weight: 400; | ||||
|   font-style: italic; | ||||
|   font-size: 16px; | ||||
| 
 | ||||
|   text-transform: uppercase; | ||||
| 
 | ||||
|   width: 100%; | ||||
| } | ||||
| 
 | ||||
| #bar-container, | ||||
| #bar-fill { | ||||
|   width: 180px; | ||||
|   height: 8px; | ||||
| 
 | ||||
|   border-radius: 4px; | ||||
| 
 | ||||
|   visibility: hidden; | ||||
| } | ||||
| 
 | ||||
| #bar-container { | ||||
|   background-color: var(--background-secondary); | ||||
| 
 | ||||
|   position: relative; | ||||
|   margin-top: 12px; | ||||
| } | ||||
| 
 | ||||
| #bar-fill { | ||||
|   background-color: var(--brand-experiment); | ||||
|   width: 0; | ||||
| } | ||||
| 
 | ||||
| #debug { | ||||
|   position: absolute; | ||||
|   bottom: 6px; | ||||
|   right: 6px; | ||||
| 
 | ||||
|   text-align: right; | ||||
|   font-size: 10px; | ||||
|   color: var(--text-muted); | ||||
|   white-space: pre; | ||||
| } | ||||
							
								
								
									
										123
									
								
								src/content/css/titlebar.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/content/css/titlebar.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,123 @@ | |||
| @import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); | ||||
| :root { | ||||
|   --window-buttons: var(--header-secondary); | ||||
|   --cord-color: var(--header-primary); | ||||
|   --armcord-color: #7289da; | ||||
|   --titlebar-color: var(--background-tertiary); | ||||
| } | ||||
| .titleebar { | ||||
|     position: absolute; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     box-sizing: border-box; | ||||
|     width: 100%; | ||||
|     font-size: 13px; | ||||
|     padding: 0 16px; | ||||
|     overflow: hidden; | ||||
|     flex-shrink: 0; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     user-select: none; | ||||
|     zoom: 1; | ||||
|     line-height: 22px; | ||||
|     height: 22px; | ||||
|     display: flex; | ||||
|     z-index: 99999; | ||||
|   } | ||||
|   .titlebar { | ||||
|     display: block; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     flex-shrink: 0; | ||||
|     overflow: hidden; | ||||
|     zoom: 1; | ||||
|     box-sizing: border-box; | ||||
|     width: 100%; | ||||
|     clear:both; | ||||
|     height: 30px; | ||||
|     line-height: 30px; | ||||
|     background-color: #202225; | ||||
|     -webkit-app-region: drag; | ||||
|     width: 100%; | ||||
|     user-select: none; | ||||
|     -webkit-user-select: none; | ||||
|     position: fixed; | ||||
|     z-index: 99999; | ||||
|      | ||||
|   } | ||||
|   .appMount-3lHmkl{ | ||||
|    | ||||
|   } | ||||
|   .titlebar #window-title { | ||||
|     width: 30%; | ||||
|     height: 100%; | ||||
|     line-height: 30px; | ||||
|     float: left; | ||||
|     padding: 0 0 0 1em; | ||||
|   } | ||||
|    | ||||
|   .titlebar #window-controls-container { | ||||
|     float: right; | ||||
|     width: 150px; | ||||
|     height: 100%; | ||||
|     line-height: 30px; | ||||
|     background-color: #202225; | ||||
|     -webkit-app-region: no-drag; | ||||
|   } | ||||
|    | ||||
|   .titlebar #window-controls-container #minimize, | ||||
|   .titlebar #window-controls-container #maximize, | ||||
|   .titlebar #window-controls-container #quit { | ||||
|     float: left; | ||||
|     height: 100%; | ||||
|     width: 33%; | ||||
|     text-align: center; | ||||
|     color: #f7f7f7; | ||||
|     cursor: default; | ||||
|   } | ||||
|    | ||||
|   .titlebar #window-controls-container #minimize:hover { | ||||
|     background-color: #99AAB5; | ||||
|   } | ||||
|   .titlebar #window-controls-container #maximize:hover { | ||||
|     background-color: #99AAB5; | ||||
|   } | ||||
|   .titlebar #window-controls-container #quit:hover { | ||||
|     background-color: #F04747; | ||||
|   } | ||||
|   .titlebar #window-controls-container #quit { | ||||
|     background-color: #f7f7f7; | ||||
|     -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") no-repeat 50% 50%; | ||||
|     mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") no-repeat 50% 50%; | ||||
|   } | ||||
|   .titlebar #window-controls-container #minimize { | ||||
|     background-color: #f7f7f7; | ||||
|     -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") no-repeat 50% 50%; | ||||
|     mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") no-repeat 50% 50%; | ||||
|   } | ||||
|   .titlebar #window-controls-container #maximize { | ||||
|     background-color: #f7f7f7; | ||||
|     -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") no-repeat 50% 50%; | ||||
|     mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") no-repeat 50% 50%; | ||||
|   } | ||||
|   .window-title:after { | ||||
|     content: "Cord"; | ||||
|     color: var(--cord-color) !important; | ||||
|     font-weight: normal; | ||||
|     font-size: 14px; | ||||
|     font-family: Discordinated; | ||||
|   } | ||||
|   .window-title:before { | ||||
|     content: "ARM"; | ||||
|     color: var(--armcord-color); | ||||
|     font-weight: normal; | ||||
|     font-size: 14px; | ||||
|     font-family: Helvetica, sans-serif; | ||||
|   } | ||||
|   .window-title { | ||||
|     font-size: 0px !important; | ||||
|     margin-left: initial !important; | ||||
|     transform: translate(10px, 0px); | ||||
|   } | ||||
							
								
								
									
										50
									
								
								src/content/index.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/content/index.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
|   <head> | ||||
|     <meta charset="UTF-8" /> | ||||
|     <title>ArmCord</title> | ||||
|     <style> | ||||
|       @import url("css/splash.css"); | ||||
|     </style> | ||||
|   </head> | ||||
| 
 | ||||
|   <body> | ||||
|     <div class="container"> | ||||
|       <video autoplay loop class="logo"> | ||||
|         <source | ||||
|           src="https://armcord.smartfridge.space/discord_loading.webm" | ||||
|           type="video/webm" | ||||
|         /> | ||||
|       </video> | ||||
|       <p id="text"></p> | ||||
|     </div> | ||||
|   </body> | ||||
|   <script> | ||||
|     const text = document.getElementById("text"); | ||||
|     if (window.navigator.onLine === false) { | ||||
|       text.innerHTML = | ||||
|         "You appear to be offline. Please connect to the internet and try again."; | ||||
|     } else { | ||||
|       text.innerHTML = "Starting ArmCord..."; | ||||
|        | ||||
|       setTimeout(() => { | ||||
|       window.armcord.splashEnd(); | ||||
|       switch (window.armcord.channel) { | ||||
|         case "stable": | ||||
|           window.location.href = "https://discord.com/app"; | ||||
|           break; | ||||
|         case "canary": | ||||
|           window.location.href = "https://canary.discord.com/app"; | ||||
|           break; | ||||
|         case "ptb": | ||||
|           window.location.href = "https://ptb.discord.com/app"; | ||||
|           break; | ||||
|         case "foss": | ||||
|           window.location.href = "https://dev.fosscord.com/app"; | ||||
|           break; | ||||
|         default: | ||||
|           window.location.href = "https://discord.com/app"; | ||||
|       }}, 5000); | ||||
|     } | ||||
|   </script> | ||||
| </html> | ||||
							
								
								
									
										24
									
								
								src/content/setup.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/content/setup.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| 
 | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| 
 | ||||
| <head> | ||||
|   <meta charset="UTF-8"/> | ||||
|   <title>ArmCord Setup</title> | ||||
|   <style> | ||||
|      @import url("css/setup.css"); | ||||
|   </style> | ||||
| </head> | ||||
| 
 | ||||
| <body>   | ||||
| <div class="container"> | ||||
|   <h1 class="logo"></h1> | ||||
|   <h2>Welcome to ArmCord!</h2> | ||||
|   <p>Select what kind of setup you want to perform:</p> | ||||
|   <button id="express">Express setup</button> | ||||
|   <button id="full">Full setup</button> | ||||
| </div> | ||||
| 
 | ||||
| </body> | ||||
| 
 | ||||
| </html> | ||||
							
								
								
									
										26
									
								
								src/extensions/plugin.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/extensions/plugin.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| import * as fs from 'fs'; | ||||
| import { app, session } from 'electron'; | ||||
| const userDataPath = app.getPath("userData"); | ||||
| const pluginFolder = userDataPath + "/plugins/"; | ||||
| if (!fs.existsSync(pluginFolder)) { | ||||
|     fs.mkdirSync(pluginFolder); | ||||
|     console.log("Created missing plugin folder"); | ||||
|   } | ||||
| app.whenReady().then(() => { | ||||
|   fs.readdirSync(pluginFolder).forEach((file) => { | ||||
|     try { | ||||
|       const manifest = fs.readFileSync( | ||||
|         `${userDataPath}/plugins/${file}/manifest.json`, | ||||
|         "utf8" | ||||
|       ); | ||||
|       var pluginFile = JSON.parse(manifest); | ||||
|       session.defaultSession.loadExtension(`${userDataPath}/plugins/${file}`); | ||||
|       console.log( | ||||
|         `%cLoaded ${pluginFile.name} made by ${pluginFile.author}`, | ||||
|         "color:red" | ||||
|       ); | ||||
|     } catch (err) { | ||||
|       console.error(err); | ||||
|     } | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										0
									
								
								src/extensions/themes.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/extensions/themes.ts
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										92
									
								
								src/main.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/main.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | |||
| // Modules to control application life and create native browser window
 | ||||
| import { app, BrowserWindow, ipcMain, shell } from "electron"; | ||||
| import * as path from "path"; | ||||
| import * as storage from 'electron-json-storage'; | ||||
| import {setup} from './utils'; | ||||
| import './extensions/plugin'; | ||||
| var isSetup = null; | ||||
| var contentPath:string = "null"; | ||||
| var frame:boolean; | ||||
| 
 | ||||
| storage.keys(function(error, keys) { | ||||
|     if (error) throw error; | ||||
|    | ||||
|     for (var key of keys) { | ||||
|       console.log('There is a key called: ' + key); | ||||
|     } | ||||
|   }); | ||||
| storage.has('firstRun', function(error, hasKey) { | ||||
|   if (error) throw error; | ||||
| 
 | ||||
|   if (!hasKey) { | ||||
|     console.log('First run of the ArmCord. Starting setup.'); | ||||
|     isSetup = true; | ||||
|     setup(); | ||||
|     contentPath = __dirname + '/content/setup.html' | ||||
|   } else { | ||||
|     console.log('ArmCord has been run before. Skipping setup.'); | ||||
|     isSetup = false; | ||||
|     contentPath = __dirname + '/content/index.html' | ||||
|   } | ||||
| }); | ||||
| storage.get('settings', function(error, data:any) { | ||||
|     if (error) throw error; | ||||
|     console.log(data); | ||||
|     frame = data.customTitlebar; | ||||
|     console.log(frame) | ||||
|   }); | ||||
| function createWindow () { | ||||
|   const mainWindow = new BrowserWindow({ | ||||
|     width: 300, | ||||
|     height: 300, | ||||
|     title: "ArmCord", | ||||
|     frame: frame, | ||||
|     webPreferences: { | ||||
|       preload: path.join(__dirname, 'preload/preload.js') | ||||
|     } | ||||
|   }) | ||||
|   ipcMain.on("get-app-path", (event, arg) => { | ||||
|     event.reply("app-path", app.getAppPath()); | ||||
|   }); | ||||
|   ipcMain.on("open-external-link", (event, href: string) => { | ||||
|     shell.openExternal(href); | ||||
|   }); | ||||
|   ipcMain.on("win-maximize", (event, arg) => { | ||||
|     mainWindow.maximize(); | ||||
|   }); | ||||
|   ipcMain.on("win-isMaximized", (event, arg) => { | ||||
|     event.returnValue = mainWindow.isMaximized(); | ||||
|   }); | ||||
|   ipcMain.on("win-minimize", (event, arg) => { | ||||
|     mainWindow.minimize(); | ||||
|   }); | ||||
|   ipcMain.on("win-show", (event, arg) => { | ||||
|     mainWindow.show(); | ||||
|   }); | ||||
|   ipcMain.on("win-hide", (event, arg) => { | ||||
|     mainWindow.hide(); | ||||
|   }); | ||||
|   ipcMain.on("get-app-version", (event) => { | ||||
|     event.returnValue = process.env.npm_package_version; | ||||
|   }) | ||||
|   ipcMain.on("splashEnd", (event, arg) => { | ||||
|     mainWindow.setSize(800, 600); | ||||
|   }); | ||||
|   ipcMain.on("channel", (event) => { | ||||
|     event.returnValue = storage.getSync('channel'); | ||||
|   }) | ||||
|   mainWindow.loadFile(contentPath) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| app.whenReady().then(() => { | ||||
|   createWindow() | ||||
| 
 | ||||
|   app.on('activate', function () { | ||||
|     if (BrowserWindow.getAllWindows().length === 0) createWindow() | ||||
|   }) | ||||
| }) | ||||
| 
 | ||||
| app.on('window-all-closed', function () { | ||||
|   if (process.platform !== 'darwin') app.quit() | ||||
| }) | ||||
							
								
								
									
										17
									
								
								src/preload/bridge.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/preload/bridge.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| 
 | ||||
| import { contextBridge, ipcRenderer } from 'electron'; | ||||
| import {getDisplayMediaSelector} from './capturer'; | ||||
| 
 | ||||
| contextBridge.exposeInMainWorld("armcord", { | ||||
|   window: { | ||||
|     show: () => ipcRenderer.sendSync('win-show'), | ||||
|     hide: () => ipcRenderer.sendSync('win-hide'), | ||||
|     minimize: () => ipcRenderer.sendSync('win-minimize'), | ||||
|     maximize: () => ipcRenderer.sendSync('win-maximize'), | ||||
|   }, | ||||
|   electron: process.versions.electron, | ||||
|   version: ipcRenderer.sendSync('get-app-version', 'app-version'), | ||||
|   getDisplayMediaSelector: getDisplayMediaSelector, | ||||
|   splashEnd: () => ipcRenderer.sendSync('splashEnd'), | ||||
|   channel: ipcRenderer.sendSync('channel') | ||||
| }); | ||||
							
								
								
									
										152
									
								
								src/preload/capturer.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								src/preload/capturer.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,152 @@ | |||
| //Fixed context isolation version https://github.com/getferdi/ferdi/blob/develop/src/webview/screenshare.ts
 | ||||
| //original https://github.com/electron/electron/issues/16513#issuecomment-602070250
 | ||||
| import { desktopCapturer } from 'electron'; | ||||
| import {addStyle, addScript} from '../utils'; | ||||
| 
 | ||||
| const CANCEL_ID = 'desktop-capturer-selection__cancel'; | ||||
| 
 | ||||
| export async function getDisplayMediaSelector() { | ||||
|   const sources = await desktopCapturer.getSources({ | ||||
|     types: ['screen', 'window'], | ||||
|   }); | ||||
|   return `<div class="desktop-capturer-selection__scroller">
 | ||||
|   <ul class="desktop-capturer-selection__list"> | ||||
|     ${sources | ||||
|       .map( | ||||
|         ({ id, name, thumbnail }) => ` | ||||
|       <li class="desktop-capturer-selection__item"> | ||||
|         <button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}"> | ||||
|           <img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" /> | ||||
|           <span class="desktop-capturer-selection__name">${name}</span> | ||||
|         </button> | ||||
|       </li> | ||||
|     `,
 | ||||
|       ) | ||||
|       .join('')} | ||||
|     <li class="desktop-capturer-selection__item"> | ||||
|       <button class="desktop-capturer-selection__btn" data-id="${CANCEL_ID}" title="Cancel"> | ||||
|         <span class="desktop-capturer-selection__name desktop-capturer-selection__name--cancel">Cancel</span> | ||||
|       </button> | ||||
|     </li> | ||||
|   </ul> | ||||
| </div>`;
 | ||||
| } | ||||
| 
 | ||||
| const screenShareCSS = ` | ||||
| .desktop-capturer-selection { | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   width: 100%; | ||||
|   height: 100vh; | ||||
|   background: rgba(30,30,30,.75); | ||||
|   color: #FFFFFF; | ||||
|   z-index: 10000000; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
| } | ||||
| .desktop-capturer-selection__scroller { | ||||
|   width: 100%; | ||||
|   max-height: 100vh; | ||||
|   overflow-y: auto; | ||||
| } | ||||
| .desktop-capturer-selection__list { | ||||
|   max-width: calc(100% - 100px); | ||||
|   margin: 50px; | ||||
|   padding: 0; | ||||
|   display: flex; | ||||
|   flex-wrap: wrap; | ||||
|   list-style: none; | ||||
|   overflow: hidden; | ||||
|   justify-content: center; | ||||
| } | ||||
| .desktop-capturer-selection__item { | ||||
|   display: flex; | ||||
|   margin: 4px; | ||||
| } | ||||
| .desktop-capturer-selection__btn { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   align-items: stretch; | ||||
|   width: 145px; | ||||
|   margin: 0; | ||||
|   border: 0; | ||||
|   border-radius: 3px; | ||||
|   padding: 4px; | ||||
|   background: #2C2F33; | ||||
|   text-align: left; | ||||
|   @media (prefers-reduced-motion: no-preference) { | ||||
|     transition: background-color .15s, box-shadow .15s, color .15s; | ||||
|   } | ||||
|   color: #dedede; | ||||
| } | ||||
| .desktop-capturer-selection__btn:hover, | ||||
| .desktop-capturer-selection__btn:focus { | ||||
|   background: #7289DA; | ||||
|   box-shadow: 0 0 4px rgba(0,0,0,0.45), 0 0 2px rgba(0,0,0,0.25); | ||||
|   color: #fff; | ||||
| } | ||||
| .desktop-capturer-selection__thumbnail { | ||||
|   width: 100%; | ||||
|   height: 81px; | ||||
|   object-fit: cover; | ||||
| } | ||||
| .desktop-capturer-selection__name { | ||||
|   margin: 6px 0; | ||||
|   white-space: nowrap; | ||||
|   color: white; | ||||
|   text-overflow: ellipsis; | ||||
|   text-align: center; | ||||
|   overflow: hidden; | ||||
| } | ||||
| .desktop-capturer-selection__name--cancel { | ||||
|   margin: auto 0; | ||||
| } | ||||
| `;
 | ||||
| 
 | ||||
| const screenShareJS = ` | ||||
| window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve, reject) => { | ||||
|   try { | ||||
|     const selectionElem = document.createElement('div'); | ||||
|     selectionElem.classList = ['desktop-capturer-selection']; | ||||
|     selectionElem.innerHTML = await window.electron.getDisplayMediaSelector(); | ||||
|     document.body.appendChild(selectionElem); | ||||
|     document | ||||
|       .querySelectorAll('.desktop-capturer-selection__btn') | ||||
|       .forEach((button) => { | ||||
|         button.addEventListener('click', async () => { | ||||
|           try { | ||||
|             const id = button.getAttribute('data-id'); | ||||
|             if (id === '${CANCEL_ID}') { | ||||
|               reject(new Error('Cancelled by user')); | ||||
|             } else { | ||||
|               const stream = await window.navigator.mediaDevices.getUserMedia({ | ||||
|                 audio: false, | ||||
|                 video: { | ||||
|                   mandatory: { | ||||
|                     chromeMediaSource: 'desktop', | ||||
|                     chromeMediaSourceId: id, | ||||
|                   }, | ||||
|                 }, | ||||
|               }); | ||||
|               resolve(stream); | ||||
|             } | ||||
|           } catch (err) { | ||||
|             reject(err); | ||||
|           } finally { | ||||
|             selectionElem.remove(); | ||||
|           } | ||||
|         }); | ||||
|       }); | ||||
|   } catch (err) { | ||||
|     reject(err); | ||||
|   } | ||||
| }); | ||||
| `;
 | ||||
| 
 | ||||
| document.addEventListener("DOMContentLoaded", function(event) {      | ||||
|   addScript(screenShareJS); | ||||
|   addStyle(screenShareCSS); | ||||
| }); | ||||
| 
 | ||||
							
								
								
									
										5
									
								
								src/preload/preload.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/preload/preload.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| import './capturer' | ||||
| import './bridge' | ||||
| import {injectTitlebar} from './titlebar'; | ||||
| injectTitlebar(); | ||||
| console.log("ArmCord"); | ||||
							
								
								
									
										46
									
								
								src/preload/titlebar.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/preload/titlebar.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| import { ipcRenderer } from 'electron'; | ||||
| import {addStyle} from '../utils' | ||||
| import * as fs from 'fs'; | ||||
| import * as path from 'path'; | ||||
| export function injectTitlebar() { | ||||
|     document.addEventListener("DOMContentLoaded", function (event) { | ||||
|         var elem = document.createElement("div"); | ||||
|         elem.innerHTML = `<nav class="titlebar">
 | ||||
|           <div class="window-title" id="window-title"></div> | ||||
|           <div id="window-controls-container"> | ||||
|               <div id="minimize"></div> | ||||
|               <div id="maximize"></div> | ||||
|               <div id="quit"></div> | ||||
|           </div> | ||||
|         </nav>`;
 | ||||
|         document.body.appendChild(elem); | ||||
|         const cssPath = path.join(__dirname, '../', '/content/css/titlebar.css'); | ||||
|         addStyle(fs.readFileSync( | ||||
|            cssPath, | ||||
|           "utf8" | ||||
|         )); | ||||
|        | ||||
|         var minimize = document.querySelector("#minimize"); | ||||
|         var maximize = document.querySelector("#maximize"); | ||||
|         var quit = document.querySelector("#quit"); | ||||
|        | ||||
|         minimize!.addEventListener("click", () => { | ||||
|           ipcRenderer.sendSync('win-minimize') | ||||
|         }); | ||||
|        | ||||
|         maximize!.addEventListener("click", () => { | ||||
|           if (ipcRenderer.sendSync('win-isMaximized') == true) { | ||||
|               ipcRenderer.sendSync('win-minimize') | ||||
|           } else { | ||||
|               ipcRenderer.sendSync('win-maximize') | ||||
|           } | ||||
|         }); | ||||
|        | ||||
|         quit!.addEventListener("click", () => { | ||||
|           ipcRenderer.sendSync('win-hide') | ||||
|         }); | ||||
|       }); | ||||
| } | ||||
| export function removeTitlebar() { | ||||
|     document.querySelector('#titlebar')!.remove(); | ||||
| } | ||||
							
								
								
									
										24
									
								
								src/utils.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/utils.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| import * as storage from 'electron-json-storage'; | ||||
| //utillity functions that are used all over the codebase or just too obscure to be put in the file used in
 | ||||
| export function addStyle(styleString: string) { | ||||
|  const style = document.createElement('style'); | ||||
|  style.textContent = styleString; | ||||
|  document.head.append(style); | ||||
| }; | ||||
| 
 | ||||
| export function addScript(scriptString: string) { | ||||
|   var script = document.createElement("script"); | ||||
|   script.textContent = scriptString; | ||||
|   document.body.append(script); | ||||
| }; | ||||
| export function setup(){ | ||||
|     console.log("Setting up ArmCord settings."); | ||||
|       storage.set('settings', { customTitlebar: true, channel: 'stable', firstRun: 'done' }, function(error) { | ||||
|         if (error) throw error; | ||||
|       }); | ||||
| } | ||||
| export interface settingsStructure { | ||||
|     channel: string, | ||||
|     customTitlebar: boolean, | ||||
|     firstRun: string, | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue