wp_posting_duo 0.0.3 → 0.0.9

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/wp_posting_duo.rb +314 -79
  3. metadata +3 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1cb4f149042a682b91d238851c8c25987205163a407d85b9a8e926799c69cec
4
- data.tar.gz: aae789d19521465e6a960341a72effe0c486ddd493b10e7a5f3aebf3761feaf9
3
+ metadata.gz: 8f5792692b65f22913ddd7aa8405378e64d2df5580380a961a39233962888226
4
+ data.tar.gz: e8dbf27faf55c087cd7dc520fc2abcad4f7afba093869daa61edb9881d0b3d41
5
5
  SHA512:
6
- metadata.gz: 5fe7df87ea12055fbd76acda4cb834ac1151b479cb72f1c044156a582a20f9bdd839944b12b93f463bd5a45396bc7e32cb0867e7213fa706e921fd6bdaf7005a
7
- data.tar.gz: fb959af20e28c265f1fa2e408c98b369d0bcf37db83e50c24195d6bb63afb4cf5763dd5d56dda162a647974defede663a2b6719fe5092f3c0fc65b0256d9c5ab
6
+ metadata.gz: 0f9684835d2fe336db76053d220cb854e624af6195348c68193716fbea417c62ce3246e6d02ba9521274343742bf2e060570cb38d1c51d82be63d665a722cdf1
7
+ data.tar.gz: 558cfa9f0c6eb0607282d6823e526aecf94fd2e4d2917124d4fa03380b868ffe7751a74e011344c6ee4d4e95be48766d9f43e69b8195b3f9ea8880d9b31964e4
@@ -11,6 +11,7 @@ require 'open3'
11
11
  require 'zlib'
12
12
  require 'stringio'
13
13
  require 'timeout'
14
+ require 'httpclient'
14
15
 
15
16
  class Wordpress
16
17
  include Glimmer
@@ -402,23 +403,111 @@ class Wordpress
402
403
  return @data2
403
404
  end
404
405
 
405
- def auto_image
406
- begin
407
- page = rand(1..15)
408
- http = HTTP.get('https://unsplash.com/napi/photos?per_page=12&page='+page.to_s)
409
- json = JSON.parse(http.to_s)
410
- mm = Array.new
411
- json.each do |i|
412
- mm << i['urls']['full']
406
+ def crop_image_height_under_width(path, min_crop_ratio = 0.625)
407
+ img = Magick::Image.read(path).first
408
+ width = img.columns
409
+ height = img.rows
410
+
411
+
412
+
413
+ if height > width
414
+ min_height = (width * min_crop_ratio).to_i
415
+ new_height = rand(min_height..width)
416
+ crop_top = ((height - new_height) / 2.0).round
417
+
418
+ cropped = img.crop(0, crop_top, width, new_height, true)
419
+ cropped.write(path)
420
+
421
+
422
+ else
423
+
424
+ end
425
+ end
426
+
427
+ def auto_image(keyword = nil)
428
+ # auto_image 내부에서만 crop 호출
429
+ keyword ||= @keyword
430
+ puts "키워드: #{keyword}"
431
+
432
+ client = HTTPClient.new
433
+ client.default_header = {
434
+ 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
435
+ '(KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
436
+ 'Accept' => 'application/json, text/javascript, */*; q=0.01',
437
+ 'Accept-Language' => 'en-US,en;q=0.9',
438
+ 'Referer' => "https://unsplash.com/s/photos/#{URI.encode_www_form_component(keyword)}",
439
+ 'X-Requested-With' => 'XMLHttpRequest'
440
+ }
441
+
442
+ retry_count = 0
443
+ max_retries = 10
444
+ results = []
445
+
446
+ begin
447
+ page = rand(1..15)
448
+ url = "https://unsplash.com/napi/search/photos?query=#{URI.encode_www_form_component(keyword)}&page=#{page}&per_page=20"
449
+ puts "Request URL: #{url}"
450
+ res = client.get(url)
451
+
452
+ unless res.status == 200
453
+ puts "HTTP Error: #{res.status}"
454
+ raise "HTTP Error"
455
+ end
456
+
457
+ json = JSON.parse(res.body)
458
+ results = json['results']
459
+ mm = []
460
+
461
+ results.each do |photo|
462
+ full_url = photo.dig('urls', 'full').to_s
463
+ regular_url = photo.dig('urls', 'regular').to_s
464
+
465
+ if full_url.start_with?("https://images.unsplash.com/photo-") &&
466
+ regular_url.include?("1080")
467
+ mm << full_url
468
+ end
469
+ end
470
+
471
+ if mm.empty?
472
+ raise "No matching image"
473
+ end
474
+
475
+ selected_url = mm.sample
476
+ destination_path = "./image/memory.png"
477
+ Down.download(selected_url, destination: destination_path)
478
+ puts "이미지 다운로드 완료: #{selected_url}"
479
+
480
+ # 오직 auto_image에서만 자르기 호출
481
+ crop_image_height_under_width(destination_path)
482
+
483
+ rescue => e
484
+ retry_count += 1
485
+ puts "auto_image 에러: #{e.message} (재시도 #{retry_count}/#{max_retries})"
486
+ sleep(3)
487
+ if retry_count < max_retries
488
+ retry
489
+ else
490
+ puts "최대 재시도 초과. 조건 무시하고 랜덤 이미지 다운로드 시도..."
491
+
492
+ if results && !results.empty?
493
+ random_photo = results.sample
494
+ fallback_url = random_photo.dig('urls', 'full')
495
+ if fallback_url
496
+ Down.download(fallback_url, destination: "./image/memory.png")
497
+ puts "랜덤 이미지 다운로드 완료: #{fallback_url}"
498
+ crop_image_height_under_width("./image/memory.png")
499
+ else
500
+ puts "랜덤 이미지 URL을 찾을 수 없습니다. 단색 배경 이미지 생성합니다."
501
+ color_image
413
502
  end
414
- url = mm.sample
415
- Down.download(url, destination: "./image/memory.png")
416
- rescue
417
- puts 'image auto download error 5초후 재시도...'
418
- sleep(5)
419
- retry
503
+ else
504
+ puts "이미지 결과가 없어 다운로드할 수 없습니다. 단색 배경 이미지 생성합니다."
505
+ color_image
506
+ end
420
507
  end
421
508
  end
509
+ end
510
+
422
511
 
423
512
  def color_image
424
513
  color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
@@ -428,80 +517,188 @@ class Wordpress
428
517
 
429
518
  def save_image
430
519
  if @data['이미지설정']['이미지'].length == 0
431
-
520
+ return
521
+ end
522
+
523
+ if @data['이미지설정']['순서사용'].checked?
524
+ image_path = @data['이미지설정']['이미지'][@image_counter][2]
525
+ @image_counter += 1
526
+ if @image_counter > @data['이미지설정']['이미지'].length - 1
527
+ @image_counter = 0
528
+ end
432
529
  else
433
- if @data['이미지설정']['순서사용'].checked?
434
- image_path = @data['이미지설정']['이미지'][@image_counter][2]
435
- @image_counter += 1
436
- if @image_counter > @data['이미지설정']['이미지'].length-1
437
- @image_counter = 0
438
- end
439
- else
440
- image_path = @data['이미지설정']['이미지'].sample[2]
530
+ # 초기화가 안됐거나 다 썼으면 새롭게 섞는다
531
+ @shuffled_images ||= []
532
+ if @shuffled_images.empty?
533
+ @shuffled_images = @data['이미지설정']['이미지'].shuffle
441
534
  end
442
- img = Magick::Image.read(image_path).first
443
- img.write('./image/memory.png')
535
+
536
+ image_path = @shuffled_images.shift[2]
444
537
  end
538
+
539
+ img = Magick::Image.read(image_path).first
540
+ img.write('./image/memory.png')
445
541
  end
446
542
 
447
543
  def change_image_size(w)
448
544
  img = Magick::Image.read('./image/memory.png').first
449
545
  width = img.columns
450
546
  height = img.rows
451
- begin
452
- if @data['image_type'][0].checked? or @data['image_type'][2].checked?
453
- img.resize!(w, w*(height.to_f/width.to_f))
454
- else
455
- img.resize!(w, w)
547
+
548
+ # '원본' 선택된 경우, 리사이징을 하지 않고 원본 이미지를 그대로 반환
549
+ if w == 'original'
550
+ return img # 원본 이미지 그대로 반환
551
+ else
552
+ begin
553
+ if @data['image_type'][0].checked? or @data['image_type'][2].checked?
554
+ # 비율을 맞추어 리사이징
555
+ img.resize!(w, w * (height.to_f / width.to_f))
556
+ else
557
+ # 정사각형으로 리사이징
558
+ img.resize!(w, w)
559
+ end
560
+ rescue
561
+ img.resize!(w, w) # 예외 처리 시에도 리사이징
456
562
  end
457
- rescue
458
- img.resize!(w, w)
459
563
  end
564
+
565
+ # 리사이징된 이미지 저장
460
566
  img.write('./image/memory.png')
461
567
  end
462
568
 
463
- def image_text(text1, text2)
464
- begin
465
- color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
466
- font = Dir.entries('./fonts')
467
- img = Magick::Image.read('./image/memory.png').first
468
- text = Magick::Draw.new
469
- color2 = color.sample
470
- font2 = './fonts/'+font.sample
471
- message = text1.to_s+"\n"+text2.to_s
472
- begin
473
- size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
474
- rescue
475
- size = 30
476
- end
477
- if @data['이미지설정']['글자그림자'].checked?
478
- img.annotate(text, 0,0, +3,+3, message) do
479
- text.gravity = Magick::CenterGravity
480
- text.pointsize = size
481
- text.fill = '#000000'
482
- text.font = font2
569
+ def wrap_text_to_fit(draw, text, max_width, max_height, font_path, initial_size)
570
+ size = initial_size
571
+ draw.font = font_path
572
+
573
+ loop do
574
+ draw.pointsize = size
575
+ words = text.chars # 글자 단위로 자름 (한국어 기준)
576
+ lines = []
577
+ line = ""
578
+
579
+ words.each do |char|
580
+ test_line = line + char
581
+ metrics = draw.get_type_metrics(test_line)
582
+ if metrics.width > max_width
583
+ lines << line
584
+ line = char
585
+ else
586
+ line = test_line
483
587
  end
484
588
  end
485
-
486
- img.annotate(text, 0,0,0,0, message) do
487
- text.gravity = Magick::CenterGravity
488
- text.pointsize = size
489
- if @data['이미지설정']['글자테두리'].checked?
490
- text.stroke_width = 2
491
- text.stroke = '#000000'
492
- end
493
- text.fill = color2
494
- text.font = font2
589
+ lines << line unless line.empty?
590
+
591
+ line_height = draw.get_type_metrics("가").height
592
+ total_height = line_height * lines.size
593
+
594
+ # 세로 초과 안 하면 성공
595
+ if total_height <= max_height || size <= 10
596
+ return [lines.join("\n"), size]
597
+ else
598
+ size -= 2
495
599
  end
496
-
497
- img.write('./image/memory.png')
600
+ end
601
+ end
602
+
603
+
604
+ def image_text(text1, text2)
605
+ begin
606
+ color = File.open('./color.ini', 'r', encoding: 'utf-8').read.split("\n").map(&:strip).reject(&:empty?)
607
+ font_files = Dir.entries('./fonts').select { |f| f.downcase.end_with?('.ttf') }
608
+ font2 = './fonts/' + font_files.sample
609
+
610
+ # 랜덤 글자색 선택
611
+ color2 = color.sample
612
+
613
+ # 헬퍼 함수: 색상 문자열 '#RRGGBB' -> [R,G,B] 배열로 변환
614
+ def hex_to_rgb(hex)
615
+ hex = hex.delete('#')
616
+ [hex[0..1], hex[2..3], hex[4..5]].map { |c| c.to_i(16) }
617
+ end
618
+
619
+ # 헬퍼 함수: 두 RGB 색상의 차이 계산 (간단한 유클리드 거리)
620
+ def color_distance(c1, c2)
621
+ Math.sqrt(
622
+ (c1[0] - c2[0])**2 +
623
+ (c1[1] - c2[1])**2 +
624
+ (c1[2] - c2[2])**2
625
+ )
626
+ end
627
+
628
+ # 대비가 충분히 되는 테두리 색상 선택
629
+ max_attempts = 10
630
+ stroke_color = nil
631
+ base_rgb = hex_to_rgb(color2)
632
+
633
+ max_attempts.times do
634
+ candidate = color.sample
635
+ candidate_rgb = hex_to_rgb(candidate)
636
+ dist = color_distance(base_rgb, candidate_rgb)
637
+
638
+ # 거리(차이) 임계값 100 (0~441 범위) — 필요시 조절 가능
639
+ if dist > 100
640
+ stroke_color = candidate
641
+ break
642
+ end
643
+ end
644
+ stroke_color ||= '#000000' # 만약 충분히 다른 색 없으면 검정색 기본값
645
+
646
+ img = Magick::Image.read('./image/memory.png').first
647
+ draw = Magick::Draw.new
648
+
649
+ raw_message = "#{text1}\n#{text2}".strip
650
+ max_width = img.columns * 0.85
651
+ max_height = img.rows * 0.6
652
+
653
+ begin
654
+ size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
498
655
  rescue
499
- puts '이미지 폰트 불러오기 오류 재시도...'
500
- sleep(3)
501
- retry
656
+ size = 30
657
+ end
658
+
659
+ wrapped_message, adjusted_size = wrap_text_to_fit(draw, raw_message, max_width, max_height, font2, size)
660
+
661
+ if @data['이미지설정']['글자그림자'].checked?
662
+ img.annotate(draw, 0, 0, 2, 2, wrapped_message) do
663
+ draw.gravity = Magick::CenterGravity
664
+ draw.pointsize = adjusted_size
665
+ draw.fill = '#000000'
666
+ draw.font = font2
667
+ end
668
+ end
669
+
670
+ if @data['이미지설정']['글자테두리'].checked?
671
+ draw_stroke = Magick::Draw.new
672
+ img.annotate(draw_stroke, 0, 0, 0, 0, wrapped_message) do
673
+ draw_stroke.gravity = Magick::CenterGravity
674
+ draw_stroke.pointsize = adjusted_size
675
+ draw_stroke.fill = 'none'
676
+ draw_stroke.stroke = stroke_color
677
+ draw_stroke.stroke_width = rand(5..10)
678
+ draw_stroke.font = font2
679
+ end
680
+ end
681
+
682
+ draw2 = Magick::Draw.new
683
+ img.annotate(draw2, 0, 0, 0, 0, wrapped_message) do
684
+ draw2.gravity = Magick::CenterGravity
685
+ draw2.pointsize = adjusted_size
686
+ draw2.fill = color2
687
+ draw2.stroke = 'none'
688
+ draw2.font = font2
502
689
  end
690
+
691
+ img.write('./image/memory.png')
692
+
693
+ rescue => e
694
+ puts "이미지 폰트 불러오기 오류 재시도... (#{e.message})"
695
+ sleep(3)
696
+ retry
697
+ end
503
698
  end
504
699
 
700
+
701
+
505
702
  def border()
506
703
  color = File.open('./color.ini', 'r',:encoding => 'utf-8').read().split("\n")
507
704
  img = Magick::Image.read('./image/memory.png').first
@@ -527,48 +724,86 @@ class Wordpress
527
724
  else
528
725
  auto_image()
529
726
  end
530
-
531
- image_size = [480,740,650,550,480]
727
+
728
+ # '원본'을 포함한 이미지 크기 옵션 추가
729
+ image_size = [480, 740, 650, 550, 480, 'original']
532
730
  size = 0
533
- for n in 0..4
731
+
732
+ for n in 0..5 # 0부터 5까지 반복, '원본' 옵션까지 포함
534
733
  if @data['image_size'][n].checked?
535
- if n == 0
536
- size = image_size.sample
734
+ if n == 5 # '원본'이 선택되었을 경우
735
+ size = 'original'
736
+ elsif n == 0
737
+ size = image_size.sample # 랜덤 선택
537
738
  else
538
739
  size = image_size[n]
539
740
  end
540
741
  end
541
742
  end
743
+
744
+ # '원본'이 선택되지 않았다면 기본 값 설정
542
745
  if size == 0
543
746
  size = 480
544
747
  end
748
+
749
+ change_image_size(size) # 크기 변경 함수 호출
545
750
 
546
- change_image_size(size)
547
751
 
548
752
  if @data['이미지설정']['필터사용'].checked?
549
753
  image_filter()
550
754
  end
551
755
 
552
- insert_image_text1 = ''
553
- insert_image_text2 = ''
554
756
  if @data['이미지설정']['글자삽입1'].checked?
555
- insert_image_text1 = @data['이미지설정']['이미지글자1'].sample
757
+ if @data['이미지설정']['이미지글자1'].length == 0
758
+ image_text_path1 = ''
759
+ else
760
+ if @data['이미지설정']['글자랜덤'].checked?
761
+ image_text_path1 = @data['이미지설정']['이미지글자1'].sample
762
+ else
763
+ image_text_path1 = @data['이미지설정']['이미지글자1'][@image_text_soon1]
764
+ @image_text_soon1 += 1
765
+ if @image_text_soon1 > @data['이미지설정']['이미지글자1'].length - 1
766
+ @image_text_soon1 = 0
767
+ end
768
+ end
769
+ end
556
770
  end
557
771
 
558
772
  if @data['이미지설정']['글자삽입2'].checked?
559
- insert_image_text2 = @data['이미지설정']['이미지글자2'].sample
773
+ if @data['이미지설정']['이미지글자2'].length == 0
774
+ image_text_path2 = ''
775
+ else
776
+ if @data['이미지설정']['글자랜덤'].checked?
777
+ image_text_path2 = @data['이미지설정']['이미지글자2'].sample
778
+ else
779
+ image_text_path2 = @data['이미지설정']['이미지글자2'][@image_text_soon2]
780
+ @image_text_soon2 += 1
781
+ if @image_text_soon2 > @data['이미지설정']['이미지글자2'].length - 1
782
+ @image_text_soon2 = 0
783
+ end
784
+ end
785
+ end
560
786
  end
561
-
787
+
562
788
  if @data['이미지설정']['글자삽입1'].checked? or @data['이미지설정']['글자삽입2'].checked?
563
- image_text(insert_image_text1, insert_image_text2)
789
+ image_text(image_text_path1, image_text_path2)
564
790
  end
565
791
 
566
792
  if @data['이미지설정']['테두리사용'].checked?
567
793
  border()
568
794
  end
569
795
 
796
+ sleep(1)
570
797
  time = Time.now.to_s.split(' ')[0..1].join('').split(':').join('').split('-').join('')
571
798
  FileUtils.cp('./image/memory.png', './image/'+@keyword+time+'.png')
799
+ hi_dir = Dir.pwd
800
+ iconv = Iconv.new('UTF-8', 'CP949')
801
+ begin
802
+ hi_dir = iconv.iconv(hi_dir)
803
+ rescue
804
+
805
+ end
806
+ return hi_dir+'/image/'+@keyword+time+'.png'
572
807
  end
573
808
 
574
809
  def image_update22
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wp_posting_duo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - zon
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-01-09 00:00:00.000000000 Z
10
+ date: 2025-06-26 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: File to Clipboard gem
14
13
  email: mymin26@naver.com
@@ -21,7 +20,6 @@ homepage: ''
21
20
  licenses:
22
21
  - zon
23
22
  metadata: {}
24
- post_install_message:
25
23
  rdoc_options: []
26
24
  require_paths:
27
25
  - lib
@@ -36,8 +34,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
36
34
  - !ruby/object:Gem::Version
37
35
  version: '0'
38
36
  requirements: []
39
- rubygems_version: 3.3.7
40
- signing_key:
37
+ rubygems_version: 3.6.7
41
38
  specification_version: 4
42
39
  summary: file to clipboard
43
40
  test_files: []