├── .gitignore ├── LICENSE ├── README.md ├── VERSION ├── build.dev.sh ├── build.prod.sh ├── extension ├── background.js ├── contentScript.js ├── gitdStyles.css ├── icons │ ├── 128.png │ ├── 16.png │ └── 32.png ├── lib │ ├── alpine-scp.js │ ├── alpine-scp.min.js │ ├── fflate.js │ ├── fflate.min.js │ └── gitdmanager.js └── manifest.json ├── gif └── gitdmanager.gif ├── manifestv2.dev.template ├── manifestv2.template ├── manifestv3.dev.template ├── manifestv3.template ├── screenshots ├── gitd-manager-bitbucket-download.jpeg ├── gitd-manager-bitbucket-download.png ├── gitd-manager-bitbucket-select.jpeg ├── gitd-manager-bitbucket-select.png ├── gitd-manager-github-download.jpeg ├── gitd-manager-github-download.png ├── gitd-manager-github-select.jpeg ├── gitd-manager-github-select.png ├── gitd-manager-github-zip.jpeg ├── gitd-manager-github-zip.png ├── gitd-manager-gitlab-download.jpeg ├── gitd-manager-gitlab-download.png ├── gitd-manager-gitlab-select.jpeg ├── gitd-manager-gitlab-select.png └── marque_promo.png └── sh ├── build.sh └── release.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.crx 3 | *.pem 4 | *.zip 5 | *_original* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Gitdownloadmanager.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gitd Download Manager Browser Extension 2 | 3 | It is a browser extension that allows you to download only the files/folders you want without having to download all of the public repository. Github.com, Bitbucket.org, Gitlab.com, Gitea.com, Gitee.com provides all of the public repos in git services to download selected files and folders as a zip files with a single click, without the need for any API key or token. 4 | 5 | If you see "Gitd Start" button, It is ready for use on every screen you see. You have to to click (checkboxes appears) and can starting to select files. 6 | 7 | > Note: Gitd Download Manager browser extension creates download lists using Gitdownloadmanager.com api service. 8 | 9 | ![video](gif/gitdmanager.gif) 10 | 11 | ## Features 12 | 13 | - Support only Github.com, Bitbucket.org, Gitlab.com, Gitea.com, Gitee.com public repositories page 14 | - Not neeeded ApiKey/ApiToken 15 | - Support single or multiple files download 16 | - Download selected contents as a zip file with one click 17 | - Support all branches 18 | - Maximum Selection Limit: 10 19 | - Maximum Download Files: 10000 20 | 21 | ![screenshot](screenshots/gitd-manager-github-download.jpeg) 22 | 23 | ## Next Features 24 | 25 | - No limitations for selection and downloading files count 26 | - Support branch names with includes slash 27 | - Support Bitbucket.org commitId url (Maybe) 28 | 29 | ## Compatibility 30 | 31 | - Chrome (Manifestv3) 32 | - Firefox (Manifestv2) 33 | - Microsoft Edge (Manifestv3) (I not login to My Microsoft Account????) 34 | 35 | ## Installation 36 | 37 | ### 1. Chrome Store/Firefox Add-Ons 38 | 39 | Go to [Gitd Download Manager](https://chrome.google.com/webstore/detail/gitd-download-manager/cbnplpkljokdodpligcaolkmodfondhl) Chrome Store Page 40 | 41 | Go to [Gitd Download Manager](https://addons.mozilla.org/en-US/firefox/addon/gitd-download-manager/) Firefox Add-Ons Page 42 | 43 | Go to [Gitd Download Manager](https://microsoftedge.microsoft.com/addons/detail/-/-) Microsoft Edge Add-Ons Page 44 | 45 | ### 2. Production Build For Chrome Store / Firefox Add-on / Microsoft Edge 46 | 47 | - Go to the folder where the `README.md` file is located and run `./build.prod.sh ` (./build.prod.sh 1.0.1) command after go to "build/prod//" folder for zip files of all versions. 48 | 49 | ```bash 50 | ./build/prod/1.0.1/gitd-1.0.1-v2.dev.zip -> Firefox Extension - Development version - Manifest version 2 51 | ./build/prod/1.0.1/gitd-1.0.1-v2.zip -> Firefox Extension - Production Version - Manifest version 2 52 | ./build/prod/1.0.1/gitd-1.0.1-v3.dev.zip -> Chrome Store Extension - Development version - Manifest version 3 53 | ./build/prod/1.0.1/gitd-1.0.1-v3.zip -> Chrome Store Extension - Production Version - Manifest version 3 54 | ``` 55 | 56 | > Your operating system has to supports `pwd`, `cat`, `sed`, `zip`, `mkdir` Linux commands. 57 | 58 | ### 3.Local Development / Testing 59 | 60 | - Run `./build..sh ` (./build.dev.sh 1.0.1) command after go to "build/dev//" folder for zip files of all versions. 61 | 62 | ```bash 63 | ./build/prod/1.0.1/gitd-1.0.1-v2.dev.zip -> Firefox Extension - Development version - Manifest version 2 64 | ./build/prod/1.0.1/gitd-1.0.1-v2.zip -> Firefox Extension - Production Version - Manifest version 2 65 | ./build/prod/1.0.1/gitd-1.0.1-v3.dev.zip -> Chrome Store Extension - Development version - Manifest version 3 66 | ./build/prod/1.0.1/gitd-1.0.1-v3.zip -> Chrome Store Extension - Production Version - Manifest version 3 67 | ``` 68 | 69 | - or install directly from browser extension page 70 | 71 | 1. Open Chrome and go to: chrome://extensions/ (same as Firefox) 72 | 2. Enable: "Developer mode" 73 | 3. Click: "Load unpacked extension" 74 | 4. Select: "extension" directory 75 | 5. Ready to use 76 | 6. Go to github.com, gitlab.com or bitbucket.org website 77 | 78 | ### Usage 79 | 80 | - In the right corner of the browser, the "Gitd Start" button notifies you that the plugin is active. 81 | - The plugin is automatically installed on Github.com and adds checkboxes, but on other websites you have to press the "Gitd Start" button. 82 | 83 | ### Find Open Source Projects: Public Repository 84 | 85 | [Github.com](https://github.com/search/advanced) advanced search page. 86 | [Gitlab.com](https://gitlab.com/explore/projects) advanced search page. 87 | [Bitbucket.org](https://bitbucket.org/repo/all) simple search page. 88 | [Gitea.com](https://gitea.com/explore/repos) simple search page. 89 | [Gitee.com](https://gitee.com/explore) simple search page. 90 | 91 | ## Licence 92 | 93 | See LICENSE for more details. 94 | 95 | ## Thanks 96 | 97 | [Alpinejs](https://alpinejs.dev) for DOM manipulation 98 | 99 | [fflate](https://github.com/101arrowz/fflate) for generate zip packages 100 | 101 | [Bootstrap Icons](https://icons.getbootstrap.com) for svg icons 102 | 103 | [Photopea](https://www.photopea.com) for create logo, icon and favicon 104 | 105 | [Liozon/Edge add-on badge.md](https://gist.github.com/Liozon/cf898c47628bfecd9896f79e6c9a8db8) for Microsoft Edge Add-On Badge 106 | 107 | ## Source 108 | 109 | [Firefox Manifest Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json) * perfect docs 110 | 111 | [Google Chrome Manifest Docs](https://developer.chrome.com/docs/extensions/mv3/manifest/) * not recomended **sorry** 112 | 113 | [Microsoft Edge Manifest Docs](https://learn.microsoft.com/en-us/microsoft-edge/extensions-chromium/getting-started/manifest-format) * firefox alternate 114 | 115 | ## Changelog 116 | 117 | v1.0.8 118 | 119 | - fixed Github new css selector for file name 120 | 121 | v1.0.7 122 | 123 | - adds Gitee.com service (archive download not supported) 124 | - fixed file list strange loop index issue 125 | 126 | v1.0.6 127 | 128 | - adds Gitea.com service 129 | - increases selection limit and files 130 | - removes auto initialize all of the services. excepts Github.com 131 | - removes Github.com turbo event listeners 132 | 133 | v1.0.5 134 | 135 | - fix checkboxes not working when browser back event 136 | - add auto initialize all of the supported services (no longer need to press the Gitd Start button) 137 | - remove Github.com turbo event listeners 138 | 139 | v1.0.4 140 | 141 | - update only manifest description 142 | 143 | v1.0.3 144 | 145 | - update manifest description 146 | 147 | v1.0.3 148 | 149 | - compatible with github both page design 150 | 151 | v1.0.2 152 | 153 | - compatible with github new design 154 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.0.8 2 | -------------------------------------------------------------------------------- /build.dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ARGS=("$@") 3 | BUILD_NUMBER_NEW="${ARGS[0]}" 4 | 5 | ./sh/build.sh "dev" $BUILD_NUMBER_NEW "https://localhost:3002" "https://localhost" -------------------------------------------------------------------------------- /build.prod.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ARGS=("$@") 4 | BUILD_NUMBER_NEW="${ARGS[0]}" 5 | 6 | ./sh/build.sh "prod" $BUILD_NUMBER_NEW "https://api.gitdownloadmanager.com" "https://*.gitdownloadmanager.com" -------------------------------------------------------------------------------- /extension/background.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // Manifest json file to object data 4 | let manifestData = chrome.runtime.getManifest() 5 | 6 | // console.log("manifestData", manifestData); 7 | // Fired when the extension is first installed, when the extension is updated to a new version, and when the browser is updated to a new version. 8 | chrome.runtime.onInstalled.addListener( 9 | function() { 10 | console.info('%c' + manifestData.name + ' Extension: %cWelcome to my world!', 'color: orange;', 'color: default;') 11 | } 12 | ) 13 | 14 | // Use APIs that support event filters to restrict listeners to the cases the extension cares about. 15 | // If an extension is listening for the tabs.onUpdated event, try using the webNavigation.onCompleted event with filters instead, as the tabs API does not support filters. 16 | // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/events/UrlFilter 17 | let urlFilters = { 18 | url: [ 19 | { 20 | hostEquals:'github.com', 21 | schemes:["https"] 22 | }, 23 | { 24 | hostEquals:'gitlab.com', 25 | schemes:["https"] 26 | }, 27 | { 28 | hostEquals:'bitbucket.org', 29 | schemes:["https"] 30 | }, 31 | { 32 | hostEquals:'gitea.com', 33 | schemes:["https"] 34 | }, 35 | { 36 | hostEquals:'gitee.com', // https://github.com/git-download-manager/gitd-extension/issues/4 37 | schemes:["https"] 38 | } 39 | ] 40 | } 41 | 42 | /*chrome.webNavigation.onDOMContentLoaded.addListener(function (details) { 43 | // send message 44 | chrome.tabs.sendMessage(details.tabId, { 45 | action: 'IM_LOADING' 46 | }) 47 | }, urlFilters)*/ 48 | 49 | chrome.webNavigation.onCompleted.addListener(function (details) { 50 | chrome.tabs.sendMessage(details.tabId, { 51 | action: 'IM_READY' 52 | }) 53 | }, urlFilters) 54 | 55 | // adds a listener to tab change 56 | chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 57 | // check for a URL in the changeInfo parameter (url is only added when it is changed) 58 | if (changeInfo.url) { 59 | chrome.tabs.sendMessage(tabId, { 60 | action: 'URL_CHANGED' 61 | }) 62 | } 63 | }) 64 | 65 | // chrome.webNavigation.onHistoryStateUpdated.addListener(function (details) { 66 | // chrome.tabs.sendMessage(details.tabId, { 67 | // action: 'IM_CHANGED' 68 | // }) 69 | // }, urlFilters) 70 | 71 | // gitdmanager api request listener 72 | chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { 73 | // console.log("bg", request, sender, sendResponse) 74 | 75 | if (request.name === "gitd-api") { 76 | // console.log(_findUrlFromManifest(request.url)) 77 | fetch(_findUrlFromManifest(request.url), { 78 | method: "POST", 79 | body: JSON.stringify(request.body), 80 | headers: { 81 | "content-type": "application/json", 82 | }, 83 | }) 84 | .then(resp => resp.json()) 85 | .then(response => sendResponse(response)) 86 | .catch(e => { 87 | //console.warn("fetch Error", e); 88 | 89 | sendResponse({status: false, message: "internal server error. something wrong!"}) 90 | }) 91 | } 92 | 93 | return true // last error fixed 94 | }) 95 | 96 | function _findUrlFromManifest(request_url) { 97 | let version = manifestData.manifest_version 98 | 99 | let url = "" 100 | if (version === 2) { 101 | url = (manifestData.permissions[0]).replace("/*", request_url) 102 | } else if (version === 3) { 103 | url = (manifestData.host_permissions[0]).replace("/*", request_url) 104 | } 105 | 106 | return url 107 | } 108 | -------------------------------------------------------------------------------- /extension/contentScript.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // declare debug mode var 4 | let gitdDebugMode = false 5 | let gitdProcessRunning = false 6 | 7 | // templates 8 | const gitdInitTemplateContainer = `
9 | 16 |
` 17 | 18 | // track body change (x-data) 19 | // trackBodyAttributes("x-data") 20 | 21 | // listen runtime message from bg 22 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { 23 | switch (request.action) { 24 | /*case "IM_CHANGED": 25 | // Dom Content Loading but not finish 26 | if (gitdDebugMode) console.log("content-script", "im changed") 27 | 28 | // start process 29 | // initGitdProcess("IM_CHANGED") 30 | 31 | break;*/ 32 | /*case "IM_LOADING": 33 | // Dom Content Loading but not finish 34 | if (gitdDebugMode) console.log("content-script", "im loading") 35 | 36 | break;*/ 37 | case "URL_CHANGED": 38 | // url changed 39 | if (gitdDebugMode) console.log("content-script", "url changed") 40 | 41 | // start process 42 | initGitdProcess("URL_CHANGED") 43 | 44 | break; 45 | case "IM_READY": 46 | // Everything Loading finished. Ready to use. 47 | if (gitdDebugMode) console.log("content-script", "im ready") 48 | 49 | // start process 50 | initGitdProcess("IM_READY") 51 | 52 | // inject gitdmanager 53 | injectGitdScripts("lib/gitdmanager.js") 54 | 55 | // inject alpine 56 | injectGitdScripts("lib/alpine-scp.min.js") 57 | 58 | // inject fflate 59 | injectGitdScripts("lib/fflate.min.js") 60 | 61 | break; 62 | default: 63 | break; 64 | } 65 | }); 66 | 67 | // listen browser submit event 68 | // via: chrome dev tools: getEventListeners(window) -> return all events 69 | // Request: gitdmanager (browser) -> contentScript -> background 70 | // Response: background -> contentScript -> gitdmanager (browser) 71 | window.addEventListener("submit-action", function(evt) { 72 | if (gitdDebugMode) console.log("content-script","submit-action", evt.detail) 73 | chrome.runtime.sendMessage(JSON.parse(evt.detail), function(response) { 74 | if (gitdDebugMode) console.log("bg-response", response); 75 | 76 | window.dispatchEvent(new CustomEvent( 77 | 'submit-action-response', 78 | { 79 | bubbles: true, 80 | detail: JSON.stringify(response) 81 | } 82 | )) 83 | }); 84 | }, false); 85 | 86 | // via: chrome dev tools: getEventListeners(window) -> return all events 87 | // only for github "turbo:load" event listen 88 | // window.addEventListener("turbo:load", function(evt) { 89 | // if (gitdDebugMode) console.log("content-script", "turbo:load", evt) 90 | 91 | // // start process 92 | // initGitdProcess("turbo:load") 93 | 94 | // }, false); 95 | 96 | // debug mode listener 97 | window.addEventListener("debug-mode-changed", function(evt) { 98 | if (gitdDebugMode) console.log("content-script", "debug-mode-changed", evt) 99 | 100 | gitdDebugMode = evt.detail 101 | 102 | }, false); 103 | 104 | // init gitd with process control 105 | function initGitdProcess(where) { 106 | if (gitdProcessRunning) { 107 | if (gitdDebugMode) console.log("gitdProcessRunning is not finished yet", where); 108 | return 109 | } 110 | 111 | // process start 112 | gitdProcessRunning = true 113 | 114 | if (document.getElementById("gitdStartButton") === null) { 115 | /////////////////// inject templates 116 | // remove template 117 | if (document.getElementById("gitd-container-template")) { 118 | document.getElementById("gitd-container-template").remove() 119 | } 120 | 121 | // remove checkboxes if exists 122 | let gitdCheckboxes = document.querySelectorAll(".gitd-tree-checkbox-container") 123 | if (gitdCheckboxes.length > 0) { 124 | // remove checkbox 125 | gitdCheckboxes.forEach(e => e.remove()) 126 | } 127 | 128 | // add x-data and template container 129 | document.body.setAttribute("x-data", "gitdManager") 130 | document.body.insertAdjacentHTML("beforeend", gitdInitTemplateContainer) 131 | } 132 | 133 | //////////////////// triggger button 134 | // if (where === "IM_CHANGED") { 135 | // hostname 136 | let hostname = window.location.hostname 137 | 138 | if (hostname === "github.com") { 139 | setTimeout(function() { 140 | if (gitdDebugMode) console.log("triggerGitdStart"); 141 | 142 | let gitdStartButton = document.getElementById("gitdStartButton") 143 | if ( !!gitdStartButton && (gitdStartButton.getAttribute("data-trigger") === null || where === "URL_CHANGED") ) { 144 | if (gitdDebugMode) console.log("gitdStartButton", "trigger", "click", gitdStartButton) 145 | 146 | gitdStartButton.setAttribute("data-trigger", where) 147 | gitdStartButton.click() 148 | } 149 | 150 | // process finished 151 | gitdProcessRunning = false 152 | }, 1500) 153 | } 154 | // } 155 | 156 | // // process finished 157 | // gitdProcessRunning = false 158 | } 159 | 160 | // inject scripts 161 | function injectGitdScripts(scrPath) { 162 | let s = document.createElement('script') 163 | s.src = chrome.runtime.getURL(scrPath); 164 | s.onload = function() { 165 | s.parentNode.removeChild(s); 166 | }; 167 | (document.body || document.documentElement).appendChild(s) 168 | if (gitdDebugMode) console.log("injectGitdScripts", s); 169 | } 170 | -------------------------------------------------------------------------------- /extension/gitdStyles.css: -------------------------------------------------------------------------------- 1 | /*Gitd Download Manager Styles*/ 2 | #gitd-init{ 3 | width: 50%; 4 | flex-wrap: wrap; 5 | flex-direction: column-reverse; 6 | position: fixed; 7 | bottom: 0; 8 | left: 0; 9 | right: 0; 10 | padding: 0.6em 1.8em; 11 | z-index: 9999; 12 | display: flex; 13 | margin:0 auto; 14 | border-radius: 0.2rem; 15 | } 16 | 17 | .gitd-shortcut-button { 18 | flex-wrap: wrap; 19 | justify-content: center; 20 | position: fixed; 21 | bottom: 20px; 22 | right: 20px; 23 | z-index: 9999; 24 | display: flex; 25 | } 26 | 27 | .gitd-btn, #gitd-init button { 28 | display: inline-block; 29 | font-weight: 600; 30 | color: #525f7f; 31 | text-align: center; 32 | vertical-align: middle; 33 | user-select: none; 34 | background-color: transparent; 35 | border: 1px solid transparent; 36 | padding: 0.625rem 1.25rem; 37 | font-size: 0.875rem; 38 | line-height: 1.5; 39 | border-radius: 0.25rem; 40 | transition: all 0.15s ease; 41 | position: relative; 42 | will-change: transform; 43 | letter-spacing: 0.025em; 44 | font-size: 0.875rem; 45 | } 46 | 47 | .gitd-btn:hover, #gitd-init button:hover { 48 | transform: translateY(-1px); 49 | } 50 | 51 | .gitd-btn:focus, #gitd-init button:focus { 52 | outline: 0; 53 | box-shadow: 0 7px 14px rgba(50, 50, 93, 0.1), 0 3px 6px rgba(0, 0, 0, 0.08); 54 | } 55 | 56 | .gitd-btn-sm, #gitd-init button.gitd-btn-sm { 57 | padding: 0.25rem 0.5rem; 58 | text-transform: uppercase; 59 | font-size: 0.75rem; 60 | line-height: 1.5; 61 | border-radius: 0.25rem; 62 | } 63 | 64 | .gitd-btn-warning, #gitd-init button.gitd-btn-warning { 65 | color: #fff; 66 | background-color: #fb6340; 67 | border-color: #fb6340; 68 | box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08); 69 | } 70 | 71 | .gitd-btn-warning:hover, #gitd-init button.gitd-btn-warning:hover { 72 | color: #fff; 73 | background-color: #fa441b; 74 | border-color: #fa3a0e; 75 | } 76 | 77 | 78 | .gitd-btn-warning:focus, #gitd-init button.gitd-btn-warning:focus { 79 | box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08), 0 0 0 0 rgba(252, 122, 93, 0.5); 80 | } 81 | 82 | .gitd-btn svg, #gitd-init button.gitd-btn svg { 83 | overflow: hidden; 84 | vertical-align: middle; 85 | } 86 | 87 | .gitd-btn svg:not(:last-child), 88 | .gitd-btn i:not(:last-child), 89 | #gitd-init button.gitd-btn svg:not(:last-child), 90 | #gitd-init button.gitd-btn i:not(:last-child) { 91 | margin-right: 0.5rem; 92 | } 93 | 94 | /*AlertBox*/ 95 | .gitd-alert { 96 | position: relative; 97 | padding: 0.75rem 1.25rem; 98 | margin-bottom: 1rem; 99 | border: 1px solid transparent; 100 | border-radius: 0.25rem; 101 | } 102 | 103 | .gitd-alert p { 104 | margin: 0; 105 | } 106 | 107 | .gitd-alert-success { 108 | color: #155724; 109 | background-color: #d4edda; 110 | border-color: #c3e6cb; 111 | } 112 | 113 | .gitd-alert-light { 114 | color: #818182; 115 | background-color: #fefefe; 116 | border-color: #adb5bd; 117 | } 118 | 119 | .gitd-alert-danger { 120 | color: #721c24; 121 | background-color: #f8d7da; 122 | border-color: #f5c6cb; 123 | } 124 | 125 | .gitd-alert-warning { 126 | color: #856404; 127 | background-color: #fff3cd; 128 | border-color: #ffeeba; 129 | } 130 | 131 | .gitd-alert-info { 132 | color: #0c5460; 133 | background-color: #d1ecf1; 134 | border-color: #bee5eb; 135 | } 136 | 137 | .gitd-alert-secondary { 138 | color: #383d41; 139 | background-color: #e2e3e5; 140 | border-color: #d6d8db; 141 | } 142 | 143 | .gitd-alert-dismissible { 144 | padding-right: 4rem; 145 | } 146 | 147 | .gitd-alert-dismissible .close, #gitd-init button.close { 148 | position: absolute; 149 | top: 0; 150 | right: 0; 151 | z-index: 2; 152 | padding: 0.75rem 1.25rem; 153 | color: inherit; 154 | } 155 | 156 | /*Progress*/ 157 | .gitd-progress-percentage { 158 | text-align: right; 159 | } 160 | 161 | .gitd-progress { 162 | display: flex; 163 | height: 1rem; 164 | overflow: hidden; 165 | font-size: 0.75rem; 166 | background-color: #e9ecef; 167 | border-radius: 0.25rem; 168 | box-shadow: inset 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1); 169 | } 170 | 171 | .gitd-progress-bar { 172 | display: flex; 173 | flex-direction: column; 174 | justify-content: center; 175 | color: #fff; 176 | text-align: center; 177 | white-space: nowrap; 178 | background-color: #5e72e4; 179 | transition: width 0.6s ease; 180 | } 181 | 182 | @media (prefers-reduced-motion: reduce) { 183 | .gitd-progress-bar { 184 | transition: none; 185 | } 186 | } 187 | 188 | .gitd-bg-success { 189 | background-color: #2dce89 !important; 190 | } 191 | 192 | .gitd-current-filename { 193 | float:left !important; 194 | white-space: nowrap; 195 | overflow: hidden; 196 | text-overflow: ellipsis; 197 | } -------------------------------------------------------------------------------- /extension/icons/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/git-download-manager/gitd-extension/f8b9f2e6aeddc69edae1b178b62a44161c7f8f3e/extension/icons/128.png -------------------------------------------------------------------------------- /extension/icons/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/git-download-manager/gitd-extension/f8b9f2e6aeddc69edae1b178b62a44161c7f8f3e/extension/icons/16.png -------------------------------------------------------------------------------- /extension/icons/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/git-download-manager/gitd-extension/f8b9f2e6aeddc69edae1b178b62a44161c7f8f3e/extension/icons/32.png -------------------------------------------------------------------------------- /extension/lib/alpine-scp.min.js: -------------------------------------------------------------------------------- 1 | (()=>{var Ge=!1,Ye=!1,B=[];function jt(e){an(e)}function an(e){B.includes(e)||B.push(e),cn()}function _e(e){let t=B.indexOf(e);t!==-1&&B.splice(t,1)}function cn(){!Ye&&!Ge&&(Ge=!0,queueMicrotask(ln))}function ln(){Ge=!1,Ye=!0;for(let e=0;ee.effect(t,{scheduler:r=>{Ze?jt(r):r()}}),Je=e.raw}function Qe(e){K=e}function Bt(e){let t=()=>{};return[n=>{let i=K(n);return e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(o=>o())}),e._x_effects.add(i),t=()=>{i!==void 0&&(e._x_effects.delete(i),J(i))},i},()=>{t()}]}var Kt=[],zt=[],Vt=[];function Ht(e){Vt.push(e)}function ge(e,t){typeof t=="function"?(e._x_cleanups||(e._x_cleanups=[]),e._x_cleanups.push(t)):(t=e,zt.push(t))}function qt(e){Kt.push(e)}function Ut(e,t,r){e._x_attributeCleanups||(e._x_attributeCleanups={}),e._x_attributeCleanups[t]||(e._x_attributeCleanups[t]=[]),e._x_attributeCleanups[t].push(r)}function Xe(e,t){!e._x_attributeCleanups||Object.entries(e._x_attributeCleanups).forEach(([r,n])=>{(t===void 0||t.includes(r))&&(n.forEach(i=>i()),delete e._x_attributeCleanups[r])})}var tt=new MutationObserver(et),rt=!1;function nt(){tt.observe(document,{subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0}),rt=!0}function fn(){un(),tt.disconnect(),rt=!1}var ne=[],it=!1;function un(){ne=ne.concat(tt.takeRecords()),ne.length&&!it&&(it=!0,queueMicrotask(()=>{dn(),it=!1}))}function dn(){et(ne),ne.length=0}function m(e){if(!rt)return e();fn();let t=e();return nt(),t}var ot=!1,xe=[];function Wt(){ot=!0}function Gt(){ot=!1,et(xe),xe=[]}function et(e){if(ot){xe=xe.concat(e);return}let t=[],r=[],n=new Map,i=new Map;for(let o=0;os.nodeType===1&&t.push(s)),e[o].removedNodes.forEach(s=>s.nodeType===1&&r.push(s))),e[o].type==="attributes")){let s=e[o].target,a=e[o].attributeName,c=e[o].oldValue,l=()=>{n.has(s)||n.set(s,[]),n.get(s).push({name:a,value:s.getAttribute(a)})},u=()=>{i.has(s)||i.set(s,[]),i.get(s).push(a)};s.hasAttribute(a)&&c===null?l():s.hasAttribute(a)?(u(),l()):u()}i.forEach((o,s)=>{Xe(s,o)}),n.forEach((o,s)=>{Kt.forEach(a=>a(s,o))});for(let o of r)if(!t.includes(o)&&(zt.forEach(s=>s(o)),o._x_cleanups))for(;o._x_cleanups.length;)o._x_cleanups.pop()();t.forEach(o=>{o._x_ignoreSelf=!0,o._x_ignore=!0});for(let o of t)r.includes(o)||!o.isConnected||(delete o._x_ignoreSelf,delete o._x_ignore,Vt.forEach(s=>s(o)),o._x_ignore=!0,o._x_ignoreSelf=!0);t.forEach(o=>{delete o._x_ignoreSelf,delete o._x_ignore}),t=null,r=null,n=null,i=null}function ye(e){return M(C(e))}function R(e,t,r){return e._x_dataStack=[t,...C(r||e)],()=>{e._x_dataStack=e._x_dataStack.filter(n=>n!==t)}}function st(e,t){let r=e._x_dataStack[0];Object.entries(t).forEach(([n,i])=>{r[n]=i})}function C(e){return e._x_dataStack?e._x_dataStack:typeof ShadowRoot=="function"&&e instanceof ShadowRoot?C(e.host):e.parentNode?C(e.parentNode):[]}function M(e){let t=new Proxy({},{ownKeys:()=>Array.from(new Set(e.flatMap(r=>Object.keys(r)))),has:(r,n)=>e.some(i=>i.hasOwnProperty(n)),get:(r,n)=>(e.find(i=>{if(i.hasOwnProperty(n)){let o=Object.getOwnPropertyDescriptor(i,n);if(o.get&&o.get._x_alreadyBound||o.set&&o.set._x_alreadyBound)return!0;if((o.get||o.set)&&o.enumerable){let s=o.get,a=o.set,c=o;s=s&&s.bind(t),a=a&&a.bind(t),s&&(s._x_alreadyBound=!0),a&&(a._x_alreadyBound=!0),Object.defineProperty(i,n,{...c,get:s,set:a})}return!0}return!1})||{})[n],set:(r,n,i)=>{let o=e.find(s=>s.hasOwnProperty(n));return o?o[n]=i:e[e.length-1][n]=i,!0}});return t}function be(e){let t=n=>typeof n=="object"&&!Array.isArray(n)&&n!==null,r=(n,i="")=>{Object.entries(Object.getOwnPropertyDescriptors(n)).forEach(([o,{value:s,enumerable:a}])=>{if(a===!1||s===void 0)return;let c=i===""?o:`${i}.${o}`;typeof s=="object"&&s!==null&&s._x_interceptor?n[o]=s.initialize(e,c,o):t(s)&&s!==n&&!(s instanceof Element)&&r(s,c)})};return r(e)}function ve(e,t=()=>{}){let r={initialValue:void 0,_x_interceptor:!0,initialize(n,i,o){return e(this.initialValue,()=>pn(n,i),s=>at(n,i,s),i,o)}};return t(r),n=>{if(typeof n=="object"&&n!==null&&n._x_interceptor){let i=r.initialize.bind(r);r.initialize=(o,s,a)=>{let c=n.initialize(o,s,a);return r.initialValue=c,i(o,s,a)}}else r.initialValue=n;return r}}function pn(e,t){return t.split(".").reduce((r,n)=>r[n],e)}function at(e,t,r){if(typeof t=="string"&&(t=t.split(".")),t.length===1)e[t[0]]=r;else{if(t.length===0)throw error;return e[t[0]]||(e[t[0]]={}),at(e[t[0]],t.slice(1),r)}}var Yt={};function x(e,t){Yt[e]=t}function z(e,t){return Object.entries(Yt).forEach(([r,n])=>{Object.defineProperty(e,`$${r}`,{get(){let[i,o]=ct(t);return i={interceptor:ve,...i},ge(t,o),n(t,i)},enumerable:!1})}),e}function we(e,t,r,...n){try{return r(...n)}catch(i){Z(i,e,t)}}function Z(e,t,r=void 0){Object.assign(e,{el:t,expression:r}),console.warn(`Alpine Expression Error: ${e.message} 2 | 3 | ${r?'Expression: "'+r+`" 4 | 5 | `:""}`,t),setTimeout(()=>{throw e},0)}var Ee=!0;function Jt(e){let t=Ee;Ee=!1,e(),Ee=t}function D(e,t,r={}){let n;return g(e,t)(i=>n=i,r),n}function g(...e){return Zt(...e)}var Zt=mn;function Qt(e){Zt=e}function mn(e,t){let r={};z(r,e);let n=[r,...C(e)];if(typeof t=="function")return lt(n,t);let i=hn(n,t,e);return we.bind(null,e,t,i)}function lt(e,t){return(r=()=>{},{scope:n={},params:i=[]}={})=>{let o=t.apply(M([n,...e]),i);Q(r,o)}}var ut={};function _n(e,t){if(ut[e])return ut[e];let r=Object.getPrototypeOf(async function(){}).constructor,n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e,o=(()=>{try{return new r(["__self","scope"],`with (scope) { __self.result = ${n} }; __self.finished = true; return __self.result;`)}catch(s){return Z(s,t,e),Promise.resolve()}})();return ut[e]=o,o}function hn(e,t,r){let n=_n(t,r);return(i=()=>{},{scope:o={},params:s=[]}={})=>{n.result=void 0,n.finished=!1;let a=M([o,...e]);if(typeof n=="function"){let c=n(n,a).catch(l=>Z(l,r,t));n.finished?(Q(i,n.result,a,s,r),n.result=void 0):c.then(l=>{Q(i,l,a,s,r)}).catch(l=>Z(l,r,t)).finally(()=>n.result=void 0)}}}function Q(e,t,r,n,i){if(Ee&&typeof t=="function"){let o=t.apply(r,n);o instanceof Promise?o.then(s=>Q(e,s,r,n)).catch(s=>Z(s,i,t)):e(o)}else e(t)}var ft="x-";function E(e=""){return ft+e}function Xt(e){ft=e}var er={};function d(e,t){er[e]=t}function ie(e,t,r){if(t=Array.from(t),e._x_virtualDirectives){let o=Object.entries(e._x_virtualDirectives).map(([a,c])=>({name:a,value:c})),s=dt(o);o=o.map(a=>s.find(c=>c.name===a.name)?{name:`x-bind:${a.name}`,value:`"${a.value}"`}:a),t=t.concat(o)}let n={};return t.map(tr((o,s)=>n[o]=s)).filter(rr).map(xn(n,r)).sort(yn).map(o=>gn(e,o))}function dt(e){return Array.from(e).map(tr()).filter(t=>!rr(t))}var pt=!1,oe=new Map,nr=Symbol();function ir(e){pt=!0;let t=Symbol();nr=t,oe.set(t,[]);let r=()=>{for(;oe.get(t).length;)oe.get(t).shift()();oe.delete(t)},n=()=>{pt=!1,r()};e(r),n()}function ct(e){let t=[],r=a=>t.push(a),[n,i]=Bt(e);return t.push(i),[{Alpine:I,effect:n,cleanup:r,evaluateLater:g.bind(g,e),evaluate:D.bind(D,e)},()=>t.forEach(a=>a())]}function gn(e,t){let r=()=>{},n=er[t.type]||r,[i,o]=ct(e);Ut(e,t.original,o);let s=()=>{e._x_ignore||e._x_ignoreSelf||(n.inline&&n.inline(e,t,i),n=n.bind(n,e,t,i),pt?oe.get(nr).push(n):n())};return s.runCleanups=o,s}var Se=(e,t)=>({name:r,value:n})=>(r.startsWith(e)&&(r=r.replace(e,t)),{name:r,value:n}),Ae=e=>e;function tr(e=()=>{}){return({name:t,value:r})=>{let{name:n,value:i}=or.reduce((o,s)=>s(o),{name:t,value:r});return n!==t&&e(n,t),{name:n,value:i}}}var or=[];function X(e){or.push(e)}function rr({name:e}){return sr().test(e)}var sr=()=>new RegExp(`^${ft}([^:^.]+)\\b`);function xn(e,t){return({name:r,value:n})=>{let i=r.match(sr()),o=r.match(/:([a-zA-Z0-9\-:]+)/),s=r.match(/\.[^.\]]+(?=[^\]]*$)/g)||[],a=t||e[r]||r;return{type:i?i[1]:null,value:o?o[1]:null,modifiers:s.map(c=>c.replace(".","")),expression:n,original:a}}}var mt="DEFAULT",Oe=["ignore","ref","data","id","bind","init","for","mask","model","modelable","transition","show","if",mt,"teleport"];function yn(e,t){let r=Oe.indexOf(e.type)===-1?mt:e.type,n=Oe.indexOf(t.type)===-1?mt:t.type;return Oe.indexOf(r)-Oe.indexOf(n)}function V(e,t,r={}){e.dispatchEvent(new CustomEvent(t,{detail:r,bubbles:!0,composed:!0,cancelable:!0}))}var ht=[],_t=!1;function Ce(e=()=>{}){return queueMicrotask(()=>{_t||setTimeout(()=>{Te()})}),new Promise(t=>{ht.push(()=>{e(),t()})})}function Te(){for(_t=!1;ht.length;)ht.shift()()}function ar(){_t=!0}function N(e,t){if(typeof ShadowRoot=="function"&&e instanceof ShadowRoot){Array.from(e.children).forEach(i=>N(i,t));return}let r=!1;if(t(e,()=>r=!0),r)return;let n=e.firstElementChild;for(;n;)N(n,t,!1),n=n.nextElementSibling}function O(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}function lr(){document.body||O("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's `