fuck_facebook 0.2.1 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd816f264c73ea38c4349c8110cade9787ae11f92de9b37ad8a1f6fbef9b2059
4
- data.tar.gz: e2862a3aee723788f459ab7b84acf84ca2b3bda8ef6176e51a1018915cb350d7
3
+ metadata.gz: 4444d134e1ae1d10b948ae6432691f99c1c22498aea2f0530359b0c93a1df967
4
+ data.tar.gz: b276c6b4a680c546b2b34366b5e28cd1af620ef7800ae7f2964bbded6235eff8
5
5
  SHA512:
6
- metadata.gz: aa5dfc850834b1ab4efd759eb853ac2bdc25c6a9cb739ee704b2e2182fc917fc43b85c504c75ad7394074f0549abd8e372906911a68da64ea0a4c78766d0d39b
7
- data.tar.gz: 8ebea4e69e013d5c2f7f7345755c5ed39768bdbcd231587ae06c64e196e718d2f57293ea9714c84cf61008bc104d05c1dfd90df7548c8eade979d76a5391f129
6
+ metadata.gz: 2e9a2254136c1886d20e7f164bbf1cf9d06d1a6191ed7522df717db580b6eea1b48f9ab5c9caebb9b84c75bc24f8467e0c92b30d5bae5f1131a99b7a6bb93b94
7
+ data.tar.gz: 5b930019d90be80fb751a487c2b71b0021278dc1952fd2a61baac57b7e88a4bcfc33be612699193bd6caeeb1c43a5fb0b7a231fce555d41c32e6d69a6cb93185
data/.gitignore CHANGED
@@ -11,3 +11,5 @@
11
11
  .rspec_status
12
12
 
13
13
  *.gem
14
+
15
+ fuck_facebook_error*.png
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.0.1
1
+ 3.0.2
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,23 @@
1
+ # Developer Guide
2
+
3
+ ## Pushing a new version of the gem
4
+
5
+ **Note:** You must have been granted access to deploy new versions of the `fuck_facebook` gem
6
+
7
+ * Bump the version in `lib/fuck_facebook/version.rb`
8
+ * Build the gem with `gem build fuck_facebook.gemspec`
9
+ * Push the gem with `gem push fuck_facebook-VERSION.gem` replacing `VERSION` with the new version number
10
+
11
+ ## Pushing a new version of the Docker image
12
+
13
+ **Note:** You must have been granted access to deploy new versions of the `fuck_facebook` Docker image
14
+
15
+ * Build the image:
16
+
17
+ ```
18
+ docker build . -t keeyan/fuck_facebook:VERSION --build-arg version=VERSION
19
+ ```
20
+
21
+ Replace `VERSION` with the version number
22
+
23
+ * Push the image with `docker push keeyan/fuck_facebook:VERSION` replacing `VERSION` with the version number
data/Dockerfile ADDED
@@ -0,0 +1,15 @@
1
+ FROM ruby:3.0.2-bullseye
2
+
3
+ RUN apt-get update && apt-get install -y chromium-driver
4
+
5
+ RUN useradd --create-home --shell /bin/bash fuckfacebook
6
+
7
+ USER fuckfacebook
8
+ WORKDIR /home/fuckfacebook
9
+
10
+ RUN mkdir -p /home/fuckfacebook/.local/share/fuck-facebook
11
+ VOLUME /home/fuckfacebook/.local/share/fuck-facebook
12
+
13
+ ARG version
14
+ COPY fuck_facebook-$version.gem .
15
+ RUN gem install fuck_facebook-$version.gem
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fuck_facebook (0.1.2)
4
+ fuck_facebook (0.4.1)
5
5
  activesupport (~> 6.1)
6
6
  highline (~> 2.0)
7
7
  mail (~> 2.7)
@@ -10,7 +10,7 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- activesupport (6.1.4)
13
+ activesupport (6.1.4.4)
14
14
  concurrent-ruby (~> 1.0, >= 1.0.2)
15
15
  i18n (>= 1.6, < 2)
16
16
  minitest (>= 5.1)
@@ -21,13 +21,13 @@ GEM
21
21
  coderay (1.1.3)
22
22
  concurrent-ruby (1.1.9)
23
23
  highline (2.0.3)
24
- i18n (1.8.10)
24
+ i18n (1.8.11)
25
25
  concurrent-ruby (~> 1.0)
26
26
  mail (2.7.1)
27
27
  mini_mime (>= 0.1.1)
28
28
  method_source (1.0.0)
29
- mini_mime (1.1.0)
30
- minitest (5.14.4)
29
+ mini_mime (1.1.2)
30
+ minitest (5.15.0)
31
31
  parallel (1.20.1)
32
32
  parser (3.0.1.1)
33
33
  ast (~> 2.4.1)
@@ -56,7 +56,7 @@ GEM
56
56
  tzinfo (2.0.4)
57
57
  concurrent-ruby (~> 1.0)
58
58
  unicode-display_width (2.0.0)
59
- zeitwerk (2.4.2)
59
+ zeitwerk (2.5.1)
60
60
 
61
61
  PLATFORMS
62
62
  ruby
@@ -67,4 +67,4 @@ DEPENDENCIES
67
67
  rubocop
68
68
 
69
69
  BUNDLED WITH
70
- 2.2.15
70
+ 2.2.22
data/README.md CHANGED
@@ -1,3 +1,51 @@
1
1
  # Fuck Facebook
2
2
 
3
3
  A collection of tools to help you use Facebook when you don't want to
4
+
5
+ ## Usage
6
+
7
+ Run `fuck-facebook --help` to get a list of options and explanations.
8
+
9
+ To get all unread messages (that haven't already been reported) run these commands:
10
+
11
+ ```
12
+ fuck-facebook --login
13
+ ```
14
+
15
+ You only need to login once
16
+
17
+ ```
18
+ fuck-facebook --unread-messages
19
+ ```
20
+
21
+ This will only show you unread messages that have been received since the last time you checked.
22
+ This way if you have emails going out for new messages, you won't get notified for the same message each time.
23
+
24
+ ## Config
25
+
26
+ Here's a complete config file along with an explanation of each option:
27
+
28
+ ```yaml
29
+ errors:
30
+ min_minutes_between_reports: 0 # Only report error if one has not occured in the past X minutes
31
+ include_screenshot: false # Generates a screenshot with the error report
32
+ smtp:
33
+ from_email: sender@example.com
34
+ to_email: receiver@example.com
35
+ address: smtp.example.com
36
+ port: 587
37
+ user_name: some_user_name
38
+ password: 123456
39
+ authentication: plain
40
+ ```
41
+
42
+ Place this file in `~/.local/share/fuck-facebook/config.yaml`
43
+
44
+ These options can be passed as environment variables, by:
45
+ * Joining the keys with `_`
46
+ * Capitalizing the entire string
47
+ * Prefixing the key with `FF_`
48
+
49
+ For example the `smtp` `from_email` will become `FF_SMTP_FROM_EMAIL`
50
+
51
+ Environment variables take precedent over the config file.
data/bin/fuck-facebook CHANGED
@@ -7,59 +7,23 @@ require_relative '../src/facebook_connection'
7
7
  require_relative '../src/config'
8
8
  require_relative '../src/initializers/mail_initializer'
9
9
  require_relative '../src/senders'
10
-
11
- options = {
12
- headless: true,
13
- clear_cookies: false,
14
- unread_messages: false,
15
- messages: false,
16
- sender: 'stdout'
17
- }
18
-
19
- OptionParser.new do |opts|
20
- opts.banner = 'Usage: fuck-facebook.rb [options]'
21
-
22
- opts.on('-h', '--[no-]headless', 'Run in a headless browser') do |v|
23
- options[:headless] = v
24
- end
25
-
26
- opts.on('--clear-cookies') do |v|
27
- options[:clear_cookies] = v
28
- end
29
-
30
- opts.on('--unread-messages') do |v|
31
- options[:unread_messages] = v
32
- end
33
-
34
- opts.on('--messages') do |v|
35
- options[:messages] = v
36
- end
37
-
38
- opts.on('--login') do |v|
39
- options[:login] = v
40
- end
41
-
42
- opts.on('--sender=SENDER') do |sender|
43
- options[:sender] = sender
44
- end
45
- end.parse!
46
-
47
- facebook_connection = FacebookConnection.new(headless: options[:headless])
48
-
49
- facebook_connection.cookie_handler.clear! if options[:clear_cookies]
50
-
51
- facebook_connection.login if options[:login]
52
-
53
- messages =
54
- if options[:unread_messages]
55
- facebook_connection.message_handler.unread
56
- elsif options[:messages]
57
- facebook_connection.message_handler.messages
58
- else
59
- []
60
- end
61
-
62
- sender = Senders.by_name(options[:sender])
63
- sender.send_messages(messages)
64
-
65
- facebook_connection.close
10
+ require_relative '../src/args_parser'
11
+ require_relative '../src/message_sender'
12
+ require_relative '../src/error_reporter'
13
+
14
+ options = ArgsParser.parse_args
15
+ facebook_connection = nil
16
+
17
+ begin
18
+ facebook_connection = FacebookConnection.new(headless: options[:headless])
19
+ raise 'Error triggered by --simulate-error flag' if options[:simulate_error]
20
+
21
+ facebook_connection.cookie_handler.clear! if options[:clear_cookies]
22
+ facebook_connection.login if options[:login]
23
+ message_sender = MessageSender.new(options[:sender], facebook_connection)
24
+ message_sender.send_unread_messages if options[:unread_messages]
25
+ message_sender.send_messages if options[:messages]
26
+ facebook_connection.close
27
+ rescue StandardError => e
28
+ ErrorReporter.report_error(options[:sender], e, facebook_connection: facebook_connection)
29
+ end
@@ -1,3 +1,3 @@
1
1
  module FuckFacebook
2
- VERSION = '0.2.1'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
@@ -0,0 +1,82 @@
1
+ class ArgsParser
2
+ DEFAULT_OPTIONS = {
3
+ headless: true,
4
+ clear_cookies: false,
5
+ unread_messages: false,
6
+ messages: false,
7
+ sender: 'stdout',
8
+ simulate_error: false
9
+ }.freeze
10
+
11
+ AVAILABLE_OPTIONS = [
12
+ {
13
+ short: '-h',
14
+ long: '--[no-]headless',
15
+ message: 'Run in a headless browser',
16
+ option: :headless
17
+ },
18
+ {
19
+ short: nil,
20
+ long: '--clear-cookies',
21
+ message: 'Clears all cookies',
22
+ option: :clear_cookies
23
+ },
24
+ {
25
+ short: nil,
26
+ long: '--unread-messages',
27
+ message: 'Outputs all unread messages sent since the last check',
28
+ option: :unread_messages
29
+ },
30
+ {
31
+ short: nil,
32
+ long: '--messages',
33
+ message: 'Outputs all messages sent since the last check',
34
+ option: :messages
35
+ },
36
+ {
37
+ short: nil,
38
+ long: '--login',
39
+ message: 'Prompts for details to login to Facebook account',
40
+ option: :login
41
+ },
42
+ {
43
+ short: nil,
44
+ long: '--sender=SENDER',
45
+ message: 'Send results to either stdout or email',
46
+ option: :sender
47
+ },
48
+ {
49
+ short: nil,
50
+ long: '--simulate-error',
51
+ message: 'Simulates an error so you can see how it will be outputted',
52
+ option: :simulate_error
53
+ }
54
+ ].freeze
55
+
56
+ def self.parse_args
57
+ passed_options = DEFAULT_OPTIONS.dup
58
+
59
+ OptionParser.new do |opts|
60
+ generate_banner(opts)
61
+
62
+ AVAILABLE_OPTIONS.each do |available_option|
63
+ parser_for_available_option(opts, available_option, passed_options)
64
+ end
65
+ end.parse!
66
+
67
+ passed_options
68
+ end
69
+
70
+ private_class_method def self.generate_banner(opts)
71
+ opts.banner = 'Usage: fuck-facebook.rb [options]'
72
+ end
73
+
74
+ private_class_method def self.parser_for_available_option(opts, available_option, passed_options)
75
+ args = [available_option[:long], available_option[:message]]
76
+ args = [available_option[:short]] + args if available_option[:short]
77
+
78
+ opts.on(*args) do |v|
79
+ passed_options[available_option[:option]] = v
80
+ end
81
+ end
82
+ end
data/src/config.rb CHANGED
@@ -3,12 +3,17 @@ require 'yaml'
3
3
  class Config
4
4
  CONFIG_FILE_PATH = "#{ENV['HOME']}/.local/share/fuck-facebook/config.yaml".freeze
5
5
 
6
- def self.option(*path)
6
+ def self.option(*path, default: nil)
7
+ env_var = "FF_#{path.join('_').upcase}"
8
+ return ENV[env_var] if ENV[env_var]
9
+
7
10
  path_strings = path.map(&:to_s)
8
- config.dig(*path_strings)
9
- end
11
+ value = config.dig(*path_strings)
10
12
 
11
- private
13
+ return value if value
14
+
15
+ default
16
+ end
12
17
 
13
18
  def self.config
14
19
  create_config_file_if_not_exists!
@@ -16,7 +21,7 @@ class Config
16
21
  YAML.load_file(CONFIG_FILE_PATH)
17
22
  end
18
23
 
19
- def self.create_config_file_if_not_exists!
24
+ private_class_method def self.create_config_file_if_not_exists!
20
25
  dirname = File.dirname(CONFIG_FILE_PATH)
21
26
  FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
22
27
  File.write(CONFIG_FILE_PATH, '{}') unless File.exist?(CONFIG_FILE_PATH)
@@ -0,0 +1,32 @@
1
+ class ErrorReporter
2
+ def self.report_error(sender_name, error, facebook_connection: nil)
3
+ raise error unless report_error?
4
+
5
+ Storage.set(:last_error_reported_time, Time.now)
6
+
7
+ screenshot = include_screenshot?(facebook_connection) ? create_screenshot(facebook_connection) : nil
8
+
9
+ Senders.by_name(sender_name).send_error(error, screenshot: screenshot)
10
+ raise error
11
+ end
12
+
13
+ private_class_method def self.include_screenshot?(facebook_connection)
14
+ Config.option(:errors, :include_screenshot) && facebook_connection.present?
15
+ end
16
+
17
+ private_class_method def self.create_screenshot(facebook_connection)
18
+ facebook_connection.driver.screenshot_as(:png)
19
+ rescue StandardError
20
+ nil
21
+ end
22
+
23
+ private_class_method def self.report_error?
24
+ min_minutes_between_reports = Config.option(:errors, :min_minutes_between_reports, default: 0)
25
+
26
+ last_error_reported_time = Storage.get(:last_error_reported_time, default: Time.new(2000))
27
+
28
+ next_report_time = last_error_reported_time + min_minutes_between_reports.minutes
29
+
30
+ Time.now > next_report_time
31
+ end
32
+ end
@@ -31,6 +31,8 @@ class FacebookConnection
31
31
 
32
32
  options = Selenium::WebDriver::Chrome::Options.new
33
33
  options.add_argument('--disable-notifications')
34
+ options.add_argument('--no-sandbox')
35
+ options.add_argument('--disable-dev-shm-usage')
34
36
  options.add_argument('--headless') if headless
35
37
  options.add_option('detach', true) unless headless
36
38
 
@@ -53,13 +53,12 @@ class MessageHandler
53
53
  end
54
54
 
55
55
  def messages_after_last_message_time(messages)
56
- last_message_time = Storage.get(:last_message_time, default: Time.new(2004, 2, 4))
56
+ last_message_check_time = Storage.get(:last_message_check_time, default: Time.new(2004, 2, 4))
57
+ last_check_time_with_buffer = last_message_check_time - 5.minutes
57
58
 
58
- messages_to_return = messages.select { _1.timestamp > last_message_time }
59
+ messages_to_return = messages.select { _1.timestamp > last_check_time_with_buffer }
59
60
 
60
- last_message_time = messages.map(&:timestamp).max
61
-
62
- Storage.set(:last_message_time, last_message_time)
61
+ Storage.set(:last_message_check_time, Time.now)
63
62
 
64
63
  messages_to_return
65
64
  end
@@ -0,0 +1,25 @@
1
+ class MessageSender
2
+ attr_accessor :sender_name, :facebook_connection
3
+
4
+ def initialize(sender_name, facebook_connection)
5
+ @sender_name = sender_name
6
+ @facebook_connection = facebook_connection
7
+ end
8
+
9
+ def send_unread_messages
10
+ messages = facebook_connection.message_handler.unread
11
+ send_array_of_messages(messages)
12
+ end
13
+
14
+ def send_messages
15
+ messages = facebook_connection.message_handler.messages
16
+ send_array_of_messages(messages)
17
+ end
18
+
19
+ private
20
+
21
+ def send_array_of_messages(messages)
22
+ sender = Senders.by_name(sender_name)
23
+ sender.send_messages(messages)
24
+ end
25
+ end
data/src/senders/email.rb CHANGED
@@ -10,5 +10,15 @@ module Senders
10
10
  end
11
11
  end
12
12
  end
13
+
14
+ def self.send_error(error, screenshot: nil)
15
+ Mail.deliver do
16
+ from Config.option(:smtp, :from_email)
17
+ to Config.option(:smtp, :to_email)
18
+ subject 'Error occurred during Fuck Facebook command'
19
+ body error.full_message(highlight: false)
20
+ add_file filename: 'error_screenshot.png', content: screenshot if screenshot
21
+ end
22
+ end
13
23
  end
14
24
  end
@@ -5,5 +5,14 @@ module Senders
5
5
  puts message
6
6
  end
7
7
  end
8
+
9
+ def self.send_error(error, screenshot: nil)
10
+ puts error
11
+ return if screenshot.nil?
12
+
13
+ filename = "fuck_facebook_error_#{Time.now.iso8601}.png"
14
+ File.write(filename, screenshot)
15
+ puts "Screenshot of error page saved as #{filename}"
16
+ end
8
17
  end
9
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fuck_facebook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keeyan Nejad
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-13 00:00:00.000000000 Z
11
+ date: 2021-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -81,6 +81,8 @@ files:
81
81
  - ".rubocop.yml"
82
82
  - ".ruby-version"
83
83
  - CHANGELOG.md
84
+ - CONTRIBUTING.md
85
+ - Dockerfile
84
86
  - Gemfile
85
87
  - Gemfile.lock
86
88
  - LICENSE.txt
@@ -92,13 +94,16 @@ files:
92
94
  - fuck_facebook.gemspec
93
95
  - lib/fuck_facebook.rb
94
96
  - lib/fuck_facebook/version.rb
97
+ - src/args_parser.rb
95
98
  - src/authenticator.rb
96
99
  - src/config.rb
97
100
  - src/cookie_handler.rb
101
+ - src/error_reporter.rb
98
102
  - src/facebook_connection.rb
99
103
  - src/fb_duration.rb
100
104
  - src/initializers/mail_initializer.rb
101
105
  - src/message_handler.rb
106
+ - src/message_sender.rb
102
107
  - src/models/message.rb
103
108
  - src/models/message_thread.rb
104
109
  - src/models/user.rb
@@ -135,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
140
  - !ruby/object:Gem::Version
136
141
  version: '0'
137
142
  requirements: []
138
- rubygems_version: 3.2.15
143
+ rubygems_version: 3.2.22
139
144
  signing_key:
140
145
  specification_version: 4
141
146
  summary: A collection of tools to help you use Facebook when you don't want to