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.
- checksums.yaml +4 -4
- data/lib/tblog_zon.rb +303 -55
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07543a1bab793080000dda29df8f97ad7f86f4a5e48ceb96513dabe2d49fb71d
|
4
|
+
data.tar.gz: d20a550f5a1f323e408b4a236f931d2114da1e6a86e865bf424176c20df11488
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
245
|
-
|
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("
|
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
|
-
|
384
|
-
|
385
|
-
|
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
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
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
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
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
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
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
|
-
|
1648
|
-
|
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
|
-
|
1652
|
-
|
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(
|
1660
|
-
|
1661
|
-
|
1662
|
-
|
1663
|
-
|
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
|
-
|
1668
|
-
|
1669
|
-
|
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
|
-
|
1672
|
-
|
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
|
-
|
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
|
-
|
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(
|
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.
|
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-
|
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
|