pr2gpx 0.1.2 → 0.2.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.
- data/README.md +8 -4
- data/lib/pr2gpx.rb +13 -6
- data/lib/pr2gpx/options.rb +6 -6
- data/lib/pr2gpx/parser.rb +31 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -1,18 +1,22 @@
|
|
1
1
|
pr2gpx
|
2
2
|
======
|
3
3
|
|
4
|
-
Converts Winlink position reports
|
4
|
+
Converts Winlink position reports into GPX tracks or waypoints.
|
5
5
|
|
6
|
-
|
6
|
+
pr2gpx understands position report data downloaded as RSS documents from the [Winlink 2000](http://www.winlink.org/) website using this Url:
|
7
|
+
|
8
|
+
http://www.winlink.org/dotnet/maps/RSSPositionReports.aspx?callsign=[callsign]
|
9
|
+
|
10
|
+
It also understands the information contained in messages sent or received with the [AirMail](http://siriuscyber.net/airmail/) client program:
|
7
11
|
- sent position reports (Window->Winlink-2000->Position Report)
|
8
12
|
- reports requested for specific stations (Window->Winlink-2000->Position Request)
|
9
13
|
- lists of nearby stations (Window->Catalogs->WL2K->Global->WL2K_USERS->WL2K_NEARBY)
|
10
14
|
|
11
|
-
pr2gpx
|
15
|
+
pr2gpx can either be given one file to parse, or it can scan all files in a directory. It can filter the data to include only stations with a given callsign, and limit the results to the last N reports per station.
|
12
16
|
|
13
17
|
The output is either one track for each station, a list of waypoints for every position report, or both.
|
14
18
|
|
15
|
-
|
19
|
+
The results can either be saved into a single file containing everything, or it can be split into one file for each station.
|
16
20
|
|
17
21
|
|
18
22
|
Installing
|
data/lib/pr2gpx.rb
CHANGED
@@ -9,9 +9,11 @@ def enumerate_files search_path
|
|
9
9
|
Dir
|
10
10
|
.glob(search_path)
|
11
11
|
.each do |filename|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
if File.file?(filename)
|
13
|
+
$stderr.puts "Reading #{filename}" if $verbose
|
14
|
+
File.open filename do |file|
|
15
|
+
e.yield file.read()
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end
|
@@ -77,11 +79,16 @@ end
|
|
77
79
|
options[:input].gsub!('\\', '/')
|
78
80
|
options[:output].gsub!('\\', '/') if options[:output]
|
79
81
|
|
80
|
-
search_path = "#{options[:input]}/#{options[:recurse] ? '**/' : ''}*.*"
|
81
|
-
$stderr.puts "Searching #{search_path}" if $verbose
|
82
|
-
|
83
82
|
filter = ReportFilter.new options[:callsign]
|
84
83
|
|
84
|
+
search_path = if File.directory?(options[:input])
|
85
|
+
"#{options[:input]}/#{options[:recurse] ? '**/' : ''}*.*"
|
86
|
+
else
|
87
|
+
options[:input]
|
88
|
+
end
|
89
|
+
|
90
|
+
$stderr.puts "Searching #{search_path}" if $verbose
|
91
|
+
|
85
92
|
stations = load_data(enumerate_files(search_path), filter)
|
86
93
|
filter_data! stations, options[:last]
|
87
94
|
|
data/lib/pr2gpx/options.rb
CHANGED
@@ -104,8 +104,6 @@ def validate_options options
|
|
104
104
|
|
105
105
|
if not File.exists?(options[:input])
|
106
106
|
errors << 'Path specified in --input does not exist.'
|
107
|
-
elsif not File.directory?(options[:input])
|
108
|
-
errors << 'Path specified in --input is not a directory.'
|
109
107
|
end
|
110
108
|
|
111
109
|
if options[:split]
|
@@ -115,10 +113,12 @@ def validate_options options
|
|
115
113
|
errors << 'Path specified in --output is not a directory.'
|
116
114
|
end
|
117
115
|
else
|
118
|
-
if
|
119
|
-
|
120
|
-
|
121
|
-
|
116
|
+
if options[:output]
|
117
|
+
if not File.exists?(File.dirname(options[:output]))
|
118
|
+
errors << 'Path specified in --output does not exist.'
|
119
|
+
elsif File.directory?(options[:output])
|
120
|
+
errors << 'Path specified in --output is a directory.'
|
121
|
+
end
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
data/lib/pr2gpx/parser.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'date'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'nokogiri/xml'
|
2
4
|
|
3
5
|
PositionReport = Struct.new "PositionReport", :callsign, :date, :position, :comment
|
4
6
|
|
@@ -24,7 +26,7 @@ end
|
|
24
26
|
|
25
27
|
class ReportParser
|
26
28
|
def initialize
|
27
|
-
@parsers = [NearbyStationsParser.new, ReportsListParser.new, OutboundReportParser.new]
|
29
|
+
@parsers = [NearbyStationsParser.new, ReportsListParser.new, OutboundReportParser.new, RSSParser.new]
|
28
30
|
end
|
29
31
|
|
30
32
|
def parse input
|
@@ -108,6 +110,34 @@ class NearbyStationsParser
|
|
108
110
|
end
|
109
111
|
end
|
110
112
|
|
113
|
+
class RSSParser
|
114
|
+
def can_parse? input
|
115
|
+
/<rss version="2\.0">/ =~ input
|
116
|
+
end
|
117
|
+
|
118
|
+
def parse input
|
119
|
+
Enumerator.new do |e|
|
120
|
+
xml = Nokogiri::XML(input)
|
121
|
+
xml.xpath('//item').each do |item|
|
122
|
+
%r{^
|
123
|
+
Position[ ]report[ ]for[ ]
|
124
|
+
(?<callsign>[^ ]*)
|
125
|
+
[ ]is[ ]
|
126
|
+
(?<latitude>[^ ]*)
|
127
|
+
[ ]/[ ]
|
128
|
+
(?<longitude>[^ ]*)
|
129
|
+
}x =~ item.xpath('title').first.content
|
130
|
+
comment = item.xpath('description').first.content
|
131
|
+
date = DateTime.parse(item.xpath('pubDate').first.content)
|
132
|
+
e.yield PositionReport.new callsign,
|
133
|
+
date,
|
134
|
+
Position.new(latitude, longitude),
|
135
|
+
comment
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
111
141
|
class ReportFilter
|
112
142
|
def initialize callsigns
|
113
143
|
@callsigns = callsigns
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pr2gpx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|