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.
- checksums.yaml +7 -0
- data/bin/lyricsender +245 -0
- 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: []
|