html_to 0.7.1 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODE_OF_CONDUCT.md +46 -0
- data/.github/CONTRIBUTING.md +14 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +11 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +22 -0
- data/README.md +13 -7
- data/Rakefile +16 -0
- data/html_to.gemspec +22 -13
- data/lib/html_to/chromium.rb +37 -0
- data/lib/html_to/configuration.rb +11 -0
- data/lib/html_to/image_generate.rb +82 -0
- data/lib/html_to/meta_image_generate_job.rb +13 -0
- data/lib/html_to/serializer.rb +7 -0
- data/lib/html_to/version.rb +4 -0
- data/lib/html_to.rb +137 -16
- data/lib/views/html_to/white.html.erb +38 -0
- metadata +30 -35
- data/.gitignore +0 -49
- data/gemfile +0 -3
- data/lib/html_to/chromium_controll.rb +0 -20
- data/lib/html_to/html_headless.rb +0 -41
- data/lib/html_to/share_uploader.rb +0 -14
- data/lib/html_to/sharing_image_generate.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cce279f63f00703d7d960adcc2917ebe0a3e58f01c03fe91680ba162afe617bb
|
4
|
+
data.tar.gz: f917e33be2c191482272351aeb26ec01913e6e499a286f691b1aace06972ef0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a06027f1cf88b104618f9b1215f00cf987acd126ceb0be77fea5503bd07b7f9b770dd7084abe65021e4606c5a2f64b50bf4d52f67815bc39e99db88968bf11bd
|
7
|
+
data.tar.gz: be7e36aa554586abe33168337955a7b477c7f12a60548a45172ba333400546ef1cbf4526d3190c821036fb650cf2a383a737f265d744b90c4f1df037323bdafe
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
6
|
+
|
7
|
+
## Our Standards
|
8
|
+
|
9
|
+
Examples of behavior that contributes to creating a positive environment include:
|
10
|
+
|
11
|
+
* Using welcoming and inclusive language
|
12
|
+
* Being respectful of differing viewpoints and experiences
|
13
|
+
* Gracefully accepting constructive criticism
|
14
|
+
* Focusing on what is best for the community
|
15
|
+
* Showing empathy towards other community members
|
16
|
+
|
17
|
+
Examples of unacceptable behavior by participants include:
|
18
|
+
|
19
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
20
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
21
|
+
* Public or private harassment
|
22
|
+
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
23
|
+
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
24
|
+
|
25
|
+
## Our Responsibilities
|
26
|
+
|
27
|
+
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
28
|
+
|
29
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
30
|
+
|
31
|
+
## Scope
|
32
|
+
|
33
|
+
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
34
|
+
|
35
|
+
## Enforcement
|
36
|
+
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project author at vchekryzhov@ya.ru. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
38
|
+
|
39
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
40
|
+
|
41
|
+
## Attribution
|
42
|
+
|
43
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
44
|
+
|
45
|
+
[homepage]: http://contributor-covenant.org
|
46
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
1. [Fork the repository.][fork]
|
4
|
+
2. [Create a topic branch.][branch]
|
5
|
+
3. Implement your feature or bug fix.
|
6
|
+
4. Don't forget to add specs and make sure they pass by running `rspec .`.
|
7
|
+
5. Make sure your code complies with the style guide by running `rubocop`. `rubocop -a` can automatically fix most issues for you.
|
8
|
+
6. If necessary, add documentation for your feature or bug fix.
|
9
|
+
7. Commit and push your changes.
|
10
|
+
8. [Submit a pull request.][pr]
|
11
|
+
|
12
|
+
[fork]: http://help.github.com/fork-a-repo/
|
13
|
+
[branch]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-branches
|
14
|
+
[pr]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests
|
@@ -0,0 +1,11 @@
|
|
1
|
+
### Summary
|
2
|
+
|
3
|
+
Provide a general description of the code changes in your pull
|
4
|
+
request. Were there any bugs you had fixed? If so, mention them. If
|
5
|
+
these bugs have open GitHub issues, be sure to tag them here as well,
|
6
|
+
to keep the conversation linked together.
|
7
|
+
|
8
|
+
### Other Information
|
9
|
+
|
10
|
+
If there's anything else that's important and relevant to your pull
|
11
|
+
request, mention that information here.
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Changelog
|
2
|
+
## 1.0.1
|
3
|
+
Bug fixes. test refactor. Added integration tests
|
4
|
+
## 1.0.0 (5-Sep-2023)
|
5
|
+
Added configuration via DSL. Added ability to generate few images on one model. Replaced carrierwave uploader to active storage. Added rspec.
|
6
|
+
## 0.7.2 (12-May-2021)
|
7
|
+
* Fixing Issues
|
8
|
+
## 0.7.0 (07-Apr-2021)
|
9
|
+
* Some Improves
|
10
|
+
## 0.0.2 (05-Apr-2021)
|
11
|
+
* Fixing Issues
|
12
|
+
## 0.0.1 (05-Apr-2021)
|
13
|
+
* Initial release
|
data/Gemfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
gemspec
|
3
|
+
gem 'image_processing'
|
4
|
+
group :test do
|
5
|
+
gem 'database_cleaner-active_record'
|
6
|
+
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
|
7
|
+
|
8
|
+
gem 'database_cleaner'
|
9
|
+
gem 'dotenv', '~> 2.5'
|
10
|
+
gem 'rails', '~> 7'
|
11
|
+
gem 'rake', '~> 13.0'
|
12
|
+
gem 'rspec', '~> 3.6'
|
13
|
+
gem 'rspec-rails', '~> 4.0'
|
14
|
+
gem 'sqlite3'
|
15
|
+
# rubocop dependencies...
|
16
|
+
gem 'rubocop', '~> 1.55'
|
17
|
+
gem 'rubocop-performance', '~> 1.18'
|
18
|
+
gem 'rubocop-rspec', '~> 2.22'
|
19
|
+
gem 'simplecov', '~> 0.16'
|
20
|
+
gem 'simplecov-cobertura'
|
21
|
+
gem 'vcr', '~> 6.0'
|
22
|
+
end
|
data/README.md
CHANGED
@@ -1,23 +1,26 @@
|
|
1
|
-
# html-to
|
2
1
|
# install
|
3
2
|
``` ruby
|
4
3
|
gem 'html_to'
|
5
4
|
```
|
6
|
-
|
7
|
-
|
5
|
+
## dependencies
|
6
|
+
### gem dependecies
|
7
|
+
- carrierwave
|
8
|
+
- sidekiq
|
9
|
+
### system dependecies
|
8
10
|
Ubuntu:
|
9
11
|
``` bash
|
12
|
+
sudo apt install imagemagick
|
10
13
|
sudo apt install -y chromium-browser
|
11
14
|
```
|
12
|
-
|
13
15
|
Debian:
|
14
16
|
```bash
|
17
|
+
sudo apt install imagemagick
|
15
18
|
apt-get install chromium chromium-l10n
|
16
19
|
```
|
17
20
|
|
18
21
|
# Get Started
|
19
22
|
### Prepare your model
|
20
|
-
|
23
|
+
add string field to youe model, for attach uploader
|
21
24
|
|
22
25
|
and add start to your model, what you want use
|
23
26
|
``` ruby
|
@@ -30,7 +33,7 @@ include HtmlTo
|
|
30
33
|
|
31
34
|
you need create, on path ```@@share_template``` how example share/post will be ```app/views/share/post.html.erb```
|
32
35
|
|
33
|
-
|
36
|
+
#### template file example:
|
34
37
|
``` html
|
35
38
|
<!DOCTYPE html>
|
36
39
|
<html lang="en">
|
@@ -73,5 +76,8 @@ you need create, on path ```@@share_template``` how example share/post will be `
|
|
73
76
|
```
|
74
77
|
In your template file you has access to your object via @obj
|
75
78
|
|
76
|
-
|
79
|
+
#### Assets, font, etc
|
77
80
|
Headless browser will be start from Rails public path, all local assets should be access in the public folder.
|
81
|
+
|
82
|
+
# Runner
|
83
|
+
gem use sidekiq worker and work at background. you need, to start your sidekiq.
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rake'
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
rescue LoadError
|
6
|
+
puts 'although not required, bundler is recommended for running the tests'
|
7
|
+
end
|
8
|
+
task default: :spec
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
RSpec::Core::RakeTask.new(:spec)
|
11
|
+
|
12
|
+
require 'rubocop/rake_task'
|
13
|
+
RuboCop::RakeTask.new do |task|
|
14
|
+
task.requires << 'rubocop-performance'
|
15
|
+
task.requires << 'rubocop-rspec'
|
16
|
+
end
|
data/html_to.gemspec
CHANGED
@@ -1,16 +1,25 @@
|
|
1
|
-
|
1
|
+
require File.expand_path('lib/html_to/version', __dir__)
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
|
-
s.name
|
5
|
-
s.
|
6
|
-
s.
|
7
|
-
s.summary
|
8
|
-
s.description = 'Simple gem for transforms html page through chromium headless.'
|
9
|
-
s.author
|
10
|
-
s.email
|
11
|
-
s.homepage
|
12
|
-
s.license
|
13
|
-
s.files
|
14
|
-
|
15
|
-
|
4
|
+
s.name = 'html_to'
|
5
|
+
s.required_ruby_version = '>= 2.5'
|
6
|
+
s.version = HtmlTo::VERSION
|
7
|
+
s.summary = 'Html-To transforms html to image'
|
8
|
+
s.description = 'Simple gem for transforms html page through chromium headless to image.'
|
9
|
+
s.author = 'Chekryzhov Viktor'
|
10
|
+
s.email = 'vchekryzhov@ya.ru'
|
11
|
+
s.homepage = 'https://github.com/Vchekryzhov/html-to'
|
12
|
+
s.license = 'MIT'
|
13
|
+
s.files = Dir['README.md', 'LICENSE',
|
14
|
+
'CHANGELOG.md', 'lib/**/*.rb',
|
15
|
+
'lib/**/*.html.erb',
|
16
|
+
'html_to.gemspec', '.github/*.md',
|
17
|
+
'Gemfile', 'Rakefile']
|
18
|
+
s.extra_rdoc_files = ['README.md']
|
19
|
+
if ENV['TEST_RAILS_VERSION'].nil?
|
20
|
+
s.add_development_dependency 'rails', '~> 7.0.6'
|
21
|
+
else
|
22
|
+
s.add_development_dependency 'rails', ENV['TEST_RAILS_VERSION'].to_s
|
23
|
+
end
|
24
|
+
s.metadata['rubygems_mfa_required'] = 'false'
|
16
25
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'English'
|
2
|
+
module HtmlTo
|
3
|
+
module Chromium
|
4
|
+
def self.execute_path
|
5
|
+
if Configuration.chromium_path.present?
|
6
|
+
raise ArgumentError, "html_to error: not found chromium by path #{Configuration.chromium_path}" unless File.exist? Configuration.chromium_path
|
7
|
+
|
8
|
+
return Configuration.chromium_path
|
9
|
+
end
|
10
|
+
|
11
|
+
path = if /darwin/.match?(RbConfig::CONFIG['host_os'])
|
12
|
+
"/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"
|
13
|
+
elsif /linux/.match?(RbConfig::CONFIG['host_os'])
|
14
|
+
release = %x(lsb_release -i -s)
|
15
|
+
%x(which chromium-browser)
|
16
|
+
if release == "Debian\n"
|
17
|
+
which_path = %x(which chromium)
|
18
|
+
raise StandardError, "html_to error: You don't have chromium, please do apt install chromium" unless $CHILD_STATUS.success?
|
19
|
+
|
20
|
+
else
|
21
|
+
which_path = %x(which chromium-browser)
|
22
|
+
raise StandardError, "html_to error: You don't have chromium, please do apt install chromium-browser" unless $CHILD_STATUS.success?
|
23
|
+
end
|
24
|
+
which_path
|
25
|
+
else
|
26
|
+
raise StandardError, "html_to error host os don't detected"
|
27
|
+
end
|
28
|
+
raise StandardError, 'html_to error: chromium executable path not found' if path.blank?
|
29
|
+
|
30
|
+
path.delete("\n")
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.version
|
34
|
+
%x(#{execute_path} --version)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require_relative 'chromium'
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
class HtmlTo::ImageGenerate
|
6
|
+
include HtmlTo::Chromium
|
7
|
+
def call(record, serializer, options)
|
8
|
+
generate_template(record, serializer, options[:template])
|
9
|
+
take_screenshot(options[:width], options[:height])
|
10
|
+
attach_image(record, options[:image_name])
|
11
|
+
rescue StandardError
|
12
|
+
raise
|
13
|
+
ensure
|
14
|
+
FileUtils.rm_f(html_file_path)
|
15
|
+
FileUtils.rm_f(optimize_screenshot) if optimize_screenshot
|
16
|
+
FileUtils.rm_f(screenshot_file_path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_template(record, serializer, template)
|
20
|
+
object = serializer.constantize.new(record)
|
21
|
+
html = ERB.new(File.read(template)).result(binding)
|
22
|
+
File.write(html_file_path, html)
|
23
|
+
end
|
24
|
+
|
25
|
+
def take_screenshot(width, height)
|
26
|
+
cmd = <<~BASH.chomp
|
27
|
+
#{HtmlTo::Chromium.execute_path} \
|
28
|
+
--headless=new \
|
29
|
+
--screenshot=#{screenshot_file_path} \
|
30
|
+
--window-size=#{width},#{height} \
|
31
|
+
--disable-gpu \
|
32
|
+
--disable-features=NetworkService #{html_file_path}
|
33
|
+
BASH
|
34
|
+
|
35
|
+
%x(#{cmd})
|
36
|
+
raise StandardError, "html_to error result = #{$CHILD_STATUS}; command = #{cmd}" unless chromium_run_success?
|
37
|
+
end
|
38
|
+
|
39
|
+
def attach_image(record, image_name)
|
40
|
+
record.send(image_name).purge
|
41
|
+
record.html_to_skip_meta_image_generate = true
|
42
|
+
record.send(image_name).attach(io: optimize_screenshot, filename: optimize_screenshot, content_type: 'image/png')
|
43
|
+
end
|
44
|
+
|
45
|
+
def html_file_path
|
46
|
+
@html_file_path ||= Rails.root.join('tmp').join("#{SecureRandom.urlsafe_base64.downcase}.html")
|
47
|
+
end
|
48
|
+
|
49
|
+
def screenshot_file_path
|
50
|
+
@screenshot_file_path ||= Rails.root.join('tmp').join("#{SecureRandom.urlsafe_base64.downcase}.png")
|
51
|
+
end
|
52
|
+
|
53
|
+
def optimize_screenshot
|
54
|
+
return nil unless File.exist?(screenshot_file_path)
|
55
|
+
|
56
|
+
@optimize_screenshot ||= if image_processing_installed?
|
57
|
+
ImageProcessing::MiniMagick
|
58
|
+
.source(screenshot_file_path)
|
59
|
+
.convert('jpg')
|
60
|
+
.saver(quality: 85)
|
61
|
+
.call
|
62
|
+
|
63
|
+
else
|
64
|
+
screenshot_file_path
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def chromium_run_success?
|
71
|
+
$CHILD_STATUS.success?
|
72
|
+
end
|
73
|
+
|
74
|
+
def image_processing_installed?
|
75
|
+
Gem::Specification.find_by_name('image_processing')
|
76
|
+
rescue Gem::LoadError
|
77
|
+
puts '[html-to] image will not processing because gem image_processing is not installed'
|
78
|
+
false
|
79
|
+
else
|
80
|
+
true
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module HtmlTo
|
2
|
+
class MetaImageGenerateJob < ::ActiveJob::Base
|
3
|
+
queue_as :html_to
|
4
|
+
def perform(id, class_name, serializer, options)
|
5
|
+
record = class_name.constantize.find(id)
|
6
|
+
generator.call(record, serializer, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def generator
|
10
|
+
HtmlTo::ImageGenerate.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/html_to.rb
CHANGED
@@ -1,22 +1,143 @@
|
|
1
1
|
module HtmlTo
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
2
|
+
require_relative 'html_to/image_generate'
|
3
|
+
require_relative 'html_to/meta_image_generate_job'
|
4
|
+
require_relative 'html_to/configuration'
|
5
|
+
require_relative 'html_to/chromium'
|
6
|
+
require_relative 'html_to/serializer'
|
7
|
+
class HtmlToImageSettings
|
8
|
+
OPTIONS = %i[
|
9
|
+
template width height image_name
|
10
|
+
].freeze
|
11
|
+
DEFAULT_OPTIONS = {
|
12
|
+
template: :white,
|
13
|
+
width: 1200,
|
14
|
+
height: 630,
|
15
|
+
image_name: :meta_image
|
16
|
+
}.freeze
|
17
|
+
attr_reader(*OPTIONS, :serializer)
|
18
|
+
|
19
|
+
def initialize(klass, serializer, options, &block)
|
20
|
+
@klass = klass
|
21
|
+
@options = options
|
22
|
+
validate_options
|
23
|
+
@serializer = serializer.to_s
|
24
|
+
setup_options
|
25
|
+
instance_exec(&block) if block_given?
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_options
|
29
|
+
@options.each_key { |opt| raise ArgumentError, "html_to error #{opt} is unknown option" unless OPTIONS.include? opt }
|
30
|
+
end
|
31
|
+
|
32
|
+
def setup_options
|
33
|
+
OPTIONS.each do |k|
|
34
|
+
instance_variable_set("@#{k}", @options[k] || DEFAULT_OPTIONS[k])
|
35
|
+
end
|
36
|
+
find_template_path!
|
37
|
+
end
|
38
|
+
|
39
|
+
def additional_images
|
40
|
+
@additional_images || {}
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_image(image_name, serializer, options = {})
|
44
|
+
@additional_images ||= {}
|
45
|
+
options[:image_name] = image_name
|
46
|
+
@klass.class_eval do
|
47
|
+
has_one_attached image_name
|
48
|
+
end
|
49
|
+
@additional_images[image_name] = HtmlToImageSettings.new(@klass, serializer, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def find_template_path!
|
53
|
+
user_template = Rails.root.join('app/views/html_to').join("#{template}.html.erb")
|
54
|
+
return user_template.to_s if File.file? user_template
|
55
|
+
|
56
|
+
gem_template = File.expand_path("views/html_to/#{template}.html.erb", __dir__)
|
57
|
+
|
58
|
+
return gem_template.to_s if File.file? gem_template
|
59
|
+
|
60
|
+
raise ArgumentError, "html_to error Template file not found #{user_template} #{gem_template} "
|
61
|
+
end
|
16
62
|
end
|
63
|
+
class << self
|
64
|
+
attr_reader :included_in
|
17
65
|
|
18
|
-
|
19
|
-
|
66
|
+
def included(klass)
|
67
|
+
@included_in ||= []
|
68
|
+
@included_in << klass
|
69
|
+
@included_in.uniq!
|
70
|
+
|
71
|
+
klass.class_eval do
|
72
|
+
extend ClassMethods
|
73
|
+
include InstanceMethods
|
74
|
+
end
|
75
|
+
end
|
20
76
|
end
|
21
77
|
|
78
|
+
module ClassMethods
|
79
|
+
def self.extended(base)
|
80
|
+
class << base
|
81
|
+
alias_method :create_meta_images!, :html_to_create_meta_images! unless method_defined? :create_meta_images!
|
82
|
+
end
|
83
|
+
base.cattr_accessor :html_to_image_settings
|
84
|
+
end
|
85
|
+
|
86
|
+
def html_to_create_meta_images!
|
87
|
+
all.each(&:html_to_create_meta_image!)
|
88
|
+
end
|
89
|
+
|
90
|
+
def html_to(serializer, options = {}, &block)
|
91
|
+
after_validation :html_to_mark_synchronous if options.delete(:synchronous) == true && respond_to?(:after_validation)
|
92
|
+
after_validation :html_to_mark_skip_meta_image_generate if options.delete(:skip_auto_update) == true && respond_to?(:after_validation)
|
93
|
+
|
94
|
+
self.html_to_image_settings = HtmlToImageSettings.new(self, serializer, options, &block)
|
95
|
+
class_eval do
|
96
|
+
has_one_attached options[:image_name] || html_to_image_settings.image_name
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
module InstanceMethods
|
102
|
+
def self.included(base)
|
103
|
+
base.attr_accessor :html_to_skip_meta_image_generate
|
104
|
+
base.instance_eval do
|
105
|
+
alias_method :create_meta_image!, :html_to_create_meta_image! unless method_defined? :create_meta_images!
|
106
|
+
end
|
107
|
+
base.after_commit :html_to_create_meta_image!, unless: :html_to_skip_meta_image_generate
|
108
|
+
end
|
109
|
+
|
110
|
+
def html_to_create_meta_image!
|
111
|
+
share_images_settings = [self.class.html_to_image_settings, *self.class.html_to_image_settings.additional_images.values].flatten
|
112
|
+
share_images_settings.each do |image_settings|
|
113
|
+
generator_args = [
|
114
|
+
id, self.class.name, image_settings.serializer, {
|
115
|
+
image_name: image_settings.image_name,
|
116
|
+
width: image_settings.width,
|
117
|
+
height: image_settings.height,
|
118
|
+
template: image_settings.find_template_path!
|
119
|
+
}
|
120
|
+
]
|
121
|
+
if html_to_synchronous?
|
122
|
+
MetaImageGenerateJob.perform_now(*generator_args)
|
123
|
+
else
|
124
|
+
MetaImageGenerateJob.perform_later(*generator_args)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def html_to_mark_synchronous
|
132
|
+
@html_to_synchronous = true
|
133
|
+
end
|
134
|
+
|
135
|
+
def html_to_mark_skip_meta_image_generate
|
136
|
+
@html_to_skip_meta_image_generate = true
|
137
|
+
end
|
138
|
+
|
139
|
+
def html_to_synchronous?
|
140
|
+
@html_to_synchronous
|
141
|
+
end
|
142
|
+
end
|
22
143
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<title>Title</title>
|
6
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Martian Mono">
|
7
|
+
<style>
|
8
|
+
|
9
|
+
body {
|
10
|
+
margin: 0;
|
11
|
+
font-family: "Martian Mono", sans-serif;
|
12
|
+
}
|
13
|
+
.image {
|
14
|
+
background-size: cover;
|
15
|
+
position: absolute;
|
16
|
+
float: left;
|
17
|
+
top: 0px;
|
18
|
+
width: 1200px;
|
19
|
+
height: 630px;
|
20
|
+
object-fit: y-repeat;
|
21
|
+
}
|
22
|
+
.description{
|
23
|
+
position: absolute;
|
24
|
+
font-size: 48px;
|
25
|
+
z-index: 1;
|
26
|
+
}
|
27
|
+
|
28
|
+
</style>
|
29
|
+
</head>
|
30
|
+
<body>
|
31
|
+
<div class="root">
|
32
|
+
<img class='image' src="https://images.unsplash.com/photo-1593642702821-c8da6771f0c6?ixid=MXwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1489&q=80" alt="img">
|
33
|
+
<p class="description">
|
34
|
+
<%=object.title%>
|
35
|
+
</p>
|
36
|
+
</div>
|
37
|
+
</body>
|
38
|
+
</html>
|
metadata
CHANGED
@@ -1,63 +1,58 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: html_to
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chekryzhov Viktor
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
type: :
|
19
|
+
version: 7.0.6
|
20
|
+
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
27
|
-
|
28
|
-
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
description: Simple gem for transforms html page through chromium headless.
|
42
|
-
email: chekryzhov@charmerstudio.com
|
26
|
+
version: 7.0.6
|
27
|
+
description: Simple gem for transforms html page through chromium headless to image.
|
28
|
+
email: vchekryzhov@ya.ru
|
43
29
|
executables: []
|
44
30
|
extensions: []
|
45
|
-
extra_rdoc_files:
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README.md
|
46
33
|
files:
|
47
|
-
- ".
|
34
|
+
- ".github/CODE_OF_CONDUCT.md"
|
35
|
+
- ".github/CONTRIBUTING.md"
|
36
|
+
- ".github/PULL_REQUEST_TEMPLATE.md"
|
37
|
+
- CHANGELOG.md
|
38
|
+
- Gemfile
|
48
39
|
- LICENSE
|
49
40
|
- README.md
|
50
|
-
-
|
41
|
+
- Rakefile
|
51
42
|
- html_to.gemspec
|
52
43
|
- lib/html_to.rb
|
53
|
-
- lib/html_to/
|
54
|
-
- lib/html_to/
|
55
|
-
- lib/html_to/
|
56
|
-
- lib/html_to/
|
44
|
+
- lib/html_to/chromium.rb
|
45
|
+
- lib/html_to/configuration.rb
|
46
|
+
- lib/html_to/image_generate.rb
|
47
|
+
- lib/html_to/meta_image_generate_job.rb
|
48
|
+
- lib/html_to/serializer.rb
|
49
|
+
- lib/html_to/version.rb
|
50
|
+
- lib/views/html_to/white.html.erb
|
57
51
|
homepage: https://github.com/Vchekryzhov/html-to
|
58
52
|
licenses:
|
59
53
|
- MIT
|
60
|
-
metadata:
|
54
|
+
metadata:
|
55
|
+
rubygems_mfa_required: 'false'
|
61
56
|
post_install_message:
|
62
57
|
rdoc_options: []
|
63
58
|
require_paths:
|
@@ -66,15 +61,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
66
61
|
requirements:
|
67
62
|
- - ">="
|
68
63
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
64
|
+
version: '2.5'
|
70
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
66
|
requirements:
|
72
67
|
- - ">="
|
73
68
|
- !ruby/object:Gem::Version
|
74
69
|
version: '0'
|
75
70
|
requirements: []
|
76
|
-
rubygems_version: 3.1
|
71
|
+
rubygems_version: 3.0.3.1
|
77
72
|
signing_key:
|
78
73
|
specification_version: 4
|
79
|
-
summary: Html-To transforms html to
|
74
|
+
summary: Html-To transforms html to image
|
80
75
|
test_files: []
|
data/.gitignore
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
*.rbc
|
2
|
-
capybara-*.html
|
3
|
-
.rspec
|
4
|
-
/log
|
5
|
-
/tmp
|
6
|
-
/db/*.sqlite3
|
7
|
-
/db/*.sqlite3-journal
|
8
|
-
/public/system
|
9
|
-
/coverage/
|
10
|
-
/spec/tmp
|
11
|
-
*.orig
|
12
|
-
rerun.txt
|
13
|
-
pickle-email-*.html
|
14
|
-
|
15
|
-
# TODO Comment out this rule if you are OK with secrets being uploaded to the repo
|
16
|
-
config/initializers/secret_token.rb
|
17
|
-
config/master.key
|
18
|
-
|
19
|
-
# Only include if you have production secrets in this file, which is no longer a Rails default
|
20
|
-
# config/secrets.yml
|
21
|
-
|
22
|
-
# dotenv
|
23
|
-
# TODO Comment out this rule if environment variables can be committed
|
24
|
-
.env
|
25
|
-
|
26
|
-
## Environment normalization:
|
27
|
-
/.bundle
|
28
|
-
/vendor/bundle
|
29
|
-
|
30
|
-
# these should all be checked in to normalize the environment:
|
31
|
-
# Gemfile.lock, .ruby-version, .ruby-gemset
|
32
|
-
|
33
|
-
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
-
.rvmrc
|
35
|
-
|
36
|
-
# if using bower-rails ignore default bower_components path bower.json files
|
37
|
-
/vendor/assets/bower_components
|
38
|
-
*.bowerrc
|
39
|
-
bower.json
|
40
|
-
|
41
|
-
# Ignore pow environment settings
|
42
|
-
.powenv
|
43
|
-
|
44
|
-
# Ignore Byebug command history file.
|
45
|
-
.byebug_history
|
46
|
-
|
47
|
-
# Ignore node_modules
|
48
|
-
node_modules/
|
49
|
-
|
data/gemfile
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
module HtmlTo::ChromiumControll
|
2
|
-
def chrome
|
3
|
-
if RbConfig::CONFIG['host_os'] =~ /darwin/
|
4
|
-
"/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"
|
5
|
-
elsif RbConfig::CONFIG['host_os'] =~ /linux/
|
6
|
-
release = IO.popen("lsb_release -i -s").read
|
7
|
-
if release == "Debian\n"
|
8
|
-
`dpkg -s chromium`
|
9
|
-
raise "html_to message: You don't have chromium, please do apt install chromium"if !$?.success?
|
10
|
-
'chromium'
|
11
|
-
else
|
12
|
-
`dpkg -s chromium-browser`
|
13
|
-
raise "html_to message: You don't have chromium, please do apt install chromium"if !$?.success?
|
14
|
-
'chromium-browser'
|
15
|
-
end
|
16
|
-
else
|
17
|
-
raise StandardError.new "host os don't detected"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
class HtmlTo::HtmlHeadless
|
2
|
-
require 'fileutils'
|
3
|
-
require 'html_to/chromium_controll.rb'
|
4
|
-
include HtmlTo::ChromiumControll
|
5
|
-
|
6
|
-
def to_image(obj, width=1200, height=630)
|
7
|
-
|
8
|
-
width = obj.class.class_variable_get(:@@html_to_width) if obj.class.class_variable_defined?(:@@html_to_width)
|
9
|
-
height = obj.class.class_variable_get(:@@html_to_height) if obj.class.class_variable_defined?(:@@html_to_height)
|
10
|
-
|
11
|
-
@template = File.read(Rails.root.join('app/views').join(obj.class.class_variable_get(:@@share_template)+".html.erb"))
|
12
|
-
html = ERB.new(@template.html_safe).result(binding)
|
13
|
-
File.open(html_file_path, 'w+') {|f| f.write(html) }
|
14
|
-
begin
|
15
|
-
cmd = "'#{chrome}'
|
16
|
-
--headless
|
17
|
-
--screenshot=#{screenshot_file_path}
|
18
|
-
--window-size=#{width},#{height}
|
19
|
-
--disable-gpu
|
20
|
-
--disable-features=NetworkService #{html_file_path}".gsub("\n",' ')
|
21
|
-
`#{cmd}`
|
22
|
-
if $?.success?
|
23
|
-
obj.skip_share_image_generate = true
|
24
|
-
obj.send("#{obj.class.class_variable_get(:@@share_uploader)}=", File.open(screenshot_file_path))
|
25
|
-
obj.save
|
26
|
-
else
|
27
|
-
raise "result = #{$?}; command = #{cmd}"
|
28
|
-
end
|
29
|
-
ensure
|
30
|
-
FileUtils.rm(html_file_path)
|
31
|
-
FileUtils.rm(screenshot_file_path)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def html_file_path
|
36
|
-
@path ||= Rails.public_path.join(SecureRandom.urlsafe_base64.downcase + ".html")
|
37
|
-
end
|
38
|
-
def screenshot_file_path
|
39
|
-
@screenshot_file_path ||= Rails.public_path.join(SecureRandom.urlsafe_base64.downcase + ".png")
|
40
|
-
end
|
41
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
class HtmlTo::ShareUploader < CarrierWave::Uploader::Base
|
2
|
-
include CarrierWave::MiniMagick
|
3
|
-
|
4
|
-
raise 'Message from html_to: Rails.application.config.asset_host not present' if Rails.application.config.asset_host.nil?
|
5
|
-
|
6
|
-
def store_dir
|
7
|
-
"storage/#{model.class.base_class.name.underscore}/#{model.id}/share"
|
8
|
-
end
|
9
|
-
|
10
|
-
def url
|
11
|
-
"#{Rails.application.config.asset_host}#{super}"
|
12
|
-
end
|
13
|
-
process resize_to_limit: [1200, 630]
|
14
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
class HtmlTo::SharingImageGenerate
|
2
|
-
require 'erb'
|
3
|
-
require 'sidekiq'
|
4
|
-
include Sidekiq::Worker
|
5
|
-
sidekiq_options queue: 'default'
|
6
|
-
|
7
|
-
def perform(id, class_name)
|
8
|
-
@obj = class_name.constantize.find(id)
|
9
|
-
HtmlTo::HtmlHeadless.new.to_image(@obj)
|
10
|
-
end
|
11
|
-
end
|