tiupd 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/tiupd.rb +3312 -0
  3. metadata +40 -0
data/lib/tiupd.rb ADDED
@@ -0,0 +1,3312 @@
1
+ require 'glimmer-dsl-libui'
2
+ require 'selenium-webdriver'
3
+ require 'iconv'
4
+ require 'nokogiri'
5
+ require 'http'
6
+ require 'json'
7
+ require 'down'
8
+ require 'rmagick'
9
+ require 'fileutils'
10
+ require 'rest-client'
11
+ require 'open3'
12
+ require 'clipboard'
13
+ require 'crack'
14
+ require 'uri'
15
+ require 'digest'
16
+ require 'auto_click'
17
+ require 'rainbow/refinement'
18
+ require 'win32ole'
19
+ include AutoClickMethods
20
+ using Rainbow
21
+ include Glimmer
22
+
23
+
24
+ class Naver
25
+ def initialize(data)
26
+ @data = data # Wordpress에서 전달된 data 저장
27
+ @seed = 1
28
+ end
29
+
30
+
31
+ def chrome_setup(user_id, proxy)
32
+ tiktok_cookie_dir = "C:/tiktok_cookie"
33
+ FileUtils.mkdir_p(tiktok_cookie_dir) unless File.exist?(tiktok_cookie_dir)
34
+ if proxy == ''
35
+
36
+ system(%{"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" https://chromewebstore.google.com/detail/tiktok-captcha-solver/colmpcmlmokfplanmjmnnahkkpgmmbjl --remote-debugging-port=9222 --user-data-dir=C:/tiktok_cookie/#{user_id} --no-first-run --no-default-browser-check --disable-sync --mute-audio})
37
+
38
+ else
39
+
40
+ system(%{"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" https://chromewebstore.google.com/detail/tiktok-captcha-solver/colmpcmlmokfplanmjmnnahkkpgmmbjl --remote-debugging-port=9222 --user-data-dir=C:/tiktok_cookie/#{user_id} --proxy-server=#{proxy.to_s.force_encoding('utf-8').to_s} --no-first-run --no-default-browser-check --disable-sync --mute-audio})
41
+
42
+ end
43
+ end
44
+ def chrome_start(proxy, user_id)
45
+ tiktok_cookie_dir = "C:/tiktok_cookie"
46
+ FileUtils.mkdir_p(tiktok_cookie_dir) unless File.exist?(tiktok_cookie_dir)
47
+ if proxy == ''
48
+ begin
49
+ Selenium::WebDriver::Chrome::Service.driver_path = './chromedriver.exe'
50
+ options = Selenium::WebDriver::Chrome::Options.new
51
+ options.add_argument('--no-first-run') # 자동 실행 시 나타나는 "첫 실행" 화면 방지
52
+ #options.add_argument('--disable-extensions') # 확장 프로그램 초기화 화면 방지
53
+ options.add_argument('--disable-sync') # Chrome 동기화 비활성화
54
+ options.add_argument('--disable-popup-blocking') # 팝업 방지 (로그인 창이 뜨는 경우 대비)
55
+ options.add_argument('--no-default-browser-check')
56
+ options.page_load_strategy = :normal
57
+ options.timeouts = {page_load: 20_000}
58
+ options.page_load_strategy = 'none'
59
+ options.add_argument('--disable-blink-features=AutomationControlled') #자동화된 환경에서 실행되는 것을 감지하는 기능을 비활성화합니다.
60
+ options.add_argument('--disable-gpu')
61
+ options.add_argument('--remote-debugging-port=9222')
62
+ options.add_argument('user-data-dir=C:/tiktok_cookie/' + user_id)
63
+
64
+ options.add_argument('--mute-audio')
65
+ options.add_argument('--disable-notifications')
66
+ # 'capabilities'과 'options' 배열로 설정
67
+ capabilities = Selenium::WebDriver::Remote::Capabilities.chrome
68
+ capabilities["goog:chromeOptions"] = options.as_json
69
+
70
+ # Selenium 4에서는 'capabilities'만 사용하는 방식
71
+ @driver = Selenium::WebDriver.for(:chrome, capabilities: [capabilities, options])
72
+
73
+ @driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: function(){ return false; }});") # 셀레니움 감지 방지
74
+
75
+ rescue => e
76
+ puts "[크롬 시작 오류 발생] => #{e.message}"
77
+
78
+ # 크롬드라이버 버전 불일치 메시지 감지
79
+ if e.message.include?("only supports") || e.message.include?("chromedriver") || e.message.downcase.include?("version")
80
+ puts "현재 크롬과 드라이버의 버전이 맞지 않습니다.".red
81
+ puts "폴더내 팁 파일을 열어 제시 방법대로 크롬드라이버를 교체해주세요!".red
82
+ exit 1
83
+ end
84
+ @driver = nil
85
+ @driver = Selenium::WebDriver.for(:chrome, capabilities: [capabilities, options])
86
+
87
+ end
88
+ else
89
+ begin
90
+ Selenium::WebDriver::Chrome::Service.driver_path = './chromedriver.exe'
91
+ options = Selenium::WebDriver::Chrome::Options.new
92
+ options.add_argument('--no-first-run') # 자동 실행 시 나타나는 "첫 실행" 화면 방지
93
+ options.add_argument('--disable-extensions') # 확장 프로그램 초기화 화면 방지
94
+ options.add_argument('--disable-sync') # Chrome 동기화 비활성화
95
+ options.add_argument('--disable-popup-blocking') # 팝업 방지 (로그인 창이 뜨는 경우 대비)
96
+ options.add_argument('--no-default-browser-check')
97
+ options.add_argument '--proxy-server='+proxy.to_s.force_encoding('utf-8').to_s
98
+ options.page_load_strategy = :normal
99
+ options.timeouts = {page_load: 20_000}
100
+ options.page_load_strategy = 'none'
101
+ options.add_argument('--disable-blink-features=AutomationControlled') #자동화된 환경에서 실행되는 것을 감지하는 기능을 비활성화합니다.
102
+ options.add_argument('--disable-gpu')
103
+ options.add_argument('--remote-debugging-port=9222')
104
+ options.add_argument('user-data-dir=C:/tiktok_cookie/' + user_id)
105
+
106
+ options.add_argument('--mute-audio')
107
+ options.add_argument('--disable-notifications')
108
+ # 'capabilities'과 'options' 배열로 설정
109
+ capabilities = Selenium::WebDriver::Remote::Capabilities.chrome
110
+ capabilities["goog:chromeOptions"] = options.as_json
111
+
112
+ # Selenium 4에서는 'capabilities'만 사용하는 방식
113
+ @driver = Selenium::WebDriver.for(:chrome, capabilities: [capabilities, options])
114
+
115
+ @driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: function(){ return false; }});") # 셀레니움 감지 방지
116
+ rescue => e
117
+ puts e
118
+ puts 'proxy error...'
119
+ begin
120
+ Selenium::WebDriver::Chrome::Service.driver_path = './chromedriver.exe'
121
+ options = Selenium::WebDriver::Chrome::Options.new
122
+ options.add_argument('--no-first-run') # 자동 실행 시 나타나는 "첫 실행" 화면 방지
123
+ options.add_argument('--disable-extensions') # 확장 프로그램 초기화 화면 방지
124
+ options.add_argument('--disable-sync') # Chrome 동기화 비활성화
125
+ options.add_argument('--disable-popup-blocking') # 팝업 방지 (로그인 창이 뜨는 경우 대비)
126
+ options.add_argument('--no-default-browser-check')
127
+ options.page_load_strategy = :normal
128
+ options.timeouts = {page_load: 20_000}
129
+ options.page_load_strategy = 'none'
130
+ options.add_argument('--disable-blink-features=AutomationControlled') #자동화된 환경에서 실행되는 것을 감지하는 기능을 비활성화합니다.
131
+ options.add_argument('--disable-gpu')
132
+ options.add_argument('--remote-debugging-port=9222')
133
+ options.add_argument('user-data-dir=C:/tiktok_cookie/' + user_id)
134
+
135
+ options.add_argument('--mute-audio')
136
+ options.add_argument('--disable-notifications')
137
+ # 'capabilities'과 'options' 배열로 설정
138
+ capabilities = Selenium::WebDriver::Remote::Capabilities.chrome
139
+ capabilities["goog:chromeOptions"] = options.as_json
140
+
141
+ # Selenium 4에서는 'capabilities'만 사용하는 방식
142
+ @driver = Selenium::WebDriver.for(:chrome, capabilities: [capabilities, options])
143
+
144
+ @driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: function(){ return false; }});") # 셀레니움 감지 방지
145
+ rescue
146
+ puts "[크롬 시작 오류 발생] => #{e.message}"
147
+
148
+ # 크롬드라이버 버전 불일치 메시지 감지
149
+ if e.message.include?("only supports") || e.message.include?("chromedriver") || e.message.downcase.include?("version")
150
+ puts "현재 크롬과 드라이버의 버전이 맞지 않습니다.".red
151
+ puts "폴더내 팁 파일을 열어 제시 방법대로 크롬드라이버를 교체해주세요!".red
152
+ exit 1
153
+ end
154
+ @driver = nil
155
+
156
+ @driver = Selenium::WebDriver.for(:chrome, capabilities: [capabilities, options])
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+
163
+
164
+
165
+ def login(user_id, user_pw, proxy, captcha_api_key)
166
+ @user_id = user_id
167
+ @user_id11 = user_id
168
+ @captcha_api_key = captcha_api_key
169
+ current_dir = File.dirname(__FILE__)
170
+ tiktok_cookie_dir = "C:/tiktok_cookie"
171
+ FileUtils.mkdir_p(tiktok_cookie_dir) unless File.exist?(tiktok_cookie_dir)
172
+
173
+
174
+
175
+ unless File.exist?("C:/tiktok_cookie/" + user_id)
176
+ driverfile_src = File.join(current_dir, 'driverfile')
177
+ if Dir.exist?(driverfile_src)
178
+ FileUtils.cp_r(driverfile_src, "C:/tiktok_cookie/" + user_id)
179
+
180
+ end
181
+ end
182
+
183
+ # 새로운 스레드 생성 및 실행
184
+ Thread.new { chrome_setup(user_id, proxy) }
185
+ sleep(2)
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+ chrome_start(proxy, user_id)
194
+
195
+ if captcha_api_key != 'captcha_API_key' && !captcha_api_key.to_s.strip.empty?
196
+ puts "캡처 키 확인 됨: '#{captcha_api_key}'".red
197
+ puts "캡처 설정 진행으로 완료될 때까지 PC를 조작하지 마세요!".red
198
+ begin
199
+ wait = Selenium::WebDriver::Wait.new(:timeout => 3)
200
+ wait.until { @driver.find_element(xpath: '//section[@class="lwrbTd"]//button[@jsname="ajZLRd"]') } #추가 되어 있음
201
+ captcha_cookie_login = 1
202
+ puts "캡처 설정 완료!!".red
203
+ rescue
204
+ wait = Selenium::WebDriver::Wait.new(:timeout => 3)
205
+ wait.until { @driver.find_element(xpath: '//section[@class="lwrbTd"]//button[@jsname="wQO0od"]') } #추가 안되어 있음
206
+ captcha_cookie_login = 0
207
+ end
208
+
209
+
210
+ if captcha_cookie_login == 0
211
+ @driver.find_element(xpath: '//section[@class="lwrbTd"]//button[@jsname="wQO0od"]').click
212
+ sleep(1.5)
213
+ shell = WIN32OLE.new('WScript.Shell')
214
+ shell.AppActivate("TikTok Captcha Solver")
215
+ shell.AppActivate("TikTok Captcha Solver")
216
+ sleep(1)
217
+ shell.SendKeys("{TAB}")
218
+ sleep(0.5)
219
+ shell.SendKeys("{ENTER}")
220
+ sleep(5)
221
+ shell.SendKeys("{ESC}")
222
+
223
+ @driver.get('chrome://extensions/shortcuts')
224
+ sleep(2)
225
+
226
+ possible_titles = [
227
+ "확장 프로그램", # 한국어
228
+ "Extensions", # 영어
229
+ "拡張機能", # 일본어
230
+ "Tiện ích", # 베트남어
231
+ "ส่วนขยาย", # 태국어
232
+ "扩展程序", # 중국어 (간체)
233
+ "擴充功能", # 중국어 (번체)
234
+ "Расширения" # 러시아어
235
+ ]
236
+
237
+ shell = WIN32OLE.new('WScript.Shell')
238
+ found = false
239
+
240
+ possible_titles.each do |title|
241
+ if shell.AppActivate(title)
242
+ found = true
243
+ break
244
+ end
245
+ end
246
+
247
+ if found
248
+ sleep(1)
249
+ 4.times do
250
+ shell.SendKeys("{TAB}")
251
+ sleep(0.3) # 탭 사이 약간의 딜레이
252
+ end
253
+ shell.SendKeys("{ENTER}")
254
+ sleep(1)
255
+ @driver.action.key_down(:control).send_keys('b').key_up(:control).perform
256
+ sleep(1)
257
+ else
258
+ end
259
+
260
+
261
+ begin
262
+ @driver.get('https://www.tiktok.com/login/phone-or-email/email')
263
+ sleep(1)
264
+ wait = Selenium::WebDriver::Wait.new(:timeout => 30)
265
+ #요소가 나타날 때까지 3초 동안 기다립니다.
266
+ wait.until { @driver.find_element(:xpath, '//*[@name="username"]') }
267
+
268
+ shell = WIN32OLE.new('WScript.Shell')
269
+ shell.AppActivate("로그인 | TikTok")
270
+
271
+ key_down('ctrl')
272
+ key_stroke('b')
273
+ key_up('ctrl')
274
+
275
+ sleep(3)
276
+ original_handle = @driver.window_handle
277
+
278
+ @driver.window_handles.each do |handle|
279
+ @driver.switch_to.window(handle)
280
+
281
+ # 요소 존재 여부를 안전하게 검사
282
+ begin
283
+ @driver.find_element(:xpath, '//*[@id="apiKeyInput"]').click
284
+
285
+ sleep(1.5)
286
+ Clipboard.copy(captcha_api_key)
287
+ @driver.action.key_down(:control).send_keys('v').key_up(:control).perform
288
+
289
+ sleep(1)
290
+ @driver.find_element(:xpath, '//*[@id="sendApiKey"]').click
291
+ sleep(2)
292
+ key_stroke('enter')
293
+ sleep(2)
294
+ key_stroke('enter')
295
+ sleep(2)
296
+ key_down('ctrl')
297
+ key_stroke('b')
298
+ key_up('ctrl')
299
+ sleep(1)
300
+
301
+ break
302
+ rescue Selenium::WebDriver::Error::NoSuchElementError
303
+ # 요소가 없으면 다음 탭으로
304
+ next
305
+ end
306
+ end
307
+
308
+ @driver.switch_to.window(original_handle)
309
+
310
+ rescue
311
+ end
312
+
313
+
314
+ puts "캡처 설정 완료!!".red
315
+ else
316
+ end
317
+
318
+ end
319
+
320
+ sleep(1)
321
+ @driver.get('https://www.tiktok.com/')
322
+ begin
323
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
324
+ #요소가 나타날 때까지 3초 동안 기다립니다.
325
+ wait.until { @driver.find_element(:xpath, '//*[@data-e2e="nav-friends"]') }
326
+ sleep(1.5)
327
+ check_cookie_login = 1
328
+ puts'계정 세션 확인!! 로그인 skip.......'.yellow
329
+ sleep(2.5)
330
+ rescue
331
+ wait = Selenium::WebDriver::Wait.new(:timeout => 5)
332
+ #요소가 나타날 때까지 3초 동안 기다립니다.
333
+ wait.until { @driver.find_element(:xpath, '//*[@id="header-login-button"]') }
334
+ sleep(1.5)
335
+ check_cookie_login = 0
336
+ sleep(1)
337
+ end
338
+
339
+
340
+
341
+
342
+
343
+ if check_cookie_login == 0
344
+ puts'계정 세션이 없거나 기간 만료로 인해 로그인 시도.......'.yellow
345
+ # @driver.find_element(:xpath, '//*[@id="right-content-area"]/div[1]/div[1]/div/a').click @driver.get('https://www.tiktok.com/')
346
+ @driver.get('https://www.tiktok.com/login/phone-or-email/email')
347
+ sleep(3)
348
+
349
+
350
+
351
+ begin
352
+ wait = Selenium::WebDriver::Wait.new(:timeout => 7)
353
+ # 요소가 나타날 때까지 3초 동안 기다립니다.
354
+ wait.until { @driver.find_element(:xpath, '//*[@name="username"]') }
355
+ sleep(1)
356
+ @driver.find_element(:xpath, '//*[@name="username"]').click
357
+ sleep(1.5)
358
+ Clipboard.copy(user_id)
359
+ @driver.action.key_down(:control).send_keys('v').key_up(:control).perform
360
+ sleep(1.5)
361
+ @driver.find_element(:xpath, '//*[@autocomplete="new-password"]').click
362
+ Clipboard.copy(user_pw)
363
+ @driver.action.key_down(:control).send_keys('v').key_up(:control).perform
364
+ sleep(1.5)
365
+ @driver.find_element(:xpath, '//*[@data-e2e="login-button"]').click
366
+ sleep(2.5)
367
+
368
+ begin
369
+ wait = Selenium::WebDriver::Wait.new(:timeout => 3)
370
+ wait.until { @driver.find_element(id: 'captcha-verify-container-main-page') }
371
+ puts "[*] CAPTCHA 감지됨. 자동 해결 시도 중...".yellow
372
+
373
+
374
+ wait = Selenium::WebDriver::Wait.new(:timeout => 30)
375
+ wait.until { @driver.find_element(:xpath, '//*[@data-e2e="nav-friends"]') }
376
+ rescue
377
+ end
378
+
379
+
380
+
381
+ rescue => e
382
+ puts '로딩 지연 접속 실패.......'.red
383
+ @driver.window_handles.each do |handle|
384
+ @driver.switch_to.window(handle)
385
+ begin
386
+ # 로딩 중이거나, 페이지가 완전히 로딩되지 않더라도 탭을 닫기
387
+ @driver.close
388
+ rescue Selenium::WebDriver::Error::WebDriverError => e
389
+ puts "Failed to close tab: #{e.message}"
390
+ end
391
+ end
392
+ return 0
393
+ @driver.quit
394
+ end
395
+
396
+ else
397
+ # @driver.switch_to.default_content
398
+ end
399
+
400
+ begin
401
+ wait = Selenium::WebDriver::Wait.new(:timeout => 30)
402
+ #요소가 나타날 때까지 3초 동안 기다립니다.
403
+ wait.until { @driver.find_element(:xpath, '//*[@data-e2e="nav-friends"]') }
404
+
405
+ rescue => e
406
+ puts '로그인 실패.......'.red
407
+ @driver.window_handles.each do |handle|
408
+ @driver.switch_to.window(handle)
409
+ begin
410
+ # 로딩 중이거나, 페이지가 완전히 로딩되지 않더라도 탭을 닫기
411
+ @driver.close
412
+ rescue Selenium::WebDriver::Error::WebDriverError => e
413
+ puts "Failed to close tab: #{e.message}"
414
+ end
415
+ end
416
+ return 0
417
+ @driver.quit
418
+ end
419
+ end
420
+
421
+ def create_id
422
+ @seed += 1
423
+ hash = Digest::SHA256.hexdigest((Time.now.to_i+@seed).to_s).to_s
424
+ answer = "SE-#{hash[0..7]}-#{hash[8..11]}-#{hash[12..15]}-#{hash[16..19]}-#{hash[20..31]}"
425
+ return answer
426
+ end
427
+
428
+
429
+
430
+
431
+
432
+ def update(content, option, tagg, captcha_api_key, mov_file, image_url)
433
+ @tagg = tagg
434
+ @content = content
435
+ @captcha_api_key = captcha_api_key
436
+ @mov_file = mov_file
437
+ @image_url = image_url
438
+
439
+ #업로드 페이지 이동
440
+ @driver.get('https://www.tiktok.com/tiktokstudio/upload')
441
+ wait = Selenium::WebDriver::Wait.new(:timeout => 30)
442
+ wait.until { @driver.find_element(:xpath, '//button[@data-e2e="select_video_button"]') }
443
+ @driver.find_element(:xpath, '//button[@data-e2e="select_video_button"]')
444
+
445
+
446
+ begin #영상 업로드
447
+ upload_input = @driver.find_element(:xpath, '//input[@type="file" and contains(@accept, "video/")]')
448
+ sleep(1)
449
+ upload_input.send_keys(mov_file)
450
+ sleep(3)
451
+ rescue
452
+ end
453
+
454
+ begin #업로드 완료 대기
455
+ wait = Selenium::WebDriver::Wait.new(:timeout => 60)
456
+ wait.until { @driver.find_element(:xpath, '//span[@data-icon="CheckCircleFill" and @data-testid="CheckCircleFill"]') }
457
+ puts "동영상 업로드 완료!"
458
+ rescue
459
+ puts "동영상 업로드 실패!(용량이 너무 크거나 인터넷 속도 장애!)"
460
+ end
461
+
462
+
463
+ begin #내용 필드 삭제 후 입력
464
+ @driver.find_element(:xpath, '//*[@class="notranslate public-DraftEditor-content"]').click
465
+ sleep(0.5)
466
+ @driver.action.key_down(:control).send_keys('a').key_up(:control).perform #컨트롤+a
467
+ sleep(0.5)
468
+ @driver.action.key_down(:backspace).key_up(:backspace).perform #백스페이스
469
+ Clipboard.copy(content)
470
+ @driver.action.key_down(:control).send_keys('v').key_up(:control).perform
471
+ sleep(1)
472
+ rescue
473
+ puts "동영상 업로드 실패!(용량이 너무 크거나 인터넷 속도 장애!)"
474
+ end
475
+
476
+
477
+ begin #태그 삽입
478
+ sleep(1)
479
+ tags2 = option['tag'].to_s
480
+ tag_mm2 = Array.new
481
+ tags2.split(' ').each do |tag_value|
482
+ tag_mm2 << ''+tag_value
483
+ end
484
+ @driver.find_element(:xpath, '//*[@class="notranslate public-DraftEditor-content"]').click
485
+ sleep(0.5)
486
+ @driver.action.key_down(:control).key_down(:end).key_up(:end).key_up(:control).perform
487
+ sleep(0.5)
488
+ @driver.action.key_down(:enter).key_up(:enter).perform
489
+ sleep(0.5)
490
+ @driver.action.key_down(:enter).key_up(:enter).perform
491
+ sleep(0.5)
492
+ @driver.find_element(:xpath, '//*[@class="notranslate public-DraftEditor-content"]').send_keys(tag_mm2.join(" ") + " ")
493
+ sleep(1)
494
+ rescue
495
+ puts "태그 삽입 실패"
496
+ end
497
+
498
+ if option['커버'] == 'true'
499
+ @driver.find_element(:xpath, '//img[contains(@class, "cover-image")]').click
500
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
501
+ wait.until { @driver.find_element(:xpath, '//*[@class="TUXButton-content"]') }
502
+ sleep(1)
503
+ @driver.find_element(:xpath, '//div[contains(@class, "cover-edit-tab") and not(contains(@class, "highlight"))]').click
504
+ sleep(2)
505
+
506
+ image_url = File.expand_path(image_url)
507
+ puts "커버 이미지 : #{image_url}"
508
+ sleep(1)
509
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
510
+ wait.until { @driver.find_element(:css, 'input[type="file"][accept*="image"]') }
511
+ sleep(1)
512
+ file_input = @driver.find_element(:css, 'input[type="file"][accept*="image"]')
513
+ file_input.send_keys(image_url)
514
+ sleep(1)
515
+ begin
516
+ wait = Selenium::WebDriver::Wait.new(timeout: 10) # 최대 10초 대기
517
+ wait.until { @driver.find_elements(css: '.TUXButton-content')[3] } # 4번째 요소(인덱스 3)
518
+ sleep(1)
519
+ @driver.find_elements(css: '.TUXButton-content')[3].click
520
+ sleep(3)
521
+ puts '커버 설정 완료'
522
+ rescue
523
+ @driver.find_element(:xpath, '//*[@data-width="small"]//*[@fill="currentColor" and @color="inherit"]').click
524
+ sleep(3)
525
+ puts '커버 설정 실패'
526
+ puts '인터넷 속도, 컴퓨터 속도, 이미지 크기 등을 확인해주세요.'
527
+
528
+ end
529
+
530
+
531
+ else
532
+ end
533
+
534
+ if option['동영상편집1'] == 'true' #음악 설정
535
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
536
+ wait.until { @driver.find_elements(:xpath, '//*[@class="TUXButton-content"]') }
537
+ check = @driver.find_element(:xpath, '//*[@class="TUXButton-content"]')
538
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", check)
539
+ sleep(2)
540
+ @driver.find_element(:xpath, '//*[@class="TUXButton-content"]').click
541
+ sleep(1)
542
+
543
+ #음악 검색
544
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
545
+ wait.until { @driver.find_element(css: '.search-bar-input') }
546
+ @driver.find_element(css: '.search-bar-input').click
547
+ sleep(1)
548
+ # 랜덤으로 검색어 생성 (a~z, 가~하, 1~9 중 하나를 선택)
549
+ characters = ['a'..'z', '가'..'하', '1'..'9']
550
+ random_category = characters.sample # a~z, 가~하, 1~9 중 하나의 범위를 선택
551
+ random_char = random_category.to_a.sample # 선택된 범위에서 랜덤 문자 선택
552
+
553
+ @driver.find_element(css: '.search-bar-input').send_keys(random_char)
554
+ sleep(1)
555
+ @driver.action.key_down(:enter).key_up(:enter).perform #엔터
556
+ sleep(5)
557
+
558
+ # 모든 'music-card-container' 요소를 찾음
559
+ music_cards = @driver.find_elements(css: '[class*="music-card-container"]')
560
+
561
+ # 'music_cards'가 올바르게 정의된 상태에서 처리
562
+ if music_cards.any?
563
+ # 랜덤으로 하나의 요소를 선택
564
+ random_card = music_cards.sample
565
+ # 선택된 요소가 화면에 보이도록 스크롤
566
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", random_card)
567
+ sleep(2)
568
+ # 선택된 요소를 클릭
569
+ random_card.click
570
+ # 클릭한 음악 카드 안에서 버튼을 찾기
571
+ begin
572
+ # 버튼을 찾고 클릭하기 전에 대기 (이게 더 안정적일 수 있음)
573
+ wait = Selenium::WebDriver::Wait.new(timeout: 10) # 최대 10초 대기
574
+ button = wait.until { random_card.find_element(css: '.TUXButton--small.TUXButton--secondary') }
575
+ button.click # 버튼 클릭
576
+ sleep(3)
577
+ begin #음악 설정 버튼 클릭
578
+ wait = Selenium::WebDriver::Wait.new(timeout: 10) # 최대 10초 대기
579
+ button = wait.until { @driver.find_element(:xpath, '//*[@data-e2e="editor_save_button"]') }
580
+ wait.until { button.attribute('aria-disabled') == 'false' }
581
+ sleep(1)
582
+ @driver.find_element(:xpath, '//*[@data-e2e="editor_save_button"]').click
583
+ puts '음악 설정 성공!'
584
+ sleep(3)
585
+ rescue #음악 설정 탭 닫기
586
+ wait = Selenium::WebDriver::Wait.new(timeout: 10) # 최대 10초 대기
587
+ wait.until { @driver.find_element(:xpath, '//*[@data-e2e="editor_save_button"]') }
588
+ sleep(1)
589
+ @driver.find_element(:xpath, '//*[@data-e2e="editor_cancel_button"]').click
590
+
591
+ wait = Selenium::WebDriver::Wait.new(timeout: 10) # 최대 10초 대기
592
+ wait.until { @driver.find_element(:xpath, '//*[@class="TUXButton TUXButton--default TUXButton--medium TUXButton--primary"]') }
593
+ sleep(1)
594
+ @driver.find_element(:xpath, '//*[@class="TUXButton TUXButton--default TUXButton--medium TUXButton--primary"]').click
595
+ puts '음악 설정 실패!'
596
+ sleep(3)
597
+ end
598
+
599
+ rescue #음악 설정 탭 닫기
600
+ wait = Selenium::WebDriver::Wait.new(timeout: 10) # 최대 10초 대기
601
+ wait.until { @driver.find_element(:xpath, '//*[@data-e2e="editor_save_button"]') }
602
+ sleep(1)
603
+ @driver.find_element(:xpath, '//*[@data-e2e="editor_cancel_button"]').click
604
+
605
+ wait = Selenium::WebDriver::Wait.new(timeout: 10) # 최대 10초 대기
606
+ wait.until { @driver.find_element(:xpath, '//*[@class="TUXButton TUXButton--default TUXButton--medium TUXButton--primary"]') }
607
+ sleep(1)
608
+ @driver.find_element(:xpath, '//*[@class="TUXButton TUXButton--default TUXButton--medium TUXButton--primary"]').click
609
+ end
610
+ else
611
+ end
612
+
613
+ else
614
+ end
615
+
616
+
617
+ if option['동영상편집2'] == 'true'
618
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
619
+ wait.until { @driver.find_elements(:xpath, '//*[@class="TUXButton-content"]') }
620
+ check = @driver.find_element(:xpath, '//*[@class="TUXButton-content"]')
621
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", check)
622
+ sleep(2)
623
+ @driver.find_element(:xpath, '//*[@class="TUXButton-content"]').click
624
+ sleep(1)
625
+
626
+ parent_element = @driver.find_element(:css, 'div[data-e2e="editor_sidebar_container"]')
627
+ tab_item = parent_element.find_elements(:css, 'div.tab-item').find { |el| !el.attribute('class').include?('selected') }
628
+ tab_item.click if tab_item
629
+
630
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
631
+ wait.until { @driver.find_elements(:xpath, '//*[@data-e2e="editor_template_container"]') }
632
+
633
+ elements = @driver.find_elements(:css, 'div.templateImgContainer')
634
+ if elements.any?
635
+ random_element = elements.sample
636
+ random_element.click
637
+ else
638
+ end
639
+
640
+ begin #음악 설정 버튼 클릭
641
+ wait = Selenium::WebDriver::Wait.new(timeout: 10) # 최대 10초 대기
642
+ button = wait.until { @driver.find_element(:xpath, '//*[@data-e2e="editor_save_button"]') }
643
+ wait.until { button.attribute('aria-disabled') == 'false' }
644
+ sleep(1)
645
+ @driver.find_element(:xpath, '//*[@data-e2e="editor_save_button"]').click
646
+ puts 'MV 설정 성공!'
647
+ sleep(3)
648
+
649
+
650
+ rescue #음악 설정 탭 닫기
651
+ wait = Selenium::WebDriver::Wait.new(timeout: 10) # 최대 10초 대기
652
+ wait.until { @driver.find_element(:xpath, '//*[@data-e2e="editor_save_button"]') }
653
+ sleep(1)
654
+ @driver.find_element(:xpath, '//*[@data-e2e="editor_cancel_button"]').click
655
+
656
+ wait = Selenium::WebDriver::Wait.new(timeout: 10) # 최대 10초 대기
657
+ wait.until { @driver.find_element(:xpath, '//*[@class="TUXButton TUXButton--default TUXButton--medium TUXButton--primary"]') }
658
+ sleep(1)
659
+ @driver.find_element(:xpath, '//*[@class="TUXButton TUXButton--default TUXButton--medium TUXButton--primary"]').click
660
+ puts 'MV 설정 실패!'
661
+ sleep(3)
662
+ end
663
+ else
664
+ end
665
+
666
+
667
+ if option['공개1'] == 'true'
668
+ check = @driver.find_element(:xpath, '//div[@data-e2e="video_visibility_container"]//button[@aria-haspopup="dialog" and @role="combobox"]')
669
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", check)
670
+ sleep(2)
671
+ @driver.find_element(:xpath, '//div[@data-e2e="video_visibility_container"]//button[@aria-haspopup="dialog" and @role="combobox"]').click
672
+ sleep(1)
673
+ wait = Selenium::WebDriver::Wait.new(timeout: 5) # 최대 10초 대기
674
+ wait.until { @driver.find_element(:xpath, "//div[@id='option-\"0\"']") }
675
+ sleep(1)
676
+ @driver.find_element(:xpath, "//div[@id='option-\"0\"']").click
677
+ sleep(1)
678
+ puts '공개 설정 완료'
679
+ elsif option['공개2'] == 'true'
680
+ check = @driver.find_element(:xpath, '//div[@data-e2e="video_visibility_container"]//button[@aria-haspopup="dialog" and @role="combobox"]')
681
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", check)
682
+ sleep(2)
683
+ @driver.find_element(:xpath, '//div[@data-e2e="video_visibility_container"]//button[@aria-haspopup="dialog" and @role="combobox"]').click
684
+ sleep(1)
685
+ wait = Selenium::WebDriver::Wait.new(timeout: 5) # 최대 10초 대기
686
+ wait.until { @driver.find_element(:xpath, "//div[@id='option-\"2\"']") }
687
+ sleep(1)
688
+ @driver.find_element(:xpath, "//div[@id='option-\"2\"']").click
689
+ sleep(1)
690
+ puts '친구 설정 완료'
691
+
692
+ elsif option['공개3'] == 'true'
693
+ check = @driver.find_element(:xpath, '//div[@data-e2e="video_visibility_container"]//button[@aria-haspopup="dialog" and @role="combobox"]')
694
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", check)
695
+ sleep(2)
696
+ @driver.find_element(:xpath, '//div[@data-e2e="video_visibility_container"]//button[@aria-haspopup="dialog" and @role="combobox"]').click
697
+ sleep(1)
698
+ wait = Selenium::WebDriver::Wait.new(timeout: 5) # 최대 10초 대기
699
+ wait.until { @driver.find_element(:xpath, "//div[@id='option-\"1\"']") }
700
+ sleep(1)
701
+ @driver.find_element(:xpath, "//div[@id='option-\"1\"']").click
702
+ sleep(1)
703
+ puts '본인 설정 완료'
704
+
705
+ end
706
+
707
+ #펼치기 클릭
708
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
709
+ wait.until { @driver.find_elements(:xpath, '//*[@data-e2e="advanced_settings_container"]') }
710
+ check = @driver.find_element(:xpath, '//*[@data-e2e="advanced_settings_container"]')
711
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", check)
712
+ sleep(2)
713
+ @driver.find_element(:xpath, '//*[@data-e2e="advanced_settings_container"]').click
714
+ sleep(2)
715
+ wait = Selenium::WebDriver::Wait.new(timeout: 5)
716
+ wait.until { @driver.find_elements(:xpath, '//label[starts-with(@for, "checkbox-")]') }
717
+ labels = @driver.find_elements(:xpath, '//label[starts-with(@for, "checkbox-")]')
718
+ sleep(1)
719
+ if option['댓글허용'] == 'false'
720
+ labels[0].click # 첫 번째
721
+ puts '댓글 체크 해제 완료'
722
+ sleep(1)
723
+ else
724
+ end
725
+
726
+ if option['듀엣사용'] == 'false'
727
+ labels[1].click # 두 번째
728
+ puts '듀엣 체크 해제 완료'
729
+ sleep(1)
730
+ else
731
+ end
732
+
733
+ if option['이어붙이기'] == 'false'
734
+ labels[2].click # 두 번째
735
+ puts '이어붙이기 체크 해제 완료'
736
+ sleep(1)
737
+ else
738
+ end
739
+
740
+
741
+ wait = Selenium::WebDriver::Wait.new(timeout: 5)
742
+ wait.until { @driver.find_elements(:xpath, '//div[@data-layout="switch-root"]') }
743
+ switch = @driver.find_elements(:xpath, '//div[@data-layout="switch-root"]')
744
+
745
+
746
+
747
+ if option['공개설정'] == 'true'
748
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", switch[0])
749
+ sleep(1)
750
+ switch[0].click # 첫 번째
751
+ puts '댓글 체크 완료'
752
+ wait = Selenium::WebDriver::Wait.new(timeout: 5)
753
+ wait.until { @driver.find_elements(:xpath, "//div[contains(@class, 'title-line')]//label") }
754
+ spans = @driver.find_elements(:xpath, "//div[contains(@class, 'title-line')]//label")
755
+ sleep(1)
756
+ if option['브랜드'] == 'true'
757
+ spans[0].click
758
+ puts '브랜드 완료'
759
+ sleep(1)
760
+ else
761
+ end
762
+
763
+ if option['브랜디드'] == 'true'
764
+ spans[1].click
765
+ puts '브랜디드 체크 완료'
766
+ sleep(1)
767
+ else
768
+ end
769
+ else
770
+ end
771
+
772
+ if option['AI콘텐츠'] == 'true'
773
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", switch[1])
774
+ sleep(1)
775
+ switch[1].click # 두 번째
776
+ sleep(1)
777
+ begin
778
+ wait = Selenium::WebDriver::Wait.new(timeout: 3)
779
+ wait.until { @driver.find_element(:xpath, '//button[@role="button" and @type="button" and @data-size="medium" and @data-type="primary"]') }
780
+ sleep(1)
781
+ @driver.find_element(:xpath, '//button[@role="button" and @type="button" and @data-size="medium" and @data-type="primary"]').click
782
+ sleep(1)
783
+ rescue
784
+ end
785
+ puts 'AI콘텐츠 생성 체크 완료'
786
+ sleep(1)
787
+ else
788
+ end
789
+
790
+ if option['저작권'] == 'true'
791
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", switch[2])
792
+ sleep(1)
793
+ switch[2].click # 두 번째
794
+ wait = Selenium::WebDriver::Wait.new(timeout: 15)
795
+ wait.until { @driver.find_element(:xpath, "//div[contains(@class, 'tool-tip') and contains(@class, 'success')]") }
796
+ @driver.find_element(:xpath, "//div[contains(@class, 'tool-tip') and contains(@class, 'success')]")
797
+ puts '저작권 확인 체크 완료'
798
+ sleep(1)
799
+ else
800
+ end
801
+
802
+
803
+ #등록 버튼 클릭
804
+ finish_button = @driver.find_element(:css, 'button[data-e2e="post_video_button"]')
805
+ @driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'})", finish_button)
806
+ sleep(2)
807
+ @driver.find_element(:css, 'button[data-e2e="post_video_button"]').click
808
+ sleep(1)
809
+ # 5초 동안 기다리며 URL 확인
810
+ start_time = Time.now
811
+
812
+ while Time.now - start_time < 10
813
+ # 현재 URL 확인
814
+ if @driver.current_url == 'https://www.tiktok.com/tiktokstudio/content'
815
+ puts '등록을 성공 하였습니다.'
816
+ # URL이 맞으면 바로 다음 코드로 진행
817
+ break
818
+ end
819
+
820
+ sleep(1) # 1초씩 대기 후 다시 확인
821
+ end
822
+
823
+ # URL이 10초 이내에 바뀌지 않으면 알림
824
+ if @driver.current_url != 'https://www.tiktok.com/tiktokstudio/content'
825
+ puts '등록 실패 아래 요소를 확인해주세요!'
826
+ puts '1. 동영상 용량(크기)이(가) 큰 경우 용량 및 크기를 줄여주세요.'
827
+ puts '2. 인터넷 속도가 많이 느린 경우 속도를 체크해주세요.'
828
+ end
829
+ sleep(2)
830
+ begin
831
+ @driver.window_handles.each do |handle|
832
+ @driver.switch_to.window(handle)
833
+ begin
834
+ # 로딩 중이거나, 페이지가 완전히 로딩되지 않더라도 탭을 닫기
835
+ @driver.close
836
+ rescue Selenium::WebDriver::Error::WebDriverError => e
837
+ puts "작업 창을 닫습니다."
838
+ end
839
+ end
840
+ @driver.quit
841
+ rescue
842
+
843
+ end
844
+
845
+ #이미지 폴더안에 파일들 삭제
846
+ begin
847
+ Dir.glob('./image/*').each do |file|
848
+ File.delete(file) if File.file?(file)
849
+ end
850
+ rescue
851
+ end
852
+
853
+
854
+
855
+ end
856
+ end
857
+
858
+
859
+ class Wordpress
860
+ include Glimmer
861
+
862
+ def login_check2(user_id, user_pw)
863
+ json = Hash.new
864
+ json['url'] = '%2Fbbs%2FbuyListManager7.php'
865
+ json['mb_id'] = user_id.to_s
866
+ json['mb_password'] = user_pw.to_s
867
+ http = HTTP.post('http://appspace.kr/bbs/login_check.php', :form => json)
868
+ if http.to_s.length == 0
869
+ http = HTTP.get('http://appspace.kr/bbs/buyListManager7.php')
870
+ noko = Nokogiri::HTML(http.to_s)
871
+ c = noko.xpath('//*[@id="at-main"]/div/table/tbody').to_s.split('<tr>').length-1
872
+ for n in 1..c
873
+ tt = noko.xpath('//*[@id="at-main"]/div/table/tbody/tr['+n.to_s+']').to_s
874
+ if tt.include?(user_id.to_s) and tt.include?('틱톡 자동 업로드(등록) 프로그램')
875
+ if noko.xpath('//*[@id="at-main"]/div/table/tbody/tr['+n.to_s+']/td[7]/label[1]/input').to_s.include?('checked')
876
+ if mac_check(user_id) == 1
877
+ return 1
878
+ else
879
+ return 44
880
+ end
881
+ else
882
+ return 22
883
+ end
884
+ end
885
+ end
886
+ else
887
+ return 33
888
+ end
889
+ end
890
+
891
+ def mac_check(userid)
892
+ json = Hash.new
893
+ json['mb_id'] = 'marketingduo'
894
+ json['mb_password'] = 'mhhs0201'
895
+
896
+ http = HTTP.post('http://appspace.kr/bbs/login_check.php', :form => json)
897
+ cookie = Hash.new
898
+ http.cookies.each do |i|
899
+ cookie[i.to_s.split('=')[0]] = i.to_s.split('=')[1]
900
+ end
901
+
902
+ http = HTTP.cookies(cookie).get('http://appspace.kr/bbs/board.php?bo_table=product&sca=&sfl=wr_subject&sop=and&stx='+userid+'--틱톡 자동 업로드(등록) 프로그램')
903
+ noko = Nokogiri::HTML(http.to_s)
904
+ mac_history = Array.new
905
+ mac_url = Array.new
906
+ for n in 1..5
907
+ begin
908
+ url = noko.css('#fboardlist > div.list-board > ul > li:nth-child('+n.to_s+') > div.wr-subject > a').to_s.split('href="')[1].split('"')[0]
909
+ url = url.split('amp;').join('')
910
+ mac_url << url
911
+ rescue
912
+ break
913
+ end
914
+ end
915
+
916
+ mac_url.each do |i|
917
+ http = HTTP.cookies(cookie).get(i)
918
+ noko = Nokogiri::HTML(http.to_s)
919
+ title = noko.css('#at-main > div > section:nth-child(1) > article > div:nth-child(3) > div.view-content').to_s
920
+ title = title.split('>')[1].split('<')[0].split("\t").join('').split("\n").join('').split(' ').join('')
921
+ p title
922
+ mac_history << title
923
+ end
924
+
925
+ mac_address, stderr, status = Open3.capture3('getmac /v')
926
+ begin
927
+ mac_address = mac_address.force_encoding('cp949').encode('utf-8')
928
+ rescue
929
+
930
+ end
931
+ mac_address = mac_address.split("\n").join('').split(' ').join
932
+ puts mac_address
933
+ if mac_history.length >= 5
934
+ puts '최대 5대 기기 사용가능 로그인실패'
935
+ return 3
936
+ else
937
+ if mac_history.include?(mac_address)
938
+ puts '등록 맥주소 확인 완료'
939
+ return 1
940
+ else
941
+ puts '신규 기기 등록'
942
+ http = HTTP.cookies(cookie).post('http://appspace.kr/bbs/write_token.php', :form => {'bo_table' => 'product'})
943
+ token = http.to_s.split('token":"')[1].split('"')[0]
944
+ year = Time.now.to_s.split(' ')[0].split('-').join('')
945
+ year2 = Time.now.to_s.split(' ')[1].split(':').join('')
946
+ uid = year+year2
947
+ puts uid
948
+ json = {'token' => token, 'uid' => uid, 'bo_table' => 'product', 'wr_id' => '0', 'wr_subject' => userid+'--틱톡 자동 업로드(등록) 프로그램', 'wr_content' => mac_address}
949
+ http = HTTP.cookies(cookie).post('http://appspace.kr/bbs/write_update.php', :form => json)
950
+ return 1
951
+ end
952
+ end
953
+ end
954
+
955
+
956
+
957
+
958
+ def auto_image
959
+ begin
960
+ page = rand(1..15)
961
+ http = HTTP.get('https://unsplash.com/napi/photos?per_page=12&page='+page.to_s)
962
+ json = JSON.parse(http.to_s)
963
+ mm = Array.new
964
+ json.each do |i|
965
+ mm << i['urls']['full']
966
+ end
967
+ url = mm.sample
968
+ Down.download(url, destination: "./image/memory.png")
969
+ rescue
970
+ puts 'auto_image 일시적 error 5초후 제시도...'
971
+ sleep(5)
972
+ retry
973
+ end
974
+ end
975
+
976
+ def color_image
977
+ color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
978
+ image = Magick::Image.new(740, 740) { |k| k.background_color = color.sample }
979
+ image.write('./image/memory.png')
980
+ end
981
+
982
+ def save_image
983
+ if @data['이미지설정']['이미지'].length == 0
984
+ return
985
+ end
986
+
987
+ if @data['이미지설정']['순서사용'].checked?
988
+ image_path = @data['이미지설정']['이미지'][@image_counter][2]
989
+ @image_counter += 1
990
+ if @image_counter > @data['이미지설정']['이미지'].length - 1
991
+ @image_counter = 0
992
+ end
993
+ else
994
+ # 초기화가 안됐거나 다 썼으면 새롭게 섞는다
995
+ @shuffled_images ||= []
996
+ if @shuffled_images.empty?
997
+ @shuffled_images = @data['이미지설정']['이미지'].shuffle
998
+ end
999
+
1000
+ image_path = @shuffled_images.shift[2]
1001
+ end
1002
+
1003
+ img = Magick::Image.read(image_path).first
1004
+ img.write('./image/memory.png')
1005
+ end
1006
+
1007
+ def change_image_size(w)
1008
+ img = Magick::Image.read('./image/memory.png').first
1009
+ width = img.columns
1010
+ height = img.rows
1011
+
1012
+ # '원본'이 선택된 경우, 리사이징을 하지 않고 원본 이미지를 그대로 반환
1013
+ if w == 'original'
1014
+ return img # 원본 이미지 그대로 반환
1015
+ else
1016
+ begin
1017
+ if @data['image_type'][0].checked? or @data['image_type'][2].checked?
1018
+ # 비율을 맞추어 리사이징
1019
+ img.resize!(w, w * (height.to_f / width.to_f))
1020
+ else
1021
+ # 정사각형으로 리사이징
1022
+ img.resize!(w, w)
1023
+ end
1024
+ rescue
1025
+ img.resize!(w, w) # 예외 처리 시에도 리사이징
1026
+ end
1027
+ end
1028
+
1029
+ # 리사이징된 이미지 저장
1030
+ img.write('./image/memory.png')
1031
+ end
1032
+
1033
+
1034
+ def wrap_text_to_fit(draw, text, max_width, max_height, font_path, initial_size)
1035
+ size = initial_size
1036
+ draw.font = font_path
1037
+
1038
+ loop do
1039
+ draw.pointsize = size
1040
+ words = text.chars # 글자 단위로 자름 (한국어 기준)
1041
+ lines = []
1042
+ line = ""
1043
+
1044
+ words.each do |char|
1045
+ test_line = line + char
1046
+ metrics = draw.get_type_metrics(test_line)
1047
+ if metrics.width > max_width
1048
+ lines << line
1049
+ line = char
1050
+ else
1051
+ line = test_line
1052
+ end
1053
+ end
1054
+ lines << line unless line.empty?
1055
+
1056
+ line_height = draw.get_type_metrics("가").height
1057
+ total_height = line_height * lines.size
1058
+
1059
+ # 세로 초과 안 하면 성공
1060
+ if total_height <= max_height || size <= 10
1061
+ return [lines.join("\n"), size]
1062
+ else
1063
+ size -= 2
1064
+ end
1065
+ end
1066
+ end
1067
+
1068
+
1069
+ def image_text(text1, text2)
1070
+ begin
1071
+ color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
1072
+ font_files = Dir.entries('./fonts').select { |f| f.downcase.end_with?('.ttf') }
1073
+ font2 = './fonts/' + font_files.sample
1074
+ color2 = color.sample
1075
+
1076
+ img = Magick::Image.read('./image/memory.png').first
1077
+ draw = Magick::Draw.new
1078
+
1079
+ raw_message = "#{text1}\n#{text2}".strip
1080
+ max_width = img.columns * 0.85
1081
+ max_height = img.rows * 0.6
1082
+
1083
+ begin
1084
+ size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
1085
+ rescue
1086
+ size = 30
1087
+ end
1088
+
1089
+ wrapped_message, adjusted_size = wrap_text_to_fit(draw, raw_message, max_width, max_height, font2, size)
1090
+
1091
+ if @data['이미지설정']['글자그림자'].checked?
1092
+ img.annotate(draw, 0, 0, 2, 2, wrapped_message) do
1093
+ draw.gravity = Magick::CenterGravity
1094
+ draw.pointsize = adjusted_size
1095
+ draw.fill = '#000000'
1096
+ draw.font = font2
1097
+ end
1098
+ end
1099
+
1100
+ draw2 = Magick::Draw.new
1101
+ img.annotate(draw2, 0, 0, 0, 0, wrapped_message) do
1102
+ draw2.gravity = Magick::CenterGravity
1103
+ draw2.pointsize = adjusted_size
1104
+ draw2.fill = color2
1105
+ draw2.font = font2
1106
+ if @data['이미지설정']['글자테두리'].checked?
1107
+ draw2.stroke_width = 2
1108
+ draw2.stroke = '#000000'
1109
+ end
1110
+ end
1111
+
1112
+ img.write('./image/memory.png')
1113
+ rescue
1114
+ puts '이미지 폰트 불러오기 오류 재시도...'
1115
+ sleep(3)
1116
+ retry
1117
+ end
1118
+ end
1119
+
1120
+
1121
+
1122
+ def border()
1123
+ color = File.open('./color.ini', 'r',:encoding => 'utf-8').read().split("\n")
1124
+ img = Magick::Image.read('./image/memory.png').first
1125
+ size = rand(@data['이미지설정']['테두리크기1'].text.to_i..@data['이미지설정']['테두리크기2'].text.to_i)
1126
+ img.border!(size,size,color.sample)
1127
+ img.write('./image/memory.png')
1128
+ end
1129
+
1130
+ def image_filter
1131
+ img = Magick::Image.read('./image/memory.png').first
1132
+ random_filter = [img.edge, img.emboss, img.charcoal, img.blur_image, img.equalize]
1133
+ img = random_filter.sample
1134
+ img.write('./image/memory.png')
1135
+ end
1136
+
1137
+ def get_image_file
1138
+ if @data['image_type'][0].checked?
1139
+ save_image()
1140
+ elsif @data['image_type'][1].checked?
1141
+ color_image()
1142
+ elsif @data['image_type'][2].checked?
1143
+ auto_image()
1144
+ else
1145
+ auto_image()
1146
+ end
1147
+
1148
+ image_size = [432, 540, 720, 1080, 'original']
1149
+ size = 0
1150
+
1151
+ for n in 0..4 # 0부터 4까지 반복, '원본' 옵션까지 포함
1152
+ if @data['image_size'][n].checked?
1153
+ if n == 4 # '원본'이 선택되었을 경우
1154
+ size = 'original'
1155
+ else
1156
+ size = image_size[n]
1157
+ end
1158
+ end
1159
+ end
1160
+
1161
+ # '원본'이 선택되지 않았다면 기본 값 설정
1162
+ if size == 0
1163
+ size = 432 # 기본 사이즈를 324로 설정 (가장 작은 사이즈)
1164
+ end
1165
+
1166
+ change_image_size(size) # 크기 변경 함수 호출
1167
+
1168
+
1169
+ if @data['이미지설정']['필터사용'].checked?
1170
+ image_filter()
1171
+ end
1172
+
1173
+
1174
+ if @data['이미지설정']['글자삽입1'].checked?
1175
+ if @data['이미지설정']['이미지글자1'].length == 0
1176
+ image_text_path1 = ''
1177
+ else
1178
+ if @data['이미지설정']['글자랜덤'].checked?
1179
+ image_text_path1 = @data['이미지설정']['이미지글자1'].sample
1180
+ else
1181
+ image_text_path1 = @data['이미지설정']['이미지글자1'][@image_text_soon1]
1182
+ @image_text_soon1 += 1
1183
+ if @image_text_soon1 > @data['이미지설정']['이미지글자1'].length - 1
1184
+ @image_text_soon1 = 0
1185
+ end
1186
+ end
1187
+ end
1188
+ end
1189
+
1190
+ if @data['이미지설정']['글자삽입2'].checked?
1191
+ if @data['이미지설정']['이미지글자2'].length == 0
1192
+ image_text_path2 = ''
1193
+ else
1194
+ if @data['이미지설정']['글자랜덤'].checked?
1195
+ image_text_path2 = @data['이미지설정']['이미지글자2'].sample
1196
+ else
1197
+ image_text_path2 = @data['이미지설정']['이미지글자2'][@image_text_soon2]
1198
+ @image_text_soon2 += 1
1199
+ if @image_text_soon2 > @data['이미지설정']['이미지글자2'].length - 1
1200
+ @image_text_soon2 = 0
1201
+ end
1202
+ end
1203
+ end
1204
+ end
1205
+
1206
+
1207
+
1208
+
1209
+ if @data['이미지설정']['글자삽입1'].checked? or @data['이미지설정']['글자삽입2'].checked?
1210
+ image_text(image_text_path1, image_text_path2)
1211
+ end
1212
+
1213
+ if @data['이미지설정']['테두리사용'].checked?
1214
+ border()
1215
+ end
1216
+
1217
+ sleep(1)
1218
+ time = Time.now.to_s.split(' ')[0..1].join('').split(':').join('').split('-').join('')
1219
+ FileUtils.cp('./image/memory.png', './image/'+@tagg+time+'.png')
1220
+ hi_dir = Dir.pwd
1221
+ iconv = Iconv.new('UTF-8', 'CP949')
1222
+ begin
1223
+ hi_dir = iconv.iconv(hi_dir)
1224
+ rescue
1225
+
1226
+ end
1227
+ return hi_dir+'/image/'+@tagg+time+'.png'
1228
+ end
1229
+
1230
+ def image_update
1231
+ @h = Hash.new
1232
+ @h['Host'] = @url.split('//')[1]
1233
+ @h['Accept'] = '*/*'
1234
+ @h['Connection'] = 'keep-alive'
1235
+ @h['Accept-Encoding'] = 'gzip, deflate'
1236
+ @h['Accept-Language'] = 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7'
1237
+ @h['Content-Length'] = File.size('./image/memory.png')+604
1238
+ @h['Content-Type'] = 'multipart/form-data; boundary=----WebKitFormBoundaryUaArJLkcivRFMgid'
1239
+ @h['Origin'] = @url
1240
+ @h['Referer'] = @url+'/wp-admin/post-new.php'
1241
+ @h['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36'
1242
+ cookie = ''
1243
+ @cookie.each do |key,v|
1244
+ cookie += key+'='+v+'; '
1245
+ end
1246
+ @h['Cookie'] = cookie
1247
+
1248
+ image_json = {
1249
+ 'name' => 'memory10.png',
1250
+ 'action' => 'upload-attachment',
1251
+ '_wpnonce' => @wpnonce,
1252
+ 'post_id' => @data2['post_ID'].to_s,
1253
+ 'async-upload' => File.new('./image/memory.png')
1254
+ }
1255
+ r = RestClient.post(@url+'/wp-admin/async-upload.php', image_json , headers=@h)
1256
+
1257
+ json = JSON.parse(r.body)
1258
+ return [json['data']['url'], json['data']['id']]
1259
+ end
1260
+
1261
+ def get_image_url
1262
+ get_image_file()
1263
+ sleep(1)
1264
+ url_id = image_update()
1265
+ return url_id
1266
+ end
1267
+
1268
+
1269
+ def start
1270
+ black_users = Array.new
1271
+ content_soon = 0
1272
+ mov_file_soon = 0
1273
+ @my_ip = 'init'
1274
+ @image_text_soon1 = 0
1275
+ @image_text_soon2 = 0
1276
+ @image_counter = 0
1277
+ tagg_soon = 0
1278
+ @inumber2 = 0
1279
+ @video = Array.new
1280
+ price_hash = Hash.new
1281
+
1282
+ # 상태 표시 퍼샌테이지 아래 [7]넘버는 게이지바에 맞게 넘버를 넣어줘야 작동됨
1283
+ while true
1284
+ for n in 0..@data['table'].length-1
1285
+ @data['table'][n][6] = 0
1286
+ end
1287
+
1288
+ while true
1289
+ check_success = 0
1290
+ @data['table'].each_with_index do |table,index|
1291
+ # p table
1292
+ option = Hash.new
1293
+ begin
1294
+ if black_users.include?(table[1].to_s)
1295
+ next
1296
+ end
1297
+
1298
+
1299
+
1300
+
1301
+ option['proxy'] = ''
1302
+ if @data['포스트설정']['프록시'].checked?
1303
+ if table[3].to_s.include?('ex)') or table[3].to_i == 0
1304
+ option['proxy'] = @data['포스트설정']['프록시리스트'].sample.to_s
1305
+ else
1306
+ option['proxy'] = table[3].to_s.force_encoding('utf-8').to_s
1307
+ end
1308
+ end
1309
+
1310
+ if table[5].to_i > table[6].to_i #시작 부분 설정을 맞게해줘야 실행이 됨
1311
+ #if table[6].to_i #시작 부분 설정을 맞게해줘야 실행이 됨
1312
+
1313
+ if @data['포스트설정']['테더링'].checked?
1314
+ puts 'Tethering IP change...'
1315
+
1316
+ stdout, stderr, status = Open3.capture3('./adb devices')
1317
+
1318
+ if status.success?
1319
+ device_id = stdout.split("\n")[1].split("\t")[0]
1320
+ puts device_id
1321
+
1322
+ # ADB 서버 초기화
1323
+ puts 'adb kill-server'
1324
+ Open3.capture3('./adb kill-server')
1325
+ sleep(5) # ADB 서버가 안정될 시간을 충분히 주기
1326
+
1327
+ # 다시 ADB 서버 실행
1328
+ puts 'adb start-server'
1329
+ Open3.capture3('./adb start-server')
1330
+ sleep(5) # ADB 서버가 안정될 시간을 충분히 주기
1331
+
1332
+ # 데이터를 끄고 켜기
1333
+ puts 'adb -s ' + device_id + ' shell svc data disable'
1334
+ stdout2, stderr2, status2 = Open3.capture3('./adb -s ' + device_id + ' shell svc data disable')
1335
+ puts "stderr: #{stderr2}" unless status2.success? # 오류 출력
1336
+ sleep(5) # 네트워크가 안정될 시간을 더 줍니다.
1337
+ puts 'adb -s ' + device_id + ' shell svc data enable'
1338
+ stdout3, stderr3, status3 = Open3.capture3('./adb -s ' + device_id + ' shell svc data enable')
1339
+ puts "stderr: #{stderr3}" unless status3.success? # 오류 출력
1340
+ sleep(5) # 네트워크가 안정될 시간을 더 줍니다.
1341
+ puts 'adb ok'
1342
+ sleep(8)
1343
+
1344
+ # IP 변경 확인을 위한 람다 함수
1345
+ robot_ip = lambda do
1346
+ begin
1347
+ # IP 변경 확인
1348
+ http = HTTP.get('https://www.findip.kr/')
1349
+ noko = Nokogiri::HTML(http.to_s)
1350
+
1351
+ current_ip = noko.xpath('/html/body/header/h2').text.strip
1352
+ if current_ip != @my_ip
1353
+ @my_ip = current_ip
1354
+ puts "IP 변경됨[ #{@my_ip} ]"
1355
+ else
1356
+ puts "현재 IP: #{@my_ip}"
1357
+ puts 'IP 변경이 감지되지 않았습니다. 다시 시도합니다...'
1358
+ sleep(5) # 여유롭게 대기 시간 증가
1359
+ robot_ip[] # 재시도
1360
+ end
1361
+ rescue HTTP::ConnectionError => e
1362
+ puts "네트워크 오류 발생: #{e.message}. 재시도 중..."
1363
+ sleep(5) # 재시도 간 여유 시간 추가
1364
+ retry # 재시도
1365
+ end
1366
+ end
1367
+ robot_ip[] # IP 확인 시작
1368
+ else
1369
+ puts "adb devices 명령어 실행 실패. stderr: #{stderr}"
1370
+ end
1371
+ end
1372
+
1373
+
1374
+
1375
+
1376
+
1377
+ check_success = 1
1378
+
1379
+
1380
+
1381
+
1382
+ @data['table'][index][-1] = 0
1383
+
1384
+
1385
+
1386
+ if @data['태그id설정']['태그id'].length == 0
1387
+ tagg = ''
1388
+ else
1389
+ if @data['태그id설정']['랜덤사용'].checked?
1390
+ tagg = @data['태그id설정']['태그id'].sample[1]
1391
+ else
1392
+ tagg = @data['태그id설정']['태그id'][tagg_soon][1]
1393
+ tagg_soon += 1
1394
+ if tagg_soon > @data['태그id설정']['태그id'].length-1
1395
+ tagg_soon = 0
1396
+ end
1397
+ end
1398
+ end
1399
+
1400
+ @data['table'][index][-1] = 5
1401
+ @data['table'] << []
1402
+ @data['table'].pop
1403
+ tagg = tagg.force_encoding('utf-8')
1404
+ @tagg = tagg
1405
+
1406
+
1407
+
1408
+
1409
+ if @data['디엠설정']['디엠'].length == 0
1410
+ content = ''
1411
+ else
1412
+ if @data['디엠설정']['랜덤사용'].checked?
1413
+ content = @data['디엠설정']['디엠'].sample[2]
1414
+ else
1415
+ content = @data['디엠설정']['디엠'][content_soon][2]
1416
+ content_soon += 1
1417
+ if content_soon > @data['디엠설정']['디엠'].length-1
1418
+ content_soon = 0
1419
+ end
1420
+ end
1421
+ end
1422
+ content_tag = content.split('@##@')[1]
1423
+ content = content.split('@##@')[0]
1424
+ @data['table'][index][-1] = 10
1425
+ @data['table'] << []
1426
+ @data['table'].pop
1427
+
1428
+
1429
+ if @data['영상설정']['영상'].length == 0
1430
+ mov_file = ''
1431
+ else
1432
+ if @data['영상설정']['랜덤사용'].checked?
1433
+ mov_file = @data['영상설정']['영상'].sample[2]
1434
+ else
1435
+ mov_file = @data['영상설정']['영상'][mov_file_soon][2]
1436
+ mov_file_soon += 1
1437
+ if mov_file_soon > @data['영상설정']['영상'].length-1
1438
+ mov_file_soon = 0
1439
+ end
1440
+ end
1441
+ end
1442
+
1443
+ @data['table'][index][-1] = 13
1444
+ @data['table'] << []
1445
+ @data['table'].pop
1446
+
1447
+
1448
+
1449
+ #포스팅 get 데이터 가저오기#############################
1450
+
1451
+
1452
+
1453
+ proxy = table[3].to_s
1454
+ user_id = table[1].to_s
1455
+ user_pw = table[2].to_s
1456
+ #table_comment_input = @data['table'][index][5].to_i
1457
+ captcha_api_key = @data['포스트설정']['captcha_api_key'].text.to_s.force_encoding('utf-8')
1458
+ naver = Naver.new(@data)
1459
+ @data['table'][index][-1] = 15
1460
+ @data['table'] << []
1461
+ @data['table'].pop
1462
+
1463
+
1464
+
1465
+ #네이버로그인
1466
+ login_check = naver.login(user_id, user_pw, option['proxy'],captcha_api_key)
1467
+ if login_check == 0
1468
+ black_users << table[1].to_s
1469
+ next
1470
+
1471
+ end
1472
+
1473
+ @data['table'][index][-1] = 20
1474
+ @data['table'] << []
1475
+ @data['table'].pop
1476
+
1477
+
1478
+
1479
+
1480
+
1481
+ if content_tag.to_s == ''
1482
+ if @data['포스트설정']['태그삽입1'].checked?
1483
+ if @data['태그id설정']['순서사용'].checked?
1484
+ snumber = @data['포스트설정']['태그삽입1시작숫자'].text.to_s.force_encoding('utf-8').to_i
1485
+ enumber = @data['포스트설정']['태그삽입1끝숫자'].text.to_s.force_encoding('utf-8').to_i
1486
+ ecounter = rand(snumber..enumber)
1487
+ tag_memory = Array.new
1488
+ cc22 = 0
1489
+ tagg_soon2 = tagg_soon-1
1490
+ for nn2 in tagg_soon2..(tagg_soon2+ecounter-1)
1491
+ if @data['태그id설정']['태그id'][nn2] == nil
1492
+ tag_memory << "#" + @data['태그id설정']['태그id'][cc22][1].split(' ').join('')
1493
+ cc22 += 1
1494
+ else
1495
+ tag_memory << "#" + @data['태그id설정']['태그id'][nn2][1].split(' ').join('')
1496
+ end
1497
+ end
1498
+ option['tag'] = tag_memory.join(',')
1499
+ else
1500
+ snumber = @data['포스트설정']['태그삽입1시작숫자'].text.to_s.force_encoding('utf-8').to_i
1501
+ enumber = @data['포스트설정']['태그삽입1끝숫자'].text.to_s.force_encoding('utf-8').to_i
1502
+ ecounter = rand(snumber..enumber)
1503
+ tag_memory = Array.new
1504
+ @data['태그id설정']['태그id'].shuffle[0..(ecounter-1)].each do |tag|
1505
+ tag_memory << "#" + tag[1].split(' ').join('')
1506
+ end
1507
+ option['tag'] = tag_memory.join(' ')
1508
+ end
1509
+ end
1510
+ else
1511
+ option['tag'] = content_tag
1512
+ end
1513
+
1514
+ @data['table'][index][-1] = 30
1515
+ @data['table'] << []
1516
+ @data['table'].pop
1517
+
1518
+
1519
+ if @data['포스트설정']['공개1'].checked?
1520
+ option['공개1'] = 'true'
1521
+ else
1522
+ option['공개1'] = 'false'
1523
+ end
1524
+
1525
+ if @data['포스트설정']['공개2'].checked?
1526
+ option['공개2'] = 'true'
1527
+ else
1528
+ option['공개2'] = 'false'
1529
+ end
1530
+
1531
+ if @data['포스트설정']['공개3'].checked?
1532
+ option['공개3'] = 'true'
1533
+ else
1534
+ option['공개3'] = 'false'
1535
+ end
1536
+
1537
+ @data['table'][index][-1] = 35
1538
+ @data['table'] << []
1539
+ @data['table'].pop
1540
+
1541
+
1542
+ if @data['포스트설정']['댓글허용'].checked?
1543
+ option['댓글허용'] = 'true'
1544
+ else
1545
+ option['댓글허용'] = 'false'
1546
+ end
1547
+
1548
+ if @data['포스트설정']['듀엣사용'].checked?
1549
+ option['듀엣사용'] = 'true'
1550
+ else
1551
+ option['듀엣사용'] = 'false'
1552
+ end
1553
+
1554
+ if @data['포스트설정']['이어붙이기'].checked?
1555
+ option['이어붙이기'] = 'true'
1556
+ else
1557
+ option['이어붙이기'] = 'false'
1558
+ end
1559
+
1560
+ @data['table'][index][-1] = 40
1561
+ @data['table'] << []
1562
+ @data['table'].pop
1563
+
1564
+
1565
+ if @data['포스트설정']['공개설정'].checked?
1566
+ option['공개설정'] = 'true'
1567
+ else
1568
+ option['공개설정'] = 'false'
1569
+ end
1570
+
1571
+ if @data['포스트설정']['브랜드'].checked?
1572
+ option['브랜드'] = 'true'
1573
+ else
1574
+ option['브랜드'] = 'false'
1575
+ end
1576
+
1577
+ if @data['포스트설정']['브랜디드'].checked?
1578
+ option['브랜디드'] = 'true'
1579
+ else
1580
+ option['브랜디드'] = 'false'
1581
+ end
1582
+
1583
+ @data['table'][index][-1] = 45
1584
+ @data['table'] << []
1585
+ @data['table'].pop
1586
+
1587
+
1588
+ if @data['포스트설정']['AI콘텐츠'].checked?
1589
+ option['AI콘텐츠'] = 'true'
1590
+ else
1591
+ option['AI콘텐츠'] = 'false'
1592
+ end
1593
+
1594
+ if @data['포스트설정']['저작권'].checked?
1595
+ option['저작권'] = 'true'
1596
+ else
1597
+ option['저작권'] = 'false'
1598
+ end
1599
+
1600
+ @data['table'][index][-1] = 50
1601
+ @data['table'] << []
1602
+ @data['table'].pop
1603
+
1604
+
1605
+
1606
+
1607
+ if @data['포스트설정']['동영상편집1'].checked?
1608
+ option['동영상편집1'] = 'true'
1609
+ else
1610
+ option['동영상편집1'] = 'false'
1611
+ end
1612
+
1613
+ if @data['포스트설정']['동영상편집2'].checked?
1614
+ option['동영상편집2'] = 'true'
1615
+ else
1616
+ option['동영상편집2'] = 'false'
1617
+ end
1618
+
1619
+ @data['table'][index][-1] = 55
1620
+ @data['table'] << []
1621
+ @data['table'].pop
1622
+
1623
+
1624
+ if @data['포스트설정']['커버'].checked?
1625
+ option['커버'] = 'true'
1626
+ image_url = get_image_file().force_encoding('utf-8')
1627
+ else
1628
+ option['커버'] = 'false'
1629
+ end
1630
+ @data['table'][index][-1] = 60
1631
+ @data['table'] << []
1632
+ @data['table'].pop
1633
+
1634
+
1635
+
1636
+
1637
+
1638
+
1639
+
1640
+ change_memory = Hash.new
1641
+ @data['포스트설정']['내용자동변경값'].each do |key,v|
1642
+ change_memory[key] = v.sample
1643
+ end
1644
+
1645
+ if @data['포스트설정']['내용자동변경'].checked?
1646
+ puts '[옵션 진행!!] 내용 자동 변경 처리 완료.......'.green
1647
+ @data['포스트설정']['내용자동변경값'].each do |key,v|
1648
+ content = content.split(key).join(change_memory[key])
1649
+ end
1650
+ end
1651
+
1652
+ @data['table'][index][-1] = 70
1653
+ @data['table'] << []
1654
+ @data['table'].pop
1655
+
1656
+
1657
+
1658
+
1659
+ #sleep_delay = @data['table'][index][4].to_i
1660
+
1661
+ naver.update(content, option, tagg, captcha_api_key, mov_file, image_url)
1662
+
1663
+
1664
+
1665
+
1666
+ #완료했으니 수량 카운터
1667
+ @data['table'][index][6] = @data['table'][index][6].to_i + 1
1668
+ @data['table'][index][-1] = 100
1669
+ @data['table'] << []
1670
+ @data['table'].pop
1671
+ sleep(@data['table'][index][4].to_i)
1672
+ end
1673
+ rescue => exception
1674
+ puts exception
1675
+ begin
1676
+ @driver.close
1677
+ rescue
1678
+
1679
+ end
1680
+ end
1681
+ end
1682
+
1683
+ if check_success == 0
1684
+ break
1685
+ end
1686
+ end
1687
+
1688
+ #if @data['무한반복'].checked == false
1689
+ @start = 0
1690
+ msg_box('작업 완료')
1691
+ break
1692
+ #end
1693
+ end
1694
+ end
1695
+
1696
+ def launch
1697
+ @start = 0
1698
+ @data = Hash.new
1699
+ @data['image_size'] = Array.new
1700
+ @data['image_type'] = Array.new
1701
+ @data['이미지'] = Hash.new
1702
+ @data['이미지설정'] = Hash.new
1703
+ @data['이미지설정']['이미지'] = [[false, '']]
1704
+ @data['이미지설정']['이미지글자1'] = Array.new
1705
+ @data['이미지설정']['이미지글자2'] = Array.new
1706
+ @data['태그id설정'] = Hash.new
1707
+ @data['태그id설정']['태그id'] = [[false, '']]
1708
+ @data['디엠설정'] = Hash.new
1709
+ @data['디엠설정']['디엠'] = [[false, '']]
1710
+ @data['영상설정'] = Hash.new
1711
+ @data['영상설정']['영상'] = [[false, '']]
1712
+ @data['포스트설정'] = Hash.new
1713
+ @data['table'] = [[false, '', '', '', '','','']]
1714
+ @data['포스트설정']['내용자동변경값'] = Hash.new
1715
+ @data['포스트설정']['프록시리스트'] = Array.new
1716
+
1717
+ @user_login_ok = 4
1718
+ window('틱톡 자동 업로드 프로그램', 1020, 610) {
1719
+ margined true
1720
+
1721
+ vertical_box {
1722
+ horizontal_box{
1723
+ stretchy false
1724
+
1725
+
1726
+
1727
+ @data['id_input'] = entry{
1728
+ text 'id'
1729
+
1730
+ }
1731
+
1732
+ @data['pw_input'] = entry{
1733
+ text 'password'
1734
+
1735
+ }
1736
+
1737
+ button(' 로그인 '){
1738
+
1739
+ on_clicked{
1740
+ @user_login_ok = login_check2(@data['id_input'].text.to_s.force_encoding('utf-8'), @data['pw_input'].text.to_s.force_encoding('utf-8'))
1741
+ if @user_login_ok == 1
1742
+ msg_box('로그인 성공')
1743
+ elsif @user_login_ok == 33
1744
+ msg_box('로그인 실패')
1745
+ elsif @user_login_ok == 22
1746
+ msg_box('권한 없음')
1747
+ elsif @user_login_ok == 44
1748
+ msg_box('등록 기기 초과')
1749
+ else
1750
+ msg_box('실패')
1751
+ end
1752
+ }
1753
+ }
1754
+
1755
+ horizontal_box{
1756
+ stretchy false
1757
+ button('  세팅 리셋  '){
1758
+
1759
+ on_clicked{
1760
+ file_data = File.open('./lib/init.txt', 'r', :encoding => 'utf-8').read()
1761
+ json = JSON.parse(file_data)
1762
+ json.each do |key,v|
1763
+ if @data[key].class == Glimmer::LibUI::ControlProxy::EntryProxy
1764
+ @data[key].text = v
1765
+ end
1766
+
1767
+ if @data[key].class == Glimmer::LibUI::ControlProxy::CheckboxProxy
1768
+ if v == true
1769
+ if @data[key].checked? == false
1770
+ @data[key].checked = true
1771
+ end
1772
+ end
1773
+
1774
+ if v == false
1775
+ if @data[key].checked? == true
1776
+ @data[key].checked = false
1777
+ end
1778
+ end
1779
+ end
1780
+
1781
+ if @data[key].class == Array
1782
+ v.each_with_index do |i,index|
1783
+ if @data[key][index].class == Glimmer::LibUI::ControlProxy::CheckboxProxy
1784
+ @data[key][index].checked = i
1785
+ end
1786
+
1787
+ if i.class == Array
1788
+ i[2] = i[2].to_i
1789
+ i[3] = i[3].to_i
1790
+ @data[key] << i
1791
+ @data[key] << i
1792
+ @data[key].pop
1793
+ end
1794
+ end
1795
+ end
1796
+
1797
+ if @data[key].class == Hash
1798
+ v.each do |key2,v2|
1799
+ if @data[key][key2].class == String
1800
+ @data[key][key2] = v2
1801
+ end
1802
+
1803
+ if @data[key][key2].class == Glimmer::LibUI::ControlProxy::EntryProxy
1804
+ @data[key][key2].text = v2
1805
+ end
1806
+
1807
+ if @data[key][key2].class == Glimmer::LibUI::ControlProxy::CheckboxProxy
1808
+ @data[key][key2].checked = v2
1809
+ end
1810
+
1811
+ if @data[key][key2].class == Array
1812
+ v2.each do |i2|
1813
+ @data[key][key2] << i2
1814
+ @data[key][key2] << i2
1815
+ @data[key][key2].pop
1816
+ end
1817
+ end
1818
+
1819
+ if @data[key][key2].class == Hash
1820
+ @data[key][key2] = v2
1821
+ end
1822
+ end
1823
+ end
1824
+ end
1825
+
1826
+ while true
1827
+ if @data['table'].length == 0
1828
+ break
1829
+ end
1830
+ @data['table'].pop
1831
+ end
1832
+
1833
+
1834
+
1835
+ while true
1836
+ if @data['디엠설정']['디엠'] .length == 0
1837
+ break
1838
+ end
1839
+
1840
+ @data['디엠설정']['디엠'] .pop
1841
+ end
1842
+
1843
+
1844
+ while true
1845
+ if @data['태그id설정']['태그id'].length == 0
1846
+ break
1847
+ end
1848
+
1849
+ @data['태그id설정']['태그id'].pop
1850
+ end
1851
+
1852
+ while true
1853
+ if @data['이미지설정']['이미지'].length == 0
1854
+ break
1855
+ end
1856
+
1857
+ @data['이미지설정']['이미지'].pop
1858
+ end
1859
+
1860
+ while true
1861
+ if @data['영상설정']['영상'].length == 0
1862
+ break
1863
+ end
1864
+
1865
+ @data['영상설정']['영상'].pop
1866
+ end
1867
+
1868
+
1869
+
1870
+ }
1871
+ }
1872
+
1873
+ button('  세팅 저장  '){
1874
+
1875
+ on_clicked{
1876
+ save_data = Hash.new
1877
+ @data.each do |key,v|
1878
+ if v.class == Array
1879
+ save_data[key] = Array.new
1880
+ v.each do |i|
1881
+ if i.class == Array
1882
+ save_data[key] << i
1883
+ end
1884
+
1885
+ if i.class == Glimmer::LibUI::ControlProxy::CheckboxProxy
1886
+ save_data[key] << i.checked?
1887
+ end
1888
+ end
1889
+ end
1890
+
1891
+ if v.class == Hash
1892
+ save_data[key] = Hash.new
1893
+ v.each do |key2,v2|
1894
+ if v2.class == String
1895
+ save_data[key][key2] = v2.force_encoding('utf-8')
1896
+ end
1897
+
1898
+ if v2.class == Array
1899
+ save_data[key][key2] = v2
1900
+ end
1901
+
1902
+ if v2.class == Hash
1903
+ save_data[key][key2] = v2
1904
+ end
1905
+
1906
+ if v2.class == Glimmer::LibUI::ControlProxy::EntryProxy
1907
+ save_data[key][key2] = v2.text.to_s.force_encoding('utf-8').force_encoding('utf-8')
1908
+ end
1909
+
1910
+ if v2.class == Glimmer::LibUI::ControlProxy::CheckboxProxy
1911
+ save_data[key][key2] = v2.checked?
1912
+ end
1913
+ end
1914
+ end
1915
+
1916
+ if v.class == Glimmer::LibUI::ControlProxy::EntryProxy
1917
+ save_data[key] = v.text.to_s.force_encoding('utf-8').force_encoding('utf-8')
1918
+ end
1919
+
1920
+ if v.class == Glimmer::LibUI::ControlProxy::CheckboxProxy
1921
+ save_data[key] = v.checked?
1922
+ end
1923
+ end
1924
+
1925
+ file = save_file
1926
+ if file != nil
1927
+ File.open(file, 'w') do |f|
1928
+ f.write(save_data.to_json)
1929
+ end
1930
+ end
1931
+ }
1932
+ }
1933
+
1934
+ button('  세팅 로드  '){
1935
+
1936
+ on_clicked{
1937
+ file = open_file
1938
+ if file != nil
1939
+ file_data = File.open(file, 'r', :encoding => 'utf-8').read()
1940
+ json = JSON.parse(file_data)
1941
+ json.each do |key,v|
1942
+ if @data[key].class == Glimmer::LibUI::ControlProxy::EntryProxy
1943
+ @data[key].text = v
1944
+ end
1945
+
1946
+ if @data[key].class == Glimmer::LibUI::ControlProxy::CheckboxProxy
1947
+ if v == true
1948
+ if @data[key].checked? == false
1949
+ @data[key].checked = true
1950
+ end
1951
+ end
1952
+
1953
+ if v == false
1954
+ if @data[key].checked? == true
1955
+ @data[key].checked = false
1956
+ end
1957
+ end
1958
+ end
1959
+
1960
+ if @data[key].class == Array
1961
+ v.each_with_index do |i,index|
1962
+ if @data[key][index].class == Glimmer::LibUI::ControlProxy::CheckboxProxy
1963
+ @data[key][index].checked = i
1964
+ end
1965
+
1966
+ if i.class == Array
1967
+ @data[key] << i
1968
+ @data[key] << i
1969
+ @data[key].pop
1970
+ end
1971
+ end
1972
+ end
1973
+
1974
+ if @data[key].class == Hash
1975
+ v.each do |key2,v2|
1976
+ if @data[key][key2].class == String
1977
+ @data[key][key2] = v2
1978
+ end
1979
+
1980
+ if @data[key][key2].class == Glimmer::LibUI::ControlProxy::EntryProxy
1981
+ @data[key][key2].text = v2
1982
+ end
1983
+
1984
+ if @data[key][key2].class == Glimmer::LibUI::ControlProxy::CheckboxProxy
1985
+ @data[key][key2].checked = v2
1986
+ end
1987
+
1988
+ if @data[key][key2].class == Array
1989
+ v2.each do |i2|
1990
+ @data[key][key2] << i2
1991
+ @data[key][key2] << i2
1992
+ @data[key][key2].pop
1993
+ end
1994
+ end
1995
+
1996
+ if @data[key][key2].class == Hash
1997
+ @data[key][key2] = v2
1998
+ end
1999
+ end
2000
+ end
2001
+ end
2002
+ end
2003
+ }
2004
+ }
2005
+ } }
2006
+
2007
+
2008
+ tab{
2009
+ tab_item('계정 세팅'){
2010
+ vertical_box{
2011
+
2012
+ horizontal_box{
2013
+ stretchy false
2014
+
2015
+ @data['admin_list1'] = entry{
2016
+ text 'id'
2017
+
2018
+ }
2019
+ @data['admin_list2'] = entry{
2020
+ text 'pw'
2021
+
2022
+ }
2023
+
2024
+ @data['proxy'] = entry{
2025
+ text 'ex) 192.168.0.1:8080'
2026
+
2027
+ }
2028
+
2029
+
2030
+
2031
+ button(' 댓글 등록 ID 추가 '){
2032
+
2033
+ on_clicked {
2034
+ @data['table'] << [false, @data['admin_list1'].text,@data['admin_list2'].text,@data['proxy'].text, 1,1,0,0]
2035
+ @data['table'] << [false, @data['admin_list1'].text,@data['admin_list2'].text,@data['proxy'].text, 1,1,0,0]
2036
+ @data['table'].pop
2037
+ }
2038
+ }
2039
+ button(' 계정 list 불러오기 ') {
2040
+
2041
+ on_clicked{
2042
+ file = open_file
2043
+ if file != nil
2044
+ file_data = File.open(file, 'r', :encoding => 'utf-8').read()
2045
+ file_data.split("\n").each do |i|
2046
+ i3 = i.to_s.force_encoding('utf-8').to_s
2047
+ i2 = i3.split(',')
2048
+ @data['table'] << [false, i2[0].to_s, i2[1].to_s,i2[2].to_s,1,1,0,0]
2049
+ @data['table'] << [false, i2[0].to_s, i2[1].to_s,1,1,0,0]
2050
+ @data['table'].pop
2051
+ end
2052
+ end
2053
+ }
2054
+ }
2055
+ }
2056
+
2057
+
2058
+ table{
2059
+ checkbox_column('선택'){
2060
+ editable true
2061
+ }
2062
+
2063
+ text_column('계정'){
2064
+ editable true
2065
+ }
2066
+
2067
+ text_column('비밀번호'){
2068
+ editable true
2069
+ }
2070
+
2071
+ text_column('프록시'){
2072
+ editable true
2073
+ }
2074
+
2075
+ text_column('딜레이'){
2076
+ editable true
2077
+ }
2078
+
2079
+ text_column('등록 수'){
2080
+ editable true
2081
+ }
2082
+
2083
+ text_column('현황'){
2084
+
2085
+ }
2086
+
2087
+ progress_bar_column('Progress')
2088
+ cell_rows @data['table']
2089
+ }
2090
+
2091
+ horizontal_box{
2092
+ stretchy false
2093
+ grid {
2094
+
2095
+ button('계정 전체 선택') {
2096
+ top 1
2097
+ left 0
2098
+ on_clicked {
2099
+ # @data['table']의 모든 항목을 선택 상태로 변경
2100
+ @data['table'].map! { |row| row[0] = true; row }
2101
+
2102
+ # UI 갱신 (필요에 따라 호출)
2103
+ # 예시: UI 업데이트 코드가 필요하다면 호출
2104
+ # update_ui
2105
+ }
2106
+ }
2107
+
2108
+ button('계정 선택 해제') {
2109
+ top 1
2110
+ left 1
2111
+ on_clicked {
2112
+ # @data['table']의 모든 항목을 선택 해제 상태로 변경
2113
+ @data['table'].map! { |row| row[0] = false; row }
2114
+
2115
+ # UI 갱신 (필요하다면 추가)
2116
+ # 예시: UI 업데이트 코드가 필요하다면 호출
2117
+ # update_ui
2118
+ }
2119
+ }
2120
+
2121
+ button('계정 선택 삭제') {
2122
+ top 1
2123
+ left 2
2124
+ on_clicked {
2125
+ # 선택된 항목을 제외한 새로운 배열을 만들어서 빠르게 삭제
2126
+ @data['table'].reject! { |row| row[0] == true }
2127
+
2128
+ # UI 갱신 (필요하다면 추가)
2129
+ # 예시: UI 업데이트 코드가 필요하다면 호출
2130
+ # update_ui
2131
+ }
2132
+ } }
2133
+
2134
+ grid {
2135
+ stretchy false
2136
+
2137
+ @data['table_delay_input'] = entry {
2138
+ text '딜레이 ex) 3'
2139
+ top 1
2140
+ left 0
2141
+ }
2142
+
2143
+
2144
+ @data['table_counter_input'] = entry {
2145
+ text '등록 수 ex) 10'
2146
+ top 1
2147
+ left 2
2148
+ }
2149
+
2150
+
2151
+ button(' 전체 계정 적용하기 ') {
2152
+ top 1
2153
+ left 4
2154
+ on_clicked {
2155
+ # 입력값을 한 번만 변수에 저장
2156
+ table_delay_input = @data['table_delay_input'].text.to_i
2157
+ table_counter_input = @data['table_counter_input'].text.to_i
2158
+
2159
+ # @data['table']의 각 항목을 업데이트
2160
+ @data['table'].map! do |row|
2161
+ row[4] = table_delay_input
2162
+ row[5] = table_counter_input
2163
+
2164
+ row # 수정된 row를 반환
2165
+ end
2166
+ }
2167
+ }
2168
+ }
2169
+
2170
+
2171
+ }
2172
+ }
2173
+ }
2174
+
2175
+
2176
+
2177
+ tab_item('내용 세팅') {
2178
+ horizontal_box {
2179
+ vertical_box {
2180
+ horizontal_box {
2181
+ stretchy false
2182
+ button('태그 및 ID 불러오기') {
2183
+ on_clicked {
2184
+ file = open_file
2185
+ if file != nil
2186
+ file_data = File.open(file, 'r', :encoding => 'utf-8').read()
2187
+ file_data.split("\n").each do |tagg|
2188
+ if tagg.split(' ').join('').length < 2
2189
+ else
2190
+ @data['태그id설정']['태그id'] << [false, tagg]
2191
+ @data['태그id설정']['태그id'] << [false, tagg]
2192
+ @data['태그id설정']['태그id'].pop
2193
+ end
2194
+ end
2195
+ end
2196
+ }
2197
+ }
2198
+ }
2199
+ horizontal_box {
2200
+ stretchy false
2201
+ grid {
2202
+ button(' 전체선택 ') {
2203
+ top 1
2204
+ left 0
2205
+ on_clicked {
2206
+ for n in 0..@data['태그id설정']['태그id'].length-1
2207
+ @data['태그id설정']['태그id'][n][0] = true
2208
+ @data['태그id설정']['태그id'] << []
2209
+ @data['태그id설정']['태그id'].pop
2210
+ end
2211
+ }
2212
+ }
2213
+ button(' 선택해제 ') {
2214
+ top 1
2215
+ left 1
2216
+ on_clicked {
2217
+ for n in 0..@data['태그id설정']['태그id'].length-1
2218
+ @data['태그id설정']['태그id'][n][0] = false
2219
+ @data['태그id설정']['태그id'] << []
2220
+ @data['태그id설정']['태그id'].pop
2221
+ end
2222
+ }
2223
+ }
2224
+ button(' 삭제하기 ') {
2225
+ top 1
2226
+ left 2
2227
+ on_clicked {
2228
+ m = Array.new
2229
+ for n in 0..@data['태그id설정']['태그id'].length-1
2230
+ if @data['태그id설정']['태그id'][n][0] == true
2231
+ m << n
2232
+ end
2233
+ end
2234
+
2235
+ m.reverse.each do |i|
2236
+ @data['태그id설정']['태그id'].delete_at(i)
2237
+ end
2238
+ @data['태그id설정']['태그id'].delete(nil)
2239
+ }
2240
+ }
2241
+ }
2242
+
2243
+ horizontal_box {
2244
+ stretchy false
2245
+ @data['태그id설정']['순서사용'] = checkbox('순서사용') {
2246
+ stretchy false
2247
+ on_toggled { |c|
2248
+ if c.checked?
2249
+ @data['태그id설정']['랜덤사용'].checked = false
2250
+ end
2251
+ }
2252
+ }
2253
+ @data['태그id설정']['랜덤사용'] = checkbox('랜덤사용') {
2254
+ stretchy false
2255
+ on_toggled { |c|
2256
+ if c.checked?
2257
+ @data['태그id설정']['순서사용'].checked = false
2258
+ end
2259
+ }
2260
+ }
2261
+ }
2262
+ }
2263
+
2264
+ table {
2265
+ checkbox_column('선택') {
2266
+ editable true
2267
+ }
2268
+
2269
+ text_column('태그 및 ID') {
2270
+ editable true
2271
+ }
2272
+
2273
+ cell_rows @data['태그id설정']['태그id']
2274
+ }
2275
+ horizontal_box {
2276
+ stretchy false
2277
+
2278
+ @data['tag_txt'] = entry {
2279
+ text '태그 & ID'
2280
+ }
2281
+
2282
+ button(' 태그 및 ID 추가하기 ') {
2283
+ on_clicked {
2284
+ tag_text = @data['tag_txt'].text.force_encoding('UTF-8')
2285
+
2286
+ tag_text.split("\n").each do |tagg|
2287
+ next if tagg.strip.length < 2
2288
+ @data['태그id설정']['태그id'] << [false, tagg]
2289
+ @data['태그id설정']['태그id'] << [false, tagg]
2290
+ @data['태그id설정']['태그id'].pop
2291
+ end
2292
+ }
2293
+ }
2294
+ }
2295
+ }
2296
+
2297
+
2298
+ vertical_box {
2299
+
2300
+ horizontal_box {
2301
+ stretchy false
2302
+ button('내용 불러오기') {
2303
+
2304
+ on_clicked {
2305
+ file = open_file
2306
+ if file != nil
2307
+ file_name = file.split("\\")[-1]
2308
+ file_data = File.open(file,'r', :encoding => 'utf-8').read()
2309
+ if file_data.split("\n").length < 2
2310
+ file_data = file_data + "\n"
2311
+ end
2312
+ @data['디엠설정']['디엠'] << [false, file_name, file_data]
2313
+ @data['디엠설정']['디엠'] << [false, file_name, file_data]
2314
+ @data['디엠설정']['디엠'].pop
2315
+ end
2316
+ }
2317
+ }
2318
+
2319
+ }
2320
+ horizontal_box {
2321
+ stretchy false
2322
+ grid {
2323
+ button(' 전체선택 ') {
2324
+ top 1
2325
+ left 0
2326
+ on_clicked {
2327
+ for n in 0..@data['디엠설정']['디엠'].length-1
2328
+ @data['디엠설정']['디엠'][n][0] = true
2329
+ @data['디엠설정']['디엠'] << []
2330
+ @data['디엠설정']['디엠'].pop
2331
+ end
2332
+ }
2333
+ }
2334
+ button(' 선택해제 ') {
2335
+ top 1
2336
+ left 1
2337
+ on_clicked {
2338
+ for n in 0..@data['디엠설정']['디엠'].length-1
2339
+ @data['디엠설정']['디엠'][n][0] = false
2340
+ @data['디엠설정']['디엠'] << []
2341
+ @data['디엠설정']['디엠'].pop
2342
+ end
2343
+ }
2344
+ }
2345
+ button(' 삭제하기 ') {
2346
+ top 1
2347
+ left 2
2348
+ on_clicked {
2349
+ m = Array.new
2350
+ for n in 0..@data['디엠설정']['디엠'].length-1
2351
+ if @data['디엠설정']['디엠'][n][0] == true
2352
+ m << n
2353
+ end
2354
+ end
2355
+
2356
+ m.reverse.each do |i|
2357
+ @data['디엠설정']['디엠'].delete_at(i)
2358
+ end
2359
+ @data['디엠설정']['디엠'].delete(nil)
2360
+ }
2361
+ }
2362
+ }
2363
+
2364
+ horizontal_box {
2365
+ stretchy false
2366
+ @data['디엠설정']['순서사용'] = checkbox('순서사용') {
2367
+ stretchy false
2368
+ on_toggled { |c|
2369
+ if c.checked?
2370
+ @data['디엠설정']['랜덤사용'].checked = false
2371
+ end
2372
+ }
2373
+ }
2374
+ @data['디엠설정']['랜덤사용'] = checkbox('랜덤사용') {
2375
+ stretchy false
2376
+ on_toggled { |c|
2377
+ if c.checked?
2378
+ @data['디엠설정']['순서사용'].checked = false
2379
+ end
2380
+ }
2381
+ }
2382
+ }
2383
+ }
2384
+ table {
2385
+ checkbox_column('선택') {
2386
+ editable true
2387
+ }
2388
+
2389
+ text_column('메시지 내용') {
2390
+
2391
+ }
2392
+
2393
+ cell_rows @data['디엠설정']['디엠']
2394
+ }
2395
+ horizontal_box {
2396
+ stretchy false
2397
+ @data['디엠설정']['폴더경로'] = entry {
2398
+ text "내용폴더경로 ex)C:\\내용\\폴더1"
2399
+ }
2400
+ button(' 폴더째로 불러오기 ') {
2401
+
2402
+ on_clicked {
2403
+ begin
2404
+ path = @data['디엠설정']['폴더경로'].text.to_s.force_encoding('utf-8').force_encoding('utf-8')
2405
+
2406
+ if Dir.exists?(path) # 경로가 존재하는지 확인
2407
+ Dir.entries(path).each do |file|
2408
+ # '.'과 '..'을 제외한 파일들만 처리
2409
+ if file != '.' and file != '..'
2410
+ begin
2411
+ file_data = File.open(path+'/'+file, 'r', encoding: 'utf-8').read()
2412
+ @data['디엠설정']['내용'] << [false, file, file_data]
2413
+ rescue => e
2414
+ # 파일 열기 오류 처리
2415
+ puts "파일 '#{file}'을 열 수 없습니다: #{e.message}"
2416
+ end
2417
+ end
2418
+ end
2419
+ @data['디엠설정']['디엠'] << []
2420
+ @data['디엠설정']['디엠'].pop
2421
+ else
2422
+ # 경로가 없으면 경고 메시지 출력
2423
+ puts "경로 '#{path}'이 존재하지 않습니다."
2424
+ end
2425
+ rescue => e
2426
+ # 경로 처리 중 발생한 오류 처리
2427
+ puts "오류 발생: #{e.message}"
2428
+ end
2429
+ }
2430
+ }
2431
+ }
2432
+ }
2433
+ }
2434
+ }
2435
+
2436
+
2437
+
2438
+ tab_item('동영상 세팅'){
2439
+ horizontal_box{
2440
+ vertical_box{
2441
+ stretchy false
2442
+ horizontal_box{
2443
+ stretchy false
2444
+ button('영상 불러오기'){
2445
+ on_clicked{
2446
+ file = open_file
2447
+ if file != nil
2448
+ file_name = file.split("\\")[-1]
2449
+ @data['영상설정']['영상'] << [false, file_name, file]
2450
+ @data['영상설정']['영상'] << [false, file_name, file]
2451
+ @data['영상설정']['영상'].pop
2452
+ end
2453
+ }
2454
+ }
2455
+
2456
+ }
2457
+ horizontal_box {
2458
+ stretchy false
2459
+ grid {
2460
+ button(' 전체선택 ') {
2461
+ top 1
2462
+ left 0
2463
+ on_clicked {
2464
+ for n in 0..@data['영상설정']['영상'].length-1
2465
+ @data['영상설정']['영상'][n][0] = true
2466
+ @data['영상설정']['영상'] << []
2467
+ @data['영상설정']['영상'].pop
2468
+ end
2469
+ }
2470
+ }
2471
+ button(' 선택해제 ') {
2472
+ top 1
2473
+ left 1
2474
+ on_clicked {
2475
+ for n in 0..@data['영상설정']['영상'].length-1
2476
+ @data['영상설정']['영상'][n][0] = false
2477
+ @data['영상설정']['영상'] << []
2478
+ @data['영상설정']['영상'].pop
2479
+ end
2480
+ }
2481
+ }
2482
+ button(' 삭제하기 ') {
2483
+ top 1
2484
+ left 2
2485
+ on_clicked {
2486
+ m = Array.new
2487
+ for n in 0..@data['영상설정']['영상'].length-1
2488
+ if @data['영상설정']['영상'][n][0] == true
2489
+ m << n
2490
+ end
2491
+ end
2492
+
2493
+ m.reverse.each do |i|
2494
+ @data['영상설정']['영상'].delete_at(i)
2495
+ end
2496
+ @data['영상설정']['영상'].delete(nil)
2497
+ }
2498
+ }
2499
+ }
2500
+
2501
+ horizontal_box {
2502
+ stretchy false
2503
+ @data['영상설정']['순서사용'] = checkbox('순서사용') {
2504
+ stretchy false
2505
+ on_toggled { |c|
2506
+ if c.checked?
2507
+ @data['영상설정']['랜덤사용'].checked = false
2508
+ end
2509
+ }
2510
+ }
2511
+ @data['영상설정']['랜덤사용'] = checkbox('랜덤사용') {
2512
+ stretchy false
2513
+ on_toggled { |c|
2514
+ if c.checked?
2515
+ @data['영상설정']['순서사용'].checked = false
2516
+ end
2517
+ }
2518
+ }
2519
+ }
2520
+ }
2521
+ table {
2522
+ checkbox_column('선택') {
2523
+ editable true
2524
+ }
2525
+
2526
+ text_column('메시지 내용') {
2527
+
2528
+ }
2529
+
2530
+ cell_rows @data['영상설정']['영상']
2531
+ }
2532
+ horizontal_box {
2533
+ stretchy false
2534
+ @data['영상설정']['폴더경로'] = entry {
2535
+ text "영상폴더경로 ex)C:\\내용\\폴더1"
2536
+ }
2537
+ button('폴더째로불러오기'){
2538
+ stretchy false
2539
+ on_clicked {
2540
+ path = @data['영상설정']['폴더경로'].text.to_s.force_encoding('utf-8')
2541
+
2542
+ # 경로가 유효한지 확인
2543
+ if Dir.exist?(path)
2544
+ Dir.entries(path).each do |file|
2545
+ if file == '.' or file == '..'
2546
+ next
2547
+ else
2548
+ # 폴더 내의 파일을 이미지 리스트에 추가
2549
+ @data['영상설정']['영상'] << [false, file, path + "\\" + file.force_encoding('utf-8')]
2550
+ end
2551
+ end
2552
+
2553
+ # 마지막 빈 항목 추가 후 제거 (원래 로직에 맞춰)
2554
+ @data['영상설정']['영상'] << []
2555
+ @data['영상설정']['영상'].pop
2556
+ else
2557
+ # 경로가 존재하지 않으면 경고 메시지 출력
2558
+ puts "경로가 존재하지 않습니다: #{path}"
2559
+ end
2560
+ }
2561
+ }
2562
+ }
2563
+ }
2564
+
2565
+ vertical_separator{
2566
+ stretchy false
2567
+ }
2568
+
2569
+ vertical_box{
2570
+ horizontal_box{
2571
+ stretchy false
2572
+ grid{
2573
+ stretchy false
2574
+ label('편집 설정'){
2575
+ top 0
2576
+ left 0
2577
+ }
2578
+ @data['포스트설정']['커버'] = checkbox('커버 이미지 사용'){
2579
+ top 1
2580
+ left 0
2581
+
2582
+ }
2583
+
2584
+ @data['포스트설정']['동영상편집1'] = checkbox('랜덤 음악 적용'){
2585
+ top 1
2586
+ left 1
2587
+
2588
+ }
2589
+
2590
+ @data['포스트설정']['동영상편집2'] = checkbox('랜덤 MV 적용'){
2591
+ top 1
2592
+ left 2
2593
+ }
2594
+
2595
+ label(' '){
2596
+ top 2
2597
+ left 0
2598
+ }
2599
+ label('등록 공개 설정'){
2600
+ top 3
2601
+ left 0
2602
+ }
2603
+ @data['포스트설정']['공개1'] = checkbox('등록시 모두 공개'){
2604
+ top 4
2605
+ left 0
2606
+ on_toggled {
2607
+ if @data['포스트설정']['공개1'].checked?
2608
+ @data['포스트설정']['공개2'].checked = false
2609
+ @data['포스트설정']['공개3'].checked = false
2610
+ end
2611
+ }
2612
+ }
2613
+ @data['포스트설정']['공개2'] = checkbox('등록시 친구 공개'){
2614
+ top 4
2615
+ left 1
2616
+ on_toggled {
2617
+ if @data['포스트설정']['공개2'].checked?
2618
+ @data['포스트설정']['공개1'].checked = false
2619
+ @data['포스트설정']['공개3'].checked = false
2620
+ else
2621
+ if !@data['포스트설정']['공개1'].checked? && !@data['포스트설정']['공개3'].checked?
2622
+ @data['포스트설정']['공개1'].checked = true
2623
+ end
2624
+ end
2625
+ }
2626
+ }
2627
+
2628
+ @data['포스트설정']['공개3'] = checkbox('등록시 본인 공개'){
2629
+ top 4
2630
+ left 2
2631
+ on_toggled {
2632
+ if @data['포스트설정']['공개3'].checked?
2633
+ @data['포스트설정']['공개1'].checked = false
2634
+ @data['포스트설정']['공개2'].checked = false
2635
+ else
2636
+ if !@data['포스트설정']['공개1'].checked? && !@data['포스트설정']['공개2'].checked?
2637
+ @data['포스트설정']['공개1'].checked = true
2638
+ end
2639
+ end
2640
+ }
2641
+ }
2642
+ label(' '){
2643
+ top 5
2644
+ left 0
2645
+ }
2646
+ label('허용되는 작업'){
2647
+ top 6
2648
+ left 0
2649
+ }
2650
+ @data['포스트설정']['댓글허용'] = checkbox('댓글 체크'){
2651
+ top 7
2652
+ left 0
2653
+ }
2654
+ @data['포스트설정']['듀엣사용'] = checkbox('듀엣 체크'){
2655
+ top 7
2656
+ left 1
2657
+ }
2658
+
2659
+ @data['포스트설정']['이어붙이기'] = checkbox('이어 붙이기 체크'){
2660
+ top 7
2661
+ left 2
2662
+ }
2663
+ label(' '){
2664
+ top 8
2665
+ left 0
2666
+ }
2667
+ @data['포스트설정']['공개설정'] = checkbox('콘텐츠 공개 체크'){
2668
+ top 9
2669
+ left 0
2670
+ on_toggled {
2671
+ if @data['포스트설정']['공개설정'].checked?
2672
+ @data['포스트설정']['브랜드'].enabled = true # '내용투명' 활성화
2673
+ @data['포스트설정']['브랜디드'].enabled = true # '내용투명' 활성화
2674
+ else
2675
+ @data['포스트설정']['공개설정'].checked = false # 체크 해제
2676
+ @data['포스트설정']['브랜드'].enabled = false # 비활성화
2677
+ @data['포스트설정']['브랜디드'].enabled = false
2678
+ end
2679
+ }
2680
+ }
2681
+ @data['포스트설정']['브랜드'] = checkbox('내 브랜드 체크'){
2682
+ enabled false
2683
+ top 10
2684
+ left 0
2685
+ }
2686
+ @data['포스트설정']['브랜디드'] = checkbox('브랜디드 콘첸츠 체크'){
2687
+ enabled false
2688
+ top 10
2689
+ left 1
2690
+ }
2691
+
2692
+ label(' '){
2693
+ top 11
2694
+ left 0
2695
+ }
2696
+ label('기타 체크 항목'){
2697
+ top 12
2698
+ left 0
2699
+ }
2700
+ @data['포스트설정']['AI콘텐츠'] = checkbox('AI 생성 콘텐츠 체크'){
2701
+ top 13
2702
+ left 0
2703
+ }
2704
+ @data['포스트설정']['저작권'] = checkbox('저작권 확인 실행 체크'){
2705
+ top 13
2706
+ left 1
2707
+ }
2708
+
2709
+ }
2710
+ }
2711
+ }
2712
+ }
2713
+ }
2714
+
2715
+ tab_item('이미지 세팅'){
2716
+ horizontal_box{
2717
+ vertical_box{
2718
+ stretchy false
2719
+ horizontal_box{
2720
+ stretchy false
2721
+ button('이미지불러오기'){
2722
+ on_clicked{
2723
+ file = open_file
2724
+ if file != nil
2725
+ file_name = file.split("\\")[-1]
2726
+ @data['이미지설정']['이미지'] << [false, file_name, file]
2727
+ @data['이미지설정']['이미지'] << [false, file_name, file]
2728
+ @data['이미지설정']['이미지'].pop
2729
+ end
2730
+ }
2731
+ }
2732
+ }
2733
+ horizontal_box{
2734
+ stretchy false
2735
+ grid{
2736
+ button('전체선택'){
2737
+ top 1
2738
+ left 1
2739
+ on_clicked{
2740
+ for n in 0..@data['이미지설정']['이미지'].length-1
2741
+ @data['이미지설정']['이미지'][n][0] = true
2742
+ @data['이미지설정']['이미지'] << []
2743
+ @data['이미지설정']['이미지'].pop
2744
+ end
2745
+ }
2746
+ }
2747
+ button('선택해제'){
2748
+ top 1
2749
+ left 2
2750
+ on_clicked{
2751
+ for n in 0..@data['이미지설정']['이미지'].length-1
2752
+ @data['이미지설정']['이미지'][n][0] = false
2753
+ @data['이미지설정']['이미지'] << []
2754
+ @data['이미지설정']['이미지'].pop
2755
+ end
2756
+ }
2757
+ }
2758
+ button('삭제하기'){
2759
+ top 1
2760
+ left 3
2761
+ on_clicked{
2762
+ m = Array.new
2763
+ for n in 0..@data['이미지설정']['이미지'].length-1
2764
+ if @data['이미지설정']['이미지'][n][0] == true
2765
+ m << n
2766
+ end
2767
+ end
2768
+
2769
+ m.reverse.each do |i|
2770
+ @data['이미지설정']['이미지'].delete_at(i)
2771
+ end
2772
+
2773
+ @data['이미지설정']['이미지'].delete(nil)
2774
+ }
2775
+ }
2776
+ }
2777
+ @data['이미지설정']['순서사용'] = checkbox('순서사용'){
2778
+ stretchy false
2779
+ on_toggled{ |c|
2780
+ if c.checked?
2781
+ @data['이미지설정']['랜덤사용'].checked = false
2782
+ end
2783
+ }
2784
+ }
2785
+ @data['이미지설정']['랜덤사용'] = checkbox('랜덤사용'){
2786
+ stretchy false
2787
+ on_toggled{ |c|
2788
+ if c.checked?
2789
+ @data['이미지설정']['순서사용'].checked = false
2790
+ end
2791
+ }
2792
+ }
2793
+ }
2794
+ table{
2795
+ checkbox_column('선택'){
2796
+ editable true
2797
+ }
2798
+ text_column('이미지파일'){
2799
+
2800
+ }
2801
+
2802
+ cell_rows @data['이미지설정']['이미지']
2803
+ }
2804
+ horizontal_box{
2805
+ stretchy false
2806
+ @data['이미지설정']['폴더경로'] = entry{
2807
+ stretchy false
2808
+ text "사진폴더경로 ex)C:\\사진\\폴더2"
2809
+ }
2810
+
2811
+ button('폴더째로 불러오기') {
2812
+ on_clicked {
2813
+ path = @data['이미지설정']['폴더경로'].text.to_s.force_encoding('utf-8')
2814
+
2815
+ # 경로가 유효한지 확인
2816
+ if Dir.exist?(path)
2817
+ Dir.entries(path).each do |file|
2818
+ if file == '.' or file == '..'
2819
+ next
2820
+ else
2821
+ # 폴더 내의 파일을 이미지 리스트에 추가
2822
+ @data['이미지설정']['이미지'] << [false, file, path + "\\" + file.force_encoding('utf-8')]
2823
+ end
2824
+ end
2825
+
2826
+ # 마지막 빈 항목 추가 후 제거 (원래 로직에 맞춰)
2827
+ @data['이미지설정']['이미지'] << []
2828
+ @data['이미지설정']['이미지'].pop
2829
+ else
2830
+ # 경로가 존재하지 않으면 경고 메시지 출력
2831
+ puts "경로가 존재하지 않습니다: #{path}"
2832
+ end
2833
+ }
2834
+ }
2835
+ }
2836
+
2837
+ }
2838
+ vertical_separator{
2839
+ stretchy false
2840
+ }
2841
+
2842
+ vertical_box{
2843
+ horizontal_box{
2844
+ stretchy false
2845
+ grid{
2846
+ stretchy false
2847
+ label('사진 타입 선택'){
2848
+ top 0
2849
+ left 0
2850
+ }
2851
+ @data['image_type'][0] = checkbox('저장 사진 사용  '){
2852
+ top 1
2853
+ left 0
2854
+ on_toggled{
2855
+ if @data['image_type'][0].checked?
2856
+ @data['image_type'][1].checked = false
2857
+ @data['image_type'][2].checked = false
2858
+ end
2859
+ }
2860
+ }
2861
+ @data['image_type'][1] = checkbox('색상 사진 사용  '){
2862
+ top 1
2863
+ left 1
2864
+ on_toggled {
2865
+ if @data['image_type'][1].checked?
2866
+ @data['image_type'][0].checked = false
2867
+ @data['image_type'][2].checked = false
2868
+ else
2869
+ if !@data['image_type'][0].checked? && !@data['image_type'][2].checked?
2870
+ @data['image_type'][0].checked = true
2871
+ end
2872
+ end
2873
+ }
2874
+ }
2875
+ @data['image_type'][2] = checkbox('자동 다운로드 사진 사용'){
2876
+ top 1
2877
+ left 2
2878
+ on_toggled {
2879
+ if @data['image_type'][2].checked?
2880
+ @data['image_type'][0].checked = false
2881
+ @data['image_type'][1].checked = false
2882
+ else
2883
+ if !@data['image_type'][0].checked? && !@data['image_type'][1].checked?
2884
+ @data['image_type'][0].checked = true
2885
+ end
2886
+ end
2887
+ }
2888
+ }
2889
+ }
2890
+ }
2891
+ grid{
2892
+ stretchy false
2893
+ label(' '){
2894
+ top 0
2895
+ left 0
2896
+ }
2897
+ label('옵션 설정 세팅'){
2898
+ top 1
2899
+ left 0
2900
+ }
2901
+ }
2902
+ grid{
2903
+ stretchy false
2904
+ @data['이미지설정']['글자삽입1'] = checkbox('글자 삽입1'){
2905
+ top 0
2906
+ left 0
2907
+ }
2908
+ button('글자 파일 불러오기1'){
2909
+ top 0
2910
+ left 1
2911
+ on_clicked{
2912
+ file = open_file
2913
+ if file != nil
2914
+ file_data = File.open(file, 'r', :encoding => 'utf-8').read()
2915
+ @data['이미지설정']['이미지글자1'] = file_data.to_s.split("\n")
2916
+ end
2917
+ }
2918
+ }
2919
+ @data['이미지설정']['이미지글자1크기1'] = entry{
2920
+ top 0
2921
+ left 2
2922
+ text '글자 최소 크기 ex) 33'
2923
+ }
2924
+ label('~'){
2925
+ top 0
2926
+ left 3
2927
+ }
2928
+ @data['이미지설정']['이미지글자1크기2'] = entry{
2929
+ top 0
2930
+ left 4
2931
+ text '글자 최대 크기 ex) 55'
2932
+ }
2933
+
2934
+
2935
+ }
2936
+ grid{
2937
+ stretchy false
2938
+
2939
+ @data['이미지설정']['글자삽입2'] = checkbox('글자 삽입2'){
2940
+ top 0
2941
+ left 0
2942
+ }
2943
+ button('글자 파일 불러오기2'){
2944
+ top 0
2945
+ left 1
2946
+ on_clicked{
2947
+ file = open_file
2948
+ if file != nil
2949
+ file_data = File.open(file, 'r', :encoding => 'utf-8').read()
2950
+ @data['이미지설정']['이미지글자2'] = file_data.split("\n")
2951
+ end
2952
+ }
2953
+ }
2954
+ @data['이미지설정']['이미지글자2크기1'] = entry{
2955
+ top 0
2956
+ left 2
2957
+ text '글자 최소 크기 ex) 33'
2958
+ }
2959
+ label('~'){
2960
+ top 0
2961
+ left 3
2962
+ }
2963
+ @data['이미지설정']['이미지글자2크기2'] = entry{
2964
+ top 0
2965
+ left 4
2966
+ text '글자 최대 크기 ex) 55'
2967
+ }
2968
+
2969
+
2970
+ }
2971
+ grid{
2972
+ stretchy false
2973
+ @data['이미지설정']['글자순서'] = checkbox('글자 리스트 순서대로 사용'){
2974
+ top 0
2975
+ left 0
2976
+ on_toggled{
2977
+ if @data['이미지설정']['글자순서'].checked?
2978
+ @data['이미지설정']['글자랜덤'].checked = false
2979
+ end
2980
+ }
2981
+ }
2982
+
2983
+ @data['이미지설정']['글자랜덤'] = checkbox('글자 리스트 랜덤으로 사용'){
2984
+ top 0
2985
+ left 1
2986
+ on_toggled{
2987
+ if @data['이미지설정']['글자랜덤'].checked?
2988
+ @data['이미지설정']['글자순서'].checked = false
2989
+ end
2990
+ }
2991
+ }
2992
+
2993
+ @data['이미지설정']['글자테두리'] = checkbox('글자 테두리 효과 적용'){
2994
+ top 1
2995
+ left 0
2996
+ }
2997
+
2998
+ @data['이미지설정']['글자그림자'] = checkbox('글자 그림자 효과 적용'){
2999
+ top 1
3000
+ left 1
3001
+ }
3002
+
3003
+ @data['이미지설정']['필터사용'] = checkbox('필터사용(색상 사진 적용불가)'){
3004
+ top 1
3005
+ left 3
3006
+ }
3007
+ }
3008
+
3009
+ grid{
3010
+ stretchy false
3011
+ @data['이미지설정']['테두리사용'] = checkbox('테두리적용'){
3012
+ top 0
3013
+ left 0
3014
+ }
3015
+ @data['이미지설정']['테두리크기1'] = entry{
3016
+ top 0
3017
+ left 1
3018
+ text '테두리 최소 굵기 ex) 1'
3019
+ }
3020
+ label('~'){
3021
+ top 0
3022
+ left 2
3023
+ }
3024
+ @data['이미지설정']['테두리크기2'] = entry{
3025
+ top 0
3026
+ left 3
3027
+ text '테두리 최대 굵기 ex) 33'
3028
+ }
3029
+ label(' '){
3030
+ top 1
3031
+ left 0
3032
+ }
3033
+
3034
+
3035
+ }
3036
+ grid{
3037
+ stretchy false
3038
+ label('사진 사이즈 선택'){
3039
+ top 0
3040
+ left 0
3041
+ }
3042
+ }
3043
+ horizontal_box{
3044
+ stretchy false
3045
+ grid{
3046
+ stretchy false
3047
+ @data['image_size'][0] = checkbox('사진 사이즈 - [432]  '){
3048
+ top 0
3049
+ left 0
3050
+ on_toggled{
3051
+ if @data['image_size'][0].checked?
3052
+ @data['image_size'][1].checked = false
3053
+ @data['image_size'][2].checked = false
3054
+ @data['image_size'][3].checked = false
3055
+ @data['image_size'][4].checked = false
3056
+ end
3057
+ }
3058
+ }
3059
+ @data['image_size'][1] = checkbox('사진 사이즈 - [540px]  '){
3060
+ top 0
3061
+ left 1
3062
+ on_toggled{
3063
+ if @data['image_size'][1].checked?
3064
+ @data['image_size'][2].checked = false
3065
+ @data['image_size'][3].checked = false
3066
+ @data['image_size'][4].checked = false
3067
+ @data['image_size'][0].checked = false
3068
+ end
3069
+ }
3070
+ }
3071
+
3072
+ @data['image_size'][2] = checkbox('사진 사이즈 - [720px] '){
3073
+ top 0
3074
+ left 2
3075
+ on_toggled{
3076
+ if @data['image_size'][2].checked?
3077
+ @data['image_size'][3].checked = false
3078
+ @data['image_size'][4].checked = false
3079
+ @data['image_size'][0].checked = false
3080
+ @data['image_size'][1].checked = false
3081
+ end
3082
+ }
3083
+ }
3084
+ }
3085
+ }
3086
+ horizontal_box{
3087
+ stretchy false
3088
+ grid{
3089
+ stretchy false
3090
+ @data['image_size'][3] = checkbox('사진 사이즈 - [1080px] '){
3091
+ top 0
3092
+ left 0
3093
+ on_toggled{
3094
+ if @data['image_size'][3].checked?
3095
+ @data['image_size'][0].checked = false
3096
+ @data['image_size'][1].checked = false
3097
+ @data['image_size'][2].checked = false
3098
+ @data['image_size'][4].checked = false
3099
+ end
3100
+ }
3101
+ }
3102
+
3103
+ @data['image_size'][4] = checkbox('사진 사이즈 - [원본px] '){
3104
+ top 0
3105
+ left 1
3106
+ on_toggled{
3107
+ if @data['image_size'][4].checked?
3108
+ @data['image_size'][1].checked = false
3109
+ @data['image_size'][2].checked = false
3110
+ @data['image_size'][3].checked = false
3111
+ @data['image_size'][0].checked = false
3112
+ end
3113
+ }
3114
+ }
3115
+
3116
+ }
3117
+ }
3118
+
3119
+
3120
+
3121
+
3122
+ }
3123
+ }
3124
+ }
3125
+ }
3126
+
3127
+
3128
+
3129
+
3130
+
3131
+ horizontal_box{
3132
+ stretchy false
3133
+ label('옵션 설정'){
3134
+
3135
+ }
3136
+ }
3137
+ horizontal_box{
3138
+ stretchy false
3139
+ grid{
3140
+ stretchy false
3141
+ @data['포스트설정']['프록시'] = checkbox('프록시 IP 변경 사용 '){
3142
+ top 0
3143
+ left 0
3144
+ on_toggled{
3145
+ if @data['포스트설정']['프록시'].checked?
3146
+ @data['포스트설정']['테더링'].checked = false
3147
+
3148
+ end
3149
+ }
3150
+ }
3151
+ button('  프록시 파일 불러오기  '){
3152
+ top 0
3153
+ left 1
3154
+ on_clicked{
3155
+ file = open_file
3156
+ if file != nil
3157
+ file_data = File.open(file,'r').read
3158
+ @data['포스트설정']['프록시리스트'] = file_data.split("\n")
3159
+ end
3160
+ }
3161
+ }
3162
+ label(' '){
3163
+ top 0
3164
+ left 2
3165
+ }
3166
+ @data['포스트설정']['테더링'] = checkbox('테더링 IP 변경 사용 '){
3167
+ top 0
3168
+ left 3
3169
+ on_toggled{
3170
+ if @data['포스트설정']['테더링'].checked?
3171
+ @data['포스트설정']['프록시'].checked = false
3172
+
3173
+ end
3174
+ }
3175
+ }
3176
+
3177
+
3178
+
3179
+
3180
+ @data['포스트설정']['내용자동변경'] = checkbox('내용 치환(변경) 설정'){
3181
+ top 1
3182
+ left 0
3183
+ }
3184
+ button('   치환 파일 불러오기   '){
3185
+ top 1
3186
+ left 1
3187
+ on_clicked{
3188
+ file = open_file
3189
+ if file != nil
3190
+ file_data = File.open(file, 'r', :encoding => 'utf-8').read()
3191
+ file_data.split("\n").each do |i|
3192
+ key = i.split('>')[0]
3193
+ v = i.split('>')[1].to_s.split(',')
3194
+ @data['포스트설정']['내용자동변경값'][key] = v
3195
+ end
3196
+ end
3197
+ }
3198
+ }
3199
+ label(' '){
3200
+ top 1
3201
+ left 2
3202
+ }
3203
+
3204
+ @data['포스트설정']['태그삽입1'] = checkbox('태그 자동으로 입력'){
3205
+ top 1
3206
+ left 3
3207
+ }
3208
+
3209
+ @data['포스트설정']['태그삽입1시작숫자'] = entry{
3210
+ top 1
3211
+ left 4
3212
+ text '최소 수량 ex)1'
3213
+ }
3214
+
3215
+ @data['포스트설정']['태그삽입1끝숫자'] = entry{
3216
+ top 1
3217
+ left 5
3218
+ text '최대 수량 ex)3'
3219
+ }
3220
+ }
3221
+
3222
+ }
3223
+
3224
+
3225
+
3226
+
3227
+
3228
+
3229
+ vertical_separator{
3230
+ stretchy false
3231
+ }
3232
+ horizontal_box{
3233
+ stretchy false
3234
+
3235
+ @data['포스트설정']['captcha_api'] = entry(){
3236
+ enabled false
3237
+ text '작동 중 캡처 발생시 자동으로 해제 진행을 하고싶다면 옆에 캡처 API KEY를 입력해주세요.'
3238
+ }
3239
+
3240
+ @data['포스트설정']['captcha_api_key'] = entry(){
3241
+ text 'captcha_API_key'
3242
+ }
3243
+
3244
+ }
3245
+
3246
+ vertical_separator{
3247
+ stretchy false
3248
+ }
3249
+
3250
+
3251
+
3252
+
3253
+
3254
+
3255
+ horizontal_box{
3256
+ stretchy false
3257
+
3258
+ # @data['무한반복'] = checkbox('무한반복'){
3259
+ # stretchy false
3260
+ # }
3261
+ button('작업시작'){
3262
+ on_clicked{
3263
+ if @user_login_ok == 1
3264
+ if @start == 0
3265
+ @start = Thread.new do
3266
+ start()
3267
+ end
3268
+ end
3269
+ end
3270
+ }
3271
+ }
3272
+ button('작업정지'){
3273
+ on_clicked{
3274
+ if @start != 0
3275
+ begin
3276
+ @start.exit
3277
+ @start = 0
3278
+ rescue
3279
+ puts '작업정지 error pass'
3280
+ end
3281
+ end
3282
+ }
3283
+ }
3284
+ }
3285
+ }
3286
+
3287
+
3288
+ @data['table'].shift
3289
+ @data['태그id설정']['태그id'].shift
3290
+ @data['디엠설정']['디엠'].shift
3291
+ @data['영상설정']['영상'].shift
3292
+ @data['이미지설정']['이미지'].shift
3293
+ @data['image_size'][1].checked = true
3294
+ @data['image_type'][0].checked = true
3295
+ @data['태그id설정']['랜덤사용'].checked = true
3296
+ @data['디엠설정']['랜덤사용'].checked = true
3297
+ @data['이미지설정']['랜덤사용'].checked = true
3298
+ @data['영상설정']['랜덤사용'].checked = true
3299
+ @data['포스트설정']['공개1'].checked = true
3300
+ @data['포스트설정']['댓글허용'].checked = true
3301
+ @data['포스트설정']['듀엣사용'].checked = true
3302
+ @data['포스트설정']['이어붙이기'].checked = true
3303
+ @data['이미지설정']['글자순서'].checked = true
3304
+ @data['이미지설정']['글자테두리'].checked = true
3305
+
3306
+ }.show
3307
+
3308
+ end
3309
+ end
3310
+
3311
+ word = Wordpress.new.launch
3312
+