cuegrowler 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/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +35 -0
- data/Rakefile +2 -0
- data/bin/cuegrowler +5 -0
- data/cuegrowler.gemspec +27 -0
- data/lib/cuegrowler.rb +171 -0
- data/lib/cuegrowler/version.rb +3 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5e72d27fdece7f08e2f64deaf3ae1882ca45871f
|
4
|
+
data.tar.gz: 07029311faa3c698b1c18f3059948de6eb9f0d74
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5ea399e1686df230920e4543f68d9edd4571f03173e323c0bf5b506d64335d41cff69d9f3d50092a0d77971df0aa16651684d76839990e97a68af20cbb709fdb
|
7
|
+
data.tar.gz: ec0c2af26a3a69a91a3fd17621d5093d28f7e8e6bf31113e170ed6c38dc71f1697d584a766115a083bddc24ffa8b9369fefedb11e6fe065db695c106fea5d3e7
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Thai Pangsakulyanont
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Cuegrowler
|
2
|
+
|
3
|
+
Displays a Growl notification when a song changes in a mix.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
gem install cuegrowler
|
9
|
+
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
|
14
|
+
### Using .cue Files
|
15
|
+
|
16
|
+
cuegrowler <path to .cue file>
|
17
|
+
|
18
|
+
|
19
|
+
### Using Description in iTunes
|
20
|
+
|
21
|
+
Some podcasts include the tracklist in form of [HH:MM:SS].
|
22
|
+
`cuegrowler` can parse the tracklist from that too.
|
23
|
+
Just
|
24
|
+
|
25
|
+
cuegrowler
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
1. Fork it ( https://github.com/[my-github-username]/cuegrowler/fork )
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/cuegrowler
ADDED
data/cuegrowler.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cuegrowler/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cuegrowler"
|
8
|
+
spec.version = Cuegrowler::VERSION
|
9
|
+
spec.authors = ["Thai Pangsakulyanont"]
|
10
|
+
spec.email = ["org.yi.dttvb@gmail.com"]
|
11
|
+
spec.summary = %q{Growl the current track using a cuesheet.}
|
12
|
+
spec.description = %q{Growl the current track using a cuesheet.}
|
13
|
+
spec.homepage = "https://github.com/dtinth/cuegrowler"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_runtime_dependency "rubycue"
|
24
|
+
spec.add_runtime_dependency "docopt"
|
25
|
+
spec.add_runtime_dependency "osaka"
|
26
|
+
spec.add_runtime_dependency "growl"
|
27
|
+
end
|
data/lib/cuegrowler.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'cuegrowler/version'
|
2
|
+
require 'rubycue'
|
3
|
+
require 'osaka'
|
4
|
+
require 'growl'
|
5
|
+
require 'open-uri'
|
6
|
+
|
7
|
+
module Cuegrowler
|
8
|
+
|
9
|
+
class ITunes
|
10
|
+
|
11
|
+
def self.get_player_position
|
12
|
+
Osaka::ScriptRunner.execute(%q(tell application "iTunes" to get the player position)).to_f
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get_track_description
|
16
|
+
Osaka::ScriptRunner.execute(%q(tell application "iTunes" to get the current track's long description))
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
module Tracklist
|
22
|
+
|
23
|
+
class ITunes
|
24
|
+
|
25
|
+
def get
|
26
|
+
parse_tracklist(Cuegrowler::ITunes.get_track_description)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
"From iTunes description"
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
def parse_tracklist(description)
|
35
|
+
description.lines.map(&:strip)
|
36
|
+
.map { |line| [line, line.match(/\[(\d+):(\d+):(\d+)\]/)] }
|
37
|
+
.reject { |text, match| match.nil? }
|
38
|
+
.map { |text, match| { text: text, time: tracklist_match_to_time(match) } }
|
39
|
+
end
|
40
|
+
|
41
|
+
def tracklist_match_to_time(m)
|
42
|
+
m[1].to_f * 3600 + m[2].to_f * 60 + m[3].to_f
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
class Cuesheet
|
48
|
+
|
49
|
+
def initialize(filename)
|
50
|
+
|
51
|
+
@filename = filename
|
52
|
+
@data = []
|
53
|
+
|
54
|
+
cuesheet = RubyCue::Cuesheet.new(open(filename).read)
|
55
|
+
cuesheet.parse!
|
56
|
+
|
57
|
+
cuesheet.songs.each_with_index do |song, index|
|
58
|
+
time = song[:index].to_f
|
59
|
+
text = "#{index + 1}. #{format time} #{song[:performer]} — #{song[:title]}"
|
60
|
+
@data << { text: text, time: time }
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
def get
|
66
|
+
@data
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
"From cuesheet #{@filename}"
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def format(time)
|
75
|
+
hours, time = time.divmod(3600)
|
76
|
+
minutes, seconds = time.divmod(60)
|
77
|
+
"[%d:%02d:%02d]" % [hours, minutes, seconds]
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
class Growler
|
85
|
+
|
86
|
+
def initialize(player, tracklist)
|
87
|
+
@current_position = -Float::INFINITY
|
88
|
+
@player = player
|
89
|
+
@tracklist = tracklist
|
90
|
+
end
|
91
|
+
|
92
|
+
def loop_forever!
|
93
|
+
loop do
|
94
|
+
tick
|
95
|
+
sleep 2
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def tick
|
100
|
+
update_position
|
101
|
+
tracklist = @tracklist.get
|
102
|
+
new_song = tracklist.reverse.find { |track|
|
103
|
+
@last_position < track[:time] && track[:time] <= @current_position }
|
104
|
+
notify(new_song) if new_song
|
105
|
+
end
|
106
|
+
|
107
|
+
protected
|
108
|
+
|
109
|
+
def update_position
|
110
|
+
@last_position = @current_position
|
111
|
+
@current_position = @player.get_player_position
|
112
|
+
end
|
113
|
+
|
114
|
+
def notify(new_song)
|
115
|
+
Growl.notify new_song[:text], name: 'cuegrowler', title: 'New Track'
|
116
|
+
puts "\n[#{Time.now}]"
|
117
|
+
puts new_song[:text]
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
class << self
|
123
|
+
|
124
|
+
def start(filename=nil)
|
125
|
+
|
126
|
+
player = ITunes
|
127
|
+
|
128
|
+
tracklist = if filename
|
129
|
+
Tracklist::Cuesheet.new(filename)
|
130
|
+
else
|
131
|
+
Tracklist::ITunes.new
|
132
|
+
end
|
133
|
+
|
134
|
+
puts "\n== Cuegrowler is running! =="
|
135
|
+
puts "Player: #{player}"
|
136
|
+
puts "Tracklist: #{tracklist}"
|
137
|
+
Growler.new(player, tracklist).loop_forever!
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
def main
|
142
|
+
|
143
|
+
require 'docopt'
|
144
|
+
|
145
|
+
doc = <<DOCOPT
|
146
|
+
Displays Growl notifications from .cue files based on current time in iTunes.
|
147
|
+
|
148
|
+
Usage:
|
149
|
+
cuegrowler [<filename>]
|
150
|
+
cuegrowler -h | --help
|
151
|
+
|
152
|
+
Options:
|
153
|
+
-h, --help Shows this screen.
|
154
|
+
<filename> The .cue filename. If specified, cuegrowler will read the
|
155
|
+
tracklist from this file. Otherwise, the tracklist is parsed
|
156
|
+
from the current podcast episode's descriptions.
|
157
|
+
DOCOPT
|
158
|
+
|
159
|
+
opts = Docopt::docopt(doc)
|
160
|
+
|
161
|
+
start opts["<filename>"]
|
162
|
+
|
163
|
+
rescue Docopt::Exit => e
|
164
|
+
|
165
|
+
puts e.message
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cuegrowler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thai Pangsakulyanont
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubycue
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: docopt
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: osaka
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: growl
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Growl the current track using a cuesheet.
|
98
|
+
email:
|
99
|
+
- org.yi.dttvb@gmail.com
|
100
|
+
executables:
|
101
|
+
- cuegrowler
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- ".gitignore"
|
106
|
+
- Gemfile
|
107
|
+
- LICENSE.txt
|
108
|
+
- README.md
|
109
|
+
- Rakefile
|
110
|
+
- bin/cuegrowler
|
111
|
+
- cuegrowler.gemspec
|
112
|
+
- lib/cuegrowler.rb
|
113
|
+
- lib/cuegrowler/version.rb
|
114
|
+
homepage: https://github.com/dtinth/cuegrowler
|
115
|
+
licenses:
|
116
|
+
- MIT
|
117
|
+
metadata: {}
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 2.2.2
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Growl the current track using a cuesheet.
|
138
|
+
test_files: []
|