tblog_zon 0.0.39 → 0.0.51

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 +4 -4
  2. data/lib/tblog_zon.rb +303 -55
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67e5e86fdb73d7c7289e465bafb25e6df65aec1c57b28da68b8cc4072094d26d
4
- data.tar.gz: 530e2bc465993abd0203eedacc1460a229f4f70bd34635258d02e0317d756ee6
3
+ metadata.gz: 07543a1bab793080000dda29df8f97ad7f86f4a5e48ceb96513dabe2d49fb71d
4
+ data.tar.gz: d20a550f5a1f323e408b4a236f931d2114da1e6a86e865bf424176c20df11488
5
5
  SHA512:
6
- metadata.gz: 6312719754b5a867969059b5acfce86869660fe7e9f5b904858dc2feac115e035bb01d490a43a409cf04bacd882a1def0a0e5465c2af6efd795700952e90ba3c
7
- data.tar.gz: 8d231b376fb6c482d403b4a78eb44e178872a66f9a2d4ece4c948ba56414ff009c2e3ad51dfa2a5ee3bb6c6b179d4beb29f680b93cbe2b24ff7d84eb793daf6a
6
+ metadata.gz: dfe99df7b7b87ba79cc4d99a2b99a2e32b5e97c53d75edd1b34b1331d7cf0bd631f3d73fced4788e75a5e75d25e744e3e055f2eef56666389e87dcfeaa34c535
7
+ data.tar.gz: 869452307e1d978769b4bed66661fd58e221d10d1f998ab96f6f170c194be592185252afc08d603d5264eba27ddf551d11878f5a84f826e95657cd66b8645df4
data/lib/tblog_zon.rb CHANGED
@@ -15,6 +15,8 @@ require 'uri'
15
15
  require 'cgi'
16
16
  require 'auto_click'
17
17
  require 'rainbow/refinement'
18
+ require 'httpclient'
19
+ require 'win32ole'
18
20
  include AutoClickMethods
19
21
  using Rainbow
20
22
  include Glimmer
@@ -241,9 +243,50 @@ end
241
243
 
242
244
  class Naver
243
245
  def initialize
244
- @seed = 1
245
- @cookie = ''
246
+ @seed = 1
247
+ @cookie = ''
248
+ kill_selenium_chrome #기존 창 모두 닫는 명령
249
+ sleep(1)
250
+ end
251
+
252
+ def kill_selenium_chrome
253
+ wmi = WIN32OLE.connect("winmgmts://")
254
+
255
+ # chromedriver 프로세스 목록을 Ruby 배열로 변환
256
+ chromedrivers_ole = wmi.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'chromedriver.exe'")
257
+ chromedrivers = []
258
+ chromedrivers_ole.each { |proc| chromedrivers << proc }
259
+ chromedriver_pids = chromedrivers.map { |proc| proc.ProcessId }
260
+
261
+ # chrome.exe 프로세스 목록을 Ruby 배열로 변환
262
+ chrome_procs_ole = wmi.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'chrome.exe'")
263
+ chrome_procs = []
264
+ chrome_procs_ole.each { |proc| chrome_procs << proc }
265
+
266
+ # chromedriver가 띄운 크롬 종료
267
+ chrome_procs.each do |proc|
268
+ if chromedriver_pids.include?(proc.ParentProcessId)
269
+ puts "→ chromedriver가 띄운 크롬 종료: PID #{proc.ProcessId}"
270
+ begin
271
+ proc.Terminate
272
+ rescue => e
273
+ puts "→ 종료 실패: PID #{proc.ProcessId} / 오류: #{e.message}"
274
+ end
275
+ end
276
+ end
277
+
278
+ # chromedriver 자체도 종료
279
+ chromedrivers.each do |proc|
280
+ puts "→ chromedriver 종료: PID #{proc.ProcessId}"
281
+ begin
282
+ proc.Terminate
283
+ rescue => e
284
+ puts "→ chromedriver 종료 실패: #{proc.ProcessId} / 오류: #{e.message}"
285
+ end
286
+ end
246
287
  end
288
+
289
+
247
290
 
248
291
  def chrome_start(proxy)
249
292
  # 공통 옵션 설정
@@ -261,7 +304,6 @@ class Naver
261
304
  end
262
305
  options = Selenium::WebDriver::Chrome::Options.new
263
306
  options.add_argument('--no-first-run') # 자동 실행 시 나타나는 "첫 실행" 화면 방지
264
- options.add_extension('./crx/app.crx') # 확장 프로그램을 첫 번째 탭에 추가
265
307
  options.add_argument('--disable-blink-features=AutomationControlled')
266
308
  options.add_argument('--disable-popup-blocking')
267
309
  options.add_argument('--dns-prefetch-disable')
@@ -370,25 +412,103 @@ class Naver
370
412
  @driver.switch_to.new_window(:tab)
371
413
  sleep(1.5)
372
414
  @driver.switch_to.window(@driver.window_handles[1])
373
- @driver.navigate.to("chrome-extension://ifibfemgeogfhoebkmokieepdoobkbpo/options/options.html")
415
+ @driver.navigate.to("https://chromewebstore.google.com/detail/captcha-solver-auto-recog/ifibfemgeogfhoebkmokieepdoobkbpo?hl=ko")
374
416
  sleep(3)
375
- @driver.find_element(:xpath, '//*[@name="apiKey"]').click
376
- Clipboard.copy(captcha_api_key)
377
- sleep(0.5)
378
- @driver.action.key_down(:control).send_keys('v').key_up(:control).perform
379
- sleep(0.5)
380
- @driver.find_element(:xpath, '//*[@data-lang="login"]').click
381
-
382
417
  begin
383
- sleep(2)
384
- @driver.switch_to.alert.dismiss
385
- sleep(1)
418
+ wait = Selenium::WebDriver::Wait.new(:timeout => 3)
419
+ wait.until { @driver.find_element(xpath: '//section[@class="lwrbTd"]//button[@jsname="ajZLRd"]') } #추가 되어 있음
420
+ captcha_solver = 0
421
+ puts'[Step.01] CAPTCHA 세션 및 브라우저 설정 완료 상태 확인!!.......'.yellow
386
422
  rescue
387
- end
388
- @driver.close
389
- sleep(1)
390
- @driver.switch_to.window(@driver.window_handles[0])
391
- sleep(2)
423
+ begin
424
+ wait = Selenium::WebDriver::Wait.new(:timeout => 3)
425
+ wait.until { @driver.find_element(xpath: '//section[@class="lwrbTd"]//button[@jsname="wQO0od"]') } #추가 안되어 있음
426
+ sleep(1.5)
427
+ @driver.find_element(xpath: '//section[@class="lwrbTd"]//button[@jsname="wQO0od"]').click
428
+ puts'[Step.01] CAPTCHA 세션 연결 없음!! 브라우저 필요 설정 미 완료 상태!!.......'.red
429
+ puts'[Step.02] CAPTCHA 세션 연결 및 브라우저 필요 설정 진행 시작!!.......'.red
430
+ sleep(1.5)
431
+ shell = WIN32OLE.new('WScript.Shell')
432
+ shell.AppActivate("Captcha Solver: Auto Recognition and Bypass")
433
+ shell.AppActivate("Captcha Solver: Auto Recognition and Bypass")
434
+ sleep(1)
435
+ shell.SendKeys("{TAB}")
436
+ sleep(0.5)
437
+ shell.SendKeys("{ENTER}")
438
+
439
+ captcha_solver = 1
440
+ sleep(1)
441
+ rescue
442
+ @driver.quit
443
+ sleep(1)
444
+ @driver.close
445
+ return 0
446
+ sleep(1)
447
+ end
448
+ end
449
+ if captcha_solver == 1
450
+ begin
451
+ @driver.get('chrome-extension://ifibfemgeogfhoebkmokieepdoobkbpo/options/options.html')
452
+ sleep(5)
453
+ @driver.get('chrome-extension://ifibfemgeogfhoebkmokieepdoobkbpo/options/options.html')
454
+ sleep(1)
455
+ # 요소 찾기 타임아웃을 10초로 설정
456
+ wait = Selenium::WebDriver::Wait.new(:timeout => 5)
457
+ #요소가 나타날 때까지 60초 동안 기다립니다.
458
+ wait.until { @driver.find_element(:xpath, '/html/body/div/div[1]/table/tbody/tr[1]/td[2]/input') }
459
+ @driver.find_element(:xpath, '/html/body/div/div[1]/table/tbody/tr[1]/td[2]/input').click
460
+ sleep(1)
461
+ Clipboard.copy(captcha_api_key)
462
+ @driver.action.key_down(:control).send_keys('v').key_up(:control).perform
463
+ sleep(1)
464
+ @driver.find_element(:xpath, '//*[@id="connect"]').click
465
+ sleep(1)
466
+
467
+ begin
468
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
469
+ wait.until do
470
+ begin
471
+ alert = @driver.switch_to.alert
472
+ alert.accept
473
+ sleep(1)
474
+ true
475
+ rescue Selenium::WebDriver::Error::NoSuchAlertError
476
+ false
477
+ end
478
+ end
479
+ sleep(1)
480
+ @driver.close
481
+ sleep(1)
482
+ @driver.switch_to.window(@driver.window_handles[0])
483
+ sleep(2)
484
+ rescue Selenium::WebDriver::Error::TimeoutError
485
+ @driver.find_element(:xpath, '//*[@id="connect"]').click
486
+ begin
487
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
488
+ wait.until do
489
+ begin
490
+ alert = @driver.switch_to.alert
491
+ alert.accept
492
+ sleep(1)
493
+ true
494
+ rescue Selenium::WebDriver::Error::NoSuchAlertError
495
+ false
496
+ end
497
+ end
498
+ rescue Selenium::WebDriver::Error::TimeoutError
499
+ puts "캡챠 기능이 완벽하게 세팅되지않아 캡챠 발생시 해제가 안될수있습니다.".red
500
+ puts "가급적 캡챠 기능 세팅시 PC 사용을 멈춰주세요!".red
501
+ sleep(1)
502
+ @driver.close
503
+ sleep(1)
504
+ @driver.switch_to.window(@driver.window_handles[0])
505
+ sleep(2)
506
+ end
507
+ end
508
+ rescue
509
+ end
510
+ else
511
+ end
392
512
  else
393
513
  end
394
514
 
@@ -1566,21 +1686,81 @@ class Wordpress
1566
1686
 
1567
1687
 
1568
1688
 
1569
- def auto_image
1689
+ def auto_image(keyword = nil)
1690
+ keyword ||= @keyword
1691
+ puts "키워드: #{keyword}"
1692
+
1693
+ client = HTTPClient.new
1694
+ client.default_header = {
1695
+ 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
1696
+ '(KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
1697
+ 'Accept' => 'application/json, text/javascript, */*; q=0.01',
1698
+ 'Accept-Language' => 'en-US,en;q=0.9',
1699
+ 'Referer' => "https://unsplash.com/s/photos/#{URI.encode_www_form_component(keyword)}",
1700
+ 'X-Requested-With' => 'XMLHttpRequest'
1701
+ }
1702
+
1703
+ retry_count = 0
1704
+ max_retries = 10
1705
+ results = []
1706
+
1570
1707
  begin
1571
1708
  page = rand(1..15)
1572
- http = HTTP.get('https://unsplash.com/napi/photos?per_page=12&page='+page.to_s)
1573
- json = JSON.parse(http.to_s)
1574
- mm = Array.new
1575
- json.each do |i|
1576
- mm << i['urls']['full']
1709
+ url = "https://unsplash.com/napi/search/photos?query=#{URI.encode_www_form_component(keyword)}&page=#{page}&per_page=20"
1710
+ puts "Request URL: #{url}"
1711
+ res = client.get(url)
1712
+
1713
+ unless res.status == 200
1714
+ puts "HTTP Error: #{res.status}"
1715
+ raise "HTTP Error"
1577
1716
  end
1578
- url = mm.sample
1579
- Down.download(url, destination: "./image/memory.png")
1580
- rescue
1581
- puts 'auto_image 일시적 error 5초후 제시도...'
1582
- sleep(5)
1717
+
1718
+ json = JSON.parse(res.body)
1719
+ results = json['results']
1720
+ mm = []
1721
+
1722
+ results.each do |photo|
1723
+ full_url = photo.dig('urls', 'full').to_s
1724
+ regular_url = photo.dig('urls', 'regular').to_s
1725
+
1726
+ if full_url.start_with?("https://images.unsplash.com/photo-") &&
1727
+ regular_url.include?("1080")
1728
+ mm << full_url
1729
+ end
1730
+ end
1731
+
1732
+ if mm.empty?
1733
+ raise "No matching image"
1734
+ end
1735
+
1736
+ selected_url = mm.sample
1737
+ Down.download(selected_url, destination: "./image/memory.png")
1738
+ puts "이미지 다운로드 완료: #{selected_url}"
1739
+
1740
+ rescue => e
1741
+ retry_count += 1
1742
+ puts "auto_image 에러: #{e.message} (재시도 #{retry_count}/#{max_retries})"
1743
+ sleep(3)
1744
+ if retry_count < max_retries
1583
1745
  retry
1746
+ else
1747
+ puts "최대 재시도 초과. 조건 무시하고 랜덤 이미지 다운로드 시도..."
1748
+
1749
+ if results && !results.empty?
1750
+ random_photo = results.sample
1751
+ fallback_url = random_photo.dig('urls', 'full')
1752
+ if fallback_url
1753
+ Down.download(fallback_url, destination: "./image/memory.png")
1754
+ puts "랜덤 이미지 다운로드 완료: #{fallback_url}"
1755
+ else
1756
+ puts "랜덤 이미지 URL을 찾을 수 없습니다. 단색 배경 이미지 생성합니다."
1757
+ color_image
1758
+ end
1759
+ else
1760
+ puts "이미지 결과가 없어 다운로드할 수 없습니다. 단색 배경 이미지 생성합니다."
1761
+ color_image
1762
+ end
1763
+ end
1584
1764
  end
1585
1765
  end
1586
1766
 
@@ -1641,40 +1821,84 @@ class Wordpress
1641
1821
  img.write('./image/memory.png')
1642
1822
  end
1643
1823
 
1824
+ def wrap_text_to_fit(draw, text, max_width, max_height, font_path, initial_size)
1825
+ size = initial_size
1826
+ draw.font = font_path
1827
+
1828
+ loop do
1829
+ draw.pointsize = size
1830
+ words = text.chars # 글자 단위로 자름 (한국어 기준)
1831
+ lines = []
1832
+ line = ""
1833
+
1834
+ words.each do |char|
1835
+ test_line = line + char
1836
+ metrics = draw.get_type_metrics(test_line)
1837
+ if metrics.width > max_width
1838
+ lines << line
1839
+ line = char
1840
+ else
1841
+ line = test_line
1842
+ end
1843
+ end
1844
+ lines << line unless line.empty?
1845
+
1846
+ line_height = draw.get_type_metrics("가").height
1847
+ total_height = line_height * lines.size
1848
+
1849
+ # 세로 초과 안 하면 성공
1850
+ if total_height <= max_height || size <= 10
1851
+ return [lines.join("\n"), size]
1852
+ else
1853
+ size -= 2
1854
+ end
1855
+ end
1856
+ end
1857
+
1858
+
1644
1859
  def image_text(text1, text2)
1645
1860
  begin
1646
1861
  color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
1647
- font = Dir.entries('./fonts')
1648
- img = Magick::Image.read('./image/memory.png').first
1649
- text = Magick::Draw.new
1862
+ font_files = Dir.entries('./fonts').select { |f| f.downcase.end_with?('.ttf') }
1863
+ font2 = './fonts/' + font_files.sample
1650
1864
  color2 = color.sample
1651
- font2 = './fonts/'+font.sample
1652
- message = text1.to_s+"\n"+text2.to_s
1865
+
1866
+ img = Magick::Image.read('./image/memory.png').first
1867
+ draw = Magick::Draw.new
1868
+
1869
+ raw_message = "#{text1}\n#{text2}".strip
1870
+ max_width = img.columns * 0.85
1871
+ max_height = img.rows * 0.6
1872
+
1653
1873
  begin
1654
1874
  size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
1655
1875
  rescue
1656
1876
  size = 30
1657
1877
  end
1878
+
1879
+ wrapped_message, adjusted_size = wrap_text_to_fit(draw, raw_message, max_width, max_height, font2, size)
1880
+
1658
1881
  if @data['이미지설정']['글자그림자'].checked?
1659
- img.annotate(text, 0,0, +3,+3, message) do
1660
- text.gravity = Magick::CenterGravity
1661
- text.pointsize = size
1662
- text.fill = '#000000'
1663
- text.font = font2
1882
+ img.annotate(draw, 0, 0, 2, 2, wrapped_message) do
1883
+ draw.gravity = Magick::CenterGravity
1884
+ draw.pointsize = adjusted_size
1885
+ draw.fill = '#000000'
1886
+ draw.font = font2
1664
1887
  end
1665
1888
  end
1666
-
1667
- img.annotate(text, 0,0,0,0, message) do
1668
- text.gravity = Magick::CenterGravity
1669
- text.pointsize = size
1889
+
1890
+ draw2 = Magick::Draw.new
1891
+ img.annotate(draw2, 0, 0, 0, 0, wrapped_message) do
1892
+ draw2.gravity = Magick::CenterGravity
1893
+ draw2.pointsize = adjusted_size
1894
+ draw2.fill = color2
1895
+ draw2.font = font2
1670
1896
  if @data['이미지설정']['글자테두리'].checked?
1671
- text.stroke_width = 2
1672
- text.stroke = '#000000'
1897
+ draw2.stroke_width = 2
1898
+ draw2.stroke = '#000000'
1673
1899
  end
1674
- text.fill = color2
1675
- text.font = font2
1676
1900
  end
1677
-
1901
+
1678
1902
  img.write('./image/memory.png')
1679
1903
  rescue
1680
1904
  puts '이미지 폰트 불러오기 오류 재시도...'
@@ -1736,18 +1960,40 @@ class Wordpress
1736
1960
  image_filter()
1737
1961
  end
1738
1962
 
1739
- insert_image_text1 = ''
1740
- insert_image_text2 = ''
1741
1963
  if @data['이미지설정']['글자삽입1'].checked?
1742
- insert_image_text1 = @data['이미지설정']['이미지글자1'].sample
1964
+ if @data['이미지설정']['이미지글자1'].length == 0
1965
+ image_text_path1 = ''
1966
+ else
1967
+ if @data['이미지설정']['글자랜덤'].checked?
1968
+ image_text_path1 = @data['이미지설정']['이미지글자1'].sample
1969
+ else
1970
+ image_text_path1 = @data['이미지설정']['이미지글자1'][@image_text_soon1]
1971
+ @image_text_soon1 += 1
1972
+ if @image_text_soon1 > @data['이미지설정']['이미지글자1'].length - 1
1973
+ @image_text_soon1 = 0
1974
+ end
1975
+ end
1976
+ end
1743
1977
  end
1744
1978
 
1745
1979
  if @data['이미지설정']['글자삽입2'].checked?
1746
- insert_image_text2 = @data['이미지설정']['이미지글자2'].sample
1980
+ if @data['이미지설정']['이미지글자2'].length == 0
1981
+ image_text_path2 = ''
1982
+ else
1983
+ if @data['이미지설정']['글자랜덤'].checked?
1984
+ image_text_path2 = @data['이미지설정']['이미지글자2'].sample
1985
+ else
1986
+ image_text_path2 = @data['이미지설정']['이미지글자2'][@image_text_soon2]
1987
+ @image_text_soon2 += 1
1988
+ if @image_text_soon2 > @data['이미지설정']['이미지글자2'].length - 1
1989
+ @image_text_soon2 = 0
1990
+ end
1991
+ end
1992
+ end
1747
1993
  end
1748
-
1994
+
1749
1995
  if @data['이미지설정']['글자삽입1'].checked? or @data['이미지설정']['글자삽입2'].checked?
1750
- image_text(insert_image_text1, insert_image_text2)
1996
+ image_text(image_text_path1, image_text_path2)
1751
1997
  end
1752
1998
 
1753
1999
  if @data['이미지설정']['테두리사용'].checked?
@@ -1811,6 +2057,8 @@ class Wordpress
1811
2057
  title_soon = 0
1812
2058
  keyword_soon = 0
1813
2059
  content_soon = 0
2060
+ @image_text_soon1 = 0
2061
+ @image_text_soon2 = 0
1814
2062
  @my_ip = 'init'
1815
2063
  @image_counter = 0
1816
2064
  @inumber2 = 0
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tblog_zon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.39
4
+ version: 0.0.51
5
5
  platform: ruby
6
6
  authors:
7
7
  - zon
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-05-12 00:00:00.000000000 Z
10
+ date: 2025-05-29 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: File to Clipboard gem
13
13
  email: mymin26@naver.com