Class: Furaffinity::Queue

Inherits:
Object
  • Object
show all
Includes:
SemanticLogger::Loggable
Defined in:
lib/furaffinity/queue.rb

Constant Summary collapse

FA_QUEUE_DIR =
".fa"
SUBMISSION_INFO_EXT =
".info.yml"
SUBMISSION_TEMPLATE =
<<~YAML
  ---
  # Submission info for %<file_name>s

  # Required field
  title: ""

  # Required field
  description: |-
    Your description goes here

  # Optional field, keywords separated by spaces
  keywords: ""

  # Required field, one of: [#{Furaffinity::Client::RATING_MAP.keys.join(", ")}]
  rating: general

  # Required field, one of: [#{Furaffinity::Client::SUBMISSION_TYPES.join(", ")}]
  type: submission

  scrap: false
  lock_comments: false

  # Create a new folder to place this submission under, leave blank if none should be created.
  create_folder_name: ""

  # Run this Ruby code after uploading
  after_upload: |-
    # Quick reference
    #
    # Available objects:
    # - `client` (Furaffinity::Client)
    #   The client object used to interact with FurAffinity.
    # - `submission_info` (Hash)
    #   The current submission information of this YAML file.  Keys are symbols.
    #   To get the description use e.g. `submission_info[:description]`.
    #   This also contains the ID of the uploaded submission, e.g.
    #   `submission_info[:id]`.
    # - `file_info` (Hash)
    #   A hash of all YAML files.  Format is
    #   `{ "filename.png" => { submission_info } }`.
    #   Like `submission_info` it also contains the submission's ID as the `:id`
    #   field if it's been uploaded.
    #
    # Helper functions:
    # - `submission_url(submission_id)`
    #   Generates a submission URL, e.g.
    #   "https://www.furaffinity.net/view/54328944/"
    # - `link_to(url_or_submission, text)`
    #   Generates a link.  If the first parameter is a submission info hash it will
    #   generate the URL using `submission_url(submission_info[:id])`.

    # Remove this `return` if you want to run Ruby code
    return

    # Append a link to this submission to a previously uploaded one
    previous_submission = file_info.fetch("previous_file.png")
    previous_submission[:description] += ("\n\n" + link_to(submission_info, "Alt version 2"))
    client.update(**previous_submission)

    # Append a link to the previous submission to the current one
    submission_info[:description] += ("\n\n" + link_to(previous_submission, "Alt version 1"))
    client.update(**submission_info)
YAML

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client, queue_dir) ⇒ Queue

Returns a new instance of Queue.

Parameters:



83
84
85
86
87
88
89
# File 'lib/furaffinity/queue.rb', line 83

def initialize(client, queue_dir)
  @client = client
  @queue_dir = queue_dir
  @queue = []
  @upload_status = {}
  @file_info = {}
end

Instance Attribute Details

#clientObject (readonly)

Returns the value of attribute client.



79
80
81
# File 'lib/furaffinity/queue.rb', line 79

def client
  @client
end

#file_infoObject (readonly)

Returns the value of attribute file_info.



79
80
81
# File 'lib/furaffinity/queue.rb', line 79

def file_info
  @file_info
end

#queueObject (readonly)

Returns the value of attribute queue.



79
80
81
# File 'lib/furaffinity/queue.rb', line 79

def queue
  @queue
end

#queue_dirObject (readonly)

Returns the value of attribute queue_dir.



79
80
81
# File 'lib/furaffinity/queue.rb', line 79

def queue_dir
  @queue_dir
end

#upload_statusObject (readonly)

Returns the value of attribute upload_status.



79
80
81
# File 'lib/furaffinity/queue.rb', line 79

def upload_status
  @upload_status
end

Instance Method Details

#add(*files) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/furaffinity/queue.rb', line 136

def add(*files)
  files.select do |file|
    unless File.exist?(file)
      logger.warn "File #{file.inspect} does not exist"
      next false
    end

    if queue.include?(file)
      logger.warn "File #{file.inspect} is already in the queue"
      next false
    end

    submission_info_path = create_submission_info(file)
    CliUtils.open_editor submission_info_path

    queue << file
    upload_status[file] = {
      uploaded: false,
      url:      nil,
    }

    save

    true
  end
end

#cleanObject



179
180
181
182
183
184
185
186
187
188
# File 'lib/furaffinity/queue.rb', line 179

def clean
  uploaded_files.each do |file, _upload_info|
    logger.trace { "Deleting #{file} ..." }
    queue.delete(file)
    upload_status.delete(file)
    File.unlink(file)
    File.unlink(file + SUBMISSION_INFO_EXT)
    save
  end
end

#create_submission_info(file) ⇒ Object



246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/furaffinity/queue.rb', line 246

def create_submission_info(file)
  template = File.read(submission_template_path)

  submission_info_path = "#{file}#{SUBMISSION_INFO_EXT}"
  return submission_info_path if File.exist?(submission_info_path)

  rendered_template = format(template, file_name: file.inspect)
  File.open(submission_info_path, "w") do |f|
    f.puts rendered_template
  end

  submission_info_path
end

#fa_info_dirObject



91
# File 'lib/furaffinity/queue.rb', line 91

def fa_info_dir = File.join(queue_dir, FA_QUEUE_DIR)

#fa_info_path(*path) ⇒ Object



93
# File 'lib/furaffinity/queue.rb', line 93

def fa_info_path(*path) = File.join(fa_info_dir, *path)

#initObject



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/furaffinity/queue.rb', line 110

def init
  if Dir.exist?(queue_dir)
    logger.trace { "Checking if directory #{queue_dir.inspect} is empty" }
    raise Error.new("#{queue_dir.inspect} is not empty") unless Dir.empty?(queue_dir)
  end

  logger.trace { "Creating directory #{fa_info_dir.inspect}" }
  FileUtils.mkdir_p(fa_info_dir)

  %w[templates].each do |dir|
    logger.trace { "Creating directory #{fa_info_path(dir).inspect}" }
    FileUtils.mkdir_p(fa_info_path(dir))
  end

  logger.trace { "Creating empty state files" }
  save

  logger.trace { "Creating submission template" }
  File.open(submission_template_path, "w") do |f|
    f.puts(SUBMISSION_TEMPLATE)
  end

  logger.debug "Created new queue dir in #{queue_dir.inspect}"
  queue_dir
end

#reloadObject

loads state info from queue dir



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/furaffinity/queue.rb', line 98

def reload
  logger.trace { "Loading state info" }

  @queue = YAML.safe_load_file(fa_info_path("queue.yml"), permitted_classes: [Symbol])
  @upload_status = YAML.safe_load_file(fa_info_path("status.yml"), permitted_classes: [Symbol])
  @file_info = Dir[File.join(queue_dir, "**/*#{SUBMISSION_INFO_EXT}")].map do |path|
    [path.delete_suffix(SUBMISSION_INFO_EXT).sub(/^#{Regexp.escape(queue_dir)}\/?/, ""), YAML.safe_load_file(path, permitted_classes: [Symbol]).transform_keys(&:to_sym)]
  end.to_h

  logger.trace "Loaded state info", queue:, file_info:
end

#remove(*files) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/furaffinity/queue.rb', line 163

def remove(*files)
  files.select do |file|
    unless queue.include?(file)
      logger.warn "File #{file.inspect} is not in the queue"
      next false
    end

    queue.delete(file)
    upload_status.delete(file)

    save

    true
  end
end

#reorderObject



190
191
192
# File 'lib/furaffinity/queue.rb', line 190

def reorder
  CliUtils.open_editor fa_info_path("queue.yml")
end

#saveObject



235
236
237
238
239
240
241
242
243
244
# File 'lib/furaffinity/queue.rb', line 235

def save
  { queue:, status: upload_status }.each do |type, content|
    path = fa_info_path("#{type}.yml")
    logger.trace { "Writing #{path}" }
    yaml_content = content.to_yaml
    File.open(path, "w") do |f|
      f.puts(yaml_content)
    end
  end
end

#submission_template_pathObject



95
# File 'lib/furaffinity/queue.rb', line 95

def submission_template_path = fa_info_path("templates", "submission.yml")

#upload(wait_time = 60) ⇒ Object

Raises:

  • (ArgumentError)


194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/furaffinity/queue.rb', line 194

def upload(wait_time = 60)
  raise ArgumentError.new("wait_time must be at least 30") if wait_time < 30

  hook_handler = QueueHook.new(client, file_info)

  while file_name = queue.shift
    info = file_info[file_name]
    unless info
      logger.warn "no file info found for #{file_name}, ignoring"
      next
    end

    code = file_info[file_name].delete(:after_upload)

    logger.info "Uploading #{info[:title].inspect} (#{file_name.inspect})"
    url = client.upload(
      File.new(file_name),
      **file_info[file_name]
    )

    upload_status[file_name][:uploaded] = true
    upload_status[file_name][:url] = url

    save

    if code
      hook_handler.update_ids(upload_status)
      hook_handler.run_hook(file_name, code)
    end

    unless queue.empty?
      logger.info "Waiting #{wait_time} seconds until the next upload"
      sleep wait_time
    end
  end
end

#uploaded_filesObject



231
232
233
# File 'lib/furaffinity/queue.rb', line 231

def uploaded_files
  upload_status.select { _2[:uploaded] }
end