lyricsender 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []