tumblr_autofixer 0.0.2 → 0.1.0
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/README.md +64 -17
- data/bin/taf +7 -3
- data/lib/autofixer/autofixer.rb +294 -0
- data/lib/autofixer/commands/generate_tags_yml.rb +69 -0
- data/lib/autofixer/commands/open_results.rb +4 -4
- data/lib/autofixer/commands/show_config.rb +9 -0
- data/lib/autofixer/commands/show_help.rb +4 -3
- data/lib/autofixer/commands/show_version.rb +3 -3
- data/lib/autofixer/config/view_config.html.erb +40 -0
- data/lib/autofixer/config/view_config.rb +60 -0
- data/lib/autofixer/data_store.rb +1 -1
- data/lib/autofixer/helpers.rb +5 -15
- data/lib/autofixer/patches/DK_Post.rb +25 -0
- data/lib/autofixer/results.rb +36 -23
- data/lib/autofixer/version.rb +2 -2
- data/lib/tumblr_autofixer.rb +2 -172
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78babced78ceb2710811757881225b103d94eeed
|
4
|
+
data.tar.gz: fb77a09e95ac5aeb4c85ee33c3a98e5437f5d1d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6c2f0b5c7941307976ab267904738b044a845b5acd9e33682ad7fd52b863f94359823f9f711f317ee30b59128fe717d05efbd6ffe0dad9ff33f0d89d173fff7
|
7
|
+
data.tar.gz: 0334ba951d9c8a4bf7cdcfa60ad626019d38368a1ae398df94354771141246117a0a28990b207b9cc305a27e8802cf5d71ac6af7f42f2fb586a3b919889cde1c
|
data/README.md
CHANGED
@@ -1,30 +1,77 @@
|
|
1
1
|
# About
|
2
2
|
\- tumblr_autofix is a configurable comment generator for Tumblr.
|
3
|
-
\-
|
3
|
+
\- Generated files are stored in ~/config_md/taf/
|
4
4
|
\- Careful when editing configuration files, as with all YAML files, indentation is crucial!
|
5
5
|
|
6
|
+
# Version 0.1.0
|
7
|
+
- New: [Tag Matcher](#using-the-tag-matcher)! Use a whitelist of tags to improve Autofixer's ability to
|
8
|
+
- Ability to include DK::Autofixer in your programs
|
9
|
+
- Started building out the test suite
|
10
|
+
- Extensive refactoring
|
11
|
+
- Please report any [issues](https://github.com/meissadia/tumblr_autofix/issues)
|
12
|
+
|
13
|
+
# Using the Tag Matcher
|
14
|
+
In order to utilize the Tag Matcher we'll need to generate a list of acceptable tags. To do this, we'll collect the tags of your last 1,000 posts as a starting point.
|
15
|
+
|
16
|
+
## Basic
|
17
|
+
`taf g:tags`
|
18
|
+
|
19
|
+
This will generate a file in your home directory '~/config_md/taf/tags.yml'
|
20
|
+
You can edit this file and delete any lines which contain tags you do not want used to automatically generate post comments.
|
21
|
+
|
22
|
+
## Advanced
|
23
|
+
You can specify a few options for the g:tags command
|
24
|
+
|
25
|
+
| Option | Description |
|
26
|
+
| :--- | :--- |
|
27
|
+
| `-l [LIMIT]` | Maximum number of posts to scan. |
|
28
|
+
| `-b [BLOG]` | Blog name to scan. Only required if scanning a secondary blog. |
|
29
|
+
| `--source [SOURCE]` | draft, queue, or publish.|
|
30
|
+
| `--config [CONFIG]` | Autofixer uses DraftKing to connect to tumblr, specify your saved config here. |
|
31
|
+
|
32
|
+
|
33
|
+
Example:
|
34
|
+
`taf -l 200 -b secondary-blog-name --source queue`
|
35
|
+
|
6
36
|
# Using ~/config_md/taf/data.yml
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
37
|
+
data.yml allows you to configure, on a blog-by-blog basis, the source of the data used to generate new comments. You may use a specific tag index, the last tag, or simply reuse the existing summary.
|
38
|
+
|
39
|
+
| Field | Type | Description |
|
40
|
+
| :--- | :---: | :--- |
|
41
|
+
| `ignore` | Array | Blogs listed here will only be processed with the Tag Matcher
|
42
|
+
| `last_tag` | Array | Use the last available tag as your comment
|
43
|
+
| `summary` | Array | Use full text of existing post.summary
|
44
|
+
| `tag_idx` | [Array] | Indicates which tag index to use as the new comment
|
45
|
+
| | | - Blogs listed in tag_idx[0] will use the first tag
|
46
|
+
| | | - Blogs listed in tag_idx[1] will use the second
|
13
47
|
|
14
48
|
|
15
49
|
# Using ~/config_md/taf/summary.yml
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
50
|
+
The summary.yml configuration allows you to code the processing steps needed
|
51
|
+
to extract the information you want from a post's comment. This can be set up on
|
52
|
+
a blog-by-blog basis.
|
53
|
+
|
54
|
+
## Available variables
|
55
|
+
| Variable | Description |
|
56
|
+
| :--- | :--- |
|
57
|
+
| `summary` | the plain text of the current post's caption
|
58
|
+
| `res` | lower case version of summary, useful for simplified text searching
|
59
|
+
| `from` | the blog name of the user you reblogged the post from
|
60
|
+
| `lines` | original summary text, split into lines
|
61
|
+
|
62
|
+
## Available methods
|
63
|
+
| Method | Description |
|
64
|
+
| :--- | :---: |
|
65
|
+
| `normalize(string)` | Applies capitalization, adds configured prefix/postfix strings
|
21
66
|
|
22
67
|
## Returning
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
68
|
+
| Method | Description |
|
69
|
+
| :--- | :--- |
|
70
|
+
| `return <value> `| Use the <value> string as the comment for this post
|
71
|
+
| `res = 'your value'` | storing your new comment in the `res` variable, without explicitly returning it, will subject it to a couple more modifications:
|
72
|
+
| | 1. capitalization - each word in the string will be capitalized
|
73
|
+
| | 2. prefix - a string passed via the `-p <PREFIX>` option will be prepended to `res`
|
74
|
+
| | 3. postfix - a string passed via the `-P <POSTFIX>` option will be appended to `res`
|
28
75
|
|
29
76
|
## Summary Example
|
30
77
|
|
data/bin/taf
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'rubygems'
|
3
3
|
require 'tumblr_draftking'
|
4
|
-
|
5
|
-
#
|
4
|
+
if ENV['DEV_ENV']
|
5
|
+
# DEV ONLY - Run development source using system installed cli
|
6
|
+
require File.join(Dir.home, "#{ENV['DIR_RUBY']}/tumblr_autofixer/lib/tumblr_autofixer")
|
7
|
+
else
|
8
|
+
require_relative '../lib/tumblr_autofixer'
|
9
|
+
end
|
6
10
|
|
7
|
-
DK::
|
11
|
+
DK::Autofixer.new(ARGV).run
|
@@ -0,0 +1,294 @@
|
|
1
|
+
module DK
|
2
|
+
class Autofixer
|
3
|
+
ERROR = '**'
|
4
|
+
POSTS = '/Users/meis/coding/rails/autofixer/db/test.posts'
|
5
|
+
CONFIGDIR = '/config_md/taf/'
|
6
|
+
INFO = 'info'
|
7
|
+
WARN = 'warning'
|
8
|
+
ERRO = 'error'
|
9
|
+
|
10
|
+
attr_accessor :dk # DraftKing for Tumblr
|
11
|
+
attr_accessor :simulate, :limit # DraftKing Settings
|
12
|
+
attr_accessor :config_dir # Autofixer Required Structure
|
13
|
+
attr_accessor :last_tag, :summary, :tag_idx # Autofixer Tagging Config
|
14
|
+
attr_accessor :spliter, :prefix, :postfix # Autofixer Tagging Options
|
15
|
+
attr_accessor :clear, :use_test, :reprocess # Autofixer Processing Options
|
16
|
+
attr_accessor :show_results, :hide_pics # Autofixer Result Options
|
17
|
+
attr_accessor :processed, :review, :updated # Autofixer Results
|
18
|
+
|
19
|
+
def initialize(opts = {})
|
20
|
+
set_instance_vars(opts)
|
21
|
+
installed_test_configuration?
|
22
|
+
read_configuration
|
23
|
+
end
|
24
|
+
|
25
|
+
# Automated Processing
|
26
|
+
def run
|
27
|
+
perform_command? # Commands will exit(#)
|
28
|
+
process(get_filtered_posts)
|
29
|
+
@review = apply_tag_matcher_to(@review)
|
30
|
+
@review = clear(@review)
|
31
|
+
show_results
|
32
|
+
end
|
33
|
+
|
34
|
+
# Execute Command
|
35
|
+
def perform_command?
|
36
|
+
show_help
|
37
|
+
show_config
|
38
|
+
show_version
|
39
|
+
open_results
|
40
|
+
generate_tags_yml
|
41
|
+
if @options.first && !@options.first[0].eql?('-')
|
42
|
+
puts "\nCommand '#{@options.first}' not found.\n\n"
|
43
|
+
exit(1)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Load data and filter out processed or seemingly unprocessible posts
|
48
|
+
def get_filtered_posts
|
49
|
+
drafts = @usetestdata ? load_test_data : @dk.get_posts
|
50
|
+
@total = drafts.size
|
51
|
+
drafts.map do |draft|
|
52
|
+
draft = DK::Post.new draft
|
53
|
+
next if filter_processed? draft
|
54
|
+
next if filter_by_info? draft
|
55
|
+
next if filter_by_trail? draft
|
56
|
+
draft
|
57
|
+
end.compact
|
58
|
+
end
|
59
|
+
|
60
|
+
# Construct new post comments based on available configurations
|
61
|
+
def process(posts)
|
62
|
+
posts.each_with_index do |post, idx|
|
63
|
+
tags = post.tags
|
64
|
+
blog = post.trail.first.blog.name
|
65
|
+
summary = post.summary
|
66
|
+
|
67
|
+
next if ignore? blog, post
|
68
|
+
# Scan for configured tag-index
|
69
|
+
comment = use_tag_index blog, post
|
70
|
+
# Use coded configuration
|
71
|
+
comment ||= use_commands blog, summary
|
72
|
+
# Use full summary text
|
73
|
+
comment ||= use_summary blog, summary
|
74
|
+
# Use last tag
|
75
|
+
comment ||= use_tag_index blog, post, @last_tag.include?(blog)
|
76
|
+
# No automated processing
|
77
|
+
comment ||= ERROR
|
78
|
+
|
79
|
+
success = update_post_comment(post, comment)
|
80
|
+
(success ? @updated : @review) << post
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Contruct a comment using any whitelisted tags
|
85
|
+
# return: [String] Normalized Comment
|
86
|
+
def tag_matcher(tags)
|
87
|
+
return ERROR if tags.empty?
|
88
|
+
joiner = ' | '
|
89
|
+
matches = tags.select{ |tag| @gtags.include? tag.downcase }
|
90
|
+
return ERROR if matches.empty?
|
91
|
+
new_comment = matches.join(joiner)
|
92
|
+
normalize(new_comment)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Mass processing based on whitelisted tags
|
96
|
+
# return: [Array] Unmatched Posts
|
97
|
+
def apply_tag_matcher_to(posts)
|
98
|
+
return posts unless @gtags
|
99
|
+
return posts if @gtags.empty?
|
100
|
+
not_matched = []
|
101
|
+
while (post = posts.shift)
|
102
|
+
next if post.tags.empty?
|
103
|
+
new_comment = tag_matcher(post.tags)
|
104
|
+
if new_comment.eql?(ERROR)
|
105
|
+
not_matched << post
|
106
|
+
next
|
107
|
+
end
|
108
|
+
success = update_post_comment(post, new_comment)
|
109
|
+
(success ? @updated : not_matched) << post
|
110
|
+
end
|
111
|
+
not_matched
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
# **************************************************************************
|
117
|
+
# Processing Methods
|
118
|
+
# **************************************************************************
|
119
|
+
# Use the user coded processing for this blog
|
120
|
+
def use_commands(blog, summary)
|
121
|
+
commands = restore(@sstore, blog.to_sym)
|
122
|
+
special_summary(summary, blog, commands)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Normalize and use the full summary text
|
126
|
+
def use_summary(blog, summary)
|
127
|
+
return nil unless @summary.include?(blog)
|
128
|
+
special_summary(summary, blog, [])
|
129
|
+
end
|
130
|
+
|
131
|
+
# Use the tag at the configured index, if available
|
132
|
+
# return: [boolean] Success?
|
133
|
+
def use_tag_index(blog_name, post, last=nil)
|
134
|
+
return normalize post.tags.last if last
|
135
|
+
@tag_idx.each_with_index do |names, idx|
|
136
|
+
next unless names.include?(blog_name)
|
137
|
+
return normalize(post.tags[idx])
|
138
|
+
end
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
|
142
|
+
def update_post_comment(post, comment)
|
143
|
+
return false if comment.eql? ERROR
|
144
|
+
post.replace_comment_with(comment)
|
145
|
+
post.save(client: @dk.client, simulate: @dk.simulate)
|
146
|
+
end
|
147
|
+
|
148
|
+
def special_summary(summary, from, commands)
|
149
|
+
return nil if summary.nil? || from.nil?
|
150
|
+
return nil unless commands
|
151
|
+
lines = summary.split("\n")
|
152
|
+
res = summary.downcase
|
153
|
+
b = binding
|
154
|
+
commands.each{ |x| eval(x, b) }
|
155
|
+
normalize(res)
|
156
|
+
endormalize(res)
|
157
|
+
end
|
158
|
+
|
159
|
+
def clear(posts)
|
160
|
+
return posts unless @clear
|
161
|
+
error = []
|
162
|
+
posts.each do |post|
|
163
|
+
success = update_post_comment(post, @prefix)
|
164
|
+
(success ? @updated : error) << post
|
165
|
+
end
|
166
|
+
error
|
167
|
+
end
|
168
|
+
|
169
|
+
def affix(s)
|
170
|
+
result = ''
|
171
|
+
result += "#{@prefix}" if @prefix
|
172
|
+
result += "#{' ' + @spliter + ' '}"
|
173
|
+
result += "#{s}"
|
174
|
+
if @postfix
|
175
|
+
result += "#{' ' + @spliter + ' '}"
|
176
|
+
result += "#{@postfix}"
|
177
|
+
end
|
178
|
+
result
|
179
|
+
end
|
180
|
+
|
181
|
+
def log(type, msg)
|
182
|
+
@messages << "#{type.capitalize}: #{msg}"
|
183
|
+
end
|
184
|
+
|
185
|
+
# **************************************************************************
|
186
|
+
# Filtration Methods
|
187
|
+
# **************************************************************************
|
188
|
+
def filter_processed?(draft)
|
189
|
+
if draft.processed?(skip: @reprocess, prefix: @prefix)
|
190
|
+
@processed << draft
|
191
|
+
return true
|
192
|
+
end
|
193
|
+
false
|
194
|
+
end
|
195
|
+
|
196
|
+
def filter_by_info?(draft)
|
197
|
+
unless draft.has_info?
|
198
|
+
@review << draft
|
199
|
+
return true
|
200
|
+
end
|
201
|
+
false
|
202
|
+
end
|
203
|
+
|
204
|
+
def filter_by_trail?(draft)
|
205
|
+
unless draft.has_trail?
|
206
|
+
@review << draft
|
207
|
+
return true
|
208
|
+
end
|
209
|
+
false
|
210
|
+
end
|
211
|
+
|
212
|
+
def ignore?(blog, post)
|
213
|
+
return false unless @ignore.include? blog
|
214
|
+
@review << post
|
215
|
+
true
|
216
|
+
end
|
217
|
+
|
218
|
+
# **************************************************************************
|
219
|
+
# Configuration Methods
|
220
|
+
# **************************************************************************
|
221
|
+
def dk_opts
|
222
|
+
{ simulate: @simulate, limit: @limit }
|
223
|
+
end
|
224
|
+
|
225
|
+
def home_file(file)
|
226
|
+
DK::Config.home_path_file(file)
|
227
|
+
end
|
228
|
+
|
229
|
+
def confile(fname)
|
230
|
+
@config_dir + fname
|
231
|
+
end
|
232
|
+
|
233
|
+
def set_instance_vars(opts)
|
234
|
+
@options = opts
|
235
|
+
@simulate = @options.include?('-s')
|
236
|
+
@limit = @options[@options.find_index('-l') + 1].to_i rescue nil
|
237
|
+
@spliter = @options[@options.find_index('-S') + 1] rescue ' '
|
238
|
+
@prefix = @options[@options.find_index('-p') + 1] rescue nil
|
239
|
+
@postfix = @options[@options.find_index('-P') + 1] rescue nil
|
240
|
+
@clear = @options.find_index('--clear')
|
241
|
+
@reprocess = @options.find_index('--reprocess')
|
242
|
+
@hide_pics = @options.find_index('--no-pics')
|
243
|
+
@usetestdata = @options.find_index('--test')
|
244
|
+
@show_results = @options.find_index('--show')
|
245
|
+
@config_dir = home_file(CONFIGDIR)
|
246
|
+
@dk = DK::Client.new(dk_opts)
|
247
|
+
@messages = []
|
248
|
+
@processed = []
|
249
|
+
@updated = []
|
250
|
+
@review = []
|
251
|
+
end
|
252
|
+
|
253
|
+
def read_configuration
|
254
|
+
# Ensure directory structure exists
|
255
|
+
FileUtils::makedirs @config_dir unless Dir.exist?(@config_dir)
|
256
|
+
|
257
|
+
# Ensure configuration files are present
|
258
|
+
@ystore = YAML::Store.new("#{confile('data.yml')}")
|
259
|
+
@sstore = YAML::Store.new("#{confile('summary.yml')}")
|
260
|
+
@tstore = YAML::Store.new("#{confile('tags.yml')}")
|
261
|
+
prep_user_data_files
|
262
|
+
|
263
|
+
# Cache config data
|
264
|
+
@last_tag = restore(@ystore, :last_tag)
|
265
|
+
@tag_idx = restore(@ystore, :tag_idx)
|
266
|
+
@summary = restore(@ystore, :summary)
|
267
|
+
@ignore = restore(@ystore, :ignore)
|
268
|
+
@gtags = restore(@tstore, :good)
|
269
|
+
end
|
270
|
+
|
271
|
+
def load_test_data
|
272
|
+
return eval(File.open(POSTS, 'r').read) if File.exist? POSTS
|
273
|
+
log INFO, "Saved post data to #{POSTS}"
|
274
|
+
posts = @dk.get_posts
|
275
|
+
File.open(POSTS, 'w') { |f| f.write posts }
|
276
|
+
posts
|
277
|
+
end
|
278
|
+
|
279
|
+
def installed_test_configuration?(result=nil)
|
280
|
+
data_yml = home_file('/coding/ruby/tumblr_autofixer/data.yml.bak')
|
281
|
+
summary_yml = home_file('/coding/ruby/tumblr_autofixer/summary.yml')
|
282
|
+
if File.exist? data_yml
|
283
|
+
`cp #{data_yml} #{confile('data.yml')}`
|
284
|
+
result = true
|
285
|
+
end
|
286
|
+
if File.exist? summary_yml
|
287
|
+
`cp #{summary_yml} #{confile('summary.yml')}`
|
288
|
+
result = true
|
289
|
+
end
|
290
|
+
result
|
291
|
+
end
|
292
|
+
|
293
|
+
end # end of DK::Autofixer
|
294
|
+
end # end of DK
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module DK
|
2
|
+
class Autofixer
|
3
|
+
# Command
|
4
|
+
def generate_tags_yml
|
5
|
+
return unless @options.include?('g:tags')
|
6
|
+
GenerateTagsYml.new(ARGV)
|
7
|
+
exit(0)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Generate tags.yml using DK
|
11
|
+
class GenerateTagsYml
|
12
|
+
def initialize(opts)
|
13
|
+
options = {}
|
14
|
+
options[:limit] = opt_val('-l') || 50
|
15
|
+
options[:blog] = opt_val('-b')
|
16
|
+
options[:config] = opt_val('--config')
|
17
|
+
options[:source] = opt_val('--source') || DK::PUBLISH
|
18
|
+
# Get Posts
|
19
|
+
dk = DK::Client.new(options)
|
20
|
+
posts = dk.get_posts.map { |post| DK::Post.new post }
|
21
|
+
posts = posts.select { |post| !post.tags.empty? }
|
22
|
+
# Collect Tags
|
23
|
+
@tags = []
|
24
|
+
posts.each { |post| @tags += post.tags }
|
25
|
+
@tstore = YAML::Store.new("#{confile('tags.yml')}")
|
26
|
+
# Preserve existing
|
27
|
+
existing = restore(@tstore, :good)
|
28
|
+
puts "Found #{existing.size} tags." if existing
|
29
|
+
@tags += existing if existing
|
30
|
+
@tags = @tags.map(&:downcase)
|
31
|
+
@tags.uniq!
|
32
|
+
@tags.sort!
|
33
|
+
# Save
|
34
|
+
puts "Saving #{@tags.size} tags"
|
35
|
+
store(@tstore, :good, @tags)
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def opt_val(opt, default=nil)
|
40
|
+
ARGV[ARGV.find_index(opt) + 1] rescue default
|
41
|
+
end
|
42
|
+
|
43
|
+
def home_file(file)
|
44
|
+
DK::Config.home_path_file(file)
|
45
|
+
end
|
46
|
+
|
47
|
+
def confile(fname)
|
48
|
+
home_file('/config_md/taf/') + fname
|
49
|
+
end
|
50
|
+
|
51
|
+
# Code to extract from summary
|
52
|
+
# unless @split = opt_val('-S')
|
53
|
+
# puts "Please provide at least one delimiter"
|
54
|
+
# puts "eg. taf g:tags -S |"
|
55
|
+
# puts "eg. taf g:tags -S ,|/\\"
|
56
|
+
# exit(1)
|
57
|
+
# end
|
58
|
+
# posts.each do |post|
|
59
|
+
# comment = post.comment
|
60
|
+
# result = nil
|
61
|
+
# @split.each do |str|
|
62
|
+
# result ||= comment.split str
|
63
|
+
# result = result.map { |str2| str2.split str }.flatten
|
64
|
+
# end
|
65
|
+
# @tags += result
|
66
|
+
# end
|
67
|
+
end # of GenerateTagsYml
|
68
|
+
end # of Autofixer
|
69
|
+
end # of DK
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module DK
|
2
|
-
|
3
|
-
def open_results
|
4
|
-
return unless
|
5
|
-
file = confile('
|
2
|
+
class Autofixer
|
3
|
+
def open_results
|
4
|
+
return unless @options.include?('open')
|
5
|
+
file = confile('updated.html')
|
6
6
|
`open #{file}` && exit(0) if File.exist?(file)
|
7
7
|
puts
|
8
8
|
puts 'Error:'
|
@@ -1,13 +1,14 @@
|
|
1
1
|
module DK
|
2
|
-
|
3
|
-
def show_help
|
4
|
-
return unless (
|
2
|
+
class Autofixer
|
3
|
+
def show_help
|
4
|
+
return unless (@options.include?('help') || @options.find_index('-h'))
|
5
5
|
puts 'Usage: '
|
6
6
|
puts ' $ taf <command?> [options?]'
|
7
7
|
puts
|
8
8
|
puts ' Commands:'
|
9
9
|
puts ' help Show this menu.'
|
10
10
|
puts ' open Open a webpage with the latest taf results.'
|
11
|
+
puts ' g:tags <command> [options] Generate a list of tags from your latest posts to serve as a whitelist for the Tag Matcher.'
|
11
12
|
puts
|
12
13
|
puts ' Options:'
|
13
14
|
puts ' -s Simulate Run (no changes saved)'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title><%= fname %></title>
|
4
|
+
<%= style %>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<h1>Ignore</h1>
|
8
|
+
<ul>
|
9
|
+
<% @ignore.each do |i| %>
|
10
|
+
<li><%= i %></li>
|
11
|
+
<% end %>
|
12
|
+
</ul>
|
13
|
+
|
14
|
+
<h1>Last Tag</h1>
|
15
|
+
<ul>
|
16
|
+
<% @last_tag.each do |i| %>
|
17
|
+
<li><%= i %></li>
|
18
|
+
<% end %>
|
19
|
+
</ul>
|
20
|
+
|
21
|
+
<h1>Summary</h1>
|
22
|
+
<ul>
|
23
|
+
<% @summary.each do |i| %>
|
24
|
+
<li><%= i %></li>
|
25
|
+
<% end %>
|
26
|
+
</ul>
|
27
|
+
|
28
|
+
<h1>Tag Index</h1>
|
29
|
+
<% @tag_idx.each_with_index do |blog_list, idx| %>
|
30
|
+
<h2>Tag <%= idx %></h2>
|
31
|
+
<ul>
|
32
|
+
<% blog_list.each do |blog| %>
|
33
|
+
<li><%= blog %></li>
|
34
|
+
<% end %>
|
35
|
+
</ul>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
<footer>Updated at <%= Time.now.strftime('%d/%m/%Y') %></footer>
|
39
|
+
</body>
|
40
|
+
</html>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'tumblr_draftking'
|
2
|
+
require 'yaml/store'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'erb'
|
5
|
+
|
6
|
+
def store(dstore, key, value)
|
7
|
+
dstore.transaction do
|
8
|
+
dstore[key] = value
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def restore(dstore, key, default=nil)
|
13
|
+
dstore.transaction do
|
14
|
+
dstore[key] || default
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def style
|
19
|
+
%q(
|
20
|
+
<style>
|
21
|
+
h1,h2 { width: 100%; background-color: rgb(140, 129, 38); color: white; text-align: center; }
|
22
|
+
ul, li { width: 100%; text-align: center; vertical-align: middle; padding: 0; margin: 0 auto;}
|
23
|
+
ul li { list-style: none; padding: 0; margin: 0 auto; }
|
24
|
+
ul li:hover { background-color: rgb(200, 200, 102); }
|
25
|
+
a, a:visited { color: white; vertical-align: middle; line-height: 100px; }
|
26
|
+
</style>
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def script
|
31
|
+
%q(
|
32
|
+
<script>
|
33
|
+
|
34
|
+
</script>
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
if $0 == __FILE__
|
39
|
+
data_yml = YAML::Store.new(DK::Config.home_path_file('/config_md/taf/data.yml'))
|
40
|
+
# special_yml = YAML::Store.new(DK::Config.home_path_file('summary.yml'))
|
41
|
+
|
42
|
+
# Cache config data
|
43
|
+
@last_tag = restore(data_yml, :last_tag)
|
44
|
+
@tag_idx = restore(data_yml, :tag_idx)
|
45
|
+
@summary = restore(data_yml, :summary)
|
46
|
+
@ignore = restore(data_yml, :ignore)
|
47
|
+
|
48
|
+
template = '.html.erb'
|
49
|
+
fname = File.basename(__FILE__, '.rb')
|
50
|
+
tname = fname + template
|
51
|
+
tdata = File.open(tname, 'rb', &:read)
|
52
|
+
result = ERB.new(tdata).result(binding)
|
53
|
+
|
54
|
+
out_file = DK::Config.home_path_file('/config_md/taf/view_config.html')
|
55
|
+
File.open(out_file, 'w') do |f|
|
56
|
+
f << result
|
57
|
+
end
|
58
|
+
|
59
|
+
`open #{out_file}`
|
60
|
+
end
|
data/lib/autofixer/data_store.rb
CHANGED
data/lib/autofixer/helpers.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
module DK
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
{ simulate: @simulate, limit: @limit }
|
2
|
+
class Autofixer
|
3
|
+
def normalize(tag, from='')
|
4
|
+
return ERROR if tag.nil?
|
5
|
+
affix(capitalize(tag))
|
7
6
|
end
|
8
7
|
|
9
8
|
def capitalize(s)
|
@@ -13,12 +12,7 @@ module DK
|
|
13
12
|
res.join(' ')
|
14
13
|
end
|
15
14
|
|
16
|
-
def
|
17
|
-
"#{@prefix}#{' ' + @spliter + ' ' if @spliter}#{s}#{@postfix}"
|
18
|
-
end
|
19
|
-
|
20
|
-
def link_to_edit(post)
|
21
|
-
id = post.id rescue post['id']
|
15
|
+
def link_to_edit(id)
|
22
16
|
"https://www.tumblr.com/edit/#{id}"
|
23
17
|
end
|
24
18
|
|
@@ -33,9 +27,5 @@ module DK
|
|
33
27
|
s
|
34
28
|
end
|
35
29
|
|
36
|
-
def home_file(file)
|
37
|
-
DK::Config.home_path_file(file)
|
38
|
-
end
|
39
|
-
|
40
30
|
end
|
41
31
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module DK
|
2
|
+
class Post
|
3
|
+
# Post has a summary or tags?
|
4
|
+
def has_info?
|
5
|
+
has_summary? || !tags.empty?
|
6
|
+
end
|
7
|
+
|
8
|
+
# Do we know where it was reblogged from?
|
9
|
+
def has_trail?
|
10
|
+
!trail.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
# Post already has prefix?
|
14
|
+
def processed?(skip: false, prefix: '')
|
15
|
+
return false if skip
|
16
|
+
return false if prefix.empty?
|
17
|
+
l_comment = Sanitize.fragment(comment).strip
|
18
|
+
l_comment.start_with?(prefix) || summary.strip.start_with?(prefix)
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_summary?
|
22
|
+
summary.strip.empty?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/autofixer/results.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module DK
|
2
|
-
|
2
|
+
class Autofixer
|
3
3
|
private
|
4
4
|
|
5
5
|
def bfrom(post)
|
@@ -9,44 +9,45 @@ module DK
|
|
9
9
|
def show_results
|
10
10
|
cli_header
|
11
11
|
|
12
|
-
fname1 = confile('
|
13
|
-
fname2 = confile('
|
12
|
+
fname1 = confile('processed.html')
|
13
|
+
fname2 = confile('review.html')
|
14
14
|
fname3 = confile('updated.html')
|
15
15
|
|
16
16
|
@file_index = [
|
17
|
-
["
|
18
|
-
["Updated (#{@updated.size})",
|
19
|
-
["
|
17
|
+
["Review (#{@review.size})", fname2],
|
18
|
+
["Updated (#{@updated.size})", fname3],
|
19
|
+
["Preprocessed (#{@processed.size})", fname1]
|
20
20
|
]
|
21
21
|
|
22
|
-
msg1 = "(#{@
|
23
|
-
msg2 = "(#{@
|
22
|
+
msg1 = "(#{@processed.size}) Drafts are ready to be queued."
|
23
|
+
msg2 = "(#{@review.size}) Drafts need visual review."
|
24
24
|
msg3 = "(#{@updated.size}) Drafts were Autofixed."
|
25
25
|
|
26
26
|
|
27
27
|
# Already Processed
|
28
|
-
@
|
29
|
-
generate_review_webpage(@
|
28
|
+
@processed.sort_by!{ |x| x.id }
|
29
|
+
generate_review_webpage(@processed, fname1, msg1)
|
30
30
|
|
31
31
|
# Need Review
|
32
|
-
@
|
32
|
+
@review.sort_by! do |x|
|
33
33
|
bname = bfrom(x)
|
34
34
|
[bname, x.id]
|
35
35
|
end
|
36
|
-
generate_review_webpage(@
|
36
|
+
generate_review_webpage(@review, fname2, msg2)
|
37
37
|
|
38
|
-
#
|
38
|
+
# Updated
|
39
39
|
@updated.sort_by!{ |x| bfrom(x)}
|
40
40
|
generate_review_webpage(@updated, fname3, msg3)
|
41
41
|
|
42
42
|
puts
|
43
43
|
puts
|
44
|
-
`open #{@file_index.first.last}` if @
|
44
|
+
`open #{@file_index.first.last}` if @show_results
|
45
45
|
end
|
46
46
|
|
47
47
|
def generate_review_webpage(post_info, fname, msg1='')
|
48
48
|
page = "<html><head>#{style}</head><body>"
|
49
49
|
page += page_nav
|
50
|
+
page += messages_html unless @messages.empty?
|
50
51
|
page += '<table>'
|
51
52
|
page += '<caption>'
|
52
53
|
page += "<p>***** SIMULATION RUN *****</p>" if @simulate
|
@@ -63,19 +64,28 @@ module DK
|
|
63
64
|
page += "</body></html>"
|
64
65
|
|
65
66
|
# Create directory structure and file if it doesn't exist
|
66
|
-
# FileUtils::mkdir_p File.dirname(fname) unless File.exist?(fname)
|
67
67
|
File.open(fname, 'w'){|f| f.puts page}
|
68
68
|
puts "** Updated file: #{fname} **:\n"
|
69
69
|
end
|
70
70
|
|
71
|
+
def messages_html
|
72
|
+
msgs = @messages.map { |msg| "<p class='log'>#{msg}</p>" }
|
73
|
+
"<div>#{msgs}</div>"
|
74
|
+
end
|
75
|
+
|
71
76
|
def post_image_code(post)
|
72
77
|
# Alt Sizes (0 - 6) Large to Small
|
73
78
|
count = post.photos.size
|
74
|
-
photo =
|
75
|
-
|
79
|
+
photo = post.photos.first.alt_sizes[4].url rescue image_missing
|
80
|
+
photo = image_missing if @hide_pics
|
81
|
+
from = bfrom(post)
|
82
|
+
url = 'http://' + tumblr_url(from)
|
83
|
+
# byebug unless url
|
84
|
+
res = "<td><a target='_blank' href='#{link_to_edit(post.id)}'>"
|
76
85
|
res += "<img src='#{photo}'>#{' (' + count.to_s + ')' if count > 1}</a></td>"
|
77
|
-
res += "<td><p>#{
|
78
|
-
res += "<td><p>#{post.comment.empty? ? '
|
86
|
+
res += "<td><p><a class='blog_link' href='#{url}' target='_blank'>#{from}</a></p></td>"
|
87
|
+
res += "<td><p>#{post.comment.empty? ? '' : post.comment}</p></td>"
|
88
|
+
res += "<td><p>#{post.summary.empty? ? '' : post.summary}</p></td>"
|
79
89
|
res += "<td><p>#{post.tags.empty? ? '-no tags-' : post.tags.join(', ')}</p></td>"
|
80
90
|
end
|
81
91
|
|
@@ -91,8 +101,8 @@ module DK
|
|
91
101
|
puts
|
92
102
|
puts "#{@total} drafts were retrieved."
|
93
103
|
puts "#{pad(@updated.size, @total, 1)} drafts were Autofixed."
|
94
|
-
puts "#{pad(@
|
95
|
-
puts "#{pad(@
|
104
|
+
puts "#{pad(@processed.size, @total, 1)} drafts were marked 'already processed'."
|
105
|
+
puts "#{pad(@review.size, @total, 1)} drafts require visual review."
|
96
106
|
puts '_'*40
|
97
107
|
puts
|
98
108
|
end
|
@@ -109,7 +119,8 @@ module DK
|
|
109
119
|
res = '<thead><tr>'
|
110
120
|
res += '<th>Photo</th>'
|
111
121
|
res += '<th>Source</th>'
|
112
|
-
res += '<th>
|
122
|
+
res += '<th>Comment</th>'
|
123
|
+
res += '<th>Summary</th>'
|
113
124
|
res += '<th>Tags</th>'
|
114
125
|
res += '</tr></thead>'
|
115
126
|
end
|
@@ -126,12 +137,14 @@ module DK
|
|
126
137
|
nav ul li a { display: inline-block; width: 100%; }
|
127
138
|
nav ul li:hover { background-color: rgb(43, 171, 171); }
|
128
139
|
a, a:visited { color: white; vertical-align: middle; line-height: 100px; }
|
140
|
+
a.blog_link { color: black; }
|
141
|
+
p.log { width: 100%; background-color: rgb(56, 103, 103); color: white; text-align: center; }
|
129
142
|
</style>
|
130
143
|
)
|
131
144
|
end
|
132
145
|
|
133
146
|
def image_missing
|
134
|
-
'https://
|
147
|
+
'https://image.freepik.com/free-icon/male-user-shadow_318-34042.jpg'
|
135
148
|
end
|
136
149
|
|
137
150
|
end
|
data/lib/autofixer/version.rb
CHANGED
data/lib/tumblr_autofixer.rb
CHANGED
@@ -2,179 +2,9 @@ require 'tumblr_draftking'
|
|
2
2
|
require 'yaml/store'
|
3
3
|
require 'sanitize'
|
4
4
|
require 'fileutils'
|
5
|
+
require 'byebug'
|
5
6
|
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
|
-
@config_dir = home_file('/config_md/taf/')
|
14
|
-
|
15
|
-
check_for_command(ARGV, opts)
|
16
|
-
extract_opts(opts)
|
17
|
-
|
18
|
-
@dk = DK::Client.new(dk_opts)
|
19
|
-
|
20
|
-
# Ensure my latest config files are in place.
|
21
|
-
`cp data.yml.bak #{confile('data.yml')}` if File.exist?('data.yml.bak')
|
22
|
-
`cp summary.yml #{confile('summary.yml')}` if File.exist?('summary.yml')
|
23
|
-
|
24
|
-
read_configuration
|
25
|
-
@already_processed, @need_review, @updated = [], [], []
|
26
|
-
|
27
|
-
autofixer(get_informative_posts)
|
28
|
-
@need_review = clear(@need_review) if @clear
|
29
|
-
show_results
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def read_configuration
|
35
|
-
# Ensure directory structure exists
|
36
|
-
FileUtils::makedirs @config_dir unless Dir.exist?(@config_dir)
|
37
|
-
|
38
|
-
# Ensure configuration files are present
|
39
|
-
@ystore = YAML::Store.new("#{confile('data.yml')}")
|
40
|
-
@sstore = YAML::Store.new("#{confile('summary.yml')}")
|
41
|
-
prep_user_data_files
|
42
|
-
|
43
|
-
# Cache config data
|
44
|
-
@last_tag = restore(@ystore, :last_tag)
|
45
|
-
@tag_idx = restore(@ystore, :tag_idx)
|
46
|
-
@summary = restore(@ystore, :summary)
|
47
|
-
@ignore = restore(@ystore, :ignore)
|
48
|
-
end
|
49
|
-
|
50
|
-
def check_for_command(args, opts)
|
51
|
-
show_help(args, opts)
|
52
|
-
show_version(opts)
|
53
|
-
open_results(args)
|
54
|
-
end
|
55
|
-
|
56
|
-
def confile(fname)
|
57
|
-
@config_dir + fname
|
58
|
-
end
|
59
|
-
|
60
|
-
def extract_opts(opts)
|
61
|
-
@simulate = opts.include?('-s')
|
62
|
-
@limit = opts[opts.find_index('-l') + 1].to_i rescue nil
|
63
|
-
@spliter = opts[opts.find_index('-S') + 1] rescue ' '
|
64
|
-
@prefix = opts[opts.find_index('-p') + 1] rescue ''
|
65
|
-
@postfix = opts[opts.find_index('-P') + 1] rescue ''
|
66
|
-
@showres = opts.find_index('--show')
|
67
|
-
@clear = opts.find_index('--clear')
|
68
|
-
end
|
69
|
-
|
70
|
-
def get_informative_posts
|
71
|
-
drafts = @dk.get_posts.map{|post| DK::Post.new(post)}
|
72
|
-
@total = drafts.size
|
73
|
-
drafts.select do |draft|
|
74
|
-
((@already_processed << draft) && next) if post_already_processed?(draft)
|
75
|
-
((@need_review << draft) && next) unless post_has_info?(draft)
|
76
|
-
((@need_review << draft) && next) unless post_has_trail?(draft)
|
77
|
-
true
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Post already has prefix?
|
82
|
-
def post_already_processed?(post)
|
83
|
-
summary = post.summary.chomp.strip
|
84
|
-
user_c = Sanitize.fragment(post.comment).strip
|
85
|
-
|
86
|
-
user_c.start_with?(@prefix) || summary.start_with?(@prefix)
|
87
|
-
end
|
88
|
-
|
89
|
-
# Post has a summary or tags?
|
90
|
-
def post_has_info?(post)
|
91
|
-
summary = post.summary.chomp.strip
|
92
|
-
!summary.empty? || !post.tags.empty?
|
93
|
-
end
|
94
|
-
|
95
|
-
# Do we know where it was reblogged from?
|
96
|
-
def post_has_trail?(post)
|
97
|
-
!post.trail.empty?
|
98
|
-
end
|
99
|
-
|
100
|
-
|
101
|
-
def autofixer(posts)
|
102
|
-
posts.each_with_index do |post, idx|
|
103
|
-
tags = post.tags
|
104
|
-
trail_name = post.trail.first.blog.name
|
105
|
-
post_summary = post.summary
|
106
|
-
|
107
|
-
((@need_review << post) && next) if @ignore.include?(trail_name)
|
108
|
-
if fix_from_tag(post, trail_name)
|
109
|
-
next # Successfully used a tag-index to process post
|
110
|
-
elsif commands = restore(@sstore, trail_name.to_sym)
|
111
|
-
# Has custom processing of post.summary data defined
|
112
|
-
new_comment = special_summary(post_summary, trail_name, commands)
|
113
|
-
elsif @summary.include?(trail_name)
|
114
|
-
# Use default processing of post.summary data
|
115
|
-
new_comment = special_summary(post_summary, trail_name, [])
|
116
|
-
elsif @last_tag.include?(trail_name)
|
117
|
-
# Use the last available post.tags
|
118
|
-
new_comment = autofix(tags.last, trail_name)
|
119
|
-
else
|
120
|
-
# Don't know what to do with it.
|
121
|
-
new_comment = ERROR_STRING
|
122
|
-
end
|
123
|
-
|
124
|
-
((@need_review << post) && next) if new_comment.eql?(ERROR_STRING)
|
125
|
-
|
126
|
-
success = update_post_comment(post, new_comment)
|
127
|
-
(success ? @updated : @need_review) << post
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def fix_from_tag(post, blog_name)
|
132
|
-
@tag_idx.each_with_index do |names, idx|
|
133
|
-
next unless names.include?(blog_name)
|
134
|
-
new_comment = autofix(post.tags[idx])
|
135
|
-
if new_comment.eql?(ERROR_STRING)
|
136
|
-
# No tag at the expected tag-index
|
137
|
-
@need_review << post
|
138
|
-
return false
|
139
|
-
end
|
140
|
-
success = update_post_comment(post, new_comment)
|
141
|
-
(success ? @updated : @need_review) << post
|
142
|
-
return true
|
143
|
-
end
|
144
|
-
false
|
145
|
-
end
|
146
|
-
|
147
|
-
def autofix(tag, from='')
|
148
|
-
return ERROR_STRING if tag.nil?
|
149
|
-
prefix(capitalize(tag))
|
150
|
-
end
|
151
|
-
|
152
|
-
def update_post_comment(post, comment)
|
153
|
-
post.replace_comment_with(comment)
|
154
|
-
post.save(client: @dk.client, simulate: @dk.simulate)
|
155
|
-
end
|
156
|
-
|
157
|
-
def special_summary(summary, from, commands)
|
158
|
-
return '' if summary.nil? || from.nil?
|
159
|
-
lines = summary.split("\n")
|
160
|
-
res = summary.downcase
|
161
|
-
b = binding
|
162
|
-
commands.each{ |x| eval(x, b) }
|
163
|
-
prefix(capitalize(res))
|
164
|
-
end
|
165
|
-
|
166
|
-
def clear(posts)
|
167
|
-
error = []
|
168
|
-
posts.each do |post|
|
169
|
-
success = update_post_comment(post, @prefix)
|
170
|
-
(success ? @updated : error) << post
|
171
|
-
end
|
172
|
-
error
|
173
|
-
end
|
174
|
-
|
175
|
-
end # end of DK::Idable
|
176
|
-
end # end of DK
|
177
7
|
|
178
8
|
if __FILE__ == $0
|
179
|
-
DK::
|
9
|
+
DK::Autofixer.new(ARGV)
|
180
10
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tumblr_autofixer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Meissa Dia
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tumblr_draftking
|
@@ -48,11 +48,17 @@ extra_rdoc_files: []
|
|
48
48
|
files:
|
49
49
|
- README.md
|
50
50
|
- bin/taf
|
51
|
+
- lib/autofixer/autofixer.rb
|
52
|
+
- lib/autofixer/commands/generate_tags_yml.rb
|
51
53
|
- lib/autofixer/commands/open_results.rb
|
54
|
+
- lib/autofixer/commands/show_config.rb
|
52
55
|
- lib/autofixer/commands/show_help.rb
|
53
56
|
- lib/autofixer/commands/show_version.rb
|
57
|
+
- lib/autofixer/config/view_config.html.erb
|
58
|
+
- lib/autofixer/config/view_config.rb
|
54
59
|
- lib/autofixer/data_store.rb
|
55
60
|
- lib/autofixer/helpers.rb
|
61
|
+
- lib/autofixer/patches/DK_Post.rb
|
56
62
|
- lib/autofixer/results.rb
|
57
63
|
- lib/autofixer/version.rb
|
58
64
|
- lib/tumblr_autofixer.rb
|