lyricsender 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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/lyricsender +245 -0
  3. metadata +191 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 285ac3c82943030c544650c567678127abc1e51bf97ab4a8656fe43797e579a1
4
+ data.tar.gz: d192927a4e3665d7a604733502161952b60aaf1eb6f2226aa545d484746e709f
5
+ SHA512:
6
+ metadata.gz: 8de40dc55989247ba5b3cf28db95f97ea2e85fadc353d15a58ce62e5a8f36968592b5daf4b4a207debdd8516222e05553ec25fc8752e827aaa7a5400f09f8ae7
7
+ data.tar.gz: dc0dedfcb8104cbc89f250ba2dcb77a679ae6686f43045d870cf9a09c1eb5ab2f87775923e9993fffeb0e82a68341ab19ef350e484f3e585b7b946f1202aaac0
data/bin/lyricsender ADDED
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'open-uri'
5
+ require 'dry/cli'
6
+ require 'os'
7
+ require 'imessage'
8
+ require 'tty-config'
9
+ require 'tty-progressbar'
10
+ require 'tty-prompt'
11
+ require 'genius'
12
+ require 'launchy'
13
+ require 'nokogiri'
14
+
15
+ module Lyricsender
16
+
17
+ VERSION = "0.1.0"
18
+
19
+ module CLI
20
+ module Commands
21
+ extend Dry::CLI::Registry
22
+
23
+ class Version < Dry::CLI::Command
24
+ desc "Print version"
25
+
26
+ def call(*)
27
+ puts "lyricsender v#{Lyricsender::VERSION}"
28
+ end
29
+ end
30
+
31
+ class Setup < Dry::CLI::Command
32
+ desc "Initial setup for lyricsender"
33
+
34
+ def call(*)
35
+
36
+ ### warning - This part is duplicated and I cannot figure out how to fix it
37
+ # Supports https://no-color.org
38
+ env_no_color = false if ENV['NO_COLOR']
39
+
40
+ pastel = Pastel.new(enabled: env_no_color)
41
+ config = TTY::Config.new
42
+ prompt = TTY::Prompt.new(enable_color: env_no_color)
43
+
44
+ config.filename = "lyricsender"
45
+ config.extname = ".toml"
46
+ config_append_path = "#{Dir.home}/.config"
47
+ config.append_path config_append_path
48
+
49
+ unless OS.mac?
50
+ puts
51
+ print pastel.bold.red "(!) Note: only macOS is supported"
52
+ puts pastel.red " (this uses iMessage and AppleScript)."
53
+ if prompt.yes? "Continue anyway?"
54
+ nil
55
+ else
56
+ exit 1
57
+ end
58
+ end
59
+ ### end duplicated part
60
+
61
+ if !config.exist?
62
+ puts
63
+ puts pastel.bold "Hi, welcome to lyricsender!"
64
+ puts "You'll need an access token from Genius to use this."
65
+ if prompt.yes? "Open genius.com/api-clients to create one?"
66
+ Launchy.open "http://genius.com/api-clients"
67
+ end
68
+ set_token = prompt.ask("Please paste your #{pastel.bold "client access token"} here and press enter:", convert: :str, required: true)
69
+ config.set(:token, value: set_token)
70
+ puts "Perfect; writing to `#{config_append_path}/#{config.filename}#{config.extname}`…"
71
+ config.write
72
+ print pastel.bold.green "Setup complete!"
73
+ puts pastel.green " You can now run `lyricsender send` to send something."
74
+ else
75
+ puts pastel.red "Looks like you're already set up!"
76
+ puts pastel.dim "(Your config file is located at #{config_append_path}/#{config.filename}#{config.extname})"
77
+ exit 1
78
+ end
79
+
80
+ end
81
+ end
82
+
83
+ class Send < Dry::CLI::Command
84
+ desc "Send a song's lyrics, line by line, to one or more recipients (default task when running lyricsender without any arguments/options)"
85
+ option :search, desc: "Which song/search query to look up on Genius (optional)"
86
+ option :song, desc: "Which search result to accept from Genius; must be in the form 'Song Name - Artist' (optional)"
87
+ option :to, desc: "The song's recipient — phone number or email (optional)"
88
+ option :delay, desc: "If set to 'true', lyricsender will prompt for approval between sending each line; if set to an integer, seconds to wait between sending each message; if set to 'false' (the default), it won't delay between messages (optional)"
89
+ option :yes, desc: "Send messages without prompting for approval at the beginning (also optional)", type: :boolean, default: false
90
+
91
+ def call(**options)
92
+
93
+ ### warning - This part is duplicated and I cannot figure out how to fix it
94
+ # Supports https://no-color.org
95
+ env_no_color = false if ENV['NO_COLOR']
96
+
97
+ pastel = Pastel.new(enabled: env_no_color)
98
+ config = TTY::Config.new
99
+ prompt = TTY::Prompt.new(enable_color: env_no_color)
100
+
101
+ config.filename = "lyricsender"
102
+ config.extname = ".toml"
103
+ config_append_path = "#{Dir.home}/.config"
104
+ config.append_path config_append_path
105
+
106
+ unless OS.mac?
107
+ puts
108
+ print pastel.bold.red "(!) Note: only macOS is supported"
109
+ puts pastel.red " (this uses iMessage and AppleScript)."
110
+ if prompt.yes? "Continue anyway?"
111
+ nil
112
+ else
113
+ exit 1
114
+ end
115
+ end
116
+ ### end duplicated part
117
+
118
+ unless config.exist?
119
+ puts pastel.red "Oops, you need to run the setup command first"
120
+ puts pastel.red "(this script requires an access key from Genius)"
121
+ puts pastel.bold.red "Try running `lyricsender setup`. Thanks!"
122
+ exit 1
123
+ end
124
+
125
+ Genius.access_token = config.read["token"]
126
+
127
+ begin
128
+ search = options.fetch(:search)
129
+ rescue
130
+ search = prompt.ask("#{pastel.bold "→ Search for a song…"}", convert: :str, required: true)
131
+ end
132
+
133
+ songs = Genius::Song.search search
134
+ songs_list = Hash.new
135
+ songs.each do |song|
136
+ songs_list["#{song.title} - #{song.primary_artist.name}"] = song.url
137
+ end
138
+
139
+ begin
140
+ song = options.fetch(:song)
141
+ rescue
142
+ nil
143
+ end
144
+
145
+ unless song
146
+ song = prompt.select("#{pastel.bold "→ Please choose a song:"}", songs_list.keys)
147
+ end
148
+ song_url = songs_list[song]
149
+
150
+ begin
151
+ to = options.fetch(:to).split(" ")
152
+ rescue
153
+ to = prompt.ask("#{pastel.bold "→ Please enter one or more recipients"} (phone numbers or email addresses), separated by commas…", convert: :array, required: true)
154
+ end
155
+
156
+ begin
157
+ delay = options.fetch(:delay)
158
+ rescue
159
+ choices = {"no delay between messages": false, "prompt between sending messages": true, "choose a time to delay": nil}
160
+ delay = prompt.select("#{pastel.bold "→ Would you like to wait between sending messages?"}", choices)
161
+ if delay.nil?
162
+ delay = prompt.ask("#{pastel.bold "→ How many seconds would you like to wait between messages?"}", convert: :int, required: true)
163
+ end
164
+ end
165
+
166
+ doc = Nokogiri::HTML(URI.open(song_url.to_s))
167
+ lyrics = Array.new
168
+ doc.css('div[class^="Lyrics__Container-"], div[class*=" Lyrics__Container-"]').each do |match|
169
+ # The following line removes newlines and the lines that are like [Intro] and [Verse 1] etc
170
+ lyric_block = Nokogiri::HTML(match.to_s.gsub("<br>", "\n").gsub(/\[.*\]$/i, "").gsub("[Intro]", "")).content.gsub(/\n+|\r+/, "\n").squeeze("\n").strip
171
+ lyric_block.each_line do |line|
172
+ lyrics << line
173
+ end
174
+ end
175
+
176
+ if lyrics.length == 0
177
+ puts pastel.red "The song you chose appears to be empty…"
178
+ exit 1
179
+ end
180
+
181
+ begin
182
+ yes = options.fetch(:yes)
183
+ rescue
184
+ yes = false
185
+ end
186
+
187
+ unless yes
188
+ puts pastel.italic.dim "Here's what will be sent:"
189
+ lyrics.each do |line|
190
+ puts " #{line}"
191
+ end
192
+ yes = prompt.yes? "#{pastel.bold "→ Send"} #{pastel.underline.bold song} #{pastel.bold "to"} #{pastel.underline.bold to.join(",")} (#{lyrics.length} messages)?"
193
+ end
194
+
195
+ if yes
196
+ sender = Imessage::Sender.new
197
+ counter = 0
198
+ bar = TTY::ProgressBar.new("sending… [:bar] :current/:total • :eta", total: lyrics.length, bar_format: :box, clear: true) unless delay == true
199
+ lyrics.each_with_index do |line, index|
200
+ send_line = true
201
+ if delay == true
202
+ if prompt.yes? "(#{index + 1}/#{lyrics.length}) Send line #{pastel.italic line.strip}?"
203
+ nil
204
+ else
205
+ send_line = false
206
+ print pastel.bold.red "Line not sent"
207
+ puts pastel.red " (continuing to next line)"
208
+ end
209
+ elsif delay.is_a? Integer
210
+ sleep delay
211
+ end
212
+ if send_line
213
+ sender.deliver({
214
+ # The gsub below replaces single quotes like those in contractions with '"'"' because the iMessage gem shells out to `oascript` to send messages and the single quotes otherwise mess up that part ('"'"' is interpreted as just ')
215
+ text: line.gsub('\'', '\'"\'"\'').strip,
216
+ contacts: to
217
+ })
218
+ counter += 1
219
+ bar.advance if bar
220
+ end
221
+ end
222
+ print pastel.bold.green "Success"
223
+ puts pastel.green " (probably)! #{counter} messages sent."
224
+ else
225
+ puts pastel.bold.italic.red "Messages not sent."
226
+ exit 1
227
+ end
228
+ end
229
+
230
+ end
231
+
232
+ register "version", Version, aliases: ["v", "-v", "--version"]
233
+ register "setup", Setup
234
+ register "send", Send
235
+
236
+ end
237
+ end
238
+ end
239
+
240
+ # Sets "send" to be the default command, basically
241
+ if ARGV.empty?
242
+ ARGV << "send"
243
+ end
244
+
245
+ Dry::CLI.new(Lyricsender::CLI::Commands).call
metadata ADDED
@@ -0,0 +1,191 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lyricsender
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jack MapelLentz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-07-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-cli
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.7.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.7.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: os
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 1.1.1
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.1'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.1.1
47
+ - !ruby/object:Gem::Dependency
48
+ name: imessage
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 0.3.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.3.1
61
+ - !ruby/object:Gem::Dependency
62
+ name: tty-config
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 0.5.0
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 0.5.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: toml
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 0.3.0
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 0.3.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: tty-progressbar
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 0.18.2
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 0.18.2
103
+ - !ruby/object:Gem::Dependency
104
+ name: tty-prompt
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: 0.23.1
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: 0.23.1
117
+ - !ruby/object:Gem::Dependency
118
+ name: genius_fixed
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: 0.1.2
124
+ type: :runtime
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: 0.1.2
131
+ - !ruby/object:Gem::Dependency
132
+ name: launchy
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '2.5'
138
+ type: :runtime
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '2.5'
145
+ - !ruby/object:Gem::Dependency
146
+ name: nokogiri
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '1.11'
152
+ type: :runtime
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '1.11'
159
+ description: This gem is a CLI that uses the Genius API and web scraping to rapid-fire
160
+ send your friends the lyrics to a song. Which is not at all annoying.
161
+ email:
162
+ executables:
163
+ - lyricsender
164
+ extensions: []
165
+ extra_rdoc_files: []
166
+ files:
167
+ - bin/lyricsender
168
+ homepage: https://github.com/jltml/lyricsender
169
+ licenses:
170
+ - MIT
171
+ metadata: {}
172
+ post_install_message:
173
+ rdoc_options: []
174
+ require_paths:
175
+ - lib
176
+ required_ruby_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ required_rubygems_version: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ requirements: []
187
+ rubygems_version: 3.0.3
188
+ signing_key:
189
+ specification_version: 4
190
+ summary: Send lyrics, line-by-line, using iMessage
191
+ test_files: []