tumblr_autofixer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a18737fe7b0fb91a113773ec90fbeda392143412
4
+ data.tar.gz: 970f4f5303a3137a2df386d7615b290494d09ecc
5
+ SHA512:
6
+ metadata.gz: c94e3ff20eab1b4d230b26fd90ffe419ff14344d2363b57b2216561ba4baaca3ecc95e63e36eb58b66da3ed5c3c8c4862647cc40efff3f12bf83251527e2659b
7
+ data.tar.gz: 29217d34b0bb4157ef8bdff68368ec3b69724a472817bebe5a88651a71a420dc4511e670f2c514cd7a02968068bcd604d9e2460ea8f30ca576d5858c8a06d2a6
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # About
2
+ \- tumblr_autofix is a configurable comment generator for Tumblr.
3
+ \- Two configuration files are created in your home directory: taf_data.yml & taf_summary.yml
4
+ \- Careful when editing configuration files, as with all YAML files, indentation is crucial!
5
+
6
+ # Using ~/config_md/taf/data.yml
7
+ no_names [Array] - Blogs listed here will be ignored during processing
8
+ summary [Array] - Will apply capitalization, add prefix and postfix strings
9
+ last_tag [Array] - Use the last available tag as your comment
10
+ tag_idx [[Array]] - Indicated which tag to use as the new comment
11
+ - Blogs listed in the first tag_idx[0] will use the first tag
12
+ - Blogs listed in tag_idx[1] will use the second
13
+
14
+
15
+ # Using ~/config_md/taf/summary.yml
16
+ ## Available variables
17
+ \- `summary` - the plain text of the current post's caption
18
+ \- `res` - lower case version of summary, useful for simplified text searching
19
+ \- `from` - the blog name of the user you reblogged the post from
20
+ \- `lines` - original summary text, split into lines
21
+
22
+ ## Returning
23
+ \- using `return <value>` in your summary.yml will make that string your new comment
24
+ \- storing your new comment in the `res` variable, without explicitly returning it, will subject it to a couple more modifications:
25
+ 1. capitalization - each word in the string will be capitalized
26
+ 2. prefix - a string passed via the `-p <PREFIX>` option will be prepended to `res`
27
+ 3. postfix - a string passed via the `-P <POSTFIX>` option will be appended to `res`
28
+
29
+ ## Summary Example
30
+
31
+ ### Get the title from the first line, then add the author
32
+ Update ~/config_md/taf/summary.yml with the following
33
+ ```
34
+ :angulargeometry:
35
+ - title = summary.split("\n")[0]
36
+ - return "#{title} by Angular Geometry"
37
+ ```
38
+
39
+ ### Add prefix & postfix to formatted strings
40
+ 1 - Update ~/config_md/taf/summary.yml
41
+ note: string must be stored in the `res` variable for pre/postfixing to work
42
+ ```
43
+ :kazu721010:
44
+ - title, architect = lines[0].split('/')
45
+ - photographer = lines[2].split("©").last
46
+ - res = "project: #{title}\narchitect: #{architect}\nphotographer: #{photographer}"
47
+ ```
48
+ 2 - Run Autofixer with options: `taf -p '**\n' -P '\n--'`
49
+
50
+
51
+ 3 - Resulting caption for kazu721010 posts:
52
+ ```
53
+ **
54
+ Project: Project Title
55
+ Architect: Architect Or Firm Name
56
+ Photographer: Photographers Name
57
+ --
58
+ ```
data/bin/taf ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'tumblr_draftking'
4
+ require_relative '../lib/tumblr_autofixer'
5
+ # require File.join(Dir.home, '/coding/ruby/tumblr_autofixer/lib/tumblr_autofixer') # DEV ONLY - Run development source using system installed cli
6
+
7
+ DK::Idable.new(ARGV)
@@ -0,0 +1,14 @@
1
+ module DK
2
+ class Idable
3
+ def open_results(args)
4
+ return unless args.include?('open')
5
+ file = confile('needs_review.html')
6
+ `open #{file}` && exit(0) if File.exist?(file)
7
+ puts
8
+ puts 'Error:'
9
+ puts ' No results have been generated yet.'
10
+ puts
11
+ exit(0)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ module DK
2
+ class Idable
3
+ def show_help(args, opts)
4
+ return unless (args.include?('help') || opts.find_index('-h'))
5
+ puts 'Usage: '
6
+ puts ' $ taf <command?> [options?]'
7
+ puts
8
+ puts ' Commands:'
9
+ puts ' help Show this menu.'
10
+ puts ' show Open a webpage with the latest taf results.'
11
+ puts
12
+ puts ' Options:'
13
+ puts ' -s Simulate Run (no changes saved)'
14
+ puts ' -p [STRING] Prefix for generated comments'
15
+ puts ' -P [STRING] Prefix for generated comments'
16
+ puts ' -S [STRING] Separator used between prefix/postfix and generated comment text.'
17
+ puts ' -l [INTEGER] Number of Drafts to select for processing.'
18
+ puts ' --clear Clear unprocessible Drafts by adding the given prefix (-p [STRING])'
19
+ puts ' causing these posts to show as "Already Processed" in future runs.'
20
+ puts ' --show Open the results webpage after processing is complete.'
21
+ exit(0)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ module DK
2
+ class Idable
3
+ def show_version(opts)
4
+ return unless opts.include?('-v')
5
+ puts "\ntumblr_autofixer v#{VERSION}"
6
+ puts
7
+ exit(0)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,46 @@
1
+ module DK
2
+ class Idable
3
+ private
4
+
5
+ def store(dstore, key, value)
6
+ dstore.transaction do
7
+ dstore[key] = value
8
+ end
9
+ end
10
+
11
+ def restore(dstore, key, default=nil)
12
+ dstore.transaction do
13
+ dstore[key] || default
14
+ end
15
+ end
16
+
17
+ def prep_user_data_files
18
+ ex_blog_name = 'example-blog-name'
19
+ keys = [:no_names, :last_tag, :tag_idx, :summary]
20
+ keys.each do |key|
21
+ unless restore(@ystore, key)
22
+ value = []
23
+ case key
24
+ when :no_names
25
+ value << 'Ignore the following blogs during processing.'
26
+ value << ex_blog_name
27
+ when :last_tag
28
+ value << 'Use the last available tag for these blogs.'
29
+ value << ex_blog_name
30
+ when :tag_idx
31
+ value = [
32
+ ['Use tag #1 for these blogs.', ex_blog_name],
33
+ ['Use tag #2 for these blogs.', ex_blog_name],
34
+ ['Use tag #3 for these blogs.', ex_blog_name]
35
+ ]
36
+ when :summary
37
+ value << 'Capitalize, add prefix and postfix to existing summary text'
38
+ value << ex_blog_name
39
+ end
40
+ store(@ystore, key, value)
41
+ end
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,41 @@
1
+ module DK
2
+ class Idable
3
+ private
4
+
5
+ def dk_opts
6
+ { simulate: @simulate, limit: @limit }
7
+ end
8
+
9
+ def capitalize(s)
10
+ return if s.nil?
11
+ res = s.gsub(/\d/,'').split(' ').map(&:strip).map(&:capitalize)
12
+ return res[0] if res.size < 2
13
+ res.join(' ')
14
+ end
15
+
16
+ def prefix(s)
17
+ "#{@prefix}#{' ' + @spliter + ' ' if @spliter}#{s}#{@postfix}"
18
+ end
19
+
20
+ def link_to_edit(post)
21
+ id = post.id rescue post['id']
22
+ "https://www.tumblr.com/edit/#{id}"
23
+ end
24
+
25
+ def pad(value, reference, prefix=nil)
26
+ s = value.to_s
27
+ r = reference.to_s.length
28
+ if prefix
29
+ s = ' ' + s while (s.length < r)
30
+ else
31
+ s += ' ' while (s.length < r)
32
+ end
33
+ s
34
+ end
35
+
36
+ def home_file(file)
37
+ DK::Config.home_path_file(file)
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,134 @@
1
+ module DK
2
+ class Idable
3
+ private
4
+
5
+ def bfrom(post)
6
+ post.trail.first.blog.name rescue '-no trail-'
7
+ end
8
+
9
+ def show_results
10
+ cli_header
11
+
12
+ fname1 = confile('already_processed.html')
13
+ fname2 = confile('need_review.html')
14
+ fname3 = confile('updated.html')
15
+
16
+ @file_index = [
17
+ ["Needs Review (#{@need_review.size})", fname2],
18
+ ["Updated (#{@updated.size})", fname3],
19
+ ["Already Processed (#{@already_processed.size})", fname1]
20
+ ]
21
+
22
+ msg1 = "(#{@already_processed.size}) Drafts are ready to be queued."
23
+ msg2 = "(#{@need_review.size}) Drafts need visual review."
24
+ msg3 = "(#{@updated.size}) Drafts were Autofixed."
25
+
26
+
27
+ # Already Processed
28
+ @already_processed.sort_by!{ |x| x.id }
29
+ generate_review_webpage(@already_processed, fname1, msg1)
30
+
31
+ # Need Review
32
+ @need_review.sort_by! do |x|
33
+ bname = bfrom(x)
34
+ [bname, x.id]
35
+ end
36
+ generate_review_webpage(@need_review, fname2, msg2)
37
+
38
+ # updated
39
+ @updated.sort_by!{ |x| bfrom(x)}
40
+ generate_review_webpage(@updated, fname3, msg3)
41
+
42
+ puts
43
+ puts
44
+ `open #{@file_index.first.last}` if @showres
45
+ end
46
+
47
+ def generate_review_webpage(post_info, fname, msg1='')
48
+ page = "<html><head>#{style}</head><body>"
49
+ page += page_nav
50
+ page += '<table>'
51
+ page += '<caption>'
52
+ page += "<p>***** SIMULATION RUN *****</p>" if @simulate
53
+ page += "<p>#{msg1}</p>"
54
+ page += "<p>Click a photo to be taken to it's edit page.</p>"
55
+ page += '</caption>'
56
+ page += table_header
57
+ post_info.each_slice(1) do |posts|
58
+ page += '<tr>'
59
+ posts.each{|post| page += post_image_code(post)}
60
+ page += '</tr>'
61
+ end
62
+ page += '</table>'
63
+ page += "</body></html>"
64
+
65
+ # Create directory structure and file if it doesn't exist
66
+ # FileUtils::mkdir_p File.dirname(fname) unless File.exist?(fname)
67
+ File.open(fname, 'w'){|f| f.puts page}
68
+ puts "** Updated file: #{fname} **:\n"
69
+ end
70
+
71
+ def post_image_code(post)
72
+ # Alt Sizes (0 - 6) Large to Small
73
+ photo = post.photos.first.alt_sizes[4].url
74
+ count = post.photos.size
75
+ res = "<td><a target='_blank' href='#{link_to_edit(post)}'>"
76
+ res += "<img src='#{photo}'>#{' (' + count.to_s + ')' if count > 1}</a></td>"
77
+ res += "<td><p>#{bfrom(post)}</p></td>"
78
+ res += "<td><p>#{post.comment.empty? ? '-no comment-' : post.comment}</p></td>"
79
+ res += "<td><p>#{post.tags.empty? ? '-no tags-' : post.tags.join(', ')}</p></td>"
80
+ end
81
+
82
+ def cli_header
83
+ puts ' '*80 + "\r\n" # Clear any lingering text
84
+ if @simulate
85
+ puts '*'*40
86
+ puts '*'*14 + ' SIMULATION ' + '*'*14
87
+ puts '*'*40
88
+ puts
89
+ end
90
+ puts '_'*40
91
+ puts
92
+ puts "#{@total} drafts were retrieved."
93
+ puts "#{pad(@updated.size, @total, 1)} drafts were Autofixed."
94
+ puts "#{pad(@already_processed.size, @total, 1)} drafts were marked 'already processed'."
95
+ puts "#{pad(@need_review.size, @total, 1)} drafts require visual review."
96
+ puts '_'*40
97
+ puts
98
+ end
99
+
100
+ def page_nav
101
+ res = '<nav><ul>'
102
+ @file_index.each do |text, file|
103
+ res += %(<li><a href='#{file}'>#{text}</a></li>)
104
+ end
105
+ res += '</ul></nav>'
106
+ end
107
+
108
+ def table_header
109
+ res = '<thead><tr>'
110
+ res += '<th>Photo</th>'
111
+ res += '<th>Source</th>'
112
+ res += '<th>Caption</th>'
113
+ res += '<th>Tags</th>'
114
+ res += '</tr></thead>'
115
+ end
116
+
117
+ def style
118
+ %q(
119
+ <style>
120
+ table, tr, nav { width: 100%; text-align: center; vertical-align: middle; }
121
+ th { background-color: grey; border: 1px solid black; color: white; }
122
+ td { width: 25%; border: 1px solid gainsboro; }
123
+ table caption { background-color: rgb(43, 171, 171); }
124
+ nav { height: 100px; background-color: black; color: white; }
125
+ nav ul li { display: inline-block; width: 30%}
126
+ nav ul li a { display: inline-block; width: 100%; }
127
+ nav ul li:hover { background-color: rgb(43, 171, 171); }
128
+ a, a:visited { color: white; vertical-align: middle; line-height: 100px; }
129
+ </style>
130
+ )
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,5 @@
1
+ module DK
2
+ class Idable
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,179 @@
1
+ require 'tumblr_draftking'
2
+ require 'yaml/store'
3
+ require 'sanitize'
4
+ require 'fileutils'
5
+ Dir[File.join(__dir__, 'autofixer', '**', '*.rb')].each {|file| require file }
6
+ # require 'pry'
7
+
8
+ module DK
9
+ class Idable
10
+ C_LEN = 25
11
+ ERROR_STRING = '**'
12
+ def initialize(opts)
13
+ check_for_command(ARGV, opts)
14
+ extract_opts(opts)
15
+
16
+ @config_dir = home_file('/config_md/taf/')
17
+ @dk = DK::Client.new(dk_opts)
18
+
19
+ # Ensure my latest config files are in place.
20
+ `cp data.yml.bak #{confile('data.yml')}` if File.exist?('data.yml.bak')
21
+ `cp summary.yml #{confile('summary.yml')}` if File.exist?('summary.yml')
22
+
23
+ read_configuration
24
+ @already_processed, @need_review, @updated = [], [], []
25
+
26
+ autofixer(get_informative_posts)
27
+ @need_review = clear(@need_review) if @clear
28
+ show_results
29
+ end
30
+
31
+ private
32
+
33
+ def read_configuration
34
+ # Ensure directory structure exists
35
+ FileUtils::makedirs @config_dir unless Dir.exist?(@config_dir)
36
+
37
+ # Ensure configuration files are present
38
+ @ystore = YAML::Store.new("#{confile('data.yml')}")
39
+ @sstore = YAML::Store.new("#{confile('summary.yml')}")
40
+ prep_user_data_files
41
+
42
+ # Cache config data
43
+ @last_tag = restore(@ystore, :last_tag)
44
+ @tag_idx = restore(@ystore, :tag_idx)
45
+ @summary = restore(@ystore, :summary)
46
+ @ignore = restore(@ystore, :ignore)
47
+ end
48
+
49
+ def check_for_command(args, opts)
50
+ show_help(args, opts)
51
+ show_version(opts)
52
+ open_results(args)
53
+ end
54
+
55
+ def confile(fname)
56
+ @config_dir + fname
57
+ end
58
+
59
+ def extract_opts(opts)
60
+ @simulate = opts.include?('-s')
61
+ @limit = opts[opts.find_index('-l') + 1].to_i rescue nil
62
+ @spliter = opts[opts.find_index('-S') + 1] rescue ' '
63
+ @prefix = opts[opts.find_index('-p') + 1] rescue ''
64
+ @postfix = opts[opts.find_index('-P') + 1] rescue ''
65
+ @showres = opts.find_index('--show')
66
+ @clear = opts.find_index('--clear')
67
+ end
68
+
69
+ def get_informative_posts
70
+ drafts = @dk.get_posts.map{|post| DK::Post.new(post)}
71
+ @total = drafts.size
72
+ drafts.select do |draft|
73
+ ((@already_processed << draft) && next) if post_already_processed?(draft)
74
+ ((@need_review << draft) && next) unless post_has_info?(draft)
75
+ ((@need_review << draft) && next) unless post_has_trail?(draft)
76
+ true
77
+ end
78
+ end
79
+
80
+ # Post already has prefix?
81
+ def post_already_processed?(post)
82
+ summary = post.summary.chomp.strip
83
+ user_c = Sanitize.fragment(post.comment).strip
84
+
85
+ user_c.start_with?(@prefix) || summary.start_with?(@prefix)
86
+ end
87
+
88
+ # Post has a summary or tags?
89
+ def post_has_info?(post)
90
+ summary = post.summary.chomp.strip
91
+ !summary.empty? || !post.tags.empty?
92
+ end
93
+
94
+ # Do we know where it was reblogged from?
95
+ def post_has_trail?(post)
96
+ !post.trail.empty?
97
+ end
98
+
99
+
100
+ def autofixer(posts)
101
+ posts.each_with_index do |post, idx|
102
+ tags = post.tags
103
+ trail_name = post.trail.first.blog.name
104
+ post_summary = post.summary
105
+
106
+ ((@need_review << post) && next) if @ignore.include?(trail_name)
107
+ if fix_from_tag(post, trail_name)
108
+ next # Successfully used a tag-index to process post
109
+ elsif commands = restore(@sstore, trail_name.to_sym)
110
+ # Has custom processing of post.summary data defined
111
+ new_comment = special_summary(post_summary, trail_name, commands)
112
+ elsif @summary.include?(trail_name)
113
+ # Use default processing of post.summary data
114
+ new_comment = special_summary(post_summary, trail_name, [])
115
+ elsif @last_tag.include?(trail_name)
116
+ # Use the last available post.tags
117
+ new_comment = autofix(tags.last, trail_name)
118
+ else
119
+ # Don't know what to do with it.
120
+ new_comment = ERROR_STRING
121
+ end
122
+
123
+ ((@need_review << post) && next) if new_comment.eql?(ERROR_STRING)
124
+
125
+ success = update_post_comment(post, new_comment)
126
+ (success ? @updated : @need_review) << post
127
+ end
128
+ end
129
+
130
+ def fix_from_tag(post, blog_name)
131
+ @tag_idx.each_with_index do |names, idx|
132
+ next unless names.include?(blog_name)
133
+ new_comment = autofix(post.tags[idx])
134
+ if new_comment.eql?(ERROR_STRING)
135
+ # No tag at the expected tag-index
136
+ @need_review << post
137
+ return false
138
+ end
139
+ success = update_post_comment(post, new_comment)
140
+ (success ? @updated : @need_review) << post
141
+ return true
142
+ end
143
+ false
144
+ end
145
+
146
+ def autofix(tag, from='')
147
+ return ERROR_STRING if tag.nil?
148
+ prefix(capitalize(tag))
149
+ end
150
+
151
+ def update_post_comment(post, comment)
152
+ post.replace_comment_with(comment)
153
+ post.save(client: @dk.client, simulate: @dk.simulate)
154
+ end
155
+
156
+ def special_summary(summary, from, commands)
157
+ return '' if summary.nil? || from.nil?
158
+ lines = summary.split("\n")
159
+ res = summary.downcase
160
+ b = binding
161
+ commands.each{ |x| eval(x, b) }
162
+ prefix(capitalize(res))
163
+ end
164
+
165
+ def clear(posts)
166
+ error = []
167
+ posts.each do |post|
168
+ success = update_post_comment(post, @prefix)
169
+ (success ? @updated : error) << post
170
+ end
171
+ error
172
+ end
173
+
174
+ end # end of DK::Idable
175
+ end # end of DK
176
+
177
+ if __FILE__ == $0
178
+ DK::Idable.new(ARGV)
179
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tumblr_autofixer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Meissa Dia
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-03-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tumblr_draftking
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.9.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: sanitize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 4.5.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 4.5.0
41
+ description: "\n Customizable automated comment generator!\n "
42
+ email:
43
+ - meissadia@gmail.com
44
+ executables:
45
+ - taf
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - README.md
50
+ - bin/taf
51
+ - lib/autofixer/commands/open_results.rb
52
+ - lib/autofixer/commands/show_help.rb
53
+ - lib/autofixer/commands/show_version.rb
54
+ - lib/autofixer/data_store.rb
55
+ - lib/autofixer/helpers.rb
56
+ - lib/autofixer/results.rb
57
+ - lib/autofixer/version.rb
58
+ - lib/tumblr_autofixer.rb
59
+ homepage: https://github.com/meissadia/tumblr_autofixer
60
+ licenses:
61
+ - Apache-2.0
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: 2.1.0
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.6.10
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Customizable automated comment generator.
83
+ test_files: []