xxx_rename 0.0.1
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 +7 -0
- data/.github/workflows/codeql-analysis.yml +42 -0
- data/.github/workflows/ruby.yml +44 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +41 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +174 -0
- data/README.md +319 -0
- data/Rakefile +12 -0
- data/bin/console +23 -0
- data/bin/install +22 -0
- data/bin/setup +8 -0
- data/codecov.yml +2 -0
- data/docs/DEVELOPMENT.md +42 -0
- data/exe/xxx_rename +12 -0
- data/lib/xxx_rename/actions/base_action.rb +20 -0
- data/lib/xxx_rename/actions/log_new_filename.rb +40 -0
- data/lib/xxx_rename/actions/resolver.rb +32 -0
- data/lib/xxx_rename/actions/stash_app_post_movie.rb +62 -0
- data/lib/xxx_rename/actors_helper.rb +117 -0
- data/lib/xxx_rename/cli.rb +211 -0
- data/lib/xxx_rename/client.rb +110 -0
- data/lib/xxx_rename/constants.rb +96 -0
- data/lib/xxx_rename/contract/config_contract.rb +241 -0
- data/lib/xxx_rename/contract/config_generator.rb +207 -0
- data/lib/xxx_rename/contract/file_rename_op_contract.rb +54 -0
- data/lib/xxx_rename/contract/types.rb +10 -0
- data/lib/xxx_rename/core_extensions/string.rb +39 -0
- data/lib/xxx_rename/data/base.rb +34 -0
- data/lib/xxx_rename/data/config.rb +97 -0
- data/lib/xxx_rename/data/file_rename_op.rb +42 -0
- data/lib/xxx_rename/data/file_rename_op_datastore.rb +111 -0
- data/lib/xxx_rename/data/naughty_america_database.rb +22 -0
- data/lib/xxx_rename/data/query_interface.rb +78 -0
- data/lib/xxx_rename/data/scene_data.rb +71 -0
- data/lib/xxx_rename/data/scene_datastore.rb +401 -0
- data/lib/xxx_rename/data/site_config.rb +84 -0
- data/lib/xxx_rename/data/types.rb +13 -0
- data/lib/xxx_rename/errors.rb +28 -0
- data/lib/xxx_rename/file_scanner.rb +49 -0
- data/lib/xxx_rename/file_utilities.rb +38 -0
- data/lib/xxx_rename/filename_generator.rb +173 -0
- data/lib/xxx_rename/integrations/base.rb +20 -0
- data/lib/xxx_rename/integrations/stash_app.rb +316 -0
- data/lib/xxx_rename/log.rb +26 -0
- data/lib/xxx_rename/migration_client.rb +139 -0
- data/lib/xxx_rename/processed_file.rb +203 -0
- data/lib/xxx_rename/search.rb +166 -0
- data/lib/xxx_rename/site_client_matcher.rb +299 -0
- data/lib/xxx_rename/site_clients/adult_time.rb +31 -0
- data/lib/xxx_rename/site_clients/algolia_common.rb +48 -0
- data/lib/xxx_rename/site_clients/algolia_v2.rb +181 -0
- data/lib/xxx_rename/site_clients/babes.rb +15 -0
- data/lib/xxx_rename/site_clients/base.rb +61 -0
- data/lib/xxx_rename/site_clients/blacked.rb +12 -0
- data/lib/xxx_rename/site_clients/blacked_raw.rb +12 -0
- data/lib/xxx_rename/site_clients/brazzers.rb +15 -0
- data/lib/xxx_rename/site_clients/configuration.rb +55 -0
- data/lib/xxx_rename/site_clients/digital_playground.rb +15 -0
- data/lib/xxx_rename/site_clients/elegant_angel.rb +168 -0
- data/lib/xxx_rename/site_clients/errors.rb +103 -0
- data/lib/xxx_rename/site_clients/evil_angel.rb +59 -0
- data/lib/xxx_rename/site_clients/goodporn.rb +109 -0
- data/lib/xxx_rename/site_clients/jules_jordan.rb +22 -0
- data/lib/xxx_rename/site_clients/jules_jordan_media.rb +175 -0
- data/lib/xxx_rename/site_clients/manuel_ferrara.rb +24 -0
- data/lib/xxx_rename/site_clients/mg_premium.rb +247 -0
- data/lib/xxx_rename/site_clients/mofos.rb +15 -0
- data/lib/xxx_rename/site_clients/naughty_america.rb +272 -0
- data/lib/xxx_rename/site_clients/nfbusty.rb +84 -0
- data/lib/xxx_rename/site_clients/query_generator/base.rb +89 -0
- data/lib/xxx_rename/site_clients/query_generator/evil_angel.rb +36 -0
- data/lib/xxx_rename/site_clients/query_generator/goodporn.rb +27 -0
- data/lib/xxx_rename/site_clients/query_generator/mg_premium.rb +26 -0
- data/lib/xxx_rename/site_clients/query_generator/naughty_america.rb +24 -0
- data/lib/xxx_rename/site_clients/query_generator/stash_db.rb +21 -0
- data/lib/xxx_rename/site_clients/query_generator/vixen.rb +27 -0
- data/lib/xxx_rename/site_clients/query_generator/whale.rb +39 -0
- data/lib/xxx_rename/site_clients/reality_kings.rb +14 -0
- data/lib/xxx_rename/site_clients/stash_db.rb +257 -0
- data/lib/xxx_rename/site_clients/tushy.rb +12 -0
- data/lib/xxx_rename/site_clients/tushy_raw.rb +12 -0
- data/lib/xxx_rename/site_clients/twistys.rb +15 -0
- data/lib/xxx_rename/site_clients/vixen.rb +12 -0
- data/lib/xxx_rename/site_clients/vixen_media.rb +130 -0
- data/lib/xxx_rename/site_clients/whale.rb +106 -0
- data/lib/xxx_rename/site_clients/wicked.rb +52 -0
- data/lib/xxx_rename/site_clients/x_empire.rb +51 -0
- data/lib/xxx_rename/site_clients/zero_tolerance.rb +36 -0
- data/lib/xxx_rename/utils.rb +81 -0
- data/lib/xxx_rename/version.rb +5 -0
- data/lib/xxx_rename.rb +60 -0
- data/output.png +0 -0
- data/xxx_rename.gemspec +42 -0
- metadata +411 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XxxRename
|
4
|
+
module Contract
|
5
|
+
class FileRenameOpValidationFailure < StandardError
|
6
|
+
# @param [Hash] errors
|
7
|
+
def initialize(errors)
|
8
|
+
@errors = errors
|
9
|
+
super(message)
|
10
|
+
end
|
11
|
+
|
12
|
+
def message
|
13
|
+
ers = []
|
14
|
+
@errors.each_pair { |code, value| ers << "#{code}: #{value.join(" ")}" }
|
15
|
+
ers.join(", ")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class FileRenameOpContract < Dry::Validation::Contract
|
20
|
+
include FileUtilities
|
21
|
+
|
22
|
+
schema do
|
23
|
+
required(:key).value(:string)
|
24
|
+
required(:directory).value(:string)
|
25
|
+
required(:source_filename).filled(:string)
|
26
|
+
required(:output_filename).filled(:string)
|
27
|
+
required(:mtime).maybe(Types::Time)
|
28
|
+
end
|
29
|
+
|
30
|
+
rule(:directory) do
|
31
|
+
key(:directory_not_exists).failure(value) unless valid_dir?(value)
|
32
|
+
key(:non_absolute_path).failure(value) unless Pathname.new(value).absolute?
|
33
|
+
end
|
34
|
+
|
35
|
+
rule(:directory, :source_filename) do
|
36
|
+
unless rule_error?(:directory_not_exists)
|
37
|
+
path = File.join(values[:directory], values[:source_filename])
|
38
|
+
key(:file_not_found).failure(path) unless valid_file?(path)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
rule(:output_filename) do
|
43
|
+
key(:output_filename_too_long).failure(value) if value.length > MAX_FILENAME_LEN
|
44
|
+
end
|
45
|
+
|
46
|
+
rule(:directory, :output_filename) do
|
47
|
+
unless rule_error?(:directory_not_exists)
|
48
|
+
path = File.join(values[:directory], values[:output_filename])
|
49
|
+
key(:output_file_already_exists).failure(path) if valid_file?(path)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XxxRename
|
4
|
+
module CoreExtensions
|
5
|
+
module String
|
6
|
+
# Remove the following characters from the input string and returns
|
7
|
+
# it in lower case
|
8
|
+
#
|
9
|
+
# \s : whitespace characters
|
10
|
+
# \W : any non-word character
|
11
|
+
# _ : underscore
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
def normalize
|
15
|
+
gsub(/[\s\W_]/, "").downcase
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [String]
|
19
|
+
def titleize_custom
|
20
|
+
re = /([A-Z]\d[A-Z]|[A-Z][a-zA-Z])/
|
21
|
+
res = []
|
22
|
+
scan(re) { |_| res << Regexp.last_match.offset(0)[0] }
|
23
|
+
res.reverse.each { |index| insert(index, " ") }
|
24
|
+
strip
|
25
|
+
end
|
26
|
+
|
27
|
+
# Remove any characters not included in the following list
|
28
|
+
# \w [a-zA-Z0-9_].
|
29
|
+
# \s Whitespace character
|
30
|
+
# - hyphen
|
31
|
+
# , comma
|
32
|
+
# [ brackets
|
33
|
+
# ] brackets
|
34
|
+
def remove_special_characters
|
35
|
+
gsub(/[^\w\s\-,\[\]']/, "").gsub(/\s{2,}/, " ")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XxxRename
|
4
|
+
module Data
|
5
|
+
class Base < Dry::Struct
|
6
|
+
transform_keys(&:to_sym)
|
7
|
+
|
8
|
+
# resolve default types on nil
|
9
|
+
# https://dry-rb.org/gems/dry-struct/1.0/recipes/#resolving-default-values-on-code-nil-code
|
10
|
+
transform_types do |type|
|
11
|
+
if type.default?
|
12
|
+
type.constructor do |value|
|
13
|
+
value.nil? ? Dry::Types::Undefined : value
|
14
|
+
end
|
15
|
+
else
|
16
|
+
type
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Until there's an easier way to convert a hash keys to string
|
21
|
+
# without using any external library, the performance penalty
|
22
|
+
# that comes from using `JSON.parse(hash.to_json)` is the
|
23
|
+
# better alternative to adding more dependencies to this project
|
24
|
+
def to_h(stringify_keys: false)
|
25
|
+
if stringify_keys
|
26
|
+
hash = super()
|
27
|
+
JSON.parse(hash.to_json)
|
28
|
+
else
|
29
|
+
super()
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "xxx_rename/data/scene_datastore"
|
4
|
+
|
5
|
+
module XxxRename
|
6
|
+
module Data
|
7
|
+
class Config < Base
|
8
|
+
attribute :global do
|
9
|
+
attribute :female_actors_prefix, Types::String
|
10
|
+
attribute :male_actors_prefix, Types::String
|
11
|
+
attribute :actors_prefix, Types::String
|
12
|
+
attribute :title_prefix, Types::String
|
13
|
+
attribute :id_prefix, Types::String
|
14
|
+
attribute :output_format, Types::Array.of(Types::String)
|
15
|
+
end
|
16
|
+
|
17
|
+
attribute :site do
|
18
|
+
attribute? :adult_time, Data::AdultTimeConfig
|
19
|
+
attribute? :babes, Data::MgPremiumConfig
|
20
|
+
attribute? :blacked, Data::VixenMediaConfig
|
21
|
+
attribute? :blacked_raw, Data::VixenMediaConfig
|
22
|
+
attribute? :brazzers, Data::MgPremiumConfig
|
23
|
+
attribute? :digital_playground, Data::MgPremiumConfig
|
24
|
+
attribute? :elegant_angel, Data::ElegantAngelConfig
|
25
|
+
attribute? :evil_angel, Data::EvilAngelConfig
|
26
|
+
attribute? :goodporn, Data::GoodpornConfig
|
27
|
+
attribute? :jules_jordan, Data::JulesJordanMediaConfig
|
28
|
+
attribute? :manuel_ferrara, Data::JulesJordanMediaConfig
|
29
|
+
attribute? :mofos, Data::MgPremiumConfig
|
30
|
+
attribute? :naughty_america, Data::NaughtyAmericaConfig
|
31
|
+
attribute? :nf_busty, Data::NfBustyConfig
|
32
|
+
attribute? :reality_kings, Data::MgPremiumConfig
|
33
|
+
attribute? :stash, Data::StashDBConfig
|
34
|
+
attribute? :tushy, Data::VixenMediaConfig
|
35
|
+
attribute? :tushy_raw, Data::VixenMediaConfig
|
36
|
+
attribute? :twistys, Data::MgPremiumConfig
|
37
|
+
attribute? :vixen, Data::VixenMediaConfig
|
38
|
+
attribute? :whale_media, Data::WhaleMediaConfig
|
39
|
+
attribute? :wicked, Data::WickedConfig
|
40
|
+
attribute? :x_empire, Data::XEmpireConfig
|
41
|
+
attribute? :zero_tolerance, Data::ZeroToleranceConfig
|
42
|
+
end
|
43
|
+
|
44
|
+
attribute :stash_app do
|
45
|
+
attribute :url, Types::String.optional
|
46
|
+
attribute :api_token, Types::String.optional
|
47
|
+
end
|
48
|
+
|
49
|
+
attribute :generated_files_dir, Types::String
|
50
|
+
# CLI Flags
|
51
|
+
attribute :force_refresh_datastore, Types::Bool
|
52
|
+
attribute :force_refresh, Types::Bool
|
53
|
+
attribute :actions, Types::Array.of(Types::String)
|
54
|
+
attribute? :override_site, Types::String
|
55
|
+
|
56
|
+
def prefix_hash
|
57
|
+
{
|
58
|
+
female_actors_prefix: global.female_actors_prefix,
|
59
|
+
male_actors_prefix: global.male_actors_prefix,
|
60
|
+
actors_prefix: global.actors_prefix,
|
61
|
+
title_prefix: global.title_prefix,
|
62
|
+
id_prefix: global.id_prefix
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def collection_tag_to_site_client
|
67
|
+
@collection_tag_to_site_client ||= {}.tap do |h|
|
68
|
+
site.attributes.each_pair do |site_name, site_config|
|
69
|
+
h[site_config.collection_tag] = site_name
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def mutex
|
75
|
+
@mutex ||= Mutex.new
|
76
|
+
end
|
77
|
+
|
78
|
+
def scene_datastore
|
79
|
+
@scene_datastore ||=
|
80
|
+
begin
|
81
|
+
store = Data::SceneDatastore.new(File.join(generated_files_dir, "..")).store
|
82
|
+
SceneDatastoreQuery.new(store, mutex)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def output_recorder
|
87
|
+
@output_recorder ||=
|
88
|
+
begin
|
89
|
+
store = Data::OutputDatastore.new(generated_files_dir).store
|
90
|
+
datastore = Data::FileRenameOpDatastore.new(store, mutex)
|
91
|
+
datastore.migration_status = 0
|
92
|
+
datastore
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "xxx_rename/file_utilities"
|
4
|
+
|
5
|
+
module XxxRename
|
6
|
+
module Data
|
7
|
+
class FileRenameOp < Base
|
8
|
+
include FileUtilities
|
9
|
+
|
10
|
+
attribute :key, Types::String
|
11
|
+
attribute :directory, Types::String
|
12
|
+
attribute :source_filename, Types::String
|
13
|
+
attribute :output_filename, Types::String
|
14
|
+
attribute :mtime, Types::Time.optional
|
15
|
+
|
16
|
+
def rename
|
17
|
+
Dir.chdir(directory) do
|
18
|
+
File.rename(source_filename, output_filename)
|
19
|
+
|
20
|
+
# This has been deprecated in favour of storing timestamps in filename
|
21
|
+
# File.utime(File.atime(output_filename), mtime, output_filename) if mtime
|
22
|
+
|
23
|
+
XxxRename.logger.info "[RENAME COMPLETE]".colorize(:blue)
|
24
|
+
XxxRename.logger.info "\t#{"WAS:".colorize(:light_magenta)} #{source_filename}"
|
25
|
+
XxxRename.logger.info "\t#{"NOW:".colorize(:green)} #{output_filename}"
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def reverse_rename
|
31
|
+
Dir.chdir(directory) do
|
32
|
+
File.rename(output_filename, source_filename)
|
33
|
+
|
34
|
+
XxxRename.logger.info "[RENAME ROLLBACK COMPLETE]".colorize(:blue)
|
35
|
+
XxxRename.logger.info "\t#{"WAS:".colorize(:light_magenta)} #{output_filename}"
|
36
|
+
XxxRename.logger.info "\t#{"NOW:".colorize(:green)} #{source_filename}"
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yaml/store"
|
4
|
+
|
5
|
+
require "xxx_rename/data/query_interface"
|
6
|
+
require "xxx_rename/contract/file_rename_op_contract"
|
7
|
+
require "xxx_rename/data/file_rename_op"
|
8
|
+
|
9
|
+
module XxxRename
|
10
|
+
module Data
|
11
|
+
OUTPUT_KEY = "___RENAME_ACTIONS___"
|
12
|
+
STATUS_KEY = "___MIGRATION_STATUS___"
|
13
|
+
FAILURES_KEY = "___FAILURES___"
|
14
|
+
|
15
|
+
class OutputDatastore
|
16
|
+
attr_reader :store
|
17
|
+
|
18
|
+
OUTPUT = "output"
|
19
|
+
|
20
|
+
def initialize(dir)
|
21
|
+
file = "#{OUTPUT}_#{Time.now.strftime("%Y%m%d%H%M")}.yml"
|
22
|
+
|
23
|
+
Dir.chdir(dir) { FileUtils.mkdir OUTPUT unless Dir.exist?(OUTPUT) }
|
24
|
+
|
25
|
+
path = File.join(dir, OUTPUT, file)
|
26
|
+
@store = YAML::Store.new path
|
27
|
+
XxxRename.logger.info "Output will be recorded in #{file}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class FileRenameOpDatastore < QueryInterface
|
32
|
+
def create!(scene_data, source_file, output_file, dir = Dir.pwd)
|
33
|
+
hash = {
|
34
|
+
key: scene_data.key,
|
35
|
+
directory: dir,
|
36
|
+
source_filename: source_file,
|
37
|
+
output_filename: output_file,
|
38
|
+
mtime: scene_data.date_released
|
39
|
+
}
|
40
|
+
data = make_file_rename_op!(hash)
|
41
|
+
semaphore.synchronize do
|
42
|
+
store.transaction do
|
43
|
+
store[OUTPUT_KEY] ||= []
|
44
|
+
store[OUTPUT_KEY] << data
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def length
|
50
|
+
semaphore.synchronize do
|
51
|
+
store.transaction(true) do
|
52
|
+
store.fetch(OUTPUT_KEY, []).length
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def all
|
58
|
+
semaphore.synchronize do
|
59
|
+
store.transaction(true) do
|
60
|
+
store.fetch(OUTPUT_KEY, [])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def failures
|
66
|
+
semaphore.synchronize do
|
67
|
+
store.transaction(true) do
|
68
|
+
store.fetch(FAILURES_KEY, {})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_failure(key, error)
|
74
|
+
semaphore.synchronize do
|
75
|
+
store.transaction do
|
76
|
+
store[FAILURES_KEY] ||= {}
|
77
|
+
store[FAILURES_KEY][key] = error
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def migration_status
|
83
|
+
semaphore.synchronize do
|
84
|
+
store.transaction(true) do
|
85
|
+
val = store.fetch(STATUS_KEY, 0)
|
86
|
+
val == 1
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def migration_status=(status)
|
92
|
+
semaphore.synchronize do
|
93
|
+
store.transaction do
|
94
|
+
store[STATUS_KEY] = status
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def make_file_rename_op!(hash)
|
102
|
+
contract = Contract::FileRenameOpContract.new.call(hash)
|
103
|
+
|
104
|
+
raise Contract::FileRenameOpValidationFailure, contract.errors.to_h unless contract.errors.empty?
|
105
|
+
|
106
|
+
valid_hash = contract.to_h.transform_keys(&:to_s)
|
107
|
+
FileRenameOp.new(valid_hash)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pstore"
|
4
|
+
|
5
|
+
module XxxRename
|
6
|
+
module Data
|
7
|
+
class NaughtyAmericaDatabase
|
8
|
+
attr_reader :store
|
9
|
+
|
10
|
+
DEFAULT_STORE_FILE = "naughtyamerica.store"
|
11
|
+
|
12
|
+
def initialize(store_file)
|
13
|
+
store_file = DEFAULT_STORE_FILE if store_file.nil?
|
14
|
+
|
15
|
+
path = File.join(Dir.pwd, store_file)
|
16
|
+
XxxRename.logger.info "Initialising database in #{path}"
|
17
|
+
|
18
|
+
@store = PStore.new path
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XxxRename
|
4
|
+
module Data
|
5
|
+
class QueryError < StandardError
|
6
|
+
def initialize(scene_data)
|
7
|
+
@scene_data = scene_data
|
8
|
+
super(message)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class UniqueRecordViolation < QueryError
|
13
|
+
def message
|
14
|
+
"Scene already present in database: #{@scene_data.inspect}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class RecordNotFound < QueryError
|
19
|
+
def message
|
20
|
+
"Scene not saved in database #{@scene_data.inspect}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class QueryInterface
|
25
|
+
# @param [PStore] store
|
26
|
+
# @param [Mutex] semaphore
|
27
|
+
def initialize(store, semaphore)
|
28
|
+
@store = store
|
29
|
+
@semaphore = semaphore
|
30
|
+
end
|
31
|
+
|
32
|
+
def find(*)
|
33
|
+
raise "Not Implemented"
|
34
|
+
end
|
35
|
+
|
36
|
+
def create!(*)
|
37
|
+
raise "Not Implemented"
|
38
|
+
end
|
39
|
+
|
40
|
+
def upsert(*)
|
41
|
+
raise "Not Implemented"
|
42
|
+
end
|
43
|
+
|
44
|
+
def destroy!(*)
|
45
|
+
raise "Not Implemented"
|
46
|
+
end
|
47
|
+
|
48
|
+
def count(*)
|
49
|
+
raise "Not Implemented"
|
50
|
+
end
|
51
|
+
|
52
|
+
def metadata(*)
|
53
|
+
raise "Not Implemented"
|
54
|
+
end
|
55
|
+
|
56
|
+
def update_metadata(*)
|
57
|
+
raise "Not Implemented"
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param [Array[String|Integer]] strs
|
61
|
+
def generate_lookup_key(*strs)
|
62
|
+
strs.map(&:to_s).map { |x| sanitize(x) }.join("$")
|
63
|
+
end
|
64
|
+
|
65
|
+
attr_reader :store
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
attr_reader :semaphore
|
70
|
+
|
71
|
+
# @param [String] str
|
72
|
+
# @return [String]
|
73
|
+
def sanitize(str)
|
74
|
+
str.to_s.normalize
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "digest/md5"
|
4
|
+
|
5
|
+
module XxxRename
|
6
|
+
module Data
|
7
|
+
class SceneData < Base
|
8
|
+
attribute :female_actors, Types::Array.of(Types::String).default([].freeze)
|
9
|
+
attribute :male_actors, Types::Array.of(Types::String).default([].freeze)
|
10
|
+
attribute :actors, Types::Array.of(Types::String)
|
11
|
+
attribute :collection, Types::String.default("")
|
12
|
+
attribute :collection_tag, Types::String.default("")
|
13
|
+
attribute :title, Types::String
|
14
|
+
attribute? :id, Types::Coercible::String.optional
|
15
|
+
attribute? :date_released, Types::Time.optional
|
16
|
+
attribute :scene_link, Types::String.default("")
|
17
|
+
attribute :original_filenames, Types::Set.default(Set.new.freeze)
|
18
|
+
attribute? :movie do
|
19
|
+
attribute :name, Types::String
|
20
|
+
attribute? :date, Types::Time
|
21
|
+
attribute? :url, Types::String
|
22
|
+
attribute :front_image, Types::String
|
23
|
+
attribute? :back_image, Types::String
|
24
|
+
attribute? :studio, Types::String
|
25
|
+
attribute? :synopsis, Types::String
|
26
|
+
end
|
27
|
+
|
28
|
+
def yyyy_mm_dd
|
29
|
+
date_released&.strftime("%Y_%m_%d")
|
30
|
+
end
|
31
|
+
|
32
|
+
def day
|
33
|
+
d = date_released&.day.to_s
|
34
|
+
return if d.empty?
|
35
|
+
|
36
|
+
d.length == 1 ? "0#{d}" : d
|
37
|
+
end
|
38
|
+
alias dd day
|
39
|
+
|
40
|
+
def month
|
41
|
+
m = date_released&.month.to_s
|
42
|
+
return if m.empty?
|
43
|
+
|
44
|
+
m.length == 1 ? "0#{m}" : m
|
45
|
+
end
|
46
|
+
alias mm month
|
47
|
+
|
48
|
+
def year
|
49
|
+
date_released&.year&.to_s
|
50
|
+
end
|
51
|
+
alias yyyy year
|
52
|
+
|
53
|
+
#
|
54
|
+
# Takes a scene information and uses as much information
|
55
|
+
# as possible to generate a unique key to minimize the
|
56
|
+
# chances of key collision
|
57
|
+
#
|
58
|
+
# @return [String]
|
59
|
+
def key
|
60
|
+
@key ||=
|
61
|
+
begin
|
62
|
+
str = "<#{title.normalize}" \
|
63
|
+
"$#{collection.to_s.normalize}" \
|
64
|
+
"$#{actors.join("-").normalize}" \
|
65
|
+
">"
|
66
|
+
Digest::MD5.hexdigest(str)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|