├── .github
└── FUNDING.yml
├── LICENSE
├── README.md
├── _build
├── README.md
└── merge.bg.v3.bat
└── extension
├── LICENSE
├── README.md
├── _locales
├── en
│ └── messages.json
└── ru
│ └── messages.json
├── env
├── css
│ ├── core.css
│ ├── coreMobile.css
│ ├── dark.css
│ ├── darkRecorderPopup.css
│ ├── recorder.css
│ ├── recorderDownloader.css
│ ├── recorderPopup.css
│ ├── single.css
│ ├── singleMobile.css
│ └── white.css
├── dynamic
│ └── dispetcher.js
├── html
│ ├── additions
│ │ ├── menu-item.html
│ │ ├── page.html
│ │ ├── profile-selector-recorder.html
│ │ └── profile-selector.html
│ ├── bookmarksParser
│ │ └── parser-form.html
│ ├── options.html
│ ├── recorderDownloader.html
│ ├── recorderPopup.html
│ ├── update.html
│ └── update_default.html
├── img
│ ├── arial-yellow.png
│ ├── cup.png
│ ├── heartr.png
│ ├── icon128x128.png
│ ├── icon32x32.png
│ ├── icon44x44.png
│ └── icon50x50.png
└── init
│ ├── background.js
│ ├── commonAbout.js
│ ├── recorderDownloader.js
│ ├── recorderFront.js
│ └── recorderPopup.js
├── lib
├── kellyAdditionsForm.js
├── kellyCAbout.js
├── kellyDispetcher.js
├── kellyDispetcherNetRequest.js
├── kellyFastSave.js
├── kellyFavItems.js
├── kellyGrabber.js
├── kellyLoc.js
├── kellyNradiowaveBg.js
├── kellyOptions.js
├── kellyStorageManager.js
├── kellyThreadWork.js
├── kellyToolbar.js
├── kellyTools.js
├── profiles
│ ├── default.js
│ └── recorder.js
└── recorder
│ ├── filters
│ ├── 9gag.js
│ ├── README.md
│ ├── _validators.js
│ ├── artstation.js
│ ├── bsky.js
│ ├── deviantart.js
│ ├── discord.js
│ ├── ehentai.js
│ ├── flickr.js
│ ├── hfoundry.js
│ ├── instagram.js
│ ├── joyreactor.js
│ ├── kemonoparty.js
│ ├── pikabu.js
│ ├── pixiv.js
│ ├── reddit.js
│ ├── twitter.js
│ ├── vk.js
│ └── yandex.js
│ ├── kellyDPage.js
│ ├── kellyEDRecorder.js
│ ├── kellyLoadDocControll.js
│ └── kellyPageWatchdog.js
├── manifest.v2.all.json
├── manifest.v3.all.json
└── widget
├── kellyImageView.js
├── kellyTileGrid.js
└── kellyTooltip.js
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NC22/KellyC-Image-Downloader/58b8909659277f953f3a560f90286cf7116af2e7/.github/FUNDING.yml
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
KellyC Image Downloader
2 |
3 | Due to low interest in the project, the project has been removed from all extension stores and left for personal use as an open source project. The project remains free and open source, any forks \ modifications are welcome
4 | Из за низкого интереса к проекту, проект убран со всех магазинов расширений и оставлен для личного использования в качестве открытого проекта. Проект остается бесплатным и открытым, любые изменения под себя приветствуются
5 |
6 |
9 |
10 |
11 |
14 | Manual install
15 | How to install manualy from source code or from releases
16 |
17 |
18 | EN | Description
19 | A browser extension for batch downloading artworks and images from sites. It allows you to download all images on the page filtering by size or other settings.
20 | Some of the sites (priority to Pixiv, Pinterest, Twitter, Joyreactor) support extended features for collect "Original" version of images from preview automatically without use filters by size manually.
21 | "Load related document" - feature allows you to download additional images from related documents of preview, if original image is not actually placed on current page. (may be helpful in some cases, check if site is supported)
22 |
23 |
24 |
25 | RU | Описание
26 | Расширение для пакетного скачивания картинок \ творчества с любых сайтов. Поддерживаются фильтры по пропорциям, строке url, загрузка дочерних документов.
27 |
28 | Некоторые сайты поддерживают дополнительный функционал, позволяющий быстро захватить оригиналы изображений без дополнительной фильтрации в ручную.
29 | Функция "Загрузка дочерних документов" используется если на основной странице доступно только изображение с низким разрешением и ссылка ведет на страницу с оригиналом. (функционал поумолчанию может не всегда сработать, см. страницу поддержки сайтов)
30 |
31 |
32 |
33 |
34 | License
35 |
36 | GNU General Public License v3
37 |
38 |
--------------------------------------------------------------------------------
/_build/README.md:
--------------------------------------------------------------------------------
1 | KellyC Image Downloader
2 |
3 | merge.bg.v3.bat is used to merge all js files required for background service worker in to one background.js if you are using manifest v3
4 |
5 | Use manifest.v[2-3].all.json from main extension folder as main manifest.json file, remove optional libs if needed
6 |
7 | Optional libs :
8 | "lib/profiles/joyreactor.js", "lib/profiles/joyreactor.unlock.js", "lib/profiles/topjoyreactor.js", "env/init/joyreactorFront.js", "lib/profiles/joyreactor.unlock.d.js"
--------------------------------------------------------------------------------
/_build/merge.bg.v3.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | pushd "%~1"
3 |
4 | SET background=..\extension\background.js
5 |
6 | break>%background%
7 |
8 | for %%x in (
9 | "%~dp0..\extension\lib\kellyTools.js"
10 | "%~dp0..\extension\lib\kellyDispetcher.js"
11 | "%~dp0..\extension\lib\kellyDispetcherNetRequest.js"
12 | "%~dp0..\extension\lib\profiles\joyreactor.unlock.d.js"
13 | "%~dp0..\extension\lib\recorder\kellyEDRecorder.js"
14 | "%~dp0..\extension\env\init\background.js"
15 | ) do (
16 |
17 | @echo.>> %background%
18 | @echo.>> %background%
19 | copy %background% + "%%~x" %background%
20 | )
21 |
22 |
23 | @echo.>> %background%
24 | @echo.>> %background%
25 | @echo.>> %background%
26 | @echo.>> %background%
27 |
28 | popd
29 | ::pause
--------------------------------------------------------------------------------
/extension/README.md:
--------------------------------------------------------------------------------
1 | KellyC Image Downloader
2 |
3 |
4 | Ready to use extension build for browsers with support manifest v2, v3
--------------------------------------------------------------------------------
/extension/env/css/coreMobile.css:
--------------------------------------------------------------------------------
1 | /* mobile version */
2 |
3 | @media (max-width: 1040px) {
4 |
5 | .__BASECLASS__-mobile .__BASECLASS__-tab {
6 | padding-top : 0;
7 | padding-left : 0;
8 | }
9 |
10 | .__BASECLASS__-mobile .__BASECLASS__-pointer-arrow {
11 | display : none;
12 | }
13 |
14 | .__BASECLASS__-mobile .__BASECLASS__-tooltipster-wrap {
15 | padding: 12px;
16 | }
17 |
18 | .__BASECLASS__-mobile .__BASECLASS__-tab-list, .__BASECLASS__-tab {
19 | padding: 0;
20 | padding-bottom : 0px;
21 | }
22 |
23 | .__BASECLASS__-mobile .__BASECLASS__-tab-list ul li {
24 | width : auto;
25 | border-radius: 0;
26 | line-height: 32px;
27 | height: 32px;
28 | padding : 0 16px;
29 | }
30 |
31 | .__BASECLASS__-mobile .__BASECLASS__-tab-list ul li a {
32 | padding-top: 0;
33 | }
34 |
35 | .__BASECLASS__-mobile .__BASECLASS__-copyright-info {
36 | font-size: 15px;
37 | }
38 |
39 | .__BASECLASS__-mobile .__BASECLASS__-copyright-info a {
40 | font-size: 15px;
41 | }
42 |
43 | .__BASECLASS__-mobile .__BASECLASS__-DBItem-name {
44 | min-width : unset;
45 | }
46 |
47 | .__BASECLASS__-mobile .__BASECLASS__-DBItem-size {
48 | min-width : unset;
49 | }
50 |
51 | .__BASECLASS__-mobile .__BASECLASS__-DBItem a.__BASECLASS__-right {
52 | margin-right : 4px;
53 | }
54 |
55 | .__BASECLASS__-mobile .__BASECLASS__-DBItem.active:after {
56 | display : none;
57 | }
58 |
59 | .__BASECLASS__-mobile .__BASECLASS__-DBItem a, .__BASECLASS__-DBItem span {
60 | margin-right : 8px;
61 | }
62 |
63 | .__BASECLASS__-mobile .__BASECLASS__-ModalBox .__BASECLASS__-ModalBox-content {
64 | min-height : 0px;
65 | }
66 |
67 | .__BASECLASS__-mobile .__BASECLASS__-exporter-buttons a {
68 | margin-right: 16px;
69 | display: block;
70 | }
71 | }
72 |
73 | @media (max-width: 800px) {
74 |
75 | .__BASECLASS__-mobile .__BASECLASS__-copyright-info {
76 | display: block;
77 | font-size: 15px;
78 | /* font-weight: bold; */
79 | float: none;
80 | margin-left: 14px;
81 | margin-bottom: 25px;
82 | margin-top: 0;
83 | }
84 |
85 | .__BASECLASS__-mobile #copyright-name {
86 | font-size: 18px;
87 | }
88 |
89 | .__BASECLASS__-mobile #copyright-software a, #copyright-software {
90 | text-align : left;
91 | }
92 | }
93 |
94 | @media (max-width: 590px) {
95 |
96 | .__BASECLASS__-mobile .__BASECLASS__-tab td {
97 | display: block;
98 | width: 100%!important;
99 | margin: 0;
100 | }
101 |
102 | .__BASECLASS__-mobile .__BASECLASS__-tab-list, .__BASECLASS__-tab {
103 | padding: 0;
104 | padding-bottom : 0;
105 | }
106 |
107 | .__BASECLASS__-mobile .__BASECLASS__-DBItem span {
108 | display : block;
109 | }
110 |
111 | .__BASECLASS__-mobile .__BASECLASS__-DBItem {
112 | height : auto;
113 | }
114 |
115 | .__BASECLASS__-mobile .__BASECLASS__-tab-list ul li {
116 | display: block;
117 | margin-bottom: 4px;
118 | margin-right : 0px;
119 | }
120 |
121 | .__BASECLASS__-mobile .__BASECLASS__-OptionsSave-wrap {
122 | margin-top : 16px;
123 | }
124 |
125 | .__BASECLASS__-mobile .__BASECLASS__-displayed-info {
126 | margin-left: 6px;
127 | padding-left: 4px;
128 | padding-right: 4px;
129 | margin-right: 6px;
130 | margin-top: 18px;
131 | display : block;
132 | }
133 | }
134 |
135 | @media (max-width: 390px) {
136 | .__BASECLASS__-mobile .__BASECLASS__-displayed-info {
137 | display: block;
138 | margin-top: 12px;
139 | margin-right: 6px;
140 | }
141 | }
142 |
143 | .__BASECLASS__-mobile .__BASECLASS__-section-header-inline {
144 | margin-left: 0;
145 | }
146 |
147 | .__BASECLASS__-mobile .__BASECLASS__-ModalBox {
148 | border-radius: 0;
149 | border-radius: 0;
150 | }
151 |
152 | .__BASECLASS__-mobile .__BASECLASS__-sidebar-wrap .__BASECLASS__-ModalBox {
153 | margin-left: 0;
154 | margin-right: 0;
155 | }
156 |
157 | .__BASECLASS__-mobile .kelly-jr-ui-FavItem-grid-first,
158 | .__BASECLASS__-mobile .kelly-jr-ui-FavItem-grid-first .__BASECLASS__-FavItem-download-state-holder {
159 | padding-left: 0;
160 | }
161 |
162 | .__BASECLASS__-mobile .kelly-jr-ui-FavItem-grid-last,
163 | .__BASECLASS__-mobile .kelly-jr-ui-FavItem-grid-last .__BASECLASS__-FavItem-download-state-holder {
164 | padding-right: 0;
165 | }
166 |
167 | .__BASECLASS__-mobile .content {
168 | width : 100%;
169 | }
170 |
171 | .__BASECLASS__-mobile .__BASECLASS__-sidebar-wrap {
172 | padding-bottom: 0;
173 | }
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/extension/env/css/dark.css:
--------------------------------------------------------------------------------
1 | body.__BASECLASS__-dark {
2 | background-color: #222;
3 | color: #cdcdcd;
4 | }
5 |
6 | .__BASECLASS__-dark button {
7 | color: #e5e5e5;
8 | }
9 |
10 | .__BASECLASS__-dark input[type=submit] {
11 | background: #e63d3d;
12 | border: 0px;
13 | padding-left: 30px;
14 | cursor: pointer;
15 | color: #fff;
16 | font-weight: bold;
17 | height: 40px;
18 | padding-right: 30px;
19 | }
20 |
21 | .__BASECLASS__-dark .__BASECLASS__-FavItem-small .__BASECLASS__-preview-wrap {
22 | border: 3px solid rgb(102 102 102);
23 | }
24 |
25 | .__BASECLASS__-dark .__BASECLASS__-FavItem-tmp-bounds .__BASECLASS__-preview-wrap,
26 | .__BASECLASS__-dark .__BASECLASS__-FavItem-tmp-bounds .__BASECLASS__-preview {
27 | background: #2f2f2f;
28 | }
29 |
30 | .__BASECLASS__-dark .__BASECLASS__-displayed-info {
31 | background: #585858;
32 | }
33 |
34 | .__BASECLASS__-dark .__BASECLASS__-tooltipster-container {
35 | background: rgb(53, 53, 53);
36 | color: #fff;
37 | border-radius: 0;
38 | }
39 |
40 | .__BASECLASS__-dark .__BASECLASS__-tooltipster-close {
41 | background: rgb(53, 53, 53);
42 | color: #fff;
43 | border-radius: 0;
44 | }
45 |
46 | .__BASECLASS__-dark .page-content {
47 | padding: 50px;
48 | padding-top: 20px;
49 | padding-bottom: 50px;
50 | }
51 |
52 | .__BASECLASS__-dark #submenu {
53 | background: #2f2f2f;
54 | border-bottom: 1px solid #5a5a5a;
55 | }
56 |
57 | .__BASECLASS__-dark .__BASECLASS__-MainMenuItem.__BASECLASS__-MainMenuItem-fav a,
58 | .__BASECLASS__-dark .__BASECLASS__-MainMenuItem.__BASECLASS__-MainMenuItem-fav.active a {
59 | background : transparent;
60 | }
61 |
62 | .__BASECLASS__-dark .__BASECLASS__-MainMenuItem a {
63 | background: #646464;
64 | font-size: 14px;
65 | font-weight: bold;
66 | color: #fff;
67 | }
68 |
69 | .__BASECLASS__-dark .__BASECLASS__-MainMenuItem-fav.active .__BASECLASS__-icon {
70 | background-color: #ff7878;
71 | }
72 |
73 | .__BASECLASS__-dark .__BASECLASS__-MainMenuItem.active a {
74 | background: #e63d3d;
75 | color : #fff;
76 | }
77 |
78 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a {
79 | color : #000;
80 | }
81 |
82 | .__BASECLASS__-dark a, .__BASECLASS__-dark a:hover {
83 | color: rgb(255, 255, 255, 0.68);
84 | }
85 |
86 | .__BASECLASS__-dark .__BASECLASS__-tab-list ul li:hover {
87 | background : #858585;
88 |
89 | }
90 |
91 | .__BASECLASS__-dark .__BASECLASS__-tab {
92 | line-height : normal;
93 | padding-top: 8px;
94 | padding-left: 2px;
95 | padding-bottom: 0;
96 | }
97 |
98 | .__BASECLASS__-dark .__BASECLASS__-tab-list ul {
99 | padding : 0;
100 | }
101 |
102 | .__BASECLASS__-dark .__BASECLASS__-tab-list ul:after {
103 | content : "";
104 | clear : both;
105 | display: block;
106 | }
107 |
108 | .__BASECLASS__-dark .__BASECLASS__-tab-list ul li {
109 | border-top-left-radius: 0;
110 | border-top-right-radius: 0;
111 | background: #646464;
112 | margin: 0;
113 | width: 25%;
114 | height: 40px;
115 | float: left;
116 | font-weight: bold;
117 | line-height: 40px;
118 | }
119 |
120 | .__BASECLASS__-dark .__BASECLASS__-tab-list ul li a,
121 | .__BASECLASS__-dark .__BASECLASS__-tab-list ul li.active a:hover {
122 | color : #fff;
123 | padding : 0;
124 | }
125 |
126 | .__BASECLASS__-dark .__BASECLASS__-tab-list ul li.active {
127 | background: #e63d3d;
128 | }
129 |
130 | .__BASECLASS__-dark .__BASECLASS__-options-table > tbody > tr > td[colspan="2"] {
131 | width: 100%;
132 | height : 22px;
133 | }
134 |
135 | .__BASECLASS__-dark .__BASECLASS__-options-table > tbody > tr > td[colspan="2"].__BASECLASS__-hidden {
136 | height : 0px;
137 | }
138 |
139 | .__BASECLASS__-dark .__BASECLASS__-options-table > tbody > tr > td {
140 | height : 44px;
141 | }
142 |
143 | /*
144 | .__BASECLASS__-dark .__BASECLASS__-radioselect input[type="radio"] {display : none;}
145 | .__BASECLASS__-dark .__BASECLASS__-radioselect input[type="radio"]:checked+label{ font-weight: bold; }
146 | */
147 |
148 | .__BASECLASS__-dark .__BASECLASS__-DBItem {
149 | background-color: #4e4e4e;
150 | padding: 6px;
151 | }
152 |
153 | .__BASECLASS__-dark .__BASECLASS__-DBItem, .__BASECLASS__-dark .__BASECLASS__-DBItem a {
154 | color: #fff;
155 | border-radius : 0;
156 | }
157 |
158 | .__BASECLASS__-dark .__BASECLASS__-downloader-controll-rangeSwitch.active,
159 | .__BASECLASS__-dark .__BASECLASS__-DBItem.active {
160 | background-color: #797979;
161 | }
162 |
163 | .__BASECLASS__-dark .__BASECLASS__-sidebar-wrap {
164 | width : 280px;
165 | }
166 |
167 | .__BASECLASS__-dark .__BASECLASS__-ModalBox {
168 | border: 0px;
169 | }
170 |
171 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-controll-buttons a {
172 | padding-left: 2px;
173 | padding-right: 2px;
174 | }
175 |
176 | .__BASECLASS__-dark .__BASECLASS__-tab h3 {
177 | font-size : 18px;
178 | }
179 |
180 | .__BASECLASS__-dark ::placeholder,
181 | .__BASECLASS__-dark input[type=text],
182 | .__BASECLASS__-dark select,
183 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-message,
184 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-header,
185 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-content input {
186 | background-color: #8d8d8d!important;
187 | color: #fff!important;
188 | border: 1px solid #9f9f9f;
189 | }
190 |
191 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-header a,
192 | .__BASECLASS__-dark ::placeholder {
193 | border : 0;
194 | color: #fff;
195 | }
196 |
197 | .__BASECLASS__-dark a.__BASECLASS__-FavItem-collection,
198 | .__BASECLASS__-dark a.__BASECLASS__-FavItem-overlay-button,
199 | .__BASECLASS__-dark .__BASECLASS__-preview-text {
200 | background: #5d5d5d;
201 | }
202 |
203 | .__BASECLASS__-dark .__BASECLASS__-extension-additions {
204 | display: inline-block;
205 | vertical-align: middle;
206 | margin-right: 16px;
207 | background: #878787;
208 | border-radius: 6px;
209 | padding: 4px;
210 | }
211 |
212 | .__BASECLASS__-dark .__BASECLASS__-extension-additions .__BASECLASS__-fast-save,
213 | .__BASECLASS__-dark .__BASECLASS__-extension-additions .__BASECLASS__-post-addtofav {
214 | display: inline-block;
215 | float: left;
216 | vertical-align: middle;
217 | font-weight : normal;
218 | padding: 0;
219 | margin: 0;
220 | color: #ffffff;
221 | margin-left: 3px;
222 | margin-right: 3px;
223 | }
224 |
225 | .__BASECLASS__-dark .__BASECLASS__-extension-additions .__BASECLASS__-post-addtofav {
226 | border-bottom: #fff solid 3px;
227 | text-decoration: none;
228 | }
229 |
230 | .__BASECLASS__-dark .__BASECLASS__-extension-additions .kelly-jr-ui-post-addtofav:after {
231 | display : none;
232 | }
233 |
234 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-content {
235 | background: #303030!important;
236 | }
237 |
238 | .__BASECLASS__-dark .__BASECLASS__-ModalBox {
239 | background: transparent!important;
240 | }
241 |
242 | .__BASECLASS__-dark .__BASECLASS__-filters-AdditionButtons a {
243 | background-color : transparent;
244 | }
245 |
246 |
247 | .__BASECLASS__-dark a.__BASECLASS__-pagination-item:hover,
248 | .__BASECLASS__-dark a.__BASECLASS__-pagination-item:focus,
249 | .__BASECLASS__-dark .__BASECLASS__-pagination-item.active {
250 | background: #666666;
251 | color: #fff;
252 | border: 3px solid #8d8d8d;
253 | }
254 |
255 | .__BASECLASS__-dark a.__BASECLASS__-pagination-item {
256 | border: 3px solid #666666;
257 | }
258 |
259 | .__BASECLASS__-dark .__BASECLASS__-FavFilter {
260 | font-size : 12px;
261 | }
262 |
263 | .__BASECLASS__-dark .__BASECLASS__-FavItem-grid-empty,
264 | .__BASECLASS__-dark .__BASECLASS__-FavItem-download-number,
265 | .__BASECLASS__-dark .__BASECLASS__-preview-dimensions,
266 | .__BASECLASS__-dark .__BASECLASS__-message.__BASECLASS__-success,
267 | .__BASECLASS__-dark .__BASECLASS__-OptionsMessage,
268 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons p,
269 | .__BASECLASS__-dark .__BASECLASS__-section-header-inline,
270 | .__BASECLASS__-dark a.__BASECLASS__-pagination-item,
271 | .__BASECLASS__-dark .__BASECLASS__-FavFilter.active,
272 | .__BASECLASS__-dark .__BASECLASS__-FavEditButton.active {
273 | background: #666666;
274 | color: #cdcdcd;
275 | }
276 |
277 | .__BASECLASS__-dark .__BASECLASS__-FavContainer {
278 | background-clip: border-box;
279 | border: 0px solid rgba(0,0,0,.125);
280 | border-radius: 0;
281 | margin: 0px auto;
282 | }
283 |
284 | .__BASECLASS__-dark .__BASECLASS__-FiltersMenu > li > button {
285 | color : #000;
286 | padding-left: 3px;
287 | padding-right: 3px;
288 | }
289 |
290 | .__BASECLASS__-dark .__BASECLASS__-section-header-inline a, .__BASECLASS__-dark .__BASECLASS__-section-header-inline a:hover {
291 |
292 | color : #cdcdcd;
293 | }
294 |
295 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons button.selected,
296 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons button:hover {
297 |
298 | background-color: #a9a9a9;
299 | }
300 |
301 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a.__BASECLASS__-downloader-button-save_as_json,
302 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a.__BASECLASS__-downloader-button-save_as_txt,
303 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a.__BASECLASS__-downloader-button-save_log,
304 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a {
305 | background-color: #919191;
306 | color : #fff;
307 | }
308 |
309 | .__BASECLASS__-dark .__BASECLASS__-Main-download-btn,
310 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a.__BASECLASS__-downloader-button-init {
311 | background-color: #e63d3d;
312 | }
313 |
314 | .__BASECLASS__-dark .__BASECLASS__-Main-download-btn:hover,
315 | .__BASECLASS__-dark .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a:hover {
316 | background-color : #e95757;
317 | }
318 |
319 | .__BASECLASS__-dark .__BASECLASS__-buttons button {
320 | background-color: #919191;
321 | font-weight : bold;
322 | color : #fff;
323 | }
324 |
325 | .__BASECLASS__-dark .__BASECLASS__-buttons button.__BASECLASS__-related-links-options {
326 | background-color: #4e4e4e;
327 | }
328 |
329 | .__BASECLASS__-dark .__BASECLASS__-OptionsMessage,
330 | .__BASECLASS__-dark .__BASECLASS__-message.__BASECLASS__-success,
331 | .__BASECLASS__-dark .__BASECLASS__-message.__BASECLASS__-error {
332 | margin-bottom: 6px;
333 | margin-top : 6px;
334 | padding : 12px;
335 | }
336 |
337 | .__BASECLASS__-dark .__BASECLASS__-message.__BASECLASS__-error {
338 | background: #ff7878;
339 | color : #fff;
340 | }
341 |
342 | .__BASECLASS__-dark button.__BASECLASS__-Main-download-btn {
343 | color : #fff;
344 | }
345 |
346 | .__BASECLASS__-dark .__BASECLASS__-FiltersMenu > li > button,
347 | .__BASECLASS__-dark .__BASECLASS__-downloader-progressbar,
348 | .__BASECLASS__-dark .__BASECLASS__-downloader-progressbar-line:after {
349 |
350 | border-radius : 0;
351 | }
352 |
353 | .__BASECLASS__-dark .profile-selector {
354 | background: #7c7c7c;
355 | }
356 |
357 | .__BASECLASS__-dark .profile-selector-selected {
358 | color: #ffffff;
359 | }
360 |
361 | .__BASECLASS__-dark li.__BASECLASS__-additions-menu-item-li.kelly-jr-ui-additions-active a {
362 | background: #979797;
363 | }
364 |
365 | .__BASECLASS__-dark .__BASECLASS__-active.__BASECLASS__-additions-page-item {
366 | min-height: 250px;
367 | padding: 6px;
368 | background: #5c5c5c;
369 | }
370 |
371 | .__BASECLASS__-dark .__BASECLASS__-active.__BASECLASS__-additions-page-item ul li a {
372 | background: #797979;
373 | padding: 5px;
374 | margin-bottom: 6px;
375 | display: block;
376 | color: rgb(255 255 255);
377 | }
378 |
379 | .__BASECLASS__-dark a.__BASECLASS__-additions-menu-item {
380 | background: #5c5c5c;
381 | }
382 |
383 | .__BASECLASS__-dark .__BASECLASS__-toolbar.__BASECLASS__-toolbar-main.__BASECLASS__-toolbar-tiny,
384 | .__BASECLASS__-dark .__BASECLASS__-toolbar.__BASECLASS__-toolbar-main.__BASECLASS__-toolbar-collapsed,
385 | .__BASECLASS__-dark .__BASECLASS__-toolbar.__BASECLASS__-toolbar-helper-container.__BASECLASS__-toolbar-tiny.__BASECLASS__-toolbar-collapsed {
386 | background: transparent;
387 | }
388 |
389 | .__BASECLASS__-dark .__BASECLASS__-toolbar-collapse {
390 | background: #919191;
391 | }
392 |
393 | .__BASECLASS__-dark .__BASECLASS__-toolbar.__BASECLASS__-toolbar-helper-container.__BASECLASS__-toolbar-tiny,
394 | .__BASECLASS__-dark .__BASECLASS__-toolbar.__BASECLASS__-toolbar-main {
395 | background: rgb(77, 77, 77, 0.84);
396 | color: #cdcdcd;
397 | }
398 |
399 | .__BASECLASS__-dark .__BASECLASS__-toolbar a {
400 | color: #ddd;
401 | }
402 |
403 | .__BASECLASS__-dark .__BASECLASS__-toolbar svg {
404 | color: #000;
405 | }
406 |
407 | .__BASECLASS__-dark .__BASECLASS__-toolbar svg path {
408 |
409 | background: #fff;
410 | stroke: #dddddd;
411 | fill: #dddddd;
412 | }
413 |
414 | .__BASECLASS__-dark .__BASECLASS__-toolbar-theme:before {
415 | display : none;
416 | }
417 |
418 | .__BASECLASS__-dark .__BASECLASS__-toolbar-theme {
419 | border: 4px solid #919191;
420 | background : #fff;
421 | }
422 |
423 | .__BASECLASS__-dark .__BASECLASS__-FavItem-download-enabled:checked+label:before {
424 |
425 | background-color: #8b8b8b;
426 | }
427 |
428 | .__BASECLASS__-pointer-up {
429 | border-bottom: 2em solid #d4d4d4;
430 | }
431 |
432 | @media (max-width: 1040px) {
433 | .__BASECLASS__-mobile .page-content {
434 | padding: 4px;
435 | }
436 | }
437 |
438 | @media (max-width: 590px) {
439 |
440 | .__BASECLASS__-mobile.__BASECLASS__-dark .page-content {
441 | padding : 0 6px;
442 | }
443 |
444 | .__BASECLASS__-mobile.__BASECLASS__-dark .__BASECLASS__-tab-list ul li {
445 | margin-top : 2px;
446 | margin-bottom : 2px;
447 | width: auto;
448 | float: unset;
449 | }
450 |
451 | .__BASECLASS__-mobile.__BASECLASS__-dark .__BASECLASS__-options-table > tbody > tr > td[colspan="2"],
452 | .__BASECLASS__-mobile.__BASECLASS__-dark .__BASECLASS__-options-table > tbody > tr > td {
453 | height : auto;
454 | }
455 |
456 | .__BASECLASS__-mobile.__BASECLASS__-dark .__BASECLASS__-options-table > tbody > tr > td br {
457 | display : inline-block;
458 | margin-left : 4px;
459 | }
460 |
461 | .__BASECLASS__-mobile.__BASECLASS__-dark input[type=submit] {
462 | width: 100%;
463 | margin-top: 12px;
464 | }
465 |
466 | /*.__BASECLASS__-mobile.__BASECLASS__-dark .__BASECLASS__-sidebar-wrap .__BASECLASS__-ModalBox.__BASECLASS__-Main-download-btn-ModalBox {
467 | display : none;
468 | }*/
469 | }
470 |
--------------------------------------------------------------------------------
/extension/env/css/darkRecorderPopup.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: #363838;
3 | border: 6px solid #fff;
4 | }
5 |
6 | button {
7 | background: #444646;
8 | color: #fff;
9 | border: 0;
10 | border-radius : 0;
11 | }
12 |
13 | button:hover {
14 | background-color: #5d5d5d;
15 | }
16 |
17 | .popup-page-button-support_project {
18 | background-color: #56afdf;
19 | }
20 |
21 | .popup-page-button-support_project:hover {
22 | background-color: #79c2ea;
23 | }
24 |
25 | .popup-page-recorded-block {
26 | color: #bfbfbf;
27 | background: #4b4b4b;
28 | }
29 |
30 | .__BASECLASS__-recorded-block a {
31 | float : right;
32 | color: #bfbfbf;
33 | }
34 |
35 | .__BASECLASS__-dark.__BASECLASS__-with-extra .__BASECLASS__-button-download_tab_extra {
36 | border-right: 2px solid;
37 | }
38 |
39 | .__BASECLASS__-dark .__BASECLASS__-button-download_right {
40 | border-left: 2px solid;
41 | }
42 |
43 | .__BASECLASS__-dark.__BASECLASS__-with-extra .__BASECLASS__-button-download_tab_extra,
44 | .__BASECLASS__-dark .__BASECLASS__-button-download_right {
45 | border-color : #363838;
46 | }
47 |
48 | .popup-page-button-download_recorded {
49 | background: #e63d3d;
50 | }
51 |
52 | .popup-page-button-download_recorded:hover {
53 | background: #ff7878;
54 | }
55 |
56 | .popup-page-button-download_record span:before {
57 | background: #e63d3d;
58 | }
59 |
60 | #copyright-software {
61 | color: #bfbfbf;
62 | background: #4b4b4b;
63 | padding: 11px 12px;
64 | }
65 |
66 | #copyright-software a {
67 | color: #bfbfbf;
68 | }
--------------------------------------------------------------------------------
/extension/env/css/recorder.css:
--------------------------------------------------------------------------------
1 | #__UNIQID__:after {
2 | content: " ";
3 | width: 24px;
4 | height: 24px;
5 | position: absolute;
6 | left: 4px;
7 | background: #ff0b0b;
8 | overflow: hidden;
9 | border-radius: 16px;
10 | /* bottom: 4px; */
11 | animation: __UNIQID__blink 0.8s cubic-bezier(.5, 0, 1, 1) infinite alternate;
12 | box-shadow: 0px 0px 17px 0px rgb(217 59 59 / 75%);
13 | }
14 |
15 | #__UNIQID__ {
16 | position: fixed;
17 | right: 12px;
18 | z-index: 1000011;
19 | bottom: 12px;
20 | color: #ff0b0b;
21 | font-weight: bold;
22 | line-height: 24px;
23 | background: rgb(255, 255, 255, 0.85);
24 | padding-left: 34px;
25 | padding-top: 5px;
26 | padding-bottom: 36px;
27 | padding-right: 6px;
28 | border-radius: 4px;
29 | border: 1px solid rgb(0, 0, 0, 0.44);
30 |
31 | font-family: 'Open Sans',Sans-serif;
32 | font-size: 15px;
33 |
34 | cursor : pointer;
35 | }
36 |
37 | #__UNIQID__-num {
38 | position: absolute;
39 | bottom: 0;
40 | border-radius: 3px;
41 | padding: 6px;
42 | min-width: 44px;
43 | right: 0;
44 | text-align: center;
45 | padding: 0;
46 | width: 100%;
47 | }
48 |
49 | #__UNIQID__-notice {
50 | position: absolute;
51 | display: none;
52 | right: 0;
53 | background: rgba(0,0,0,0.29);
54 | color: #fff;
55 | padding: 6px;
56 | min-width: 255px;
57 | text-align: left;
58 | bottom: 88px;
59 | }
60 |
61 | @keyframes __UNIQID__blink {
62 | from { opacity: 1; }
63 | to { opacity: 0; }
64 | }
--------------------------------------------------------------------------------
/extension/env/css/recorderDownloader.css:
--------------------------------------------------------------------------------
1 | .__BASECLASS__-TypeFiltersContainer {
2 | display : none;
3 | }
4 |
5 | .__BASECLASS__-td-opt-1 {
6 | display : none;
7 | }
8 |
9 | .__BASECLASS__-ModalBox {
10 | min-height : 0;
11 | }
12 |
13 | .__BASECLASS__-FavItem {
14 | cursor : pointer;
15 | }
16 |
17 | .__BASECLASS__-preview {
18 | border-radius : 0;
19 | }
20 |
21 | .__BASECLASS__-FavItem-download-number {
22 | border-radius : 0;
23 | }
24 |
25 | .__BASECLASS__-section-header-inline.__BASECLASS__-section-sidebar_section_extra_progress {
26 | display : none;
27 | }
28 |
29 | .__BASECLASS__-preview-dimensions {
30 | position: absolute;
31 | bottom: 6px;
32 | display: block;
33 | background: #ffa73acc;
34 | line-height: 20px;
35 | text-decoration : none;
36 | height: 22px;
37 | padding: 0px 4px;
38 | }
39 |
40 | .__BASECLASS__-FavItem-small .__BASECLASS__-preview-wrap {
41 | border: 3px solid rgba(255, 121, 26, 0.45);
42 | }
43 |
44 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons p {
45 | background: #ffc78e;
46 | color : #000;
47 | padding: 6px;
48 | margin: 0;
49 | margin-bottom: 6px;
50 | }
51 |
52 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons button.selected,
53 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons button:hover {
54 | background-color: #ffc78e;
55 | }
56 |
57 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons button {
58 | border: 0;
59 | height: 32px;
60 | display: inline-block;
61 | margin-right: 2%;
62 | background-color: #ff8509;
63 | width: 49%;
64 | float: left;
65 | cursor : pointer;
66 | }
67 |
68 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons.__BASECLASS__-buttons-single button {
69 | width : 100%;
70 | }
71 |
72 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons button:last-child {
73 | margin-right : 0;
74 | }
75 |
76 | .__BASECLASS__-ModalBox-addition input[type=text], .__BASECLASS__-ModalBox-addition select {
77 | width: 100%;
78 | height: 32px;
79 | margin-bottom: 6px;
80 | }
81 |
82 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-downloader-progressbar {
83 | width: 100%;
84 | }
85 |
86 | .__BASECLASS__-ModalBox-addition, .__BASECLASS__-ModalBox-addition .__BASECLASS__-ModalBox-content {
87 | min-height: unset;
88 | }
89 |
90 | .__BASECLASS__-related-links-options {
91 | padding-top : 12px;
92 | }
93 |
94 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-downloader-statistic.hidden,
95 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-downloader-errors.hidden,
96 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-downloader-progressbar.hidden {
97 | display : none;
98 | }
99 |
100 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-url-exclude label,
101 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-url label {
102 | display: block;
103 | }
104 |
105 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-downloader-statistic,
106 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-downloader-progressbar,
107 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons,
108 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-url-exclude label,
109 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-url label {
110 | margin-bottom: 6px;
111 | }
112 |
113 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons-last {
114 | margin-bottom : 0;
115 | }
116 |
117 | .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll tr.__BASECLASS__-downloader-quality-tr,
118 | .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll tr.__BASECLASS__-downloader-controll-extended-grabber_anim_format {
119 | display : none;
120 | }
121 |
122 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-bounds input {
123 | width: 59px;
124 | height: 32px;
125 | }
126 |
127 | .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons:after {
128 | content: ' ';
129 | clear: both;
130 | display: block;
131 | }
132 |
133 | .__BASECLASS__-process-docLoader-work .__BASECLASS__-buttons-filter,
134 | .__BASECLASS__-process-docLoader-work .__BASECLASS__-extra-sort,
135 | .__BASECLASS__-process-docLoader-work .__BASECLASS__-section-sidebar_section_extra_sort,
136 | .__BASECLASS__-process-docLoader-work .__BASECLASS__-bounds,
137 | .__BASECLASS__-process-docLoader-work .__BASECLASS__-url-exclude,
138 | .__BASECLASS__-process-docLoader-work .__BASECLASS__-related-links-options-wrap,
139 | .__BASECLASS__-process-docLoader-work .__BASECLASS__-url {
140 |
141 | display : none;
142 | }
143 |
144 | .__BASECLASS__-displayed-info {
145 |
146 | font-size: 12px;
147 |
148 | background: #ffefc985;
149 | display: inline-block;
150 | height: 30px;
151 | vertical-align: middle;
152 | line-height: 30px;
153 | padding-left: 12px;
154 | padding-right: 12px;
155 | }
156 |
157 | .__BASECLASS__-buttons button.__BASECLASS__-proportions,
158 | .__BASECLASS__-buttons button.__BASECLASS__-related-links-options,
159 | .__BASECLASS__-buttons button.__BASECLASS__-related-links {
160 | background-color: #ffd6a4;
161 | }
162 |
163 | .__BASECLASS__-buttons button.__BASECLASS__-related-links-options {
164 | float: right;
165 | height: 32px;
166 | width: 18%;
167 | display: block;
168 | background-position: center;
169 | }
170 |
171 | .__BASECLASS__-buttons button.__BASECLASS__-related-links {
172 | width : 80%;
173 | }
174 |
175 | .__BASECLASS__-checkmark {
176 | display:inline-block;
177 | width: 22px;
178 | height:22px;
179 | transform: rotate(45deg);
180 | vertical-align: middle;
181 | }
182 |
183 | .__BASECLASS__-checkmark:before {
184 | position: absolute;
185 | width:3px;
186 | height:9px;
187 | content:"";
188 | background-color:#5fff0d;
189 | left:11px;
190 | top:6px;
191 | }
192 |
193 | .__BASECLASS__-checkmark:after {
194 | position: absolute;
195 | content:"";
196 | width:3px;
197 | height:3px;
198 | background-color:#5fff0d;
199 | left:8px;
200 | top:12px;
201 | }
202 |
203 | .__BASECLASS__-Main-download-btn {
204 | display: block;
205 | text-align: center;
206 | width: 100%;
207 | height: 100%;
208 | padding: 7px;
209 | font-size: 16px;
210 | text-decoration: none;
211 | background: #ff6900;
212 | }
213 |
214 | .__BASECLASS__-Main-download-btn-ModalBox.__BASECLASS__-hidden {
215 | margin-bottom : 0;
216 | margin-top : 0;
217 | }
218 |
219 | .__BASECLASS__-Main-download-btn-ModalBox {
220 | border : 0;
221 | }
--------------------------------------------------------------------------------
/extension/env/css/recorderPopup.css:
--------------------------------------------------------------------------------
1 | body {
2 | box-sizing: border-box;
3 | margin: 0;
4 | padding: 0;
5 | width: 248px;
6 | font-size: 12px;
7 | font-family: 'Open Sans',Sans-serif;
8 | background: #ffffff;
9 | border: 6px solid #fff;
10 | }
11 |
12 | * {
13 | box-sizing: border-box;
14 | }
15 |
16 | button {
17 | background: #f4f4f4;
18 | color: #000;
19 | border: 1px solid #9f9f9f;
20 | border-radius: 2px;
21 | width: 100%;
22 | margin-bottom: 2px;
23 | padding: 10px 16px;
24 | font-weight: bold;
25 | cursor: pointer;
26 | position: relative;
27 | font-size: 14px;
28 | font-family: 'Open Sans',Sans-serif;
29 | /* border-bottom: 1px solid #000; */
30 | }
31 |
32 | button:hover {
33 | background-color: #b7b7b7;
34 | }
35 |
36 | .__BASECLASS__-button-support_project:hover {
37 | background-color : #56afdf;
38 | }
39 |
40 | .__BASECLASS__-button-support_project {
41 | background-color: #3cc0ff;
42 | color: #fff;
43 | border-color: #717171;
44 | }
45 |
46 | button span.__BASECLASS__-icon {
47 | display: inline-block;
48 | vertical-align: middle;
49 | margin : 0;
50 | }
51 |
52 | button span.__BASECLASS__-icon-cup {
53 | background-image: url(../../env/img/cup.png);
54 | background-size: 28px;
55 | width: 28px;
56 | height: 20px;
57 | background-repeat: no-repeat;
58 | background-position: center;
59 | }
60 |
61 | button span.__BASECLASS__-text {
62 | vertical-align: middle;
63 | margin-left: 4px;
64 | }
65 |
66 | .__BASECLASS__-recorded-block {
67 | width: 100%;
68 | padding: 6px;
69 | color: #000000;
70 | margin-bottom: 2px;
71 | padding: 12px 7px;
72 | }
73 |
74 | .__BASECLASS__-recorded-block a {
75 | float : right;
76 | color: #ff1515;
77 | }
78 |
79 | .__BASECLASS__-with-extra .__BASECLASS__-button-download_current_tab {
80 | width : 80%;
81 | border-bottom-left-radius: 0;
82 | border-top-left-radius: 0;
83 | }
84 |
85 | .__BASECLASS__-with-extra .__BASECLASS__-button-download_tab_extra {
86 | width : 20%;
87 | float : left;
88 | border-right: 0px;
89 | border-bottom-right-radius: 0;
90 | border-top-right-radius: 0;
91 | }
92 |
93 | .__BASECLASS__-button-download_right {
94 | border-bottom-left-radius: 0;
95 | border-top-left-radius: 0;
96 | border-left: 0px;
97 | }
98 |
99 | .__BASECLASS__-button-download_left {
100 | border-bottom-right-radius: 0;
101 | border-top-right-radius: 0;
102 | }
103 |
104 | .__BASECLASS__-button-download_right, .__BASECLASS__-button-download_left {
105 | width: 50%;
106 | }
107 |
108 | .__BASECLASS__-recording button {
109 | opacity : 0.1;
110 | pointer-events: none;
111 | }
112 |
113 | .__BASECLASS__-recording button.__BASECLASS__-button-download_record {
114 | opacity : 1;
115 | pointer-events: unset;
116 | }
117 |
118 | .__BASECLASS__-button-download_recorded {
119 | background: #4bb9ff;
120 | border-color: #4b8db7;
121 | color: #fff;
122 | margin-bottom: 3px;
123 | }
124 |
125 | .__BASECLASS__-button-download_recorded:hover {
126 | background: #70bff2;
127 | }
128 |
129 | .__BASECLASS__-button-download_record span:before {
130 | display: inline-block;
131 | content: " ";
132 | width: 12px;
133 | height: 12px;
134 | background: #e63d3d;
135 | border-radius: 6px;
136 | margin-right: 6px;
137 | overflow: hidden;
138 | vertical-align: middle;
139 | }
140 |
141 | #copyright-software {
142 | text-align: right;
143 | color: #242424;
144 | background: #ffffff;
145 | padding: 4px 3px;
146 | }
147 |
148 | #copyright-software a:first-child {
149 | float: left;
150 | }
151 |
152 | #copyright-software a {
153 | color: #242424;
154 | }
--------------------------------------------------------------------------------
/extension/env/css/single.css:
--------------------------------------------------------------------------------
1 | /* css for display extension as separate page */
2 |
3 | html {
4 | overflow-y : scroll;
5 | }
6 |
7 | body, html {
8 | margin: 0px;
9 | padding: 0px;
10 | }
11 |
12 | body {
13 | background-color : #fff;
14 | min-width : 320px;
15 |
16 | font-family: "Open Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
17 | font-weight: 400;
18 | line-height: 1.5;
19 | font-size : 14px;
20 | text-align: left;
21 | }
22 |
23 | a {
24 | color: #212121;
25 | font-size: 14px;
26 | }
27 |
28 | ul {
29 | margin: 0px;
30 | padding: 0px;
31 | }
32 |
33 | *, *:before, *:after {
34 | -webkit-box-sizing: border-box;
35 | -moz-box-sizing: border-box;
36 | box-sizing: border-box;
37 | }
38 |
39 | *,:after,:before {
40 | box-sizing: border-box;
41 | }
42 |
43 | input[type=submit] {
44 | background: #fb0;
45 | border: 0px;
46 | padding: 6px;
47 | cursor: pointer;
48 | }
49 |
50 | .page-content {
51 | padding : 50px;
52 | padding-top : 20px;
53 | }
54 |
55 | .page-content > div {
56 | float : left;
57 | }
58 |
59 | .content {
60 | width : 75%;
61 | min-height : 100px;
62 | }
63 |
64 | .page-content > div.clear {
65 | clear : both;
66 | float: none;
67 | }
68 |
69 | #sidebar {
70 | width : 25%;
71 | min-height : 100px;
72 | }
73 |
74 | #submenu {
75 | padding: 50px;
76 | padding-bottom: 20px;
77 | padding-top: 20px;
78 | background-color: #ffd6a4;
79 | min-height : 72px;
80 | border-bottom: 1px solid #ffa429;
81 | }
82 |
83 | .__BASECLASS__-imagesBlock-container {
84 | width : 100%;
85 | overflow : hidden;
86 | margin-bottom : 16px;
87 | }
88 |
89 | .__BASECLASS__-MainMenuItem {
90 | display : inline-block;
91 | }
92 |
93 | .__BASECLASS__-MainMenuItem a {
94 | background: #ffefc9;
95 | height: 30px;
96 | display: inline-block;
97 | vertical-align: middle;
98 | padding-left: 12px;
99 | padding-right: 12px;
100 | line-height: 28px;
101 | text-decoration: none;
102 | font-size: 14px;
103 | }
104 |
105 | .__BASECLASS__-FavFilter.active {
106 | padding : 6px;
107 | }
108 |
109 | .__BASECLASS__-FavItemsCount.__BASECLASS__-FavItemsCount-1 {
110 | border-radius : 6px;
111 | }
112 |
113 | .__BASECLASS__-FavItem-tmp-bounds .__BASECLASS__-preview-wrap,
114 | .__BASECLASS__-FavItem-tmp-bounds .__BASECLASS__-preview {
115 | background: #efefef;
116 | }
117 |
118 | .__BASECLASS__-copyright-info a {
119 | font-size : 18px;
120 | }
121 |
122 | .options_page .__BASECLASS__-ModalBox {
123 | margin-top: 6px;
124 | margin-left: 16px;
125 | margin-bottom : 6px;
126 | }
127 |
128 | .__BASECLASS__-copyright-info {
129 | font-size: 18px;
130 | float: right;
131 | line-height: normal;
132 | margin-top: -4px;
133 | }
134 |
135 | #copyright-software a, #copyright-software {
136 | font-size : 12px;
137 | text-align: right;
138 | }
139 |
140 | /* additions section */
141 |
142 | a.__BASECLASS__-additions-menu-item {
143 | display: block;
144 | /* height: 20px; */
145 | width: 100%;
146 | padding: 6px;
147 | margin-bottom: 4px;
148 | text-decoration : none;
149 | }
150 |
151 | li.__BASECLASS__-additions-menu-item-li {
152 | /* display: inline-block; */
153 | margin-right: 6px;
154 | list-style: none;
155 | }
156 |
157 | .__BASECLASS__-active.__BASECLASS__-additions-page-item {
158 | min-height: 250px;
159 | padding: 6px;
160 | }
161 |
162 | .__BASECLASS__-active.__BASECLASS__-additions-page-item ul {
163 | margin: 0px;
164 | padding: 0px;
165 | margin-left: 6px;
166 | }
167 |
168 | .__BASECLASS__-active.__BASECLASS__-additions-page-item ul li {
169 | display : block;
170 | list-style : none;
171 | }
172 |
173 | .__BASECLASS__-active.__BASECLASS__-additions-page-item ul li a {
174 | padding: 3px;
175 | margin-bottom: 6px;
176 | display: block;
177 | color: #000;
178 | text-decoration: underline;
179 | }
180 |
181 | .__BASECLASS__-additions-additions_menu {
182 | float: left;
183 | width: 20%;
184 | }
185 |
186 | .__BASECLASS__-additions-pages {
187 | float: right;
188 | width: 80%;
189 | min-height: 250px;
190 | }
191 |
192 | .__BASECLASS__-active.__BASECLASS__-additions-page-item h2 {
193 | margin: 0;
194 | margin-bottom: 34px;
195 | padding: 0 12px;
196 | font-weight: normal;
197 | }
198 |
199 | .__BASECLASS__-active.__BASECLASS__-additions-page-item p {
200 | margin: 0;
201 | margin-bottom: 6px;
202 | font-size: 16px;
203 | padding : 0 12px;
204 | }
205 |
206 | .__BASECLASS__-active.__BASECLASS__-additions-page-item li a {
207 | text-decoration : none;
208 | }
209 |
210 | .__BASECLASS__-active.__BASECLASS__-additions-page-item a {
211 | font-size: 16px;
212 | }
213 |
214 | .__BASECLASS__-additions-page:after {
215 | content: "";
216 | clear: both;
217 | display: block;
218 | }
219 |
220 | .profile-selector {
221 | padding: 6px;
222 | margin-bottom: 6px;
223 | }
224 |
225 | .profile-selector-hostlist {
226 | font-size: 12px;
227 | margin-top: 14px;
228 | }
229 |
230 | .profile-selector-selected {
231 | display : none;
232 | }
233 |
234 | .profile-selector-selected.active {
235 | display : inline-block;
236 | }
237 |
238 | .profile-selector {
239 | background: #ffefc9;
240 | }
241 |
242 | li.__BASECLASS__-additions-menu-item-li.__BASECLASS__-additions-active a {
243 | background: #fdb201;
244 | }
245 |
246 | a.__BASECLASS__-additions-menu-item {
247 | background: #ffefc9;
248 | }
249 |
250 | .__BASECLASS__-active.__BASECLASS__-additions-page-item {
251 | min-height: 250px;
252 | padding: 0;
253 | background: transparent;
254 | }
255 |
256 | .profile-selector-selected {
257 | display: none;
258 | color: #ff5600;
259 | font-weight: bold;
260 | font-size: 14px;
261 | }
262 |
263 | @media (max-width: 1240px) {
264 |
265 | .content {
266 | width: 65%;
267 | min-height: 100px;
268 | }
269 |
270 | #sidebar {
271 | width: 35%;
272 | min-height: 100px;
273 | }
274 | }
--------------------------------------------------------------------------------
/extension/env/css/singleMobile.css:
--------------------------------------------------------------------------------
1 | /* css for display extension as separate page */
2 | /* mobile version */
3 |
4 |
5 | .__BASECLASS__-mobile #sidebar {
6 | display : none;
7 | }
8 |
9 |
10 | @media (max-width: 1040px) {
11 | .__BASECLASS__-mobile .page-content {
12 | padding: 4px;
13 | }
14 |
15 | .__BASECLASS__-mobile #submenu {
16 | padding: 30px;
17 | padding-bottom: 20px;
18 | padding-top: 20px;
19 | }
20 | }
21 |
22 | @media (max-width: 1000px) {
23 |
24 | .__BASECLASS__-mobile .__BASECLASS__-additions-additions_menu {
25 | float : none;
26 | width : 100%;
27 | padding-top: 6px;
28 | }
29 |
30 | .__BASECLASS__-mobile .__BASECLASS__-additions-pages{
31 | float : none;
32 | width : 100%;
33 | }
34 |
35 | .__BASECLASS__-mobile .__BASECLASS__-active.__BASECLASS__-additions-page-item ul {
36 | margin: 0px;
37 | padding: 0px;
38 | margin-left: 0;
39 | margin-top : 12px;
40 | }
41 |
42 | .__BASECLASS__-mobile .__BASECLASS__-additions-additions_menu ul li.__BASECLASS__-additions-menu-item-li {
43 | margin-right: 0;
44 | }
45 | }
46 |
47 | @media (max-width: 590px) {
48 |
49 | .__BASECLASS__-mobile #submenu {
50 | padding-left: 0;
51 | padding-right: 0;
52 | }
53 | }
--------------------------------------------------------------------------------
/extension/env/css/white.css:
--------------------------------------------------------------------------------
1 | .__BASECLASS__-white button {
2 | color: #262626;
3 | }
4 |
5 | .__BASECLASS__-white .__BASECLASS__-FavItem-small .__BASECLASS__-preview-wrap {
6 | border: 3px solid rgb(102 102 102);
7 | }
8 |
9 | .__BASECLASS__-white .__BASECLASS__-FavItem-tmp-bounds .__BASECLASS__-preview-wrap,
10 | .__BASECLASS__-white .__BASECLASS__-FavItem-tmp-bounds .__BASECLASS__-preview {
11 | background: #2f2f2f;
12 | }
13 |
14 | .__BASECLASS__-white .__BASECLASS__-displayed-info {
15 | background: #c2c2c2ab;
16 | color: #575757;
17 | font-weight: bold;
18 | }
19 |
20 | .__BASECLASS__-white #submenu {
21 | color: #2c1e52;
22 | background-color: #dedede;
23 | border-color: #9f9f9f;
24 | }
25 |
26 | .__BASECLASS__-white .__BASECLASS__-MainMenuItem.__BASECLASS__-MainMenuItem-fav a,
27 | .__BASECLASS__-white .__BASECLASS__-MainMenuItem.__BASECLASS__-MainMenuItem-fav.active a {
28 | background : transparent;
29 | }
30 |
31 | .__BASECLASS__-white input[type=submit],
32 | .__BASECLASS__-white .__BASECLASS__-MainMenuItem a {
33 | background: #80838d;
34 | font-size: 16px;
35 | color: #fff;
36 | }
37 |
38 | .__BASECLASS__-white .__BASECLASS__-MainMenuItem-fav.active .__BASECLASS__-icon {
39 | background-color: #80838d;
40 | }
41 |
42 | .__BASECLASS__-white .__BASECLASS__-MainMenuItem.active a {
43 | background: #b4b7c2;
44 | color : #fff;
45 | }
46 |
47 | .__BASECLASS__-white .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a {
48 | color : #000;
49 | }
50 |
51 | .__BASECLASS__-white #submenu a,
52 | .__BASECLASS__-white a.__BASECLASS__-help {
53 | color: #ffffff;
54 | }
55 |
56 | .__BASECLASS__-white a, .__BASECLASS__-white a:hover {
57 | color: #fff;
58 | }
59 |
60 | .__BASECLASS__-white .__BASECLASS__-tab-list ul li:hover {
61 | background : #c0c4d1;
62 |
63 | }
64 |
65 | .__BASECLASS__-white .__BASECLASS__-tab-list ul li {
66 | background: #b4b7c2;
67 | }
68 |
69 | .__BASECLASS__-white .__BASECLASS__-tab-list ul li.active {
70 | background: #80838d;
71 | }
72 |
73 | .__BASECLASS__-white .__BASECLASS__-DBItem {
74 | background-color: #4e4e4e;
75 | }
76 |
77 | .__BASECLASS__-white .__BASECLASS__-DBItem, .__BASECLASS__-white .__BASECLASS__-DBItem a {
78 | color: #fff;
79 | }
80 |
81 | .__BASECLASS__-white .__BASECLASS__-downloader-controll-rangeSwitch.active,
82 | .__BASECLASS__-white .__BASECLASS__-DBItem.active {
83 | background-color: #979aa7;
84 | color: #fff;
85 | }
86 |
87 | .__BASECLASS__-white .__BASECLASS__-ModalBox-controll-buttons a {
88 | padding-left: 2px;
89 | padding-right: 2px;
90 | }
91 |
92 | .__BASECLASS__-white a.__BASECLASS__-FavItem-collection,
93 | .__BASECLASS__-white a.__BASECLASS__-FavItem-overlay-button,
94 | .__BASECLASS__-white .__BASECLASS__-preview-text {
95 | background: #5d5d5d;
96 | }
97 |
98 | .__BASECLASS__-white .__BASECLASS__-FavItem-grid-empty,
99 | .__BASECLASS__-white .__BASECLASS__-FavItem-download-number,
100 | .__BASECLASS__-white .__BASECLASS__-preview-dimensions,
101 | .__BASECLASS__-white .__BASECLASS__-message.__BASECLASS__-success,
102 | .__BASECLASS__-white .__BASECLASS__-OptionsMessage,
103 | .__BASECLASS__-white .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons p,
104 | .__BASECLASS__-white .__BASECLASS__-section-header-inline,
105 | .__BASECLASS__-white a.__BASECLASS__-pagination-item,
106 | .__BASECLASS__-white .__BASECLASS__-FavFilter.active,
107 | .__BASECLASS__-white .__BASECLASS__-FavEditButton.active {
108 | background: #80838d;
109 | color: #fffbfb;
110 | }
111 |
112 | .__BASECLASS__-white .__BASECLASS__-section-header-inline a, .__BASECLASS__-white .__BASECLASS__-section-header-inline a:hover {
113 |
114 | color : #cdcdcd;
115 | }
116 |
117 | .__BASECLASS__-white .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons button.selected,
118 | .__BASECLASS__-white .__BASECLASS__-ModalBox-addition .__BASECLASS__-buttons button:hover {
119 |
120 | background-color: #989ca9;
121 | }
122 |
123 | .__BASECLASS__-white #submenu .__BASECLASS__-copyright-info a {
124 | color: #121212;
125 | }
126 |
127 | .__BASECLASS__-white .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a.__BASECLASS__-downloader-button-save_as_json,
128 | .__BASECLASS__-white .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a.__BASECLASS__-downloader-button-save_as_txt,
129 | .__BASECLASS__-white .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a.__BASECLASS__-downloader-button-save_log,
130 | .__BASECLASS__-white .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a {
131 | background: rgb(183 185 192);
132 | color : #fff;
133 | }
134 |
135 | .__BASECLASS__-white .__BASECLASS__-Main-download-btn,
136 | .__BASECLASS__-white .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a.__BASECLASS__-downloader-button-init {
137 | background-color: #80838d;
138 | }
139 |
140 | .__BASECLASS__-white .__BASECLASS__-Main-download-btn:hover,
141 | .__BASECLASS__-white .__BASECLASS__-ModalBox-downloader .__BASECLASS__-downloader-controll-buttons a:hover {
142 | background-color : #989ca9;
143 | }
144 |
145 | .__BASECLASS__-white .__BASECLASS__-buttons button {
146 | background-color: #80838d;
147 | color : #fff;
148 | }
149 |
150 | .__BASECLASS__-white .__BASECLASS__-buttons button.__BASECLASS__-related-links-options {
151 | background-color: #6a6a6a;
152 | }
153 |
154 | .__BASECLASS__-white .__BASECLASS__-message.__BASECLASS__-error {
155 | background: #ff7878;
156 | color : #fff;
157 | }
158 |
159 | .__BASECLASS__-white button.__BASECLASS__-Main-download-btn {
160 | color : #fff;
161 | }
162 |
163 | .__BASECLASS__-white .profile-selector {
164 | background: #b4b7c2;
165 | }
166 |
167 | .__BASECLASS__-white .profile-selector-selected {
168 | color: #ffffff;
169 | }
170 |
171 | .__BASECLASS__-white li.__BASECLASS__-additions-menu-item-li.kelly-jr-ui-additions-active a {
172 | background: #b4b7c2;
173 | }
174 |
175 | .__BASECLASS__-white .__BASECLASS__-active.__BASECLASS__-additions-page-item ul li a {
176 |
177 | }
178 |
179 | .__BASECLASS__-white .__BASECLASS__-additions-page-item a {
180 | color: #000;
181 | }
182 |
183 | .__BASECLASS__-white a.__BASECLASS__-additions-menu-item {
184 | background: #80838d;
185 | }
186 |
--------------------------------------------------------------------------------
/extension/env/dynamic/dispetcher.js:
--------------------------------------------------------------------------------
1 | // part of KellyFavItems extension
2 | // требуется для обработки событий в "небезопасном" окне вне расширения.
3 | // используемые функции
4 | // - активирует подтверждение на закрытие окна если выполняется процесс загрузки профилей \ тегов или скачивание картинок
5 |
6 | (function() {
7 |
8 | var KellyDynamicDispetcher = new Object;
9 | KellyDynamicDispetcher.enabledEvents = {};
10 | KellyDynamicDispetcher.messageNameBase = 'kelly_dynaminc';
11 | KellyDynamicDispetcher.getMessage = function(e) {
12 |
13 | var handler = KellyDynamicDispetcher;
14 |
15 | if (!e.data || !e.data.method || !e.data[handler.messageNameBase]) return false;
16 |
17 | var response = {
18 |
19 | senderId : 'dynamic_dispetcher',
20 | error : '',
21 | method : e.data.method,
22 | location : window.location.href,
23 | };
24 |
25 |
26 | if (e.data.method == handler.messageNameBase + '.unbind.beforeunload') {
27 |
28 | handler.removeBeforeUnload();
29 |
30 | } else if (e.data.method == handler.messageNameBase + '.bind.beforeunload') {
31 |
32 | if (!handler.enabledEvents['before_unload']) {
33 |
34 | handler.enabledEvents['before_unload'] = function(e) {
35 | e.preventDefault();
36 | e.returnValue = '';
37 |
38 | return "";
39 | };
40 |
41 | window.addEventListener('beforeunload', handler.enabledEvents['before_unload']);
42 | }
43 |
44 | } else if (e.data.method == handler.messageNameBase + '.getvar') {
45 |
46 |
47 | if (e.data.varList) {
48 |
49 | var getVarAsString = function(value) {
50 | if (typeof value != 'string' && typeof String != 'undefined') value = String(value);
51 | return value;
52 | }
53 |
54 | response.varList = {};
55 | for (var i = 0; i < e.data.varList.length; i++) response.varList[e.data.varList[i]] = typeof window[e.data.varList[i]] != 'undefined' ? getVarAsString(window[e.data.varList[i]]) : false;
56 |
57 | } else {
58 |
59 | response.error = 'var_name is undefined';
60 | }
61 |
62 | } else if (e.data.method == handler.messageNameBase + '.self.remove') {
63 |
64 | handler.remove();
65 | }
66 |
67 | e.source.postMessage(response, window.location.origin);
68 | };
69 |
70 | KellyDynamicDispetcher.removeBeforeUnload = function() {
71 |
72 | if (this.enabledEvents['before_unload']) {
73 |
74 | window.removeEventListener('beforeunload', this.enabledEvents['before_unload']);
75 | this.enabledEvents['before_unload'] = false;
76 | }
77 | }
78 |
79 | KellyDynamicDispetcher.init = function() {
80 | window.addEventListener('message', KellyDynamicDispetcher.getMessage);
81 | }
82 |
83 | KellyDynamicDispetcher.remove = function() {
84 |
85 | this.removeBeforeUnload();
86 | window.removeEventListener('message', KellyDynamicDispetcher.getMessage);
87 | }
88 |
89 | KellyDynamicDispetcher.init();
90 | }());
--------------------------------------------------------------------------------
/extension/env/html/additions/menu-item.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/extension/env/html/additions/page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 | __MODULES__
11 |
12 |
13 |
20 |
21 |
29 |
30 |
31 |
32 |
33 |
Thank you for helping to improve this project!
34 |
Please consider donating if you like this project. I have put a lot of efforts into this project and donations help me justify it.
35 |
You can find actual donate links here
36 |
37 |
Or you can add review on:
38 |
39 |
Add review on Chrome Web Store
40 |
Add review on FireFox Web Store
41 |
42 |
My e-mail contact : radiokellyc@gmail.com
43 |
44 |
45 |
It's also important and would be great help!
46 |
If you want to report issue, or may be report about some translation mistake, send some suggestions \ request, you can send feedback on github ("issues" section), mail
47 |
48 |
49 |
Thank You for Your support!
50 |
You can hide additional extension annotations, support button from popup if you want hide bring back
51 |
52 |
53 |
54 |
Спасибо, что помогаете улучшить проект!
55 |
Если у вас есть желание поддержать развитие разработки расширения,
56 | вы можете перевести любую сумму одним из возможных способов приведенных здесь
57 |
58 |
Так же вы можете оставить отзыв :
59 |
60 |
Добавить отзыв в Chrome Web Store
61 |
Добавить отзыв в FireFox Web Store
62 |
63 |
64 |
Оставить обратную связь так же можно на e-mail : radiokellyc@gmail.com или на GitHub
65 |
Если хотите, можете скрыть любые кнопки поддержки расширения ссылающиеся на эту страницу - скрыть вернуть
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/extension/env/html/additions/profile-selector-recorder.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
@options_page_recorder_desc@
10 |
11 |
--------------------------------------------------------------------------------
/extension/env/html/additions/profile-selector.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @options_page_module_enabled@
5 |
6 |
7 |
11 |
12 |
@options_page_custom_sites@ __HOSTLIST__
13 |
14 |
--------------------------------------------------------------------------------
/extension/env/html/bookmarksParser/parser-form.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Страницы : (если нужно скачать все страницы, оставьте не заполненным)
6 |
7 |
8 | [__RATING_FILTER__Мин. рейтинг постов :
9 |
]
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
30 |
31 |
32 |
35 |
36 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/extension/env/html/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/extension/env/html/recorderDownloader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/extension/env/html/recorderPopup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/extension/env/html/update.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | KellyC Image Downloader
11 |
12 |
13 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
291 |
292 |
293 |
294 |
Migration to
295 |
296 | Ko-Fi
297 |
298 |
299 | Hello!
This extension done by myself in spare time and with your support I tried to keep it always up-to-dated and without any ads.
300 |
301 |
302 | Sadly at date 20.02.24 service
BuyMeaCoffee (service that accepted donations from supporters) started make scam actions and blocked my donations page without warnings & now ignore any questions
303 |
304 | (
discussion & more info ) so now I have to move my projects to
analog
305 |
Thank you for people who supported my development work all this time! I'll hope all be fine...
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
317 |
318 |
319 |
320 |
Переход на
321 |
322 | Ko-Fi
323 |
324 |
325 | Привет!
Это расширение разрабатывается мной в свободное время по мере возможности и все это время я старался поддерживать его в актуальном рабочем состоянии и без какой либо рекламы.
326 |
327 |
328 | К сожалению 20.02.24 сервис
BuyMeaCoffee (сервис добровольных пожертвований) начал совершать мошеннические действия и заблокировал мою страницу без предупреждений и возможности обратной связи
329 |
330 | (
обсуждение & доп. информация ) по этому на данный момент приходится переходить на
аналог
331 |
Спасибо тем людям кто поддерживал разработку все это время!
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
--------------------------------------------------------------------------------
/extension/env/img/arial-yellow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NC22/KellyC-Image-Downloader/58b8909659277f953f3a560f90286cf7116af2e7/extension/env/img/arial-yellow.png
--------------------------------------------------------------------------------
/extension/env/img/cup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NC22/KellyC-Image-Downloader/58b8909659277f953f3a560f90286cf7116af2e7/extension/env/img/cup.png
--------------------------------------------------------------------------------
/extension/env/img/heartr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NC22/KellyC-Image-Downloader/58b8909659277f953f3a560f90286cf7116af2e7/extension/env/img/heartr.png
--------------------------------------------------------------------------------
/extension/env/img/icon128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NC22/KellyC-Image-Downloader/58b8909659277f953f3a560f90286cf7116af2e7/extension/env/img/icon128x128.png
--------------------------------------------------------------------------------
/extension/env/img/icon32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NC22/KellyC-Image-Downloader/58b8909659277f953f3a560f90286cf7116af2e7/extension/env/img/icon32x32.png
--------------------------------------------------------------------------------
/extension/env/img/icon44x44.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NC22/KellyC-Image-Downloader/58b8909659277f953f3a560f90286cf7116af2e7/extension/env/img/icon44x44.png
--------------------------------------------------------------------------------
/extension/env/img/icon50x50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NC22/KellyC-Image-Downloader/58b8909659277f953f3a560f90286cf7116af2e7/extension/env/img/icon50x50.png
--------------------------------------------------------------------------------
/extension/env/init/background.js:
--------------------------------------------------------------------------------
1 | KellyEDispetcher.init();
2 |
3 | // keep empty space to prevent syntax errors if some symbols will added at end
--------------------------------------------------------------------------------
/extension/env/init/commonAbout.js:
--------------------------------------------------------------------------------
1 | KellyCAbout.init();
--------------------------------------------------------------------------------
/extension/env/init/recorderDownloader.js:
--------------------------------------------------------------------------------
1 | KellyTools.loadFrontJs(function() {
2 | KellyDPage.init();
3 | });
--------------------------------------------------------------------------------
/extension/env/init/recorderFront.js:
--------------------------------------------------------------------------------
1 |
2 | if (typeof K_WATCHDOG == 'undefined') {
3 |
4 | var onDOMRendered = function() {
5 |
6 | K_WATCHDOG = new KellyPageWatchdog();
7 | K_WATCHDOG.exec();
8 | }
9 |
10 | if (document.body) { // "run_at": "document_idle"
11 |
12 | onDOMRendered();
13 |
14 | } else { // "run_at": "document_start"
15 |
16 | document.addEventListener("DOMContentLoaded", onDOMRendered);
17 | }
18 |
19 | }
20 |
21 | // keep empty space to prevent syntax errors if some symbols will added at end
--------------------------------------------------------------------------------
/extension/lib/kellyAdditionsForm.js:
--------------------------------------------------------------------------------
1 | KellyAdditionsForm = {
2 | tpl : ['menu-item', 'page', 'profile-selector', 'profile-selector-recorder'],
3 | menu : ['additions_about', 'additions_help', 'additions_modules', 'additions_donate'],
4 |
5 | initToggleProfile : function(p, favEnv) {
6 |
7 | var settings = false, el = document.querySelector('[data-profile=' + p.profile + ']');
8 | if (!el) return;
9 |
10 | if (!favEnv) {
11 | favEnv = new KellyFavItems({env : p})
12 | favEnv.load('cfg', function(fav) { settings = fav; el.checked = !settings.coptions.disabled;});
13 | } else {
14 | settings = favEnv.getGlobal('fav');
15 | el.checked = !settings.coptions.disabled;
16 | }
17 |
18 | el.onchange = function() {
19 | settings.coptions.disabled = settings.coptions.disabled ? false : true;
20 | favEnv.save('cfg');
21 | }
22 | },
23 | show : function(container, favEnv, pageId) {
24 |
25 | if (typeof KellyProfileRecorder == 'undefined') {
26 | KellyAdditionsForm.menu = ['additions_about', 'additions_donate'];
27 | }
28 |
29 | pageId = pageId ? pageId : KellyAdditionsForm.menu[0];
30 |
31 | favEnv.closeSidebar();
32 |
33 | KellyTools.getBrowser().runtime.sendMessage({method: "getResources", asObject : true, items : KellyAdditionsForm.tpl, itemsRoute : {module : 'additions', type : 'html'}}, function(request) {
34 |
35 | var pModulesHtml = '', menuHtml = '', css = '';
36 | var pModules = [];
37 | var defaultLinks = false;
38 |
39 | if (typeof KellyProfileRecorder != 'undefined') pModules.push(KellyProfileRecorder);
40 | if (typeof KellyProfileJoyreactor != 'undefined') pModules.push(KellyProfileJoyreactor);
41 |
42 | var curP = favEnv.getGlobal('env'), options = favEnv.getGlobal('options'), bcEnv = curP.className, bc = bcEnv + '-additions';
43 |
44 | var languages = ['en', 'ru'], defaultLangugage = KellyLoc.detectLanguage();
45 |
46 | for (var i = 0; i < languages.length; i++) {
47 | if (defaultLangugage.indexOf(languages[i]) == -1) {
48 | css += '.' + bc + '-language-' + languages[i] + ' { display : none; }';
49 | }
50 | }
51 |
52 | KellyTools.addCss(bc + '-language', css);
53 |
54 | KellyTools.tplClass = bc;
55 |
56 | for (var i = 0; i < pModules.length; i++) {
57 |
58 | var p = pModules[i].getInstance(), tplName = '', tplData = '';
59 |
60 | if (!defaultLinks && p.extLinks) defaultLinks = p.extLinks;
61 |
62 | if (p.profile == 'recorder') {
63 |
64 | tplName = 'profile-selector-recorder';
65 | tplData = {
66 | CURRENT : curP.profile == p.profile,
67 | };
68 |
69 | } else {
70 |
71 | tplName = 'profile-selector';
72 | tplData = {
73 | HOSTLIST : p.hostList.join(', '),
74 | PROFILEID : p.profile,
75 | CURRENT : curP.profile == p.profile,
76 | PROFILENAME : KellyLoc.s('', 'options_page_custom_cfg', {PROFILENAME : KellyTools.getCamelWord(p.profile)}),
77 | };
78 | }
79 |
80 | pModulesHtml += KellyTools.getTpl(request.data.loadedData, tplName, tplData);
81 | }
82 |
83 | for (var i = 0; i < KellyAdditionsForm.menu.length; i++) {
84 | menuHtml += KellyTools.getTpl(request.data.loadedData, 'menu-item', {NAME : KellyLoc.s(KellyAdditionsForm.menu[i], KellyAdditionsForm.menu[i]), TARGET : KellyAdditionsForm.menu[i]});
85 | }
86 |
87 | KellyTools.setHTMLData(container, KellyTools.getTpl(request.data.loadedData, 'page', {
88 | MODULES : pModulesHtml,
89 | MENU : menuHtml,
90 | HIDDENCLASS : bcEnv + '-hidden',
91 | INSTALL_FF : defaultLinks['install_ff'],
92 | INSTALL_CHROME : defaultLinks['install_chrome'],
93 | AUTHOR : defaultLinks['author'],
94 | GITHUB : defaultLinks['github'],
95 | PP : defaultLinks['pp'],
96 | }));
97 |
98 | for (var i = 0; i < pModules.length; i++) {
99 | KellyAdditionsForm.initToggleProfile(pModules[i].getInstance(), curP == pModules[i].getInstance() ? favEnv : false);
100 | }
101 |
102 | var selectMenu = function(el) {
103 |
104 | var opened = el.parentElement.classList.contains(bc + '-active');
105 |
106 | for (var i = 0; i < KellyAdditionsForm.menu.length; i++) {
107 |
108 | container.getElementsByClassName(bc + '-' + KellyAdditionsForm.menu[i] + '-menu-item')[0].parentElement.classList.remove(bc + '-active');
109 | container.getElementsByClassName(bc + '-' + KellyAdditionsForm.menu[i])[0].classList.add(bcEnv + '-hidden');
110 | container.getElementsByClassName(bc + '-' + KellyAdditionsForm.menu[i])[0].classList.remove(bcEnv + '-active');
111 | }
112 |
113 | container.getElementsByClassName(el.getAttribute('data-target') + '-menu-item')[0].parentElement.classList.add(bc + '-active');
114 | container.getElementsByClassName(el.getAttribute('data-target'))[0].classList.remove(bcEnv + '-hidden');
115 | container.getElementsByClassName(el.getAttribute('data-target'))[0].classList.add(bcEnv + '-active');
116 | }
117 |
118 | var menu = container.getElementsByClassName(bc + '-menu-item');
119 | for (var i = 0; i < menu.length; i++) {
120 |
121 | menu[i].onclick = function() {
122 | selectMenu(this); return false;
123 | };
124 |
125 | if (menu[i].getAttribute('data-target').indexOf(pageId) != -1) {
126 | selectMenu(menu[i]);
127 | }
128 | }
129 |
130 | var heart = container.getElementsByClassName(bc + '-heart');
131 | var updateHeartsDisplay = function() {
132 | for (var i = 0; i < heart.length; i++) {
133 | heart[i].style.display = '';
134 | if (options.toolbar.heartHidden && heart[i].classList.contains(bc + '-heart-hide')) {
135 | heart[i].style.display = 'none';
136 | } else if (!options.toolbar.heartHidden && heart[i].classList.contains(bc + '-heart-show')) {
137 | heart[i].style.display = 'none';
138 | }
139 | }
140 | }
141 | for (var i = 0; i < heart.length; i++) {
142 | heart[i].onclick = function() {
143 |
144 | if (this.classList.contains(bc + '-heart-hide')) {
145 | options.toolbar.heartHidden = true;
146 | } else {
147 | options.toolbar.heartHidden = false;
148 | }
149 |
150 | favEnv.getToolbar().init();
151 | favEnv.save('cfg');
152 | updateHeartsDisplay();
153 | return false;
154 | };
155 | }
156 |
157 | updateHeartsDisplay();
158 | });
159 | },
160 | }
--------------------------------------------------------------------------------
/extension/lib/kellyCAbout.js:
--------------------------------------------------------------------------------
1 | // related to About page
2 |
3 | var KellyCAbout = new Object();
4 | KellyCAbout.language = 'en';
5 |
6 | KellyCAbout.showPage = function(cfg) {
7 |
8 | var handler = KellyCAbout;
9 | handler.cfg = cfg;
10 |
11 | var url = new URL(window.location.href), mode = url.searchParams.get('mode');
12 | if (!mode || ['update', 'about'].indexOf(mode) == -1) mode = 'about';
13 |
14 |
15 | document.body.classList.add('mode-' + mode);
16 |
17 | if (KellyCAbout.jr) document.body.classList.add('env-jr');
18 |
19 | handler.container = document.getElementsByClassName('notice-' + handler.language)[0];
20 | handler.container.style.display = '';
21 |
22 | if (mode == 'update') {}
23 |
24 | handler.container.getElementsByClassName('version')[0].innerText = KellyTools.getBrowser().runtime.getManifest().version;
25 | handler.bgManager = new KellyNradiowaveBg();
26 | handler.bgManager.init();
27 | }
28 |
29 | KellyCAbout.initVideos = function() {
30 |
31 | var video = document.querySelectorAll('video');
32 | for (var i = 0; i < video.length; i++) {
33 | video[i].onclick = function() {
34 |
35 | if (this.paused) {
36 | this.play();
37 | } else {
38 | this.pause();
39 | }
40 |
41 | return false;
42 | }
43 | }
44 | }
45 |
46 | KellyCAbout.initSpoilers = function() {
47 |
48 | var spoiler = document.querySelectorAll('.spoiler-show');
49 | for (var i = 0; i < spoiler.length; i++) {
50 | spoiler[i].onclick = function() {
51 | var target = this.parentElement.querySelector('.spoiler');
52 | if (!target) return true;
53 |
54 | if (target.classList.contains('spoiler-hidden')) target.classList.remove('spoiler-hidden');
55 | else target.classList.add('spoiler-hidden');
56 | return false;
57 | }
58 | }
59 | }
60 |
61 | KellyCAbout.init = function()
62 | {
63 | var jrDb = 'kelly_cfg_joyreactor_config';
64 |
65 | KellyTools.getBrowser().runtime.sendMessage({
66 | method: "getApiStorageItem",
67 | dbName : jrDb,
68 | }, function(response) {
69 |
70 | if (!response.item || response.item === null || !response.item[jrDb]) {
71 | KellyCAbout.jr = false;
72 | } else {
73 | KellyCAbout.jr = true;
74 | }
75 |
76 | var lang = KellyTools.getBrowser().i18n.getUILanguage();
77 | if (lang.indexOf('ru') != -1) KellyCAbout.language = 'ru';
78 |
79 | KellyCAbout.initSpoilers();
80 | KellyCAbout.initVideos();
81 | KellyCAbout.showPage();
82 |
83 | });
84 | }
--------------------------------------------------------------------------------
/extension/lib/kellyDispetcherNetRequest.js:
--------------------------------------------------------------------------------
1 | // compatibility \ testing for manifest v3
2 |
3 | // createObjectURL - dosnt work from background (window - is undefined), so base64 transport method is impossible to implement
4 | // downloader.download - api - crashs browser if you try to download blob - tested on 88.0.4324.96 chrome
5 |
6 | // check rules acception - some passed only after page reload. check difference between dinamic rules and session rules
7 | // CONNECTED Error already connected - check tab disconnect
8 | // todo - keep alive
9 |
10 | // todo - предусмотреть инструменты для фикса 301 редиректов которые легко учесть в webRequestах но нельзя в declarativeNetRequest - возможно подстановка referer так же сработает
11 | // например добавлять в редирект контрольный get параметр или cookie и по ней отсеивать для простановки referer (+2 правила на каждую картинку)
12 |
13 | var KellyEDispetcherDR = {
14 | declaredRulesId : 1000,
15 | };
16 |
17 | KellyEDispetcherDR.init = function() {
18 |
19 | if (KellyTools.getManifestVersion() > 2) {
20 |
21 | KellyEDispetcher.api.declarativeNetRequest.getSessionRules(function(rules) {
22 |
23 | if (KellyTools.getBrowser().runtime.lastError) {
24 | KellyTools.log('Error : ' + KellyTools.getBrowser().runtime.lastError.message, 'KellyEDispetcher | declarativeNetRequest');
25 | return;
26 | }
27 |
28 | if (rules.length > 0) {
29 | for (var i = 0; i < rules.length; i++) {
30 | if (KellyEDispetcherDR.declaredRulesId < rules[i].id) {
31 | KellyEDispetcherDR.declaredRulesId = rules[i].id + 1;
32 | }
33 | }
34 | }
35 | });
36 |
37 | KellyEDispetcher.events.push({onTabConnect : KellyEDispetcherDR.onTabConnect});
38 | }
39 | }
40 |
41 | KellyEDispetcherDR.cleanupSessionRulesForTab = function(tabId, onReady) {
42 |
43 | KellyEDispetcher.api.declarativeNetRequest.getSessionRules(function(rules) {
44 |
45 | if (KellyTools.getBrowser().runtime.lastError) {
46 | KellyTools.log('Error : ' + KellyTools.getBrowser().runtime.lastError.message, 'KellyEDispetcher | declarativeNetRequest');
47 | if (onReady) onReady(false);
48 | return;
49 | }
50 |
51 | if (rules.length > 0) {
52 | var ids = [];
53 | for (var i = 0; i < rules.length; i++) {
54 | if (rules[i].condition.tabIds && rules[i].condition.tabIds.indexOf(tabId) !== -1) {
55 | ids.push(rules[i].id);
56 | }
57 | }
58 |
59 | KellyEDispetcher.api.declarativeNetRequest.updateSessionRules({addRules : [], removeRuleIds : ids}, function() {
60 |
61 | KellyTools.log('[Cleanup] session Rules | Num : ' + ids.length + ' [TabId : ' + tabId + '] ', 'KellyEDispetcher | declarativeNetRequest');
62 |
63 | if (KellyTools.getBrowser().runtime.lastError) {
64 | KellyTools.log('Error : ' + KellyTools.getBrowser().runtime.lastError.message, 'KellyEDispetcher | declarativeNetRequest');
65 | if (onReady) onReady(false);
66 | return;
67 | } else {
68 | if (onReady) onReady(true);
69 | }
70 |
71 | });
72 | } else {
73 |
74 | KellyTools.log('[Cleanup] session Rules | Num : [nothing to cleanup] [TabId : ' + tabId + '] ', 'KellyEDispetcher | declarativeNetRequest');
75 |
76 | if (onReady) onReady(true);
77 | }
78 | });
79 | }
80 |
81 | /*
82 | tabData request rules described in kellyDispetcher
83 | */
84 |
85 | KellyEDispetcherDR.addRequestListeners = function(tabData, onRegistered) {
86 |
87 | tabData.declaredRules = [];
88 |
89 | var addRule = function(params) {
90 |
91 | var priority = 2;
92 |
93 | // match any url - used in downloader to prevent 301 redirects go without referer from extension page
94 |
95 | if (typeof params.matches == "string" && params.matches == 'ANY') {
96 | priority = 1;
97 | params.matches = '|http*';
98 | }
99 |
100 | var responseHeaders, requestHeaders;
101 |
102 | if (typeof params.additionResponseHeaders != 'undefined') {
103 |
104 | responseHeaders = [];
105 |
106 | for (var key in params.additionResponseHeaders) {
107 |
108 | responseHeaders.push({"header" : key, "operation" : "set", "value" : params.additionResponseHeaders[key]});
109 | }
110 |
111 | } else {
112 |
113 | responseHeaders = [
114 | { "header" : "Access-Control-Allow-Origin", "operation" : "set", "value": "*" },
115 |
116 | { "header" : "Pragma-directive", "operation" : "set", "value": "no-cache" },
117 | { "header" : "Cache-directive", "operation" : "set", "value": "no-cache" },
118 | { "header" : "Cache-control", "operation" : "set", "value": "no-cache" },
119 | { "header" : "Pragma", "operation" : "set", "value": "no-cache" },
120 | { "header" : "Expires", "operation" : "set", "value": "0" },
121 | ]
122 | }
123 |
124 | if (typeof params.additionRequestHeaders != 'undefined') {
125 |
126 | requestHeaders = [];
127 |
128 | for (var key in params.additionRequestHeaders) {
129 |
130 | requestHeaders.push({"header" : key, "operation" : "set", "value" : params.additionRequestHeaders[key]});
131 | }
132 |
133 | } else {
134 |
135 | requestHeaders = [
136 | { "header" : "cache-control", "operation" : "set", "value" : "no-cache, must-revalidate, post-check=0, pre-check=0" },
137 | { "header" : "pragma", "operation" : "set", "value" : 'no-cache' },
138 | { "header" : "Referer", "operation" : "set", "value" : params.referrer },
139 | // { "header" : "Origin", "operation" : "set", "value" : params.referrer },
140 | ];
141 |
142 | }
143 |
144 | if (typeof params.matches == "string") {
145 | params.matches = [params.matches];
146 | }
147 |
148 | for (var i = 0; i < params.matches.length; i++) {
149 |
150 | KellyEDispetcherDR.declaredRulesId++;
151 |
152 | tabData.declaredRules.push({
153 | "id" : KellyEDispetcherDR.declaredRulesId, // tabData.declaredRules.length + 1,
154 | "action": {
155 | "type" : "modifyHeaders",
156 | "requestHeaders" : requestHeaders,
157 | "responseHeaders" : responseHeaders,
158 | },
159 | "condition": {
160 | "urlFilter" : params.matches[i],
161 | "resourceTypes" : tabData.types ? tabData.types : ['main_frame', 'image', 'xmlhttprequest', 'media'],
162 | "tabIds" : [tabData.id],
163 | },
164 | "priority" : priority,
165 | });
166 | }
167 | }
168 |
169 | if (tabData.referrer) {
170 | addRule({matches : KellyTools.getHostlistMatches(tabData.hostList, true), referrer : tabData.referrer});
171 | }
172 |
173 | if (tabData.urlMap) {
174 | for (var i = 0; i < tabData.urlMap.length; i++) {
175 |
176 | addRule({
177 | matches : tabData.urlMap[i][0],
178 | referrer : tabData.urlMap[i][1],
179 | additionRequestHeaders : tabData.urlMap[i][2],
180 | additionResponseHeaders : tabData.urlMap[i][3],
181 | });
182 | }
183 | }
184 |
185 | KellyEDispetcher.callEvent('onBeforeUpdateNetRequestRules', tabData);
186 |
187 | KellyTools.getBrowser().declarativeNetRequest.updateSessionRules({addRules : tabData.declaredRules, removeRuleIds : []}, function() {
188 |
189 | if (KellyTools.getBrowser().runtime.lastError) {
190 | KellyTools.log('Error : ' + KellyTools.getBrowser().runtime.lastError.message, 'KellyEDispetcher | declarativeNetRequest');
191 | } else {
192 |
193 | KellyTools.log('[ADD] session Rules | Num : ' + tabData.declaredRules.length + ' [TabId : ' + tabData.id + ']', 'KellyEDispetcher | declarativeNetRequest');
194 | }
195 |
196 | onRegistered();
197 | });
198 |
199 | }
200 |
201 | KellyEDispetcherDR.onTabConnect = function(self, data) {
202 |
203 | var port = data.port, reconect = false;
204 | var tabData = false;
205 |
206 | KellyTools.log('[Downloader] CONNECTED Tab ' + port.sender.tab.id, 'KellyEDispetcher | declarativeNetRequest');
207 |
208 | // Check is extension from front was already connected before
209 | // This can happen IN case worker was killed, or some other unpredicted event happend (port closed, page reloaded without callback, etc.)
210 |
211 | for (var i = 0; i < KellyEDispetcher.downloaderTabs.length; i++) {
212 | if (KellyEDispetcher.downloaderTabs[i].id == port.sender.tab.id) {
213 | KellyTools.log('[Downloader] Tab was already connected : reset connection, change port', 'KellyEDispetcher | declarativeNetRequest');
214 | reconect = true;
215 |
216 | tabData = KellyEDispetcher.downloaderTabs[i];
217 | tabData.closePort();
218 |
219 | tabData.port = port;
220 | break;
221 | }
222 | }
223 |
224 | var onDownloaderMessage = function(request) {
225 |
226 | var response = {
227 | notice : false,
228 | message : 'ok',
229 | method : request.method,
230 | ready : function() {
231 |
232 | if (response.notice) KellyTools.log(response.notice, 'KellyEDispetcher [PORT]');
233 |
234 | tabData.port.postMessage({method : response.method, message : response.message});
235 | }
236 | }
237 |
238 | if (request.method == 'registerDownloader') {
239 |
240 | tabData.resetEvents('Init new tab', function() {
241 |
242 | response.notice = 'Update registerDownloader request modifiers';
243 | response.message = request.disable ? "disabled" : "registered";
244 |
245 | if (!request.disable) {
246 |
247 | tabData.referrer = request.referrer;
248 | tabData.types = request.types;
249 | tabData.hostList = request.hostList;
250 |
251 | if (request.urlMap) tabData.urlMap = request.urlMap;
252 | if (tabData.urlMap && request.unlistedReferer) tabData.urlMap.push(['ANY', request.unlistedReferer]);
253 |
254 | KellyEDispetcherDR.addRequestListeners(tabData, response.ready);
255 |
256 | tabData.eventsEnabled = true;
257 |
258 | } else {
259 |
260 | tabData.eventsEnabled = false;
261 | response.ready();
262 |
263 | }
264 |
265 | });
266 |
267 | } else if (request.method == 'setDebugMode') {
268 |
269 | KellyTools.DEBUG = request.state;
270 | response.notice = 'Tab loaded in debug mode, switch background process debug mode to ' + (KellyTools.DEBUG ? 'TRUE' : 'FALSE');
271 | response.ready();
272 |
273 | } else if (request.method == 'updateUrlMap') {
274 |
275 | tabData.resetEvents('Update url map', function() {
276 |
277 | if (!tabData.eventsEnabled) {
278 |
279 | response.message = "tab not initialized. use registerDownloader method first";
280 | KellyTools.log('[updateUrlMap] ' + response.message);
281 |
282 | response.ready();
283 | return;
284 | }
285 |
286 | if (request.urlMap) {
287 | tabData.urlMap = request.urlMap;
288 | }
289 |
290 | if (tabData.urlMap && request.unlistedReferer) tabData.urlMap.push(['ANY', request.unlistedReferer]);
291 |
292 | KellyEDispetcherDR.addRequestListeners(tabData, response.ready);
293 |
294 | });
295 |
296 | } else {
297 |
298 | KellyTools.log('Unknown request', 'KellyEDispetcher [PORT]');
299 | KellyTools.log(request);
300 | }
301 | }
302 |
303 | if (tabData === false) {
304 |
305 | tabData = {port : port, tab : port.sender.tab, id : port.sender.tab.id, declaredRules : [], eventsEnabled : false};
306 | tabData.resetEvents = function(reason, onReady) {
307 |
308 | KellyEDispetcherDR.cleanupSessionRulesForTab(tabData.id, function() {
309 |
310 | KellyTools.log('resetEvents [READY] | Reason : ' + (reason ? reason : 'no reason'), 'KellyEDispetcher [PORT]');
311 | tabData.declaredRules = [];
312 | if (onReady) onReady();
313 | });
314 | }
315 |
316 | tabData.closePort = function() {
317 | tabData.port.onMessage.removeListener(onDownloaderMessage);
318 | tabData.port.disconnect();
319 | }
320 |
321 | KellyEDispetcher.downloaderTabs.push(tabData);
322 | }
323 |
324 | tabData.port.postMessage({method : 'onPortCreate', message : 'connected', isDownloadSupported : KellyEDispetcher.isDownloadSupported()});
325 | tabData.port.onMessage.addListener(onDownloaderMessage);
326 |
327 | tabData.port.onDisconnect.addListener(function(p){
328 |
329 | KellyTools.log('[DISCONECTED] | Reason : ' + (p.error ? p.error : 'Close tab'), 'KellyEDispetcher [PORT]');
330 | tabData.resetEvents('Disconect tab');
331 | tabData.closePort();
332 |
333 | if (KellyEDispetcher.downloaderTabs.indexOf(tabData) != -1) KellyEDispetcher.downloaderTabs.splice(KellyEDispetcher.downloaderTabs.indexOf(tabData), 1);
334 | });
335 |
336 | return true;
337 | }
338 |
339 | KellyEDispetcherDR.init();
--------------------------------------------------------------------------------
/extension/lib/kellyLoc.js:
--------------------------------------------------------------------------------
1 | var KellyLoc = new Object();
2 |
3 | // buffered i18n.getMessage data
4 | KellyLoc.locs = {};
5 | KellyLoc.browser = -1;
6 |
7 | // deprecated, detectLanguage not required for i18n mode, - better replace to chrome.i18n.getAcceptLanguages(callback?: function,) if needed
8 | KellyLoc.detectLanguage = function() {
9 |
10 | var language = window.navigator.userLanguage || window.navigator.language;
11 | if (language) {
12 | if (language.indexOf('-') != -1) language = language.split('-')[0];
13 |
14 | language = language.trim();
15 |
16 | return language;
17 | } else return this.defaultLanguage;
18 |
19 | }
20 |
21 | KellyLoc.parseText = function(text, vars) {
22 |
23 | if (!text) return '';
24 |
25 | if (vars) {
26 | for (var key in vars){
27 | if (typeof vars[key] != 'function') {
28 | text = text.replace('__' + key + '__', vars[key]);
29 | }
30 | }
31 | }
32 |
33 | return text;
34 | }
35 |
36 | KellyLoc.s = function(defaultLoc, key, vars) {
37 |
38 | if (this.locs[key]) return this.parseText(this.locs[key], vars);
39 |
40 | if (this.browser == -1) this.browser = KellyTools.getBrowser();
41 |
42 | if (!this.browser || !this.browser.i18n || !this.browser.i18n.getMessage) return this.parseText(defaultLoc, vars);
43 |
44 | this.locs[key] = this.browser.i18n.getMessage(key);
45 | if (!this.locs[key]) this.locs[key] = defaultLoc;
46 |
47 | return this.parseText(this.locs[key], vars);
48 | }
--------------------------------------------------------------------------------
/extension/lib/kellyNradiowaveBg.js:
--------------------------------------------------------------------------------
1 | function KellyNradiowaveBg(cfg) {
2 |
3 | var bgItem = false; // current loaded item
4 | var character = false;
5 | var characterGhost = false;
6 | var order = false;
7 |
8 | var updateTimer = false;
9 |
10 | var loader = {image : document.createElement('IMG'), imageGhost : document.createElement('IMG')};
11 |
12 | var bgItems = [
13 | {src : 'light1.png', xAnim : {offset : 0, time : 40}, yAnim : {offsetX : 'center', time : 40}},
14 | {src : 'light2.png', xAnim : {offset : 0, time : 40}, yAnim : {offsetX : 'center', time : 40}},
15 |
16 | {src : 'bg5.png', xAnim : {offset : 0, time : 40}, yAnim : {offsetX : 'center', time : 40}},
17 | {src : 'bg2.png', xAnim : {offset : 0, time : 40}, yAnim : {offsetX : 'center', time : 40}},
18 | ];
19 |
20 | function shuffleArray(array) {
21 | var currentIndex = array.length, randomIndex;
22 |
23 | while (currentIndex != 0) {
24 |
25 | randomIndex = Math.floor(Math.random() * currentIndex);
26 | currentIndex--;
27 |
28 | [array[currentIndex], array[randomIndex]] = [
29 | array[randomIndex], array[currentIndex]];
30 | }
31 |
32 | return array;
33 | }
34 |
35 | function getNextRandItem() {
36 |
37 | if (!order) {
38 |
39 | order = localStorage.getItem('kelly-bg-order');
40 | cursor = parseInt(localStorage.getItem('kelly-bg-cursor'));
41 |
42 | if (isNaN(cursor)) cursor = 0;
43 |
44 | if (order) order = order.split(',');
45 | if (!order || order.length != bgItems.length) order = false;
46 |
47 | if (!order) {
48 |
49 | order = [];
50 | for (var i = 0; i < bgItems.length; i++) order.push(i);
51 |
52 | // order = shuffleArray(order);
53 |
54 | }
55 |
56 | } else {
57 |
58 | cursor++;
59 | if (cursor > order.length-1) cursor = 0;
60 | }
61 |
62 | if (typeof bgItems[cursor] == 'undefined') {
63 | console.log('item ' + cursor + ' was removed - reset order');
64 | cursor = 0;
65 | }
66 |
67 | localStorage.setItem('kelly-bg-order', order.join(','));
68 | localStorage.setItem('kelly-bg-cursor', cursor);
69 |
70 |
71 | return order[cursor];
72 | }
73 |
74 | var handler = this;
75 |
76 | var addCss = function(id, css, clean) {
77 |
78 | var style = document.getElementById(id), head = document.head || document.getElementsByTagName('head')[0];
79 | if (!style) {
80 |
81 | style = document.createElement('style');
82 | style.type = 'text/css';
83 | style.id = id;
84 | head.appendChild(style);
85 |
86 | }
87 |
88 | if (style.styleSheet){
89 |
90 | if (clean) style.styleSheet.cssText = '';
91 | style.styleSheet.cssText += css;
92 |
93 | } else {
94 |
95 | if (clean) style.innerHTML = '';
96 | style.appendChild(document.createTextNode(css));
97 | }
98 |
99 | }
100 |
101 | var getRand = function(min, max) {
102 |
103 | min = Math.ceil(min);
104 | max = Math.floor(max);
105 |
106 | return Math.floor(Math.random() * (max - min + 1)) + min;
107 | }
108 |
109 | var getViewport = function() {
110 |
111 | var elem = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body;
112 | return { screenHeight: elem.clientHeight, screenWidth: elem.clientWidth};
113 | }
114 |
115 | var getBgImageSize = function(imageBounds) {
116 |
117 | var bgSize = {}, viewport = getViewport();
118 | if (viewport.screenHeight > viewport.screenWidth) { // resize image by screen height
119 |
120 | // viewport.screenWidth += bgItem.xAnim.maxMove;
121 |
122 | var imageRatio = viewport.screenHeight / imageBounds.h;
123 |
124 | bgSize.w = imageRatio * imageBounds.w;
125 | bgSize.h = viewport.screenHeight;
126 |
127 | if (bgSize.w < viewport.screenWidth) {
128 |
129 | imageRatio = viewport.screenWidth / imageBounds.w;
130 |
131 | bgSize.w = viewport.screenWidth;
132 | bgSize.h = imageRatio * imageBounds.h;
133 |
134 | }
135 |
136 | } else { // by screen width
137 |
138 | // viewport.screenHeight += bgItem.yAnim.maxMove;
139 |
140 | var imageRatio = viewport.screenWidth / imageBounds.w;
141 |
142 | bgSize.w = viewport.screenWidth;
143 | bgSize.h = imageRatio * imageBounds.h;
144 |
145 | if (bgSize.h < viewport.screenHeight) {
146 |
147 | imageRatio = viewport.screenHeight / imageBounds.h;
148 |
149 | bgSize.w = imageRatio * imageBounds.w;
150 | bgSize.h = viewport.screenHeight;
151 | }
152 |
153 | }
154 |
155 | return bgSize;
156 | }
157 |
158 | this.resetLoad = function() {
159 |
160 | loader.inUse = false;
161 |
162 | loader.imageGhost.src = '';
163 | loader.imageGhost.onload = function() {};
164 | loader.imageGhost.onerror = function() {};
165 |
166 | loader.image.src = '';
167 | loader.image.onload = function() {};
168 | loader.image.onerror = function() {};
169 | }
170 |
171 | this.loadBgItem = function(itemN) {
172 |
173 | if (typeof itemN == 'number') bgItem = bgItems[itemN];
174 |
175 | if (!bgItem || itemN == 'random') {
176 | itemN = getNextRandItem();
177 | bgItem = bgItems[itemN];
178 | }
179 |
180 | handler.resetLoad();
181 | loader.inUse = true;
182 |
183 | //character.classList.remove('fade-in');
184 |
185 | loader.imageGhost.src = 'https://nradiowave.ru//style/Default/img/nradiowave/bg/o_' + bgItem.src;
186 | loader.imageGhost.onload = function() {
187 |
188 | var imageBounds = {w : this.naturalWidth, h : this.naturalHeight};
189 | var bgSize = getBgImageSize(imageBounds);
190 |
191 | characterGhost.style.backgroundImage = 'url(' + this.src + ')';
192 | characterGhost.style.backgroundSize = bgSize.w + 'px ' + bgSize.h + 'px';
193 |
194 | characterGhost.classList.add('fade-in');
195 |
196 |
197 | loader.image.src = 'https://nradiowave.ru/style/Default/img/nradiowave/bg/' + bgItem.src;
198 | loader.image.onload = function() {
199 |
200 | var imageBounds = {w : this.naturalWidth, h : this.naturalHeight};
201 | var viewport = getViewport(), bgSize = getBgImageSize(imageBounds), workAnim = 'xAnim';
202 |
203 |
204 | if (viewport.screenHeight > viewport.screenWidth) { // resize image by screen height
205 |
206 | if (!bgItem.xAnim.offset) bgItem.xAnim.offset = 0;
207 | if (!bgItem.xAnim.maxMove) bgItem.xAnim.maxMove = bgSize.w - viewport.screenWidth - bgItem.xAnim.offset;
208 |
209 | character.style.animation = 'bg-move-x-'+ itemN +' ' + bgItem.xAnim.time + 's ease-in-out infinite';
210 |
211 | if (bgItem.xAnim.offsetY) {
212 | character.style.backgroundPositionY = bgItem.xAnim.offsetY == 'center' ? 'center' : '-' + bgItem.xAnim.offsetY + 'px';
213 | }
214 |
215 | } else { // by screen width
216 |
217 | workAnim = 'yAnim';
218 | if (!bgItem.yAnim.offset) bgItem.yAnim.offset = 0;
219 | if (!bgItem.yAnim.maxMove) bgItem.yAnim.maxMove = bgSize.h - viewport.screenHeight - bgItem.yAnim.offset;
220 |
221 | character.style.animation = 'bg-move-'+ itemN +' ' + bgItem.yAnim.time + 's ease-in-out infinite';
222 |
223 | if (bgItem.yAnim.offsetX) {
224 | character.style.backgroundPositionX = bgItem.yAnim.offsetX == 'center' ? 'center' : '-' + bgItem.yAnim.offsetX + 'px';
225 | }
226 | }
227 |
228 | if (!bgItem[workAnim].time) {
229 | bgItem[workAnim].time = 0.2 * bgItem[workAnim].maxMove * 0.58; // 58px per 20s
230 | }
231 |
232 | handler.loadBgItemDelay('random', bgItem[workAnim].time * 0.5 * 1000);// bgItem[workAnim].time * 1.5 * 1000);
233 |
234 |
235 | var css = '\
236 | @keyframes bg-move-'+ itemN +' {\
237 | 0%, 100% {\
238 | background-position-y: -' + (bgItem.yAnim.revers ? bgItem.yAnim.maxMove : bgItem.yAnim.offset) + 'px;\
239 | }\
240 | 50% {\
241 | background-position-y: -' + (bgItem.yAnim.revers ? bgItem.yAnim.offset : bgItem.yAnim.maxMove) + 'px;\
242 | }\
243 | }\
244 | \
245 | @keyframes bg-move-x-'+ itemN +' {\
246 | 0%, 100% {\
247 | background-position-x: -' + bgItem.xAnim.offset + ';\
248 | }\
249 | 50% {\
250 | background-position-x: -' + bgItem.xAnim.maxMove + 'px;\
251 | }\
252 | }\
253 | ';
254 |
255 | addCss('random-character-anims', css, true);
256 |
257 | character.style.backgroundImage = 'url(' + this.src + ')';
258 | character.style.backgroundSize = bgSize.w + 'px ' + bgSize.h + 'px';
259 |
260 | character.classList.add('fade-in');
261 | setTimeout(function() {characterGhost.classList.remove('fade-in');}, 900);
262 | handler.resetLoad();
263 |
264 | }
265 | }
266 |
267 |
268 | }
269 |
270 | this.loadBgItemDelay = function(itemN, delay) {
271 | if (updateTimer !== false) clearTimeout(updateTimer);
272 |
273 | updateTimer = setTimeout(function() {
274 |
275 | updateTimer = false;
276 | character.classList.remove('fade-in');
277 | setTimeout(function() { handler.loadBgItem(itemN); }, 1000);
278 |
279 | }, delay);
280 | }
281 |
282 | this.init = function() {
283 |
284 | character = document.getElementsByClassName('random-character-main')[0];
285 | characterGhost = document.getElementsByClassName('random-character-ghost')[0];
286 |
287 | handler.loadBgItem('random');
288 |
289 | window.addEventListener('resize', function() {
290 | character.classList.remove('fade-in');
291 | character.style.backgroundSize = 'cover';
292 | character.style.backgroundPositionX = '0px';
293 | character.style.backgroundPositionY = '0px';
294 | character.style.animation = '';
295 |
296 | handler.loadBgItemDelay('current', 100);
297 | });
298 | }
299 | }
300 |
--------------------------------------------------------------------------------
/extension/lib/kellyThreadWork.js:
--------------------------------------------------------------------------------
1 | function KellyThreadWork(cfg) {
2 |
3 | var jobs = [];
4 | var maxThreads = 1; // эксперименты чреваты баном за спам запросами, пробовать только за впном или если у вас динамический адрес
5 | var threads = [];
6 |
7 | var timeout = 15; // таймаут ожидания загрузки страницы в секундах, в обработчик onLoad попадет response = false
8 | var timeoutOnEnd = [2, 2.2, 1.1, 3.4, 4, 3, 3, 3, 4.6]; // таймер перехода к следующей задаче после выполнения - сек. рандомно из массива
9 |
10 | // long pause every
11 | var pauseEvery = [40,30,20];
12 | var untilPause = getRandom(pauseEvery);
13 | var pauseTimer = [10,14,20];
14 |
15 | var events = { onProcess : false, onEnd : false };
16 | var handler = this;
17 | var threadId = 1;
18 | var beasy = false, pause = false;
19 |
20 | function constructor(cfg) {
21 | handler.updateCfg(cfg);
22 | }
23 |
24 | function parseTimeset(text) {
25 |
26 | if (typeof text == 'number') text = KellyTools.val(text, 'string');
27 | if (typeof text == 'string') text = KellyTools.getVarList(text, 'float');
28 |
29 | if (text && text.length) {
30 |
31 | var list = [];
32 |
33 | for (var i = 0; i < text.length; i++) {
34 |
35 | var tmp = text[i];
36 |
37 | if (typeof tmp != 'number') {
38 | tmp = KellyTools.val(tmp, 'float');
39 | }
40 |
41 | if (tmp <= 0) continue;
42 |
43 | list[list.length] = tmp;
44 | }
45 |
46 | return list;
47 |
48 | } else {
49 | return [];
50 | }
51 |
52 | }
53 |
54 | function timesetToString(timeset) {
55 | var string = '';
56 |
57 | for (var i = 0; i < timeset.length; i++) {
58 | string += string ? ',' + timeset[i] : timeset[i];
59 | }
60 |
61 | return string;
62 | }
63 |
64 | this.getCfg = function() {
65 | return {
66 | pauseEvery : timesetToString(pauseEvery),
67 | pauseTimer : timesetToString(pauseTimer),
68 | timeoutOnEnd : timesetToString(timeoutOnEnd),
69 | timeout : timeout,
70 | maxThreads : maxThreads,
71 | }
72 | }
73 |
74 | this.pause = function(state) {
75 |
76 | var oldPause = pause;
77 | pause = state ? true : false;
78 |
79 | if (pause == false) {
80 |
81 | if (oldPause) jobContinue();
82 | KellyTools.log('work continue', 'KellyThreadWork');
83 |
84 | } else {
85 |
86 |
87 | for (var i = 0; i < threads.length; i++) {
88 |
89 | if (threads[i].job) {
90 | jobs.push(threads[i].job);
91 | KellyTools.log('work paused - return task back to jobs pool', 'KellyThreadWork');
92 | }
93 |
94 | handler.clearThreadTimers(threads[i]);
95 | }
96 |
97 | threads = [];
98 | beasy = false;
99 | }
100 | }
101 |
102 | this.updateCfg = function(cfg) {
103 |
104 | if (!cfg) return;
105 |
106 | var tmp = parseTimeset(cfg.pauseEvery);
107 | if (tmp.length) {
108 | pauseEvery = tmp;
109 | untilPause = getRandom(pauseEvery);
110 | }
111 |
112 | tmp = parseTimeset(cfg.pauseTimer);
113 | if (tmp.length) pauseTimer = tmp;
114 |
115 | tmp = parseTimeset(cfg.timeoutOnEnd);
116 | if (tmp.length) timeoutOnEnd = tmp;
117 |
118 | tmp = KellyTools.val(cfg.timeout, 'float');
119 | if (tmp > 2) timeout = tmp;
120 |
121 | tmp = KellyTools.val(cfg.maxThreads, 'int');
122 | if (tmp >= 1 && tmp <= 15) maxThreads = tmp;
123 | }
124 |
125 | function getRandom(input) {
126 | return input[Math.floor(Math.random() * ((input.length - 1) + 1))];
127 | }
128 |
129 | this.getJobs = function() {
130 | return jobs;
131 | }
132 |
133 | this.getThreads = function() {
134 | return threads;
135 | }
136 |
137 | this.setEvent = function(name, f) {
138 |
139 | events[name] = f;
140 | }
141 |
142 | this.stop = function(noCleanJobs) {
143 |
144 | KellyTools.log('clean job', 'KellyThreadWork');
145 | onEnd('stop', true);
146 | }
147 |
148 | function removeThreadItem(thread) {
149 |
150 | var threadIndex = threads.indexOf(thread);
151 | if (threadIndex == -1) return false;
152 |
153 | threads.splice(threadIndex, 1);
154 | return true;
155 | }
156 |
157 | function jobContinue() {
158 |
159 | if (!jobs.length && !threads.length) {
160 |
161 | onEnd('onJobEnd');
162 |
163 | } else if (jobs.length > 0) {
164 |
165 | var timeout = getRandom(timeoutOnEnd);
166 |
167 | if (pauseEvery && pauseEvery.length) {
168 |
169 | if (untilPause > 0) {
170 | untilPause--;
171 | KellyTools.log('before pause ' + untilPause, 'KellyThreadWork');
172 | } else {
173 | untilPause = getRandom(pauseEvery);
174 | timeout = getRandom(pauseTimer);
175 |
176 | KellyTools.log('timeout ' + timeout + ' | new pause ' + untilPause, 'KellyThreadWork');
177 |
178 | }
179 | }
180 |
181 | var threadPlaceholder = {};
182 | threadPlaceholder.applayTimer = setTimeout(function() {
183 | applayJob(threadPlaceholder);
184 | }, timeout * 1000);
185 |
186 | threads.push(threadPlaceholder);
187 | }
188 | }
189 |
190 | this.onJobEnd = function(thread) {
191 |
192 | removeThreadItem(thread);
193 |
194 | if (pause) {
195 | return;
196 | }
197 |
198 | if (!thread.response) {
199 | // error
200 | KellyTools.log('job end without load document', 'KellyThreadWork');
201 | KellyTools.log(thread, 'KellyThreadWork');
202 | }
203 |
204 | var isUnfinished = thread.job.onLoad(handler, thread, jobs.length); // for addition sub requests, dont use unfinished state if you dont know how threads class works
205 | if (isUnfinished === true) return;
206 |
207 | if (events.onProcess) events.onProcess(jobs.length, thread);
208 |
209 | handler.clearThreadTimers(thread);
210 |
211 | if (pause) {
212 |
213 | KellyTools.log('Global pause, dont take actions', 'KellyThreadWork');
214 |
215 | } else jobContinue();
216 | }
217 |
218 | function applayJob(threadPlaceholder) {
219 |
220 | if (threadPlaceholder) removeThreadItem(threadPlaceholder);
221 |
222 | if (threads.length >= maxThreads || pause) {
223 | return false;
224 | }
225 |
226 | if (!jobs.length && !threads.length) {
227 | onEnd('applayJob');
228 | return false;
229 | }
230 |
231 | if (!jobs.length) {
232 | return false;
233 | }
234 |
235 | threadId++;
236 | var thread = {
237 | job : jobs.pop(),
238 | response : false,
239 | request : false,
240 | id : threadId,
241 | error : '',
242 | }
243 |
244 | var config = thread.job.config ? thread.job.config : {method : 'GET', responseType : 'text'};
245 |
246 | // method | responseType
247 |
248 | thread.rules = [];
249 |
250 | if (thread.job.url.indexOf('##FETCH_RULES##') != -1) {
251 | thread.job.url = thread.job.url.split('##FETCH_RULES##');
252 | thread.rules = thread.job.url.length == 2 ? thread.job.url[1] : false;
253 | thread.job.url = thread.job.url[0];
254 |
255 | thread.rules = thread.rules.split('&');
256 | thread.rules.forEach(function(rule) {
257 | rule = rule.split('=');
258 | if (rule.length == 2 && rule.indexOf('mark_') == -1) config[rule[0]] = rule[1];
259 | });
260 | }
261 |
262 | thread.request = KellyTools.xmlRequest(thread.job.url, config, handler.createDefaultHttpRequestCallback(thread));
263 | thread.timeoutTimer = setTimeout(function() { handler.onJobEnd(thread); }, timeout * 1000);
264 | threads.push(thread);
265 |
266 | return true;
267 | }
268 |
269 | this.createDefaultHttpRequestCallback = function(thread) {
270 |
271 | var defaultCallback = function(urlOrig, data, errorCode, errorText, controller) {
272 |
273 | if (pause) return;
274 |
275 | if (data !== false) {
276 | thread.response = data;
277 | } else {
278 | thread.response = false;
279 | thread.error = '[HTTP Request ERROR] Error code : ' + errorCode + ' | error message : ' + errorText;
280 | }
281 |
282 | handler.onJobEnd(thread);
283 | }
284 |
285 | return defaultCallback;
286 | }
287 |
288 | this.isBeasy = function() {
289 | return beasy;
290 | }
291 |
292 | this.clearThreadTimers = function(thread) {
293 |
294 | if (thread.applayTimer) {
295 | clearTimeout(thread.applayTimer);
296 | thread.applayTimer = false;
297 | }
298 |
299 | if (thread.request) {
300 | thread.request.abort();
301 | threadrequest = false;
302 | }
303 |
304 | if (thread.timeoutTimer) {
305 | clearTimeout(thread.timeoutTimer);
306 | thread.timeoutTimer = false;
307 | }
308 | }
309 |
310 | function onEnd(cname, forced) {
311 |
312 | for (var i = 0; i < threads.length; i++) handler.clearThreadTimers(threads[i]); // stops any requests and addition timers
313 |
314 | threads = []; jobs = [];
315 |
316 | forced = forced ? true : false;
317 | beasy = false;
318 | pause = false;
319 |
320 | if (events.onEnd) events.onEnd(cname, forced);
321 | }
322 |
323 | this.exec = function() {
324 |
325 | if (this.isBeasy()) return false;
326 |
327 | if (!jobs.length) {
328 | onEnd('exec');
329 | return false;
330 | }
331 |
332 | for (var i = 1; i <= maxThreads; i++) {
333 | if (!applayJob()) break;
334 | else beasy = true;
335 | }
336 |
337 | // job exist, but not applayed (bad maxThreads \ applayJob)
338 |
339 | if (!this.isBeasy()) {
340 | onEnd('exec_fail');
341 | return false;
342 | }
343 |
344 | return true;
345 | }
346 |
347 | // data - page \ nik \ etc
348 |
349 | this.addJob = function(url, onLoad, data, requestCfg) {
350 |
351 | if (typeof onLoad !== 'function') {
352 | onLoad = false;
353 | }
354 |
355 | var job = {
356 | url : url,
357 | onLoad : onLoad,
358 | data : data,
359 | config : requestCfg ? requestCfg : false,
360 | };
361 |
362 | jobs[jobs.length] = job;
363 | return job;
364 | }
365 |
366 | constructor(cfg);
367 | }
--------------------------------------------------------------------------------
/extension/lib/kellyToolbar.js:
--------------------------------------------------------------------------------
1 | // todo readonly check on after delete
2 |
3 | function KellyToolbar(cfg) {
4 |
5 | var handler = this;
6 | handler.container = false;
7 | handler.cfg = {show : false, heartNewWindow : false, themeHidden : false, deselectBtn : false};
8 | handler.className = 'toolbar';
9 | handler.dom = {};
10 | handler.events = {
11 | onDisplayBlock : function(mode, action, oldMode) {
12 | handler.show(handler.cfg.userCfg.enabled && mode == 'fav' && action == 'show');
13 | },
14 | onUpdateFilteredData : function(displayedItems) {
15 | handler.show(handler.cfg.show);
16 | },
17 | }
18 |
19 | function constructor(cfg) {
20 |
21 | handler.container = cfg.container;
22 | handler.className = cfg.className;
23 | handler.cfg = cfg;
24 | handler.env = cfg.favController.getGlobal('env');
25 | handler.favController = cfg.favController;
26 | }
27 |
28 | function getCatListHtml(title, filter, logic) {
29 |
30 | var html = '';
31 | var db = handler.favController.getGlobal('fav');
32 |
33 | if (filter.length > 0) {
34 |
35 | html = '[' + title + '';
36 |
37 | if (filter.length == 1) {
38 | html += ' ' + KellyLoc.s('', 'toolbar_from_single_cat');
39 | } else {
40 | if (logic == 'and') html += ' ' + KellyLoc.s('', 'toolbar_from_and_cats');
41 | else html += ' ' + KellyLoc.s('', 'toolbar_from_or_cats');
42 | }
43 |
44 | html += ': ';
45 |
46 | for (var i = 0; i < filter.length; i++) {
47 | if (i >= 3) {
48 | html += '...';
49 | break;
50 | }
51 |
52 | var group = handler.favController.getStorageManager().getCategoryById(db, filter[i]);
53 | var name = group.name;
54 | if (name.length > 20) {
55 | name = name.substring(0, 20) + '...';
56 | }
57 |
58 | if (group.id > 0) html += (i > 0 ? ', ' : '') + '' + name + ' '; // todo - check - after sort - some unexist items adds to exclude filter
59 | }
60 |
61 | html += ']';
62 | }
63 |
64 | return html;
65 | }
66 |
67 | function updateStatesInfo() {
68 |
69 | var filters = handler.favController.getFilters();
70 | var html = '';
71 |
72 | if (!filters.readOnly) {
73 | html += '[' + KellyLoc.s('', 'toolbar_edit_mode') + ' ]';
74 | }
75 |
76 | if (filters.catFilters.length <= 0 && filters.catIgnoreFilters.length <= 0) {
77 | html += '[' + KellyLoc.s('', 'toolbar_cat_not_selected') + ']';
78 | } else {
79 | html += getCatListHtml(KellyLoc.s('', 'toolbar_selected_images'), filters.catFilters, filters.logic);
80 | if (filters.catFilters.length > 0) html += ' ';
81 | html += getCatListHtml(KellyLoc.s('', 'toolbar_deselected_images'), filters.catIgnoreFilters, filters.logic);
82 | }
83 |
84 | KellyTools.setHTMLData(handler.dom['catlist'], '' + html + ' ');
85 | }
86 |
87 | function initBlock(html, name) {
88 |
89 | handler.dom[name] = KellyTools.setHTMLData(handler.dom[name] ? handler.dom[name] : document.createElement('DIV'), html);
90 | handler.container.appendChild(handler.dom[name]);
91 | }
92 |
93 | function updateBlocksClass() {
94 |
95 | var className = handler.env.hostClass + ' ' + handler.className + ' ' + handler.className + '-' + (handler.cfg.userCfg.tiny ? 'tiny' : 'full');
96 | if (handler.cfg.userCfg.collapsed) className += ' ' + handler.className + '-collapsed';
97 | if (handler.cfg.show) className += ' ' + handler.className + '-shown';
98 |
99 | handler.dom['main'].className = className + ' ' + handler.className + '-main';
100 | handler.dom['helper-container'].className = className + ' ' + handler.className + '-helper-container';
101 | if (handler.cfg.deselectBtn || !handler.cfg.userCfg.tiny) handler.dom['helper-container'].className += ' ' + handler.className + '-helper-enabled';
102 | }
103 |
104 | this.init = function() {
105 |
106 | initBlock('\
107 |
\
108 | \
\
109 | ', 'helper-container');
110 |
111 | initBlock('\
112 | \
113 |
\
114 |
\
115 |
\
116 |
\
117 | ', 'main');
118 |
119 | var dom = ['deselect-wrap', 'catlist', 'theme', 'collapse', 'help'];
120 | for (var i = 0; i < dom.length; i++) {
121 | handler.dom[dom[i]] = handler.container.getElementsByClassName(handler.className + '-' + dom[i])[0];
122 | }
123 |
124 | handler.dom['help'].onclick = function() {
125 |
126 | if (handler.cfg.heartNewWindow) {
127 |
128 | KellyTools.getBrowser().runtime.sendMessage({method: "openTab", url : '/env/html/' + handler.env.profile + 'Downloader.html?tab=donate'}, function(request) {});
129 |
130 | } else {
131 | handler.setDeselectBtn(handler.cfg.deselectBtn); // reset state
132 | handler.favController.showAdditionsDialog('additions_donate');
133 | }
134 |
135 | return false;
136 | }
137 |
138 | handler.dom['collapse'].onclick = function() {
139 |
140 | handler.cfg.userCfg.collapsed = !handler.cfg.userCfg.collapsed;
141 | updateBlocksClass();
142 | handler.favController.save('cfg');
143 | }
144 |
145 | handler.dom['theme'].onclick = function() {
146 |
147 | var options = handler.favController.getGlobal('options');
148 | var delayUpdate = false;
149 |
150 | if (document.body.classList.contains(handler.env.className + '-dark')) {
151 |
152 | document.body.classList.remove(handler.env.className + '-dark');
153 | document.body.classList.add(handler.env.className + '-white');
154 | options.darkTheme = false;
155 |
156 | } else {
157 |
158 | document.body.classList.add(handler.env.className + '-dark');
159 | document.body.classList.remove(handler.env.className + '-white');
160 | options.darkTheme = true;
161 | }
162 |
163 | if (!document.getElementById(handler.className + '-dyn-css')) {
164 | KellyTools.getBrowser().runtime.sendMessage({method: "getResources", items : [options.darkTheme ? 'dark' : 'white']}, function(request) {
165 | if (!request || !request.data.loadedData) return false;
166 |
167 | KellyTools.addCss(handler.className + '-dyn-css', KellyTools.replaceAll(request.data.loadedData, '__BASECLASS__', handler.env.className), true);
168 | handler.favController.updateImageGrid();
169 | });
170 |
171 | delayUpdate = true;
172 | }
173 |
174 | if (!delayUpdate) handler.favController.updateImageGrid();
175 | handler.favController.save('cfg');
176 | }
177 |
178 | handler.setDeselectBtn(handler.cfg.deselectBtn);
179 | }
180 |
181 | this.setDeselectBtn = function(btn) {
182 |
183 | if (!handler.dom['main']) handler.init();
184 |
185 | handler.dom['deselect-wrap'].innerHTML = '';
186 | handler.cfg.deselectBtn = btn;
187 |
188 | if (!btn) return;
189 |
190 | KellyTools.setHTMLData(handler.dom['deselect-wrap'], '\
191 | \
192 | ' + KellyLoc.s('', btn.loc ? btn.loc : 'toolbar_deselect_all') + ' \
193 | ');
194 |
195 | handler.dom['deselect-all'] = document.getElementById(handler.className + '-deselect-all');
196 | handler.dom['deselect-all'].onclick = function(e) {
197 | return btn.callback(handler, this, e);
198 | }
199 | }
200 |
201 | this.show = function(visible) {
202 |
203 | if (!handler.cfg.userCfg.enabled) return false;
204 | if (!handler.dom['main']) handler.init();
205 |
206 | handler.cfg.show = visible;
207 | updateBlocksClass();
208 |
209 | if (handler.cfg.show) {
210 |
211 | if (handler.cfg.themeHidden) handler.dom['theme'].style.display = 'none';
212 | if (handler.cfg.userCfg.heartHidden) handler.dom['help'].style.display = 'none';
213 | if (handler.cfg.userCfg.tiny) handler.dom['catlist'].innerHTML = '';
214 | else updateStatesInfo();
215 | }
216 | }
217 |
218 | constructor(cfg);
219 | }
--------------------------------------------------------------------------------
/extension/lib/profiles/default.js:
--------------------------------------------------------------------------------
1 | // part of KellyFavItems extension
2 | // todo addEventListener
3 |
4 | function KellyProfileDefault() {
5 |
6 | var handler = this;
7 |
8 | this.hostList = [];
9 | this.webRequestsRules = false;
10 |
11 | this.profile = 'default';
12 | this.className = 'kelly-jr-ui'; // base class for every extension container \ element
13 |
14 | this.sidebarConfig = {
15 | topMax : 0,
16 | paddingTop : 0,
17 | nDisabled : -1, // 1 - sidebar not found or hidden (jras - sidebar can be hidden)
18 | };
19 |
20 | this.fav = false;
21 |
22 | /* imp, could be helpfull for set webreuqest rules, addition variables, depends on page environment. Unused in universal recorder */
23 |
24 | this.setLocation = function(location) {
25 |
26 | handler.location = {
27 | protocol : location.protocol,
28 | host : location.host,
29 | href : location.href,
30 | };
31 |
32 | handler.hostClass = handler.className + '-' + location.host.split('.').join("-");
33 | }
34 |
35 | // calls every time o request image link for download request or for show on page
36 |
37 | this.getImageDownloadLink = function(url, full, format) { return url; }
38 | this.getStaticImage = function(url) { return url; }
39 |
40 | this.getMainContainers = function() {
41 |
42 | // todo move create buttons methods from faitems core
43 |
44 | if (!handler.mContainers) {
45 | handler.mContainers = {
46 |
47 | // public
48 |
49 | body : document.getElementById('container'), // place where to put all dynamic absolute position elements
50 | siteContent : document.getElementById('contentinner'), // site main container
51 | favContent : false, // main extension container - image grid \ options block
52 | sideBar : false, // place where to put extension sidebar block (add post \ filters menu)
53 | menu : document.getElementById('submenu'), // currently used in kellyFavItems to create menu buttons
54 |
55 | // private
56 |
57 | sideBlock : document.getElementById('sidebar'), // helps to detect width of sideBar, only for updateSidebarPosition()
58 | };
59 |
60 | handler.mContainers.sideBar = handler.mContainers.body;
61 |
62 | if (handler.mContainers.siteContent) {
63 | handler.mContainers.favContent = document.createElement('div');
64 | handler.mContainers.favContent.className = handler.className + '-FavContainer ' + handler.hostClass;
65 | handler.mContainers.siteContent.parentNode.insertBefore(handler.mContainers.favContent, handler.mContainers.siteContent);
66 | }
67 |
68 | if (!handler.mContainers.favContent || !handler.mContainers.body) {
69 | KellyTools.log('getMainContainers : cant create containers, check selectors', KellyTools.E_ERROR);
70 | KellyTools.log(handler.mContainers, KellyTools.E_ERROR);
71 | return false;
72 | }
73 | }
74 |
75 | return handler.mContainers;
76 | }
77 |
78 | this.events = {
79 |
80 | /*
81 | calls when new cfg | items list loaded
82 |
83 | storage - current actual storage | loadType - cfg | items | false (both) | context - undefined (from any other method) | selectDB (from options page)
84 | if return true - prevent default callback
85 | */
86 |
87 | onStorageAfterload : function(storage, loadType, context) { return false; },
88 |
89 | /*
90 | calls on document.ready, or if getPosts find some data
91 | if return true prevent native init environment logic (initFormatPage -> InitWorktop)
92 | */
93 |
94 | onPageReady : function() { return false; },
95 |
96 | /*
97 | calls after extension resources is loaded
98 | if return true prevent native init worktop logic (image viewer initialization)
99 | */
100 |
101 | onInitWorktop : function() {return false; },
102 |
103 | onExtensionReady : function() {
104 | handler.sidebarConfig.topMax = handler.getMainContainers().siteContent.getBoundingClientRect().top;
105 |
106 | KellyTools.addEventPListener(window, "resize", updateSidebarPosition, '_fav_dialog');
107 | KellyTools.addEventPListener(window, "scroll", updateSidebarPosition, '_fav_dialog');
108 | },
109 |
110 | onSideBarShow : function(sideBarWrap, close) {
111 |
112 | if (!sideBarWrap) return;
113 |
114 | var siteSideBlock = handler.getMainContainers().sideBlock;
115 | if (siteSideBlock) {
116 | siteSideBlock.style.visibility = close ? 'visible' : 'hidden';
117 | siteSideBlock.style.opacity = close ? '1' : '0';
118 | }
119 |
120 | if (close) {
121 | sideBarWrap.style.top = '50px';
122 | return;
123 | }
124 |
125 | updateSidebarProportions(sideBarWrap);
126 | updateSidebarPosition();
127 | },
128 |
129 | onSideBarUpdate : updateSidebarPosition,
130 | onOptionsUpdate : function(refreshPosts) {},
131 | onDisplayBlock : function(mode, action, oldMode) {},
132 | onBeforeGoToFavPage : function(newPage) {},
133 | }
134 |
135 | function updateSidebarProportions(sideBarWrap) {
136 |
137 | if (sideBarWrap.className.indexOf('inline') !== -1) return;
138 | var filters = KellyTools.getElementByClass(sideBarWrap, handler.className + '-FiltersMenu');
139 | if (filters && filters.offsetHeight > 440 && filters.className.indexOf('calculated') == -1) {
140 |
141 | var filtersBlock = KellyTools.getElementByClass(sideBarWrap, handler.className + '-FiltersMenu-container');
142 |
143 | filtersBlock.style.maxHeight = '0';
144 | filtersBlock.style.overflow = 'hidden';
145 |
146 | var modalBox = KellyTools.getElementByClass(document, handler.className + '-ModalBox-main');
147 | modalBox.style.minHeight = '0';
148 |
149 | var modalBoxHeight = modalBox.getBoundingClientRect().height;
150 |
151 | var viewport = KellyTools.getViewport();
152 | if (viewport.screenHeight < modalBoxHeight + filters.offsetHeight + handler.sidebarConfig.paddingTop) {
153 | filtersBlock.style.maxHeight = (viewport.screenHeight - modalBoxHeight - handler.sidebarConfig.paddingTop - 44 - handler.sidebarConfig.paddingTop) + 'px';
154 | filtersBlock.style.overflowY = 'scroll';
155 |
156 | } else {
157 |
158 | filtersBlock.style.maxHeight = 'none';
159 | filtersBlock.style.overflow = 'auto';
160 | }
161 |
162 | filters.className += ' calculated';
163 | }
164 | }
165 |
166 | function updateSidebarPosition() {
167 |
168 | if (!handler.fav) return false;
169 |
170 | var sideBarWrap = handler.fav.getView('sidebar'), sideBlock = handler.getMainContainers().sideBlock;
171 | if (!sideBarWrap || sideBarWrap.className.indexOf('hidden') !== -1 || sideBarWrap.className.indexOf('inline') !== -1) return false;
172 |
173 | if (handler.sidebarConfig.nDisabled == -1) { // first time update position, validate sidebar block
174 |
175 | if (sideBlock && window.getComputedStyle(sideBlock).position == 'absolute') {
176 |
177 | KellyTools.log('Bad sidebar position', 'updateSidebarPosition');
178 | handler.sidebarConfig.nDisabled = 1;
179 | }
180 |
181 | if (!sideBlock) {
182 | KellyTools.log('Sidebar not found', 'updateSidebarPosition');
183 | handler.sidebarConfig.nDisabled = 1;
184 | }
185 |
186 | if (handler.sidebarConfig.nDisabled == 1) {
187 |
188 | var collapseButton = KellyTools.getElementByClass(sideBarWrap, handler.className + '-sidebar-collapse');
189 | if (collapseButton) {
190 | KellyTools.classList('add', collapseButton, handler.className + '-active');
191 | }
192 | }
193 | }
194 |
195 | if (handler.sidebarConfig.nDisabled == 1) sideBlock = false;
196 |
197 | var scrollTop = KellyTools.getScrollTop(), scrollLeft = KellyTools.getScrollLeft();
198 | var topMax = handler.sidebarConfig.topMax, top = topMax;
199 |
200 | if (!handler.fav.sideBarLock && handler.sidebarConfig.paddingTop + scrollTop > top) top = handler.sidebarConfig.paddingTop + scrollTop;
201 |
202 | sideBarWrap.style.top = top + 'px';
203 |
204 | if (sideBlock) {
205 |
206 | var widthBase = 0, sideBlockBounds = sideBlock.getBoundingClientRect();
207 | sideBarWrap.style.right = 'auto';
208 | sideBarWrap.style.left = Math.round(sideBlockBounds.left + scrollLeft) + 'px';
209 | sideBarWrap.style.width = Math.round(sideBlockBounds.width + widthBase) + 'px';
210 |
211 | } else {
212 | sideBarWrap.style.right = '20px';
213 | sideBarWrap.style.left = 'auto';
214 | }
215 | }
216 |
217 | /* imp */
218 |
219 | this.setFav = function(fav) {
220 | handler.fav = fav;
221 | }
222 |
223 | /* not imp */
224 |
225 | this.getRecomendedDownloadSettings = function() {
226 |
227 | var browser = KellyTools.getBrowserName();
228 | return {
229 | transportMethod : browser == 'opera' || browser == 'chrome' ? KellyGrabber.TRANSPORT_BLOB : KellyGrabber.TRANSPORT_BLOBBASE64,
230 | requestMethod : KellyGrabber.REQUEST_FETCH
231 | }
232 | }
233 | }
234 |
235 | KellyProfileDefault.getInstance = function() {
236 | if (typeof KellyProfileDefault.self == 'undefined') {
237 | KellyProfileDefault.self = new KellyProfileDefault();
238 | }
239 |
240 | return KellyProfileDefault.self;
241 | }
--------------------------------------------------------------------------------
/extension/lib/profiles/recorder.js:
--------------------------------------------------------------------------------
1 | // part of KellyFavItems extension
2 |
3 | var KellyProfileRecorder = new Object();
4 | KellyProfileRecorder.create = function() {
5 |
6 | KellyProfileRecorder.self = new KellyProfileDefault();
7 | var handler = KellyProfileRecorder.self;
8 |
9 | handler.profile = 'recorder';
10 | handler.extLinks = {
11 |
12 | pp : 'https://github.com/NC22/KellyC-Image-Downloader/wiki/%5BPP%5D-Privacy-Policy',
13 | github : 'https://github.com/NC22/KellyC-Image-Downloader',
14 |
15 | install_ff : 'https://addons.mozilla.org/ru/firefox/addon/kellyc-favorites/',
16 | install_chrome : 'https://chrome.google.com/webstore/detail/kellyc-image-downloader/mbhkdmjolnhcppnkldbdfaomeabjiofm?hl=en',
17 | install_edge : 'https://microsoftedge.microsoft.com/addons/detail/kellyc-image-downloader/dgjfegjceojpbngijkaekoihllhhdocn',
18 | install_opera : 'https://kdl.catface.ru/ru/install-opera/',
19 |
20 | author : 'https://nradiowave.catface.ru/',
21 | };
22 | }
23 |
24 | KellyProfileRecorder.getInstance = function() {
25 | if (typeof KellyProfileRecorder.self == 'undefined') KellyProfileRecorder.create();
26 | return KellyProfileRecorder.self;
27 | }
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/9gag.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilter9Gag = new Object();
2 | KellyRecorderFilter9Gag.manifest = {host : '9gag.com', detectionLvl : ['imagePreview', 'imageOriginal', 'imageByDocument']};
3 |
4 | KellyRecorderFilter9Gag.parseImagesDocByDriver = function(handler, data) {
5 |
6 | if (handler.url.indexOf('9gag.com') == -1) return;
7 |
8 | var pageDataRegExp = /window\._config[\s]*=[\s]*JSON\.parse\(\"\{([\s\S]*)\}\}\"\)\;[\s]*\<\/script/g
9 | var pageData = pageDataRegExp.exec(data.thread.response);
10 |
11 | if (pageData) {
12 |
13 | try {
14 |
15 | var gagData = KellyTools.parseJSON('{' + pageData[1] + '}}', true, true); // parse escaped json
16 | var bigImage = false;
17 | console.log(gagData);
18 |
19 | for (var imageId in gagData.data.post.images) {
20 | if (!bigImage || bigImage.width < gagData.data.post.images[imageId].width) {
21 | bigImage = gagData.data.post.images[imageId];
22 | }
23 | }
24 |
25 | if (bigImage) {
26 | handler.imagesPool.push({
27 | relatedSrc : [ bigImage.url ],
28 | relatedGroups : [['imageOriginal']]
29 | });
30 | }
31 |
32 | } catch (e) {
33 | console.log(e);
34 | }
35 | }
36 |
37 | return true;
38 | }
39 |
40 | KellyPageWatchdog.validators.push({
41 | url : '9gag.com',
42 | host : '9gag.com',
43 | patterns : [
44 | ['img-9gag-fun', 'imagePreview'],
45 | ]
46 | });
47 |
48 | KellyPageWatchdog.filters.push(KellyRecorderFilter9Gag);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/README.md:
--------------------------------------------------------------------------------
1 | Documentation available on official extension page
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/_validators.js:
--------------------------------------------------------------------------------
1 | KellyPageWatchdog.validators.push({url : 'catface.ru', host : 'catface.ru', patterns : [['catface.ru/get', 'imageOriginal'], ['/userfiles/media/previews', 'imagePreview'] ]});
2 | KellyPageWatchdog.validators.push({url : 'patreon.com', host : 'patreon.com', patterns : [['patreon-media/p/post/', 'imageAny']]});
3 | KellyPageWatchdog.validators.push({url : 'pinterest.', host : ['pinterest.com', 'pinterest.ru'], patterns : [['/originals/', 'imageOriginal'], ['i.pinimg.com/474x', 'imagePreview'], ['i.pinimg.com/736x', 'imagePreview'], ['i.pinimg.com/236x', 'imagePreview']]});
4 |
5 | KellyPageWatchdog.validators.push({url : 'fanbox.cc', host : 'fanbox.cc', patterns : [['fanbox/public/images', 'imagePreview']]});https://thumbs.hentai-foundry.com/thumb.php?pid=768245&size=1550
6 | KellyPageWatchdog.validators.push({url : '2ch.hk', host : '2ch.hk', patterns : [[new RegExp('//2ch.hk/[a-zA-Z0-9]+/src/'), 'imageOriginal'], [new RegExp('//2ch.hk/[a-zA-Z0-9]+/thumb/'), 'imagePreview']]});
7 | KellyPageWatchdog.validators.push({url : 'furaffinity.net', host : 'furaffinity.net', patterns : [[new RegExp('//t.[a-zA-Z0-9]+.net/[0-9]+@[0-9]+\-[0-9]+.[a-zA-Z]+'), 'imagePreview'], ['/profile_banner', 'imageTrash'], [new RegExp('//d.[a-zA-Z0-9]+.net/art'), 'imageByDocument']]});
8 | // KellyPageWatchdog.validators.push({url : 'exhentai.org', host : 'exhentai.org', patterns : [[new RegExp('//exhentai.org/t/[0-9]+@[0-9]+\-[0-9]+.[a-zA-Z]+'), 'imagePreview'], ['/h/', 'imageByDocument']]});
9 | KellyPageWatchdog.validators.push({url : 'sankakucomplex.com', host : ['sankakucomplex.com', 'chan.sankakucomplex.com'], patterns : [['data/preview/', 'imagePreview'], ['data/sample/', 'imageByDocument']]});
10 |
11 | KellyPageWatchdog.validators.push({url : 'boards.4channel.org', host : ['4chan.org', '4channel.org'], patterns : [[new RegExp('//i.4cdn.org/[a-zA-Z0-9]+/[0-9]+s\\.[a-zA-Z]+'), 'imagePreview'], [new RegExp('//i.4cdn.org/[a-zA-Z0-9]+/[0-9]+\\.[a-zA-Z]+'), 'imageOriginal']]});
12 |
13 | KellyPageWatchdog.filtersHelp.push({host : 'vk.com', link : 'https://www.youtube.com/watch?v=XpXhwndWYyg', loc : 'help_vk'});
14 | KellyPageWatchdog.filtersHelp.push({host : 'twitter.com', link : 'https://www.youtube.com/watch?v=x1-kqKMnMmA', loc : 'help_twitter'});
15 | KellyPageWatchdog.filtersHelp.push({host : 'pixiv.net', link : 'https://www.youtube.com/watch?v=1Nivs34BDbI', loc : 'help_pixiv'});
16 | KellyPageWatchdog.filtersHelp.push({host : 'pinterest.com', link : 'https://www.youtube.com/watch?v=ImKbC_1Oz8c', loc : 'help_pinterest'});
17 | KellyPageWatchdog.filtersHelp.push({host : 'deviantart.com', link : 'https://www.youtube.com/watch?v=O3JDEhig0P8', loc : 'help_deviantart'});
18 | KellyPageWatchdog.filtersHelp.push({host : 'instagram.com', link : 'https://www.youtube.com/watch?v=RenHptOCnh8', loc : 'help_instagram'});
19 | KellyPageWatchdog.filtersHelp.push({host : 'pikabu.ru', link : 'https://www.youtube.com/watch?v=QNm4L8hmoDs', loc : 'help_pikabu'});
20 | KellyPageWatchdog.filtersHelp.push({host : '9gag.com', link : 'https://youtu.be/bTU7FpUzeao', loc : 'help_9gag'});
21 | KellyPageWatchdog.filtersHelp.push({host : 'reddit.com', link : 'https://youtu.be/PLkNKM7Trlw', loc : 'help_reddit'});
22 |
23 | KellyPageWatchdog.bannedUrls.push('counter.yadro.ru', 'bat.bing.com', 'ads.adfox');
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/artstation.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterArtstation = new Object();
2 | KellyRecorderFilterArtstation.manifest = {host : 'artstation.com', detectionLvl : ['imageAny', 'imageByDocument']};
3 | KellyRecorderFilterArtstation.parseImagesDocByDriver = function(handler, data) {
4 |
5 | if (handler.url.indexOf('artstation') != -1) {
6 |
7 | var meta = data.thread.response.match(/<\meta name="twitter:image"([\s\S]*?)>/g); // todo - parse graphql data to detect multiple images for one publication
8 | if (meta) {
9 | var image = KellyTools.val('' + meta[0] + '
', 'html').querySelector('meta[name="twitter:image"]');
10 | if (image) image = image.getAttribute('content');
11 | if (image) handler.imagesPool.push({relatedSrc : [image]});
12 | }
13 |
14 | data.thread.response = '';
15 | }
16 | }
17 |
18 | KellyPageWatchdog.validators.push({url : 'artstation', patterns : [['assets/images', 'imageAny']]});
19 | KellyPageWatchdog.filters.push(KellyRecorderFilterArtstation);
20 |
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/bsky.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterBsky = new Object();
2 | KellyRecorderFilterBsky.manifest = {host : 'bsky.app', detectionLvl : ['imageAny', 'imagePreview', 'imageOriginal']};
3 |
4 | KellyRecorderFilterBsky.addItemByDriver = function(handler, data) {
5 | if (handler.url.indexOf('bsky.app') != -1 && data.el.tagName == 'IMG' && data.el.src.indexOf('img/feed_') != -1) {
6 | console.log(' KellyRecorderFilterBsky tst');
7 | handler.addSingleSrc(data.item, data.el.src, 'addSrcFromAttributes-src', data.el, 'imagePreview');
8 | handler.addSingleSrc(data.item, data.el.src.replace('feed_thumbnail', 'feed_fullsize'), 'addSrcFromAttributes-src', data.el, 'imageOriginal');
9 |
10 | return data.item.relatedSrc.length > 0 ? handler.addDriverAction.ADD : handler.addDriverAction.SKIP;
11 | }
12 | }
13 |
14 | KellyPageWatchdog.validators.push({url : 'bsky.app', patterns : [['cdn.bsky.app', 'imageAny']]});
15 | KellyPageWatchdog.filters.push(KellyRecorderFilterBsky);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/deviantart.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterDA = new Object();
2 | KellyRecorderFilterDA.manifest = {host : 'deviantart.com', detectionLvl : ['imagePreview', 'imageAny', 'imageByDocument']};
3 |
4 | KellyRecorderFilterDA.addItemByDriver = function(handler, data) {
5 |
6 | if (handler.url.indexOf('deviantart') == -1) return;
7 |
8 | if (data.el.tagName == 'IMG' && data.el.src.indexOf('images-wixmp') != -1) {
9 |
10 |
11 | handler.addSrcFromAttributes(data.el, data.item);
12 | if (data.item.relatedSrc.length <= 0) return handler.addDriverAction.SKIP;
13 |
14 | var relatedDoc = KellyTools.getParentByTag(data.el, 'A');
15 | if (!relatedDoc) return handler.addDriverAction.SKIP;
16 |
17 | data.item.relatedDoc = relatedDoc.href;
18 |
19 | data.item.relatedGroups = [];
20 | data.item.relatedGroups[data.item.relatedSrc.length-1] = ['imagePreview'];
21 |
22 | return (data.item.relatedSrc.length > 0 && data.item.relatedDoc) ? handler.addDriverAction.ADD : handler.addDriverAction.SKIP;
23 | }
24 | }
25 |
26 | KellyRecorderFilterDA.parseImagesDocByDriver = function(handler, data) {
27 |
28 | if (handler.url.indexOf('deviantart') != -1) {
29 |
30 | try {
31 |
32 | var begin = 'window.__INITIAL_STATE__ = JSON.parse("', end = '")';
33 |
34 | KellyRecorderFilterDA.strDa = data.thread.response.substring(data.thread.response.lastIndexOf(begin) + begin.length);
35 | KellyRecorderFilterDA.strDa = KellyRecorderFilterDA.strDa.substring(0, KellyRecorderFilterDA.strDa.indexOf(end));
36 |
37 | // todo - DA currently have some JSON stringified blocks inside comments sections and this brock parse sintax
38 |
39 | var da = JSON.parse(JSON.parse('"' + KellyRecorderFilterDA.strDa.replace(/\\'/g, '') + '"'));
40 |
41 | KellyRecorderFilterDA.lastDa = da;
42 |
43 | for (var daName in da['@@entities']['deviation']) {
44 | var deviation = da['@@entities']['deviation'][daName], mediaQuality = false;
45 |
46 | if (data.thread.job.url.indexOf(deviation.url) == -1) continue; // check is data image related to preview image by relatedDoc url
47 |
48 | deviation['media']['types'].forEach(function(type) { // select biggest resolution
49 | if ((!mediaQuality || type.h > mediaQuality.h) && type.h) mediaQuality = type;
50 | });
51 |
52 | var url = '', baseUrl = deviation['media']['baseUri'];
53 | if (baseUrl[baseUrl.length-1] == '/') baseUrl = baseUrl.substr(0, baseUrl.length-1); // double delimiter simbol / is not allowed
54 |
55 | if (mediaQuality && mediaQuality.c) { // formating url depending on media type
56 |
57 | url = mediaQuality.c.replace('', deviation['media']['prettyName'] ? deviation['media']['prettyName'] : '');
58 |
59 | if (url[0] != '/') url = '/' + url;
60 | url = baseUrl + url;
61 |
62 | } else if (mediaQuality && mediaQuality.t == 'gif') {
63 |
64 | url = mediaQuality.b;
65 |
66 | } else if (mediaQuality && mediaQuality.t == 'fullview') {
67 |
68 | url = baseUrl;
69 | }
70 |
71 | if (url) handler.imagesPool.push({relatedSrc : [url + '?token=' + deviation['media']['token'][0]]});
72 | }
73 |
74 | } catch (e) {
75 | handler.docLoader.lastError = 'DeviantArt page JSON parse (KellyRecorderFilterDA.strDa) error in url : ' + handler.url + ' ';
76 | console.log(e);
77 | }
78 |
79 | data.thread.response = '';
80 | return true;
81 | }
82 | }
83 |
84 | KellyPageWatchdog.validators.push({url : 'deviantart', patterns : [['images-wixmp', 'imageAny']]});
85 | KellyPageWatchdog.filters.push(KellyRecorderFilterDA);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/discord.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterDiscord = new Object();
2 | KellyRecorderFilterDiscord.manifest = {host : 'discord.com', detectionLvl : ['imageOriginal', 'imagePreview']};
3 |
4 | KellyRecorderFilterDiscord.addItemByDriver = function(handler, data) {
5 |
6 | if (handler.url.indexOf('discord.com') == -1) return;
7 |
8 | if (data.el.tagName == 'DIV' && data.el.className.indexOf('imageWrapper') != -1) {
9 |
10 | var video = data.el.getElementsByTagName('VIDEO');
11 | if (video.length > 0) {
12 |
13 | handler.addSingleSrc(data.item, video[0].src, 'addSrcFromAttributes-src', video[0], ['imageOriginal']);
14 | handler.addSingleSrc(data.item, video[0].getAttribute('poster'), 'addSrcFromAttributes-src', data.el, ['imagePreview']);
15 |
16 | } else {
17 |
18 | var full = data.el.getElementsByTagName('A');
19 | var preview = data.el.getElementsByTagName('IMG');
20 |
21 | if (preview.length > 0) {
22 | handler.addSingleSrc(data.item, preview[0].src, 'addSrcFromAttributes-src', preview[0], ['imagePreview']);
23 | } else return handler.addDriverAction.SKIP;
24 |
25 | if (full.length > 0 && full[0].getAttribute('data-safe-src')) {
26 |
27 | var url = new URL(full[0].getAttribute('data-safe-src'));
28 | url.searchParams.delete('height');
29 | url.searchParams.delete('width');
30 |
31 | handler.addSingleSrc(data.item, url.href, 'addSrcFromAttributes-src', full[0], ['imageOriginal']);
32 |
33 | }
34 |
35 | }
36 |
37 | if (data.item.relatedSrc.length <= 0) return handler.addDriverAction.SKIP;
38 | return handler.addDriverAction.ADD;
39 | }
40 | }
41 |
42 | // KellyPageWatchdog.validators.push({url : 'discord.', host : 'discord.com', patterns : [['cdn.discordapp.com/attachments', 'imageOriginal'], ['&height=', 'imagePreview']]});
43 |
44 | KellyPageWatchdog.filters.push(KellyRecorderFilterDiscord);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/ehentai.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterEHentai = new Object();
2 | KellyRecorderFilterEHentai.manifest = {host : ['e-hentai.org', 'exhentai.org'], detectionLvl : ['imagePreview', 'imageByDocument']};
3 | KellyRecorderFilterEHentai.previewTileMap = false;
4 | KellyRecorderFilterEHentai.canvas = document.createElement('canvas');
5 | KellyRecorderFilterEHentai.previewImagesPool = [];
6 |
7 | KellyRecorderFilterEHentai.getPreviewTileBounds = function(el) {
8 | return { x : Math.abs(parseInt(el.style.backgroundPositionX)), y : parseInt(el.style.backgroundPositionY), width : parseInt(el.style.width), height : parseInt(el.style.height) }
9 | }
10 |
11 | KellyRecorderFilterEHentai.addItemByDriver = function(handler, data) {
12 |
13 | if (handler.url.indexOf('e-hentai.org') == -1 && handler.url.indexOf('exhentai.org') == -1) return;
14 |
15 | if (data.el.tagName != 'DIV') return;
16 |
17 | var previewUrl = handler.getSrcFromStyle(data.el);
18 | if (previewUrl && data.el.style.backgroundPosition) {
19 |
20 | var relatedDoc = KellyTools.getElementByTag(data.el, 'A'), bounds = KellyRecorderFilterEHentai.getPreviewTileBounds(data.el);
21 | if (!relatedDoc) return handler.addDriverAction.SKIP;
22 |
23 | handler.addSingleSrc(data.item, 'data:image-tilemap;' + previewUrl + ',' + bounds.x + ',' + bounds.y + ',' + bounds.width + ',' + bounds.height, 'addSrcFromStyle', data.el, 'imagePreview');
24 | data.item.relatedDoc = relatedDoc.href;
25 |
26 | console.log(data.item);
27 |
28 | return handler.addDriverAction.ADD;
29 | }
30 |
31 | }
32 |
33 | KellyRecorderFilterEHentai.parseImagesDocByDriver = function(handler, data) {
34 |
35 | if (handler.url.indexOf('e-hentai.org') != -1 && typeof data.thread.response == 'string') {
36 |
37 | var parser = new DOMParser();
38 | data.thread.loadDoc = parser.parseFromString(data.thread.response, 'text/html');
39 |
40 | var image = data.thread.loadDoc.querySelector('#i3 img');
41 | if (image){
42 | handler.imagesPool.push({relatedSrc : [image.getAttribute('src')], relatedGroups : []});
43 | return true;
44 | }
45 |
46 | data.thread.response = '';
47 | return;
48 | }
49 |
50 | }
51 |
52 | KellyPageWatchdog.filters.push(KellyRecorderFilterEHentai);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/flickr.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterFlickr = new Object();
2 | KellyRecorderFilterFlickr.manifest = {host : 'flickr.com', detectionLvl : ['imagePreview', 'imageOriginal', 'imageByDocument']};
3 | KellyRecorderFilterFlickr.addItemByDriver = function(handler, data) {
4 |
5 | if (handler.url.indexOf('flickr.com') == -1) return;
6 |
7 | if (data.el.className && data.el.classList.contains('photo-list-photo-view')) {
8 |
9 | handler.addSrcFromStyle(data.el, data.item, 'imagePreview');
10 | var relatedDoc = data.el.getElementsByTagName('A');
11 | if (relatedDoc.length > 0) data.item.relatedDoc = relatedDoc[0].href;
12 |
13 | return (data.item.relatedSrc.length > 0 && data.item.relatedDoc) ? handler.addDriverAction.ADD : handler.addDriverAction.SKIP;
14 | }
15 | }
16 |
17 | KellyRecorderFilterFlickr.parseImagesDocByDriver = function(handler, data) {
18 |
19 | if (handler.url.indexOf('flickr.com') == -1 && data.thread.response) return;
20 |
21 | var parser = new DOMParser();
22 | var doc = parser.parseFromString(data.thread.response, 'text/html');
23 | var src = doc.querySelector('[property="og:image"]').getAttribute('content');
24 | if (src) handler.imagesPool.push({relatedSrc : [src]});
25 |
26 | return true;
27 | }
28 |
29 | KellyPageWatchdog.filters.push(KellyRecorderFilterFlickr);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/hfoundry.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterHFoundry = new Object();
2 | KellyRecorderFilterHFoundry.manifest = {host : 'hentai-foundry.com', detectionLvl : ['imagePreview', 'imageByDocument']};
3 | KellyRecorderFilterHFoundry.parseImagesDocByDriver = function(handler, data) {
4 |
5 | if (handler.url.indexOf('hentai-foundry.com') == -1) return;
6 | if (!data.thread.response) return;
7 |
8 | var parser = new DOMParser();
9 | var doc = parser.parseFromString(data.thread.response, 'text/html');
10 | var image = doc.querySelector('#picBox img');
11 |
12 | if (image) {
13 |
14 | var imageSrc = false;
15 |
16 | if (image.getAttribute('onclick') && image.getAttribute('onclick').indexOf('resize_message') != -1) {
17 |
18 | imageSrc = image.getAttribute('onclick').split("'")[1];
19 |
20 | if (!imageSrc) imageSrc = image.getAttribute('src');
21 | else imageSrc = 'https:' + imageSrc;
22 |
23 | } else {
24 |
25 | imageSrc = image.getAttribute('src');
26 | }
27 |
28 | var item = {relatedSrc : []};
29 | handler.addSingleSrc(item, imageSrc, 'addSrcFromAttributes-src', image, []);
30 |
31 | console.log(item);
32 | if (item.relatedSrc.length > 0) handler.imagesPool.push(item);
33 |
34 | } else {
35 | handler.docLoader.lastError = 'Original image not found in document : ' + handler.url + ' ';
36 | }
37 |
38 | data.thread.response = '';
39 | return true;
40 | }
41 |
42 | KellyPageWatchdog.validators.push({url : 'hentai-foundry.', host : 'hentai-foundry.com', patterns : [['thumb.php', 'imagePreview'], [new RegExp('pictures.hentai-foundry.com/[0-9a-zA-Z]+\/'), 'imageByDocument']]});
43 | KellyPageWatchdog.filters.push(KellyRecorderFilterHFoundry);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/instagram.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterInstagram = new Object();
2 | KellyRecorderFilterInstagram.manifest = {host : 'instagram.com', detectionLvl : ['imageAny', 'imageByDocument']};
3 | KellyRecorderFilterInstagram.addItemByDriver = function(handler, data) {
4 |
5 | if (handler.url.indexOf('instagram') != -1 && data.el.tagName == 'IMG' && data.el.src.indexOf('instagram.com') != -1) {
6 |
7 | var link = KellyTools.getParentByTag(data.el, 'A'); // match pattern https://www.instagram.com/p/CJdsKX4DEDK/
8 | if (link && link.getAttribute('href').length > 4) data.item.relatedDoc = link.href;
9 |
10 | if (data.item.relatedDoc && KellyTools.getParentByTag(data.el, 'ARTICLE')) {
11 | var cat = 'inst_post';
12 | } else {
13 | var cat = 'inst_story';
14 | if (link || !KellyTools.getParentByTag(data.el, 'SECTION')) return handler.addDriverAction.SKIP;
15 | }
16 |
17 | handler.addSingleSrc(data.item, data.el.getAttribute('src'), 'addSrcFromAttributes-src', data.el, cat);
18 |
19 | if ( data.item.relatedSrc.length > 0 ) {
20 | return handler.addDriverAction.ADD;
21 | } else {
22 | return handler.addDriverAction.SKIP;
23 | }
24 | }
25 | }
26 |
27 | KellyRecorderFilterInstagram.getBestQuality = function(instImageItem, imagesPool) {
28 |
29 | var mediaQuality = false;
30 | instImageItem.image_versions2.candidates.forEach(function(srcData) {
31 | if (!mediaQuality || srcData.width > mediaQuality.width) mediaQuality = srcData;
32 | });
33 |
34 | if (mediaQuality) imagesPool.push({relatedSrc : [mediaQuality.url]});
35 | }
36 |
37 | KellyRecorderFilterInstagram.onBeforeParseImagesDocByDriver = function(handler, data) {
38 |
39 | if (data.thread.instagramRequest) return;
40 |
41 | if (handler.url.indexOf('instagram') != -1){
42 |
43 | var appIdRegExp = /\"appId\"\:\"([0-9]+)?\"/;
44 | var mediaIdRegExp = /\"media_id\"\:\"([0-9]+)?\"/;
45 |
46 | var pageData = {
47 | appId : appIdRegExp.exec(data.thread.response),
48 | mediaId : mediaIdRegExp.exec(data.thread.response),
49 | };
50 |
51 | if (pageData.appId) pageData.appId = pageData.appId[1].trim();
52 | if (pageData.mediaId) pageData.mediaId = pageData.mediaId[1].trim();
53 |
54 | if (!pageData.appId || !pageData.mediaId) {
55 |
56 | console.log('[Instagram] : bad media info');
57 | console.log(pageData);
58 | return;
59 | } else {
60 |
61 | console.log(pageData);
62 | }
63 |
64 | var requestUrl = 'https://i.instagram.com/api/v1/media/' + pageData.mediaId + '/info/';
65 |
66 | data.thread.instagramRequest = 'mediaRequest';
67 |
68 | return {requestUrl : requestUrl, cfg : {method : 'GET', xHeaders : {'x-ig-app-id' : pageData.appId}, responseType : 'json'}};
69 | }
70 | }
71 |
72 | // debug throw KellyDPage.aDProgress.docLoader.parser
73 |
74 | KellyRecorderFilterInstagram.parseImagesDocByDriver = function(handler, data) {
75 |
76 | if (data.thread.instagramRequest == 'mediaRequest' && handler.url.indexOf('instagram') != -1){
77 |
78 | try {
79 | handler.lastThreadJson = data.thread.response;
80 | if (!handler.lastThreadJson) {
81 |
82 | handler.lastThreadJson = {error : 'empty page data. check regexp'};
83 | return;
84 | }
85 |
86 | var item = handler.lastThreadJson.items[0];
87 | if (item.carousel_media) {
88 | item.carousel_media.forEach(function(instImageItem) {
89 | KellyRecorderFilterInstagram.getBestQuality(instImageItem, handler.imagesPool);
90 | });
91 | } else {
92 | KellyRecorderFilterInstagram.getBestQuality(handler.lastThreadJson.items[0], handler.imagesPool);
93 | }
94 |
95 | } catch (e) {
96 |
97 | handler.lastThreadJson = {error : 'parse fail'};
98 | console.log(e);
99 | }
100 |
101 | return true;
102 | }
103 | }
104 |
105 | KellyRecorderFilterInstagram.onStartRecord = function(handler, data) {
106 | if (handler.url.indexOf('instagram') == -1) return;
107 |
108 | handler.additionCats = {
109 | inst_story : {name : 'Stories & Misc', selected : 80, color : '#b7dd99'},
110 | inst_post : {name : 'Publication Preview', selected : 90, color : '#b7dd99'},
111 | };
112 | }
113 |
114 | KellyPageWatchdog.validators.push({url : 'instagram', patterns : [['cdninstagram', 'imageAny']]}); // may be use regexp pattern for previews - [any symbol]instagram[any symbol]640x640[any]
115 | KellyPageWatchdog.filters.push(KellyRecorderFilterInstagram);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/joyreactor.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterJoyreactor = new Object();
2 | KellyRecorderFilterJoyreactor.manifest = {host : ['joyreactor.cc', 'reactor.cc'], detectionLvl : ['imagePreview', 'imageOriginal']};
3 | KellyRecorderFilterJoyreactor.addItemByDriver = function(handler, data) {
4 |
5 | if (handler.url.indexOf('reactor.cc') != -1) {
6 |
7 | if (data.el.tagName == 'IMG' && data.el.src && (data.el.src.indexOf('pics/post') != -1 || data.el.src.indexOf('pics/comment') != -1)) {
8 | var src = data.el.src.indexOf('full') == -1 ? data.el.src : data.el.src.replace('full/', '');
9 | if (src.indexOf('static') != -1) {
10 | src = src.replace('static/', '');
11 | src = src.substr(0, src.lastIndexOf('.') + 1) + 'gif';
12 | }
13 |
14 | var groups = ['imageOriginal'];
15 | if (src.indexOf('comment/') != -1) groups.push('Comment');
16 | else if (src.indexOf('post/') != -1) groups.push('Post');
17 |
18 | handler.addSingleSrc(data.item, src, 'addSrcFromAttributes-src', data.el, 'imagePreview');
19 | handler.addSingleSrc(data.item, src.replace('comment/', 'comment/full/').replace('post/', 'post/full/'), 'addSrcFromAttributes-src', data.el, groups);
20 |
21 | return data.item.relatedSrc.length > 0 ? handler.addDriverAction.ADD : handler.addDriverAction.SKIP;
22 | } else if (data.el.tagName == 'A' && data.el.href && data.el.href.indexOf('/full/') != -1) {
23 |
24 | return handler.addDriverAction.SKIP;
25 | }
26 |
27 | }
28 | }
29 |
30 | KellyPageWatchdog.filters.push(KellyRecorderFilterJoyreactor);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/kemonoparty.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterKemono = new Object();
2 | KellyRecorderFilterKemono.manifest = {host : ['kemono.su', 'kemono.party', 'coomer.party'], detectionLvl : ['imagePreview', 'imageOriginal', 'imageByDocument']};
3 |
4 | KellyRecorderFilterKemono.parseImagesDocByDriver = function(handler, data) {
5 |
6 | if (handler.url.indexOf('kemono.su') == -1 && handler.url.indexOf('kemono.party') == -1 && handler.url.indexOf('coomer.party') == -1 && data.thread.response) return;
7 |
8 | var parser = new DOMParser();
9 | var doc = parser.parseFromString(data.thread.response, 'text/html');
10 |
11 | var images = doc.querySelectorAll('.fileThumb');
12 | for (var i = 0; i < images.length; i++) {
13 | var href = KellyTools.getLocationFromUrl(images[i].href).pathname;
14 | if (href && href.indexOf('/data/') === 0) handler.imagesPool.push({relatedSrc : ['https://' + handler.hostname + href]});
15 | }
16 |
17 | data.thread.response = '';
18 | return true;
19 | }
20 |
21 | KellyRecorderFilterKemono.onStartRecord = function(handler, data) {
22 | if (handler.url.indexOf('kemono.su') == -1 && handler.url.indexOf('kemono.party') == -1) return;
23 | handler.allowDuplicates = true;
24 | }
25 |
26 | KellyPageWatchdog.validators.push({
27 | url : 'kemono.party',
28 | host : 'kemono.party',
29 | patterns : [['/thumbnail/', 'imagePreview']]
30 | });
31 |
32 | KellyPageWatchdog.validators.push({
33 | url : 'kemono.su',
34 | host : 'kemono.su',
35 | patterns : [['/thumbnail/', 'imagePreview']]
36 | });
37 |
38 | KellyPageWatchdog.validators.push({
39 | url : 'coomer.party',
40 | host : 'coomer.party',
41 | patterns : [['/thumbnail/', 'imagePreview']]
42 | });
43 |
44 | KellyPageWatchdog.filters.push(KellyRecorderFilterKemono);
45 |
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/pixiv.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterPixiv = new Object();
2 | KellyRecorderFilterPixiv.manifest = {host : 'pixiv.net', detectionLvl : ['imagePreview', 'imageByDocument']};
3 | KellyRecorderFilterPixiv.artworkReg = {id : new RegExp('[0-9]+'), url : new RegExp('/artworks/[0-9]+')};
4 |
5 | KellyRecorderFilterPixiv.validateByDriver = function(handler, data) {
6 |
7 | if (handler.url.indexOf('pixiv.net') == -1 || data.item.relatedSrc.length != 1 || !data.item.relatedDoc) return;
8 | if (data.item.relatedDoc.match(KellyRecorderFilterPixiv.artworkReg.url) === null) return;
9 |
10 | var artworkId = KellyRecorderFilterPixiv.artworkReg.id.exec(data.item.relatedDoc)[0];
11 | data.item.relatedDoc = 'https://www.pixiv.net/ajax/illust/' + artworkId + '/pages' + '##FETCH_RULES##method=GET&responseType=json';
12 | data.item.relatedGroups = [['imagePreview']];
13 |
14 | // https://www.pixiv.net/ajax/illust/112344306/ugoira_meta
15 | // https://github.com/Stuk/jszip/tree/main
16 | // https://github.com/thenickdude/webm-writer-js
17 |
18 | // animations on pixiv has different design and require zip archivator libraries to work with
19 | }
20 |
21 | KellyRecorderFilterPixiv.parseImagesDocByDriver = function(handler, data) {
22 |
23 | if (handler.url.indexOf('pixiv.net') != -1) {
24 | if (typeof data.thread.response == 'object' && !data.thread.response.error && typeof data.thread.response.body == 'object') {
25 |
26 | for (var i = 0; i < data.thread.response.body.length; i++) {
27 | // todo - take width \ height and put this data to relatedBounds pool - implement kellyLoadDocControll to accept this data
28 | var urls = data.thread.response.body[i].urls;
29 | if (urls && (urls.regular || urls.original)) handler.imagesPool.push({relatedSrc : [urls.original ? urls.original : urls.regular]});
30 | }
31 |
32 | } else console.log('bad response - cant recognize object - check KellyDPage.aDProgress.docLoader.parser.lastThreadReport');
33 |
34 | data.thread.response = '';
35 | return true;
36 |
37 | }
38 | }
39 |
40 | KellyPageWatchdog.filters.push(KellyRecorderFilterPixiv);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/reddit.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterReddit = new Object();
2 | KellyRecorderFilterReddit.manifest = {host : 'reddit.com', detectionLvl : ['imageOriginal', 'imagePreview', 'imageByDocument']};
3 |
4 | KellyRecorderFilterReddit.addItemByDriver = function(handler, data) {
5 |
6 | if (handler.url.indexOf('reddit.com') == -1) return;
7 |
8 | if (data.el.getAttribute('data-click-id') == 'image') return handler.addDriverAction.SKIP;
9 |
10 | if (data.el.getAttribute('data-testid') && data.el.getAttribute('data-testid') == 'post-container') {
11 |
12 | // bookmarks, upvoted, downvoted etc.
13 |
14 | var preview = false;
15 | if (handler.url.indexOf('/user/') != -1 || handler.url.indexOf('/search/?q=') != -1) {
16 |
17 | preview = data.el.querySelector('[data-click-id="image"]');
18 | if (preview) {
19 | handler.addSrcFromStyle(preview, data.item, 'reddit_post');
20 | }
21 | }
22 |
23 | if (!preview) {
24 | preview = data.el.querySelector('[data-click-id="media"] img');
25 | if (preview) {
26 | handler.addSingleSrc(data.item, preview.src, 'addSrcFromAttributes-src', preview, 'reddit_post');
27 | }
28 | }
29 |
30 | // console.log(data.item);
31 | // console.log(handler.lastError);
32 | // console.log(preview);
33 |
34 | var link = data.el.querySelector('a[data-click-id="body"]');
35 | if (link) {
36 | data.item.relatedDoc = link.href;
37 | } else {
38 | data.item.relatedSrc = [];
39 | }
40 |
41 | return data.item.relatedSrc.length > 0 ? handler.addDriverAction.ADD : handler.addDriverAction.SKIP;
42 | }
43 | }
44 |
45 | KellyRecorderFilterReddit.parseImagesDocByDriver = function(handler, data) {
46 |
47 | if (handler.url.indexOf('reddit.com') == -1) return;
48 |
49 | var pageDataRegExp = /window\.___r[\s]*=[\s]*\{([\s\S]*)\}\}\;\<\/script/g
50 | var pageData = pageDataRegExp.exec(data.thread.response);
51 |
52 | if (pageData) {
53 |
54 | try {
55 | var redditData = JSON.parse('{' + pageData[1] + '}}');
56 |
57 | for (var postId in redditData.posts.models) {
58 |
59 | var model = redditData.posts.models[postId];
60 |
61 | if (model.media.mediaMetadata ) {
62 | for (var mediaId in model.media.mediaMetadata) {
63 |
64 | if (model.media.mediaMetadata[mediaId].s) {
65 |
66 | handler.imagesPool.push({
67 | relatedSrc : [ model.media.mediaMetadata[mediaId].s.u ],
68 | relatedGroups : [['reddit_orig']]
69 | });
70 | }
71 |
72 | }
73 |
74 | } else if (redditData.posts.models[postId].media.content) {
75 | handler.imagesPool.push({
76 | relatedSrc : [ redditData.posts.models[postId].media.content ],
77 | relatedGroups : [['reddit_orig']]
78 | });
79 | }
80 |
81 | break;
82 | }
83 |
84 | } catch (e) {
85 | console.log(e);
86 | }
87 | }
88 |
89 | return true;
90 | }
91 |
92 | KellyRecorderFilterReddit.onStartRecord = function(handler, data) {
93 | if (handler.url.indexOf('reddit.com') == -1) return;
94 |
95 | handler.additionCats = {
96 | reddit_post : {name : 'Post (Preview)', color : '#b7dd99', selected : 90},
97 | reddit_orig : {name : 'Post media', color : '#b7dd99', selected : 91},
98 | };
99 | }
100 |
101 | KellyPageWatchdog.validators.push({
102 | url : 'reddit.com',
103 | host : 'reddit.com',
104 | patterns : [
105 | ['preview.redd.it/award_images', 'imageTrash'],
106 | ['preview.redd.it', 'imagePreview'],
107 | ['i.imgur.com', 'imagePreview'],
108 | ['i.redd.it', 'imagePreview'],
109 | ]
110 | });
111 |
112 |
113 | KellyPageWatchdog.filters.push(KellyRecorderFilterReddit);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/twitter.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterTwitter = new Object();
2 | KellyRecorderFilterTwitter.manifest = {host : 'twitter.com', detectionLvl : ['imageAny', 'imagePreview', 'imageOriginal']};
3 |
4 | KellyRecorderFilterTwitter.onInitLocation = function(handler, data) {
5 | if (handler.url.indexOf('twitter') != -1) {
6 |
7 | handler.getConfig(function(options, source) {
8 |
9 |
10 | if (options.tweekTwitter18W) {
11 |
12 | KellyRecorderFilterTwitter.observer = new MutationObserver(function(mutations) {
13 |
14 | for (var i = 0; i < mutations.length; i++) {
15 |
16 | if (mutations[i].addedNodes.length > 0) {
17 |
18 | for (var b = 0; b < mutations[i].addedNodes.length; b++) {
19 |
20 | if (mutations[i].addedNodes[b] != handler.recorder &&
21 | mutations[i].addedNodes[b].nodeType == Node.ELEMENT_NODE) {
22 |
23 | KellyRecorderFilterTwitter.delayUpdate18wTweek();
24 | }
25 | }
26 |
27 | }
28 | }
29 | });
30 |
31 | KellyRecorderFilterTwitter.observer.observe(document.body, {childList: true, subtree: true});
32 | KellyRecorderFilterTwitter.delayUpdate18wTweek();
33 | }
34 | });
35 | }
36 | }
37 |
38 | KellyRecorderFilterTwitter.update18wTweek = function() {
39 |
40 | var getParentByTag = function(el, tagName) {
41 | var parent = el;
42 | if (!tagName) return false;
43 |
44 | tagName = tagName.toLowerCase();
45 |
46 | while (parent && parent.tagName.toLowerCase() != tagName) {
47 | parent = parent.parentElement;
48 | }
49 |
50 | return parent;
51 | }
52 |
53 | var findSignMainBlock = function(el) {
54 | var parent = el;
55 |
56 | while (parent) {
57 | parent = parent.parentElement;
58 | if (parent.children.length == 1) {
59 | var testBlock = parent.children[0].querySelector('div[role="button"]') ;
60 | if (testBlock) return parent;
61 | }
62 | }
63 |
64 | return false;
65 | }
66 |
67 |
68 | if (window.location.href.indexOf('/media') != -1) {
69 |
70 | var posts = document.querySelectorAll('li[role="listitem"]');
71 |
72 | for(var i=0; i < posts.length; i++) {
73 |
74 | var post = posts[i];
75 | var containers = post.getElementsByTagName('DIV');
76 |
77 | for (var b = 0; b < containers.length; b++) {
78 |
79 | if (containers[b].children.length == 2 && containers[b].children[0].tagName == 'DIV' && containers[b].children[1].tagName == 'DIV') {
80 | var style = window.getComputedStyle(containers[b].children[0]);
81 | if (style.filter && style.filter.indexOf('blur') != -1 && style.filter.indexOf('blur(0px)') == -1) {
82 | containers[b].children[0].style.filter = 'blur(0px)';
83 | containers[b].children[1].style.display = 'none';
84 | break;
85 | }
86 | }
87 | }
88 | }
89 |
90 | } else {
91 |
92 | var posts = document.getElementsByTagName('ARTICLE');
93 | for(var i=0; i < posts.length; i++) {
94 |
95 | var post = posts[i];
96 | var containers = post.getElementsByTagName('DIV');
97 | var warningEl = false;
98 |
99 | for (var b = 0; b < containers.length; b++) {
100 |
101 | if (!warningEl) {
102 | var sign = containers[b].getElementsByTagName('SPAN');
103 |
104 | if (sign.length > 0 && sign[0].innerHTML.indexOf('sensitive') != -1) {
105 |
106 | warningEl = findSignMainBlock(sign[0]);
107 | warningEl.style.display = 'none';
108 | }
109 | }
110 |
111 | var style = window.getComputedStyle(containers[b]);
112 | if (style.filter && style.filter.indexOf('blur') != -1) {
113 | containers[b].style.filter = 'blur(0px)';
114 | //containers[b].style.webkitFilter = '';
115 | //console.log(containers[b]);
116 | }
117 | }
118 | }
119 |
120 | }
121 | }
122 |
123 | KellyRecorderFilterTwitter.delayUpdate18wTweek = function() {
124 |
125 | if (KellyRecorderFilterTwitter.timer18wTweek) {
126 | clearTimeout(KellyRecorderFilterTwitter.timer18wTweek);
127 | }
128 |
129 |
130 | KellyRecorderFilterTwitter.timer18wTweek = setTimeout(KellyRecorderFilterTwitter.update18wTweek, 300);
131 | }
132 |
133 | KellyRecorderFilterTwitter.addItemByDriver = function(handler, data) {
134 | if (handler.url.indexOf('twitter') != -1 && data.el.tagName == 'IMG' && data.el.src.indexOf('name=') != -1 && data.el.src.indexOf('pbs.twimg.com/media') != -1) {
135 |
136 | handler.addSingleSrc(data.item, data.el.src, 'addSrcFromAttributes-src', data.el, 'imagePreview');
137 | handler.addSingleSrc(data.item, data.el.src.split('&name=')[0] + '&name=orig', 'addSrcFromAttributes-src', data.el, 'imageOriginal');
138 |
139 | return data.item.relatedSrc.length > 0 ? handler.addDriverAction.ADD : handler.addDriverAction.SKIP;
140 | }
141 | }
142 |
143 | KellyPageWatchdog.validators.push({url : 'twitter', patterns : [['twimg.com/media', 'imageAny']]});
144 | KellyPageWatchdog.filters.push(KellyRecorderFilterTwitter);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/vk.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterVK = new Object();
2 | KellyRecorderFilterVK.manifest = {host : 'vk.com', detectionLvl : ['imagePreview', 'imageByDocument']};
3 |
4 | KellyRecorderFilterVK.addHelperGroups = function(data) {
5 | if (data.item.relatedSrc.length <= 0) return;
6 | if (KellyTools.getParentByClass(data.el, 'reply_content')) {
7 | data.item.relatedGroups[0].push('vk_comment');
8 | } else {
9 | data.item.relatedGroups[0].push('vk_post');
10 | }
11 | }
12 |
13 | KellyRecorderFilterVK.addItemByDriver = function(handler, data) {
14 |
15 | // Document file separate page \ GIFS on page
16 |
17 | if (handler.url.indexOf('vk.com') != -1 && (data.el.classList.contains('page_doc_photo_href') || data.el.classList.contains('page_post_thumb_unsized'))) {
18 |
19 | data.item.relatedDoc = data.el.href;
20 | if (KellyTools.getParentByClass(data.el, 'reply_content')) {
21 | data.item.relatedDoc += '##FETCH_RULES##mark_comment=1';
22 | }
23 |
24 | if (data.el.getAttribute('data-thumb')) handler.addSingleSrc(data.item, data.el.getAttribute('data-thumb'), 'addSrcFromAttributes-src', data.el, 'imagePreview');
25 | else handler.addSrcFromStyle(data.el, data.item, 'imagePreview');
26 |
27 | KellyRecorderFilterVK.addHelperGroups(data);
28 |
29 | return data.item.relatedSrc.length > 0 ? handler.addDriverAction.ADD : handler.addDriverAction.SKIP;
30 |
31 | // Album items \ feed
32 |
33 | } else if (handler.url.indexOf('vk.com') != -1 && (data.el.getAttribute('data-id') || data.el.getAttribute('data-photo-id'))) {
34 |
35 | if (data.el.children[0] && data.el.children[0].tagName == 'IMG') {
36 | handler.addSingleSrc(data.item, data.el.children[0].src, 'addSrcFromAttributes-src', data.el.children[0], 'imagePreview');
37 | } else {
38 | handler.addSrcFromStyle(data.el, data.item, 'imagePreview');
39 | }
40 |
41 | if (data.item.relatedSrc.length <= 0) return handler.addDriverAction.SKIP;
42 |
43 | // Mobile
44 |
45 | if (data.el.getAttribute('data-src_big')) {
46 | handler.addSingleSrc(data.item, data.el.getAttribute('data-src_big'), 'addSrcFromAttributes-src', data.el, 'imageOriginal');
47 | return handler.addDriverAction.ADD;
48 | }
49 |
50 | // Desktop - OLD \ NEW design
51 |
52 | var query = '&module=feed', params = [], marks = '', relatedDoc = data.el.tagName == 'A' ? data.el : KellyTools.getElementByTag(data.el, 'A');
53 |
54 | if (data.el.getAttribute('data-list-id')) {
55 |
56 | params = [data.el.getAttribute('data-photo-id'), data.el.getAttribute('data-list-id')];
57 |
58 | } else {
59 |
60 | if (!relatedDoc || !relatedDoc.getAttribute('onclick') || relatedDoc.getAttribute('onclick').indexOf('showPhoto') == -1) return handler.addDriverAction.SKIP;
61 |
62 | var paramList = relatedDoc.getAttribute('onclick').split('{')[0], regexpParam = /[\'\"]([-A-Za-z0-9_]+)[\'\"]/g, match = null;
63 |
64 | while((match = regexpParam.exec(paramList)) !== null) { params.push(match[1]); }
65 |
66 | }
67 |
68 | if (params.length > 1) {
69 | if (params[1].indexOf('wall-') != -1) query = '&module=public&list=' + params[1];
70 | else if (params[1].indexOf('mail') != -1) query = '&module=im&list=' + params[1];
71 | else if (params[1]) query = '&module=feed&list=' + params[1];
72 | } else if (params.length <= 0) return handler.addDriverAction.SKIP;
73 |
74 | if (KellyTools.getParentByClass(data.el, 'reply_content')) {
75 | marks += '&mark_comment=1';
76 | }
77 |
78 | KellyRecorderFilterVK.addHelperGroups(data);
79 |
80 | data.item.relatedDoc = 'https://vk.com/al_photos.php?act=show&al=1&al_ad=0&dmcah=' + query + '&photo=' + params[0];
81 | data.item.relatedDoc += '##FETCH_RULES##method=POST&responseType=json&contentType=application/x-www-form-urlencoded&xRequestedWith=XMLHttpRequest' + marks;
82 |
83 | return handler.addDriverAction.ADD;
84 | }
85 | }
86 |
87 | KellyRecorderFilterVK.onStartRecord = function(handler, data) {
88 | if (handler.url.indexOf('vk.com') == -1) return;
89 |
90 | handler.additionCats = {
91 | vk_comment : {name : 'Comment', color : '#b7dd99'},
92 | vk_post : {name : 'Post', color : '#b7dd99'},
93 | };
94 | }
95 |
96 | KellyRecorderFilterVK.parseImagesDocByDriver = function(handler, data) {
97 | if (handler.url.indexOf('vk.com') != -1 && typeof data.thread.response == 'object' && handler.url.indexOf('photo=') != -1) {
98 |
99 | var photoId = handler.url.split('photo=');
100 | photoId = photoId.length == 2 ? photoId[1] : false;
101 |
102 | var findSrc = function(response) {
103 | if (!response) return;
104 |
105 | if (typeof response['id'] != 'undefined' && response['id'] == photoId) {
106 | if (typeof response['w_src'] != 'undefined') return response['w_src'];
107 | else if (typeof response['y_src'] != 'undefined') return response['y_src'];
108 | else if (typeof response['z_src'] != 'undefined') return response['z_src'];
109 | else if (typeof response['x_src'] != 'undefined') return response['x_src'];
110 | else return;
111 | }
112 |
113 | for (var name in response) {
114 | if (typeof response[name] == 'object') {
115 | var result = findSrc(response[name]);
116 | if (result) return result;
117 | }
118 | }
119 | }
120 |
121 | var image = findSrc(data.thread.response);
122 | if (image) handler.imagesPool.push({relatedSrc : [image], relatedGroups : data.thread.rules.indexOf('mark_comment=1') != -1 ? [['vk_comment']] : []});
123 |
124 | data.thread.response = '';
125 | return true;
126 |
127 | } else if (handler.url.indexOf('vk.com/doc') != -1 && typeof data.thread.response == 'string' && handler.url.indexOf('hash=') != -1) {
128 |
129 | data.thread.loadDoc = KellyTools.val(KellyTools.validateHtmlDoc(data.thread.response), 'html');
130 | var image = data.thread.loadDoc.querySelector('center img');
131 | if (image) handler.imagesPool.push({relatedSrc : [image.getAttribute('src')], relatedGroups : data.thread.rules.indexOf('mark_comment=1') != -1 ? [['vk_comment']] : []});
132 |
133 | data.thread.response = '';
134 | return true;
135 | }
136 | }
137 |
138 | KellyPageWatchdog.filters.push(KellyRecorderFilterVK);
--------------------------------------------------------------------------------
/extension/lib/recorder/filters/yandex.js:
--------------------------------------------------------------------------------
1 | KellyRecorderFilterYandex = new Object();
2 | KellyRecorderFilterYandex.manifest = {host : 'yandex.ru', detectionLvl : ['imageOriginal', 'imagePreview']};
3 | KellyRecorderFilterYandex.addItemByDriver = function(handler, data) {
4 |
5 | if (handler.url.indexOf('yandex.ru') != -1) {
6 |
7 | if (data.el.classList.contains('serp-item__thumb') && data.el.tagName == 'IMG' && data.el.src) {
8 |
9 | var orig = KellyTools.getParentByClass(data.el, 'serp-item');
10 | if (!orig || !orig.getAttribute('data-bem')) return;
11 |
12 | var origImage = false;
13 | try {
14 | var origData = JSON.parse(orig.getAttribute('data-bem'));
15 | origImage = origData['serp-item']['img_href'];
16 | } catch(e) {
17 | return;
18 | }
19 |
20 | if (!origImage) return;
21 |
22 | data.item.referrer = KellyTools.getLocationFromUrl(origImage).host;
23 |
24 | handler.addSingleSrc(data.item, data.el.src, 'addSrcFromAttributes-src', data.el, 'imagePreview');
25 | handler.addSingleSrc(data.item, origImage, 'addSrcFromAttributes-src', data.el, 'imageOriginal');
26 |
27 | return data.item.relatedSrc.length > 0 ? handler.addDriverAction.ADD : handler.addDriverAction.SKIP;
28 | }
29 | }
30 | }
31 |
32 | KellyPageWatchdog.filters.push(KellyRecorderFilterYandex);
--------------------------------------------------------------------------------
/extension/lib/recorder/kellyEDRecorder.js:
--------------------------------------------------------------------------------
1 | var KellyEDRecorder = new Object;
2 | KellyEDRecorder.cacheEnabled = false;
3 | KellyEDRecorder.recorder = {};
4 |
5 | // todo - save recorder state cache for manifest v3
6 |
7 | KellyEDRecorder.getDefaultRecorder = function() {
8 | return {
9 | images : [], // array of founded images, could be collected from various tabs - see kellyPageWatchdog (imagesPool = []) for object description
10 | record : false, // is recording enabled
11 | cats : {}, // array of category objects that extends KellyDPage.cats
12 | host : false, // used as profile name only, images[] could be taken from various hosts and contain different [referrer]
13 | url : false, // used as profile name only
14 | srcs : [], // list of all added relatedSrc strings during record process, to prevent dublicates
15 | };
16 | }
17 |
18 | KellyEDRecorder.loadState = function() {
19 | KellyEDispetcher.api.storage.local.get('kelly_cache_recorder', function(response) {
20 |
21 | var result = 'OK';
22 | if (KellyEDispetcher.api.runtime.lastError) {
23 | result = KellyEDispetcher.api.runtime.lastError.message;
24 | }
25 |
26 | if (!response || response === null || !response['kelly_cache_recorder'] || typeof response['kelly_cache_recorder'].srcs == 'undefined') {
27 | result = 'Bad storage item - Reset';
28 | response['kelly_cache_recorder'] = KellyEDRecorder.getDefaultRecorder();
29 | }
30 |
31 | KellyEDRecorder.recorder = response['kelly_cache_recorder'];
32 | KellyTools.log('[loadState] [' + result + ']', 'KellyEDRecorder');
33 | });
34 | }
35 |
36 | // base64 items can be very heavy, calc max size ?
37 |
38 | KellyEDRecorder.saveState = function() {
39 |
40 | KellyEDispetcher.api.storage.local.set({'kelly_cache_recorder' : KellyEDRecorder.recorder}, function() {
41 |
42 | var result = 'OK';
43 | if (KellyEDispetcher.api.runtime.lastError) {
44 | result = KellyEDispetcher.api.runtime.lastError.message;
45 | }
46 |
47 | KellyTools.log('[saveState] [' + result + ']', 'KellyEDRecorder');
48 | });
49 | }
50 |
51 | KellyEDRecorder.init = function() {
52 |
53 | KellyEDRecorder.cacheEnabled = KellyTools.getManifestVersion() > 2 ? true : false;
54 | if (KellyEDRecorder.cacheEnabled) KellyEDRecorder.loadState();
55 |
56 | KellyEDispetcher.events.push({onMessage : KellyEDRecorder.onMessage});
57 | }
58 |
59 | KellyEDRecorder.onMessage = function(dispetcher, data) {
60 |
61 | var response = data.response; // default response array {senderId : 'dispetcher', error : '', method : request.method,}
62 | var request = data.request;
63 | var callback = function (cacheUpdate) {
64 |
65 | if (cacheUpdate && KellyEDRecorder.cacheEnabled) KellyEDRecorder.saveState();
66 | if (data.callback) data.callback(response);
67 |
68 | return true;
69 | }
70 |
71 | if (request.method == 'addRecord') {
72 |
73 | response.imagesNum = 0;
74 |
75 | if (request.clean) { // start record and skip check recording state
76 |
77 | KellyEDRecorder.recorder = KellyEDRecorder.getDefaultRecorder();
78 |
79 | } else if (!KellyEDRecorder.recorder.record) { // add if recording
80 |
81 | response.error = 'Record is not enabled';
82 | return callback();
83 | }
84 |
85 | if (request.host && !KellyEDRecorder.recorder.host) {
86 |
87 | KellyEDRecorder.recorder.host = request.host;
88 | KellyEDRecorder.recorder.url = request.url;
89 | }
90 |
91 | KellyTools.log('[addRecord] : images : ' + request.images.length + ' | cats : ' + (request.cats ? Object.keys(request.cats).length : 'not setted'));
92 |
93 | // addition categories information (color \ name etc.)
94 |
95 | if (request.cats) {
96 |
97 | for (var k in request.cats) {
98 |
99 | if (typeof KellyEDRecorder.recorder.cats[k] == 'undefined') {
100 |
101 | KellyEDRecorder.recorder.cats[k] = request.cats[k];
102 | }
103 | }
104 | }
105 |
106 | if (request.images) {
107 |
108 | for (var i = 0; i < request.images.length; i++) {
109 |
110 | var validatedSrc = [], validatedGroups = [];
111 |
112 | for (var srcIndex = 0; srcIndex < request.images[i].relatedSrc.length; srcIndex++) {
113 |
114 | if (KellyEDRecorder.recorder.srcs.indexOf(request.images[i].relatedSrc[srcIndex]) != -1) {
115 |
116 | if (!request.allowDuplicates) continue;
117 | // console.log('skip ' + request.images[i].relatedSrc[srcIndex]);
118 |
119 | } else {
120 |
121 | KellyEDRecorder.recorder.srcs.push(request.images[i].relatedSrc[srcIndex]);
122 | }
123 |
124 | validatedSrc.push(request.images[i].relatedSrc[srcIndex]);
125 | if (request.images[i].relatedGroups && request.images[i].relatedSrc[srcIndex]) validatedGroups[srcIndex] = request.images[i].relatedGroups[srcIndex];
126 | }
127 |
128 | if (validatedSrc.length > 0) {
129 |
130 | request.images[i].relatedSrc = validatedSrc;
131 |
132 | if (validatedGroups.length > 0) request.images[i].relatedGroups = validatedGroups;
133 | else delete request.images[i].relatedGroups;
134 |
135 | KellyEDRecorder.recorder.images.push(request.images[i]);
136 | } else {
137 | // console.log('skip, no new images');
138 | // console.log(KellyEDRecorder.recorder.images[i]);
139 | }
140 | }
141 | }
142 |
143 | // todo - skip save state for zero
144 | response.imagesNum = KellyEDRecorder.recorder.images.length;
145 | return callback(true);
146 |
147 | } else if (request.method == 'getRecord') {
148 |
149 | if (!KellyEDRecorder.recorder || !KellyEDRecorder.recorder.images) {
150 | KellyEDRecorder.recorder = KellyEDRecorder.getDefaultRecorder();
151 | }
152 |
153 | response.images = KellyEDRecorder.recorder.images;
154 | response.cats = KellyEDRecorder.recorder.cats;
155 | response.url = KellyEDRecorder.recorder.url;
156 | response.host = KellyEDRecorder.recorder.host;
157 |
158 | return callback();
159 |
160 | } else if (request.method == 'startRecord') {
161 |
162 | response.isRecorded = true;
163 |
164 | KellyEDRecorder.recorder = KellyEDRecorder.getDefaultRecorder();
165 | KellyEDRecorder.recorder.record = true;
166 |
167 | return callback(true);
168 |
169 | } else if (request.method == 'stopRecord') {
170 |
171 | if (request.clean) KellyEDRecorder.recorder = KellyEDRecorder.getDefaultRecorder();
172 |
173 | response.isRecorded = false;
174 | response.imagesNum = KellyEDRecorder.recorder.images.length;
175 | KellyEDRecorder.recorder.record = false;
176 |
177 | return callback(true);
178 |
179 | } else if (request.method == 'isRecorded') {
180 |
181 | response.isRecorded = KellyEDRecorder.recorder.record ? true : false;
182 | response.imagesNum = 0;
183 |
184 | if (response.isRecorded) response.imagesNum = KellyEDRecorder.recorder.images.length;
185 |
186 | return callback();
187 | }
188 |
189 | return false;
190 | }
191 |
192 | KellyEDRecorder.init();
--------------------------------------------------------------------------------
/extension/manifest.v2.all.json:
--------------------------------------------------------------------------------
1 | {
2 | "content_scripts": [ {
3 | "run_at": "document_start",
4 | "js": [
5 | "widget/kellyTooltip.js",
6 | "widget/kellyTileGrid.js",
7 | "widget/kellyImageView.js",
8 | "lib/kellyLoc.js",
9 | "lib/kellyStorageManager.js",
10 | "lib/kellyThreadWork.js",
11 | "lib/kellyGrabber.js",
12 | "lib/kellyFastSave.js",
13 | "lib/kellyToolbar.js",
14 | "lib/kellyTools.js",
15 | "lib/kellyOptions.js",
16 | "lib/kellyAdditionsForm.js",
17 | "lib/kellyFavItems.js",
18 | "lib/profiles/joyreactor.js",
19 | "lib/profiles/joyreactor.unlock.js",
20 | "lib/profiles/topjoyreactor.js",
21 | "lib/recorder/kellyPageWatchdog.js",
22 | "lib/recorder/kellyLoadDocControll.js",
23 | "lib/recorder/kellyDPage.js",
24 | "lib/recorder/filters/artstation.js",
25 | "lib/recorder/filters/deviantart.js",
26 | "lib/recorder/filters/ehentai.js",
27 | "lib/recorder/filters/instagram.js",
28 | "lib/recorder/filters/joyreactor.js",
29 | "lib/recorder/filters/kemonoparty.js",
30 | "lib/recorder/filters/pixiv.js",
31 | "lib/recorder/filters/twitter.js",
32 | "lib/recorder/filters/vk.js",
33 | "lib/recorder/filters/flickr.js",
34 | "lib/recorder/filters/pikabu.js",
35 | "lib/recorder/filters/reddit.js",
36 | "lib/recorder/filters/bsky.js",
37 | "lib/recorder/filters/9gag.js",
38 | "lib/recorder/filters/hfoundry.js",
39 | "lib/recorder/filters/yandex.js",
40 | "lib/recorder/filters/discord.js",
41 | "lib/recorder/filters/_validators.js",
42 | "lib/profiles/default.js",
43 | "lib/profiles/recorder.js",
44 | "env/init/recorderFront.js",
45 | "env/init/joyreactorFront.js"
46 | ],
47 | "all_frames": false,
48 | "matches": [
49 | "http://*/*",
50 | "https://*/*"
51 | ]
52 | } ],
53 | "manifest_version" : 2,
54 | "version": "1.2.9.5",
55 | "name": "KellyC Image Downloader",
56 | "description": "__MSG_ext_description_recorder__",
57 | "icons": {
58 | "32": "env/img/icon32x32.png",
59 | "44": "env/img/icon44x44.png",
60 | "128": "env/img/icon128x128.png" },
61 | "author" : "nradiowave",
62 | "default_locale" : "en",
63 | "permissions": [
64 | "downloads",
65 | "storage",
66 | "tabs",
67 | "unlimitedStorage",
68 | "webRequest",
69 | "webRequestBlocking",
70 | ""
71 | ],
72 | "background": {
73 | "scripts": [
74 | "lib/kellyTools.js",
75 | "lib/kellyDispetcher.js",
76 | "env/init/background.js",
77 | "lib/profiles/joyreactor.unlock.d.js",
78 | "lib/recorder/kellyEDRecorder.js"
79 | ],
80 | "persistent": true
81 | },
82 | "options_ui": {
83 | "page": "env/html/recorderDownloader.html?tab=modules",
84 | "open_in_tab": true
85 | },
86 | "browser_action": {
87 | "default_popup": "env/html/recorderPopup.html",
88 | "default_icon": {
89 | "32": "env/img/icon32x32.png"
90 | }
91 | },
92 | "web_accessible_resources": [
93 | "env/css/*.css",
94 | "env/html/*.html",
95 | "env/dynamic/*.js"
96 | ]
97 | }
98 |
--------------------------------------------------------------------------------
/extension/manifest.v3.all.json:
--------------------------------------------------------------------------------
1 | {
2 | "content_scripts": [ {
3 | "run_at": "document_start",
4 | "js": [
5 | "widget/kellyTooltip.js",
6 | "widget/kellyTileGrid.js",
7 | "widget/kellyImageView.js",
8 | "lib/kellyLoc.js",
9 | "lib/kellyStorageManager.js",
10 | "lib/kellyThreadWork.js",
11 | "lib/kellyGrabber.js",
12 | "lib/kellyFastSave.js",
13 | "lib/kellyToolbar.js",
14 | "lib/kellyTools.js",
15 | "lib/kellyOptions.js",
16 | "lib/kellyAdditionsForm.js",
17 | "lib/kellyFavItems.js",
18 | "lib/profiles/joyreactor.js",
19 | "lib/profiles/joyreactor.unlock.js",
20 | "lib/profiles/topjoyreactor.js",
21 | "lib/recorder/kellyPageWatchdog.js",
22 | "lib/recorder/kellyLoadDocControll.js",
23 | "lib/recorder/kellyDPage.js",
24 | "lib/recorder/filters/artstation.js",
25 | "lib/recorder/filters/deviantart.js",
26 | "lib/recorder/filters/ehentai.js",
27 | "lib/recorder/filters/instagram.js",
28 | "lib/recorder/filters/joyreactor.js",
29 | "lib/recorder/filters/kemonoparty.js",
30 | "lib/recorder/filters/pixiv.js",
31 | "lib/recorder/filters/twitter.js",
32 | "lib/recorder/filters/vk.js",
33 | "lib/recorder/filters/flickr.js",
34 | "lib/recorder/filters/pikabu.js",
35 | "lib/recorder/filters/reddit.js",
36 | "lib/recorder/filters/bsky.js",
37 | "lib/recorder/filters/9gag.js",
38 | "lib/recorder/filters/hfoundry.js",
39 | "lib/recorder/filters/yandex.js",
40 | "lib/recorder/filters/discord.js",
41 | "lib/recorder/filters/_validators.js",
42 | "lib/profiles/default.js",
43 | "lib/profiles/recorder.js",
44 | "env/init/recorderFront.js",
45 | "env/init/joyreactorFront.js"
46 | ],
47 | "matches": ["*://*/*"]
48 | } ],
49 | "host_permissions": ["*://*/*"],
50 | "manifest_version" : 3,
51 | "version": "1.2.9.5",
52 | "name": "KellyC Image Downloader",
53 | "description": "__MSG_ext_description_recorder__",
54 | "icons": {
55 | "32": "env/img/icon32x32.png",
56 | "44": "env/img/icon44x44.png",
57 | "128": "env/img/icon128x128.png" },
58 | "author" : "nradiowave",
59 | "default_locale" : "en",
60 | "permissions": [
61 | "downloads",
62 | "storage",
63 | "webRequest",
64 | "declarativeNetRequest",
65 | "tabs",
66 | "unlimitedStorage"
67 | ],
68 | "background": {
69 | "service_worker": "background.js"
70 | },
71 | "options_ui": {
72 | "page": "env/html/recorderDownloader.html?tab=modules",
73 | "open_in_tab": true
74 | },
75 | "action": {
76 | "default_popup": "env/html/recorderPopup.html",
77 | "default_icon": {
78 | "32": "env/img/icon32x32.png"
79 | }
80 | },
81 | "web_accessible_resources": [{
82 | "resources": ["env/css/*.css", "env/html/*.html", "env/dynamic/*.js"],
83 | "matches": ["*://*/*"],
84 | "extension_ids": []
85 | }]
86 | }
--------------------------------------------------------------------------------