number_station 0.2.0 → 0.4.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: 9ffaf0a85087f356cdd5227039ec8731ff0a89d9cdf7e2a5020bb53cc0be74a6
4
- data.tar.gz: 88c9c3a558e45684db5f85e0bf32c02ab55b026f146b6b5d2c2816fa6d01f21c
3
+ metadata.gz: 28bb32733b0cc2c4dd9a9258985a762e6cf558b9ec3a05d7438a5d4b53332dfe
4
+ data.tar.gz: dc4f7d34bd69879eb4eda6ac0774f2fa20c65433d6d841a98a7f97968562daf8
5
5
  SHA512:
6
- metadata.gz: a7757a314e15e2fda90ec3689ff63fa45e93a1e0e840c3c3c1a8e8313bb86a6b98acfa464f6ad2c3ed8f15dfbc4f26433fc8bdd2c0ee7795266bd177a81d9632
7
- data.tar.gz: 9e7885c467a9804e10ae8d478e4ee8d5253c999e8e9fdbc6fef0c632ee182689c48a7184e9897f6245182d38b3e66335f1214dfc33874bb159e55c61d1a025d0
6
+ metadata.gz: a86c1b266dd7d5837bf99d1eafecb545fe36ebb86649013dee3bb9a5cff9d507021f257c8595452a0a0f2c91a96cbb579769cadf0245f3983bf9f31371e82891
7
+ data.tar.gz: a8be3d5d110b854ac1254c9fdfb38b062dbb7fbbdbc828617c7c63fdfc40426627a6d1f086c772dfe6c6360a4a88f9eefdaea111d0ec1e6d7e98c53d308d236d
data/README.asciidoc CHANGED
@@ -1,8 +1,143 @@
1
1
  == number_station ==
2
- This gem (WIP) contains a number of utilities to aid in the running of a number station.
2
+
3
+ This gem contains utilities to aid in the running of a number station.
3
4
 
4
5
  image:https://badge.fury.io/rb/number_station.svg["Gem Version", link="https://badge.fury.io/rb/number_station"]
5
6
 
7
+ === Installation ===
8
+
9
+ [source,bash]
10
+ ----
11
+ gem install number_station
12
+ ----
13
+
14
+ === Usage ===
15
+
16
+ ==== Configuration ====
17
+
18
+ Create the initial configuration:
19
+
20
+ [source,bash]
21
+ ----
22
+ number_station create_config
23
+ ----
24
+
25
+ This creates `~/number_station/conf.yaml` and copies template files (`intro_message.txt`, `outro_message.txt`, `repeat_message.txt`) to the same directory.
26
+
27
+ ==== Agent Management ====
28
+
29
+ Manage agents using the `agents` subcommand:
30
+
31
+ *Create an agent:*
32
+
33
+ [source,bash]
34
+ ----
35
+ number_station agents create NAME [--location LOCATION] [--handler HANDLER]
36
+ ----
37
+
38
+ *Activate/Deactivate:*
39
+
40
+ [source,bash]
41
+ ----
42
+ number_station agents activate NAME [--start-date DATE]
43
+ number_station agents deactivate NAME [--end-date DATE]
44
+ ----
45
+
46
+ *Update handler codeword:*
47
+
48
+ [source,bash]
49
+ ----
50
+ number_station agents update-handler NAME HANDLER
51
+ ----
52
+
53
+ *View agents:*
54
+
55
+ [source,bash]
56
+ ----
57
+ number_station agents list # Active agents only
58
+ number_station agents list-all # All agents with history
59
+ number_station agents stats # Detailed statistics
60
+ ----
61
+
62
+ ==== One-Time Pads ====
63
+
64
+ *Create pads:*
65
+
66
+ [source,bash]
67
+ ----
68
+ number_station pad create [--name AGENT] [--numpads NUM] [--length LENGTH]
69
+ ----
70
+
71
+ If `--name` is provided, creates pad in `~/number_station/pads/AGENT/` directory.
72
+ Defaults: 500 pads, 500 characters (rounded up to nearest multiple of 5).
73
+
74
+ *View pad statistics:*
75
+
76
+ [source,bash]
77
+ ----
78
+ number_station pad stats [--path PATH]
79
+ ----
80
+
81
+ Shows pad statistics grouped by agent, including unconsumed pad counts.
82
+
83
+ ==== Message Encryption/Decryption ====
84
+
85
+ *Encrypt:*
86
+
87
+ [source,bash]
88
+ ----
89
+ number_station encrypt [MESSAGE] [--file FILE] [--agent AGENT] [--padpath PADPATH] [--numpad NUMPAD]
90
+ ----
91
+
92
+ If `--agent` is provided, searches for oldest pad in agent-specific directory.
93
+ Only active agents can encrypt messages.
94
+
95
+ *Decrypt:*
96
+
97
+ [source,bash]
98
+ ----
99
+ number_station decrypt [MESSAGE] [--file FILE] [--padpath PADPATH] [--numpad NUMPAD]
100
+ ----
101
+
102
+ ==== Phonetic Conversion ====
103
+
104
+ *Convert to phonetic:*
105
+
106
+ [source,bash]
107
+ ----
108
+ number_station convert_to_phonetic FILE [--intro INTRO_FILE] [--outro OUTRO_FILE] [--repeat REPEAT_FILE]
109
+ ----
110
+
111
+ Converts encrypted message to phonetic alphabet. Output saved as `FILENAME_phonetic.txt`.
112
+ Intro, outro, and repeat messages are included as-is (not converted).
113
+
114
+ *Convert to espeak XML:*
115
+
116
+ [source,bash]
117
+ ----
118
+ number_station convert_to_espeak PHONETIC_FILE
119
+ ----
120
+
121
+ Generates GLaDOS-style espeak XML file. Output saved as `FILENAME.xml`.
122
+
123
+ *Generate MP3:*
124
+
125
+ [source,bash]
126
+ ----
127
+ number_station convert_to_mp3 XML_FILE
128
+ ----
129
+
130
+ Converts XML to MP3 using espeak and ffmpeg. Output saved as `FILENAME.mp3`.
131
+
132
+ *Play audio:*
133
+
134
+ [source,bash]
135
+ ----
136
+ number_station espeak XML_FILE
137
+ ----
138
+
139
+ Plays the XML file using espeak with GLaDOS voice settings.
140
+
6
141
  === Contributing ===
7
142
  Contributions are welcome, please fork the repo, create a branch, add your code, and make a PR
8
143
  against master on this repo. For more information see _CONTRIBUTING.asciidoc_
@@ -14,5 +149,3 @@ file.
14
149
  === Number Station Resources ===
15
150
 
16
151
  - https://linuxcoffee.com/numbers/
17
- - http://users.telenet.be/d.rijmenants/en/onetimepad.htm
18
- - https://www.numbers-stations.com/
data/Rakefile CHANGED
@@ -21,20 +21,74 @@
21
21
 
22
22
  require 'bundler'
23
23
  require 'fileutils'
24
+
25
+ # Ensure we load from local lib directory, not installed gem
26
+ # This must happen before requiring number_station/version
27
+ lib = File.expand_path('lib', __FILE__)
28
+ # Remove gem paths that might interfere
29
+ gem_paths = $LOAD_PATH.select { |p| p.include?('gems') && p.include?('number_station') }
30
+ gem_paths.each { |p| $LOAD_PATH.delete(p) }
31
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
32
+
33
+ # Load version from local source
34
+ require_relative 'lib/number_station/version'
35
+
24
36
  Bundler::GemHelper.install_tasks
25
37
 
26
38
  task :default => :menu
27
39
 
40
+ desc "Show available rake tasks"
28
41
  task :menu do
29
- puts welcomeMsg = <<-MSG
30
- rake build # Build number_station-x.x.x.gem into the pkg directory
31
- rake install # Build and install number_station-x.x.x.gem into system gems
32
- rake release # Create tag vx.x.x and build and push number_station-x.x.x.gem to http://rubygems.org/
42
+ puts <<-MSG
43
+ Available tasks:
44
+
45
+ rake build # Build number_station-x.x.x.gem into the pkg directory
46
+ rake install # Build and install number_station-x.x.x.gem into system gems
47
+ rake release # Create tag vx.x.x and build and push number_station-x.x.x.gem to http://rubygems.org/
48
+ rake clean # Clean up build artifacts (.gem files and pkg directory)
49
+ rake version # Show the current version
50
+ rake validate # Validate the gemspec
51
+ rake console # Start an interactive console with the gem loaded
52
+
33
53
  MSG
34
54
  end
35
55
 
36
56
  desc "Clean up build artifacts"
37
57
  task :clean do
38
58
  FileUtils.rm_rf("./pkg/")
59
+ FileUtils.rm_f(Dir.glob("*.gem"))
60
+ puts "Cleaned build artifacts"
61
+ end
62
+
63
+ desc "Show the current version"
64
+ task :version do
65
+ puts "number_station version: #{NumberStation::VERSION}"
66
+ end
67
+
68
+ desc "Validate the gemspec"
69
+ task :validate do
70
+ require 'rubygems/specification'
71
+
72
+ begin
73
+ spec = Gem::Specification.load('number_station.gemspec')
74
+ puts "✓ Gemspec is valid"
75
+ puts " Name: #{spec.name}"
76
+ puts " Version: #{spec.version}"
77
+ puts " Dependencies: #{spec.dependencies.map(&:name).join(', ')}"
78
+ rescue => e
79
+ puts "✗ Gemspec validation failed: #{e.message}"
80
+ exit 1
81
+ end
39
82
  end
40
83
 
84
+ desc "Start an interactive console"
85
+ task :console do
86
+ require 'irb'
87
+ require 'number_station'
88
+ ARGV.clear
89
+ IRB.start
90
+ end
91
+
92
+ # Clean before building
93
+ task :build => :clean
94
+
@@ -1,36 +1,79 @@
1
- def template(word)
2
- sign = randomsign() || ""
3
- return "<prosody pitch=\"#{sign + rand(0..80).to_s}\">#{word}</prosody>"
4
- end
1
+ =begin
2
+ Ruby Number Station
3
+ Author: David Kirwan https://gitub.com/davidkirwan
4
+ Licence: GPL 3.0
5
+ NumberStation is a collection of utilities to aid in the running of a number station
6
+ Copyright (C) 2018 David Kirwan
5
7
 
6
- def randomsign()
7
- rnum = rand(0..1)
8
+ This program is free software: you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation, either version 3 of the License, or
11
+ (at your option) any later version.
8
12
 
9
- if rnum == 0
10
- return "-"
11
- else
12
- return "+"
13
- end
14
- end
13
+ This program is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
15
17
 
18
+ You should have received a copy of the GNU General Public License
19
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
20
+ =end
16
21
 
17
- message = "This was a triumph! I'm making a note here, huge success."
22
+ module NumberStation
23
+ def self.generate_glados_espeak(input_file_path)
24
+ # Read message from file
25
+ message = File.read(input_file_path)
26
+
27
+ # Generate output filename: remove .txt extension and append .xml
28
+ input_basename = File.basename(input_file_path, File.extname(input_file_path))
29
+ output_filename = "#{input_basename}.xml"
30
+ output_path = File.join(File.dirname(input_file_path), output_filename)
31
+
32
+ # Process message into GLaDOS-style XML
33
+ # Split by whitespace but preserve the structure - handle spaces and newlines
34
+ # Split on whitespace boundaries but keep track of what was between words
35
+ sentence = "<speak version=\"1.0\" xmlns=\"\" xmlns:xsi=\"\" xsi:schemaLocation=\"\" xml:lang=\"\"><voice gender=\"female\">"
36
+ sentenceend = "</voice></speak>"
18
37
 
19
- words = message.split(" ")
20
- sentence = "<speak version=\"1.0\" xmlns=\"\" xmlns:xsi=\"\" xsi:schemaLocation=\"\" xml:lang=\"\"><voice gender=\"female\">"
21
- sentenceend = "</voice></speak>"
38
+ # Split message into words, preserving spacing structure
39
+ # Use a regex that captures words and the whitespace after them
40
+ parts = message.split(/(\s+)/)
41
+
42
+ parts.each do |part|
43
+ if part.match?(/^\s+$/)
44
+ # This is whitespace - preserve it (spaces or newlines)
45
+ sentence += part
46
+ elsif !part.empty?
47
+ # This is a word - wrap it in prosody tags
48
+ sentence += template(part)
49
+ end
50
+ end
22
51
 
23
- words.each do |i|
24
- sentence += template(i)
25
- end
52
+ final = sentence + sentenceend
26
53
 
27
- final = sentence + sentenceend
54
+ # Write XML file
55
+ File.write(output_path, final)
56
+ if NumberStation.respond_to?(:log) && NumberStation.log
57
+ NumberStation.log.info "Generated GLaDOS espeak XML: #{output_path}"
58
+ end
59
+
60
+ output_path
61
+ end
28
62
 
63
+ private
29
64
 
30
- filename = "GLaDOS_espeak_config.xml"
31
- f = File.open(filename, "w")
32
- f.write(final)
33
- f.close
65
+ def self.template(word)
66
+ sign = randomsign() || ""
67
+ "<prosody pitch=\"#{sign + rand(0..80).to_s}\">#{word}</prosody>"
68
+ end
69
+
70
+ def self.randomsign()
71
+ rnum = rand(0..1)
34
72
 
35
- cmd = "espeak -ven+f3 -m -p 60 -s 180 -f #{filename}"
36
- `#{cmd}`
73
+ if rnum == 0
74
+ return "-"
75
+ else
76
+ return "+"
77
+ end
78
+ end
79
+ end