ruby-freedb 0.6

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ac0470c2d99f0522088f36660bbc98a407674bea
4
+ data.tar.gz: 05b89f019dfa43587b5c49a82f59e83db746e859
5
+ SHA512:
6
+ metadata.gz: d779275beaf433f832ac0af4fb6bb531cbd36fa0da8fc4a6882ab7d37ff0eac1a9f43e15ef7f90170a3d5b7860ed9dad6902edc75712e7aa3ade66bad3255f90
7
+ data.tar.gz: 1987cfe6889b95dac68a282e3799040741425a003b55496e148856a75a273928314062e1da233bf65cd82bc8334f81e71fec01915990485ecc3ed788b2dc433e
@@ -0,0 +1,9 @@
1
+ require 'mkmf'
2
+
3
+ printf("checking for OS... ")
4
+ STDOUT.flush
5
+ os = /-([a-z]+)[0-9]*.*/.match(RUBY_PLATFORM)[1]
6
+ puts(os)
7
+ $CFLAGS += " -DOS_#{os.upcase}"
8
+ create_makefile("freedb_cdrom/freedb_cdrom")
9
+ #with_config(debug)
@@ -0,0 +1,207 @@
1
+ /* $Id: freedb_cdrom.c,v 1.5 2003/02/07 14:16:16 moumar Exp $ */
2
+ /*
3
+ * Copyright (c) 1999,2001 Robert Woodcock <rcw@debian.org>
4
+ * This code is hereby licensed for public consumption under either the
5
+ * GNU GPL v2 or greater, or Larry Wall's Artistic license - your choice.
6
+
7
+ * You should have received a copy of the GNU General Public License
8
+ * along with this program; if not, write to the Free Software
9
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
10
+ */
11
+ #include <stdio.h>
12
+ #include <stdlib.h>
13
+ #include <fcntl.h>
14
+ #include <sys/ioctl.h>
15
+ #include <unistd.h>
16
+
17
+ #include <ruby.h>
18
+
19
+ /* Porting credits:
20
+ * Solaris: David Champion <dgc@uchicago.edu>
21
+ * FreeBSD: Niels Bakker <niels@bakker.net>
22
+ * OpenBSD: Marcus Daniel <danielm@uni-muenster.de>
23
+ * NetBSD: Chris Gilbert <chris@NetBSD.org>
24
+ */
25
+
26
+ /* Modified for ruby/freedb by Guillaume Pierronnet <moumar@netcourrier.com> */
27
+
28
+ #if defined(OS_LINUX)
29
+ # include <linux/cdrom.h>
30
+
31
+ #elif defined(OS_SOLARIS)
32
+ # include <sys/cdio.h>
33
+ # define CD_MSF_OFFSET 150
34
+ # define CD_FRAMES 75
35
+
36
+ #elif defined(OS_FREEBSD)
37
+ #include <sys/cdio.h>
38
+ #define CDROM_LBA CD_LBA_FORMAT /* first frame is 0 */
39
+ #define CD_MSF_OFFSET 150 /* MSF offset of first frame */
40
+ #define CD_FRAMES 75 /* per second */
41
+ #define CDROM_LEADOUT 0xAA /* leadout track */
42
+ #define CDROMREADTOCHDR CDIOREADTOCHEADER
43
+ #define CDROMREADTOCENTRY CDIOREADTOCENTRY
44
+ #define cdrom_tochdr ioc_toc_header
45
+ #define cdth_trk0 starting_track
46
+ #define cdth_trk1 ending_track
47
+ #define cdrom_tocentry ioc_read_toc_single_entry
48
+ #define cdte_track track
49
+ #define cdte_format address_format
50
+ #define cdte_addr entry.addr
51
+
52
+ #elif defined(OS_OPENBSD) || defined(OS_NETBSD)
53
+ #include <sys/cdio.h>
54
+ #define CDROM_LBA CD_LBA_FORMAT /* first frame is 0 */
55
+ #define CD_MSF_OFFSET 150 /* MSF offset of first frame */
56
+ #define CD_FRAMES 75 /* per second */
57
+ #define CDROM_LEADOUT 0xAA /* leadout track */
58
+ #define CDROMREADTOCHDR CDIOREADTOCHEADER
59
+ #define cdrom_tochdr ioc_toc_header
60
+ #define cdth_trk0 starting_track
61
+ #define cdth_trk1 ending_track
62
+ #define cdrom_tocentry cd_toc_entry
63
+ #define cdte_track track
64
+ #define cdte_addr addr
65
+
66
+ #endif
67
+
68
+ VALUE cFreedb;
69
+
70
+ int cddb_sum (int n)
71
+ {
72
+ /* a number like 2344 becomes 2+3+4+4 (13) */
73
+ int ret=0;
74
+
75
+ while (n > 0) {
76
+ ret = ret + (n % 10);
77
+ n = n / 10;
78
+ }
79
+
80
+ return ret;
81
+ }
82
+
83
+ /*
84
+ * Returns a valid DISCID for the CD in (device)
85
+ */
86
+ static VALUE fdb_get_cdrom(VALUE self, VALUE device) {
87
+ char str[1201];
88
+ #if defined(OS_OPENBSD) || defined(OS_NETBSD)
89
+ struct ioc_read_toc_entry t;
90
+ #endif
91
+ int len;
92
+ int drive, i, totaltime;
93
+ long int cksum=0;
94
+ unsigned char last=1;
95
+ struct cdrom_tochdr hdr;
96
+ struct cdrom_tocentry *TocEntry;
97
+
98
+
99
+ char offsets[1089] = "", buff[255];
100
+
101
+ SafeStringValue(device);
102
+ drive = open(RSTRING_PTR(device), O_RDONLY | O_NONBLOCK);
103
+
104
+ if (drive < 0) {
105
+ rb_sys_fail(RSTRING_PTR(device));
106
+ }
107
+
108
+ if (ioctl(drive,CDROMREADTOCHDR,&hdr) < 0) {
109
+ close(drive);
110
+ rb_sys_fail("Failed to read TOC entry");
111
+ }
112
+
113
+ last=hdr.cdth_trk1;
114
+ len = (last + 1) * sizeof (struct cdrom_tocentry);
115
+ /*
116
+ if (TocEntry) {
117
+ free(TocEntry);
118
+ TocEntry = 0;
119
+ }
120
+ */
121
+ TocEntry = malloc(len);
122
+ if (!TocEntry) {
123
+ close(drive);
124
+ rb_sys_fail("Can't allocate memory for TOC entries");
125
+ }
126
+ #if defined(OS_OPENBSD)
127
+ t.address_format = CDROM_LBA;
128
+ t.starting_track = 0;
129
+ t.data_len = len;
130
+ t.data = TocEntry;
131
+
132
+ if (ioctl(drive, CDIOREADTOCENTRYS, (char *) &t) < 0)
133
+ free(TocEntry);
134
+ close(drive);
135
+ rb_sys_fail("Failed to read TOC entry");
136
+ }
137
+ #elif defined(OS_NETBSD)
138
+ t.address_format = CDROM_LBA;
139
+ t.starting_track = 1;
140
+ t.data_len = len;
141
+ t.data = TocEntry;
142
+ memset(TocEntry, 0, len);
143
+
144
+ if(ioctl(drive, CDIOREADTOCENTRYS, (char *) &t) < 0) {
145
+ free(TocEntry);
146
+ close(drive);
147
+ rb_sys_fail("Failed to read TOC entry");
148
+ }
149
+ #else
150
+
151
+ for (i=0; i < last; i++) {
152
+ TocEntry[i].cdte_track = i + 1; /* tracks start with 1, but i must start with 0 on OpenBSD */
153
+ TocEntry[i].cdte_format = CDROM_LBA;
154
+ if (ioctl(drive, CDROMREADTOCENTRY, &TocEntry[i]) < 0) {
155
+ free(TocEntry);
156
+ close(drive);
157
+ rb_sys_fail("Failed to read TOC entry");
158
+ }
159
+ }
160
+
161
+ TocEntry[last].cdte_track = CDROM_LEADOUT;
162
+ TocEntry[last].cdte_format = CDROM_LBA;
163
+ if (ioctl(drive, CDROMREADTOCENTRY, &TocEntry[i]) < 0) {
164
+ free(TocEntry);
165
+ close(drive);
166
+ rb_sys_fail("Failed to read TOC entry");
167
+ }
168
+ #endif
169
+ close(drive);
170
+
171
+ #if defined(OS_FREEBSD)
172
+ TocEntry[i].cdte_addr.lba = ntohl(TocEntry[i].cdte_addr.lba);
173
+ #endif
174
+
175
+ for (i=0; i < last; i++) {
176
+ #if defined(OS_FREEBSD)
177
+ TocEntry[i].cdte_addr.lba = ntohl(TocEntry[i].cdte_addr.lba);
178
+ #endif
179
+ cksum += cddb_sum((TocEntry[i].cdte_addr.lba + CD_MSF_OFFSET) / CD_FRAMES);
180
+ }
181
+
182
+ totaltime = ((TocEntry[last].cdte_addr.lba + CD_MSF_OFFSET) / CD_FRAMES) -
183
+ ((TocEntry[0].cdte_addr.lba + CD_MSF_OFFSET) / CD_FRAMES);
184
+
185
+
186
+ for (i = 0; i < last; i++) { /* write offsets */
187
+ sprintf(buff, "%d ", TocEntry[i].cdte_addr.lba + CD_MSF_OFFSET);
188
+ strcat(offsets, buff);
189
+ }
190
+
191
+ sprintf(buff,"%d", (TocEntry[last].cdte_addr.lba + CD_MSF_OFFSET) / CD_FRAMES);
192
+ strcat(offsets, buff);
193
+
194
+ sprintf(str, "%08lx %d %s", (cksum % 0xff) << 24 | totaltime << 8 | last, last, offsets);
195
+
196
+ free(TocEntry);
197
+
198
+ return rb_str_new2(str);
199
+ }
200
+
201
+ void Init_freedb_cdrom() {
202
+
203
+ cFreedb = rb_define_class("Freedb", rb_cObject);
204
+ rb_define_private_method(cFreedb, "get_cdrom", fdb_get_cdrom, 1);
205
+ //rb_require("freedb_misc.rb");
206
+
207
+ }
@@ -0,0 +1,638 @@
1
+ # $Id: freedb.rb,v 1.22 2003/02/13 15:52:04 moumar Exp $
2
+ # = Description
3
+ #
4
+ # ruby-freedb is a Ruby library who provide access to cddb/freedb servers as
5
+ # well as local database, can dump the "discid" from a CD and submit new
6
+ # entries to the freedb database.
7
+ #
8
+ #
9
+ # = Download
10
+ #
11
+ # get tar.gz and debian packages at
12
+ # http://davedd.free.fr/ruby-freedb/download/
13
+ #
14
+ #
15
+ # = Installation
16
+ #
17
+ # <b>CAUTION</b>: Some files have changed since 0.4, please clean up your old ruby-freedb
18
+ # (0.3.1 and older) installation before installing this one by deleting our
19
+ # freedb_misc.rb and freedb.so.
20
+ #
21
+ # $ ruby extconf.rb
22
+ # $ make
23
+ # $ make install
24
+ #
25
+ #
26
+ # = Examples
27
+ # see examples/ directory for more advanced examples
28
+ #
29
+ # === get all possible matches for CD in "/dev/cdrom"
30
+ #
31
+ # freedb = Freedb.new("/dev/cdrom")
32
+ # freedb.fetch
33
+ # freedb.results.each { |r| puts r }
34
+ #
35
+ # === getting full description
36
+ # # get "rock" match for this cd
37
+ # freedb.get_result("rock")
38
+ #
39
+ # === make something with your freedb object
40
+ # puts freedb.title # disc's title
41
+ # puts freedb.artist # disc's artist
42
+ # puts freedb.length # disc's length in seconds
43
+ # puts freedb.tracks.size # number of tracks on the CD
44
+ # puts freedb.tracks[3]["title"] # title of the track 4
45
+ # # (indexing begin at 0)
46
+ # puts freedb.tracks[5]["length"] # length of track 6 in seconds
47
+ #
48
+ #
49
+ # = Testing
50
+ #
51
+ # In order to run all tests, you have to burn the "freedb CD Test" at
52
+ # http://ftp.freedb.org/pub/freedb/misc/freedb_testcd.zip
53
+ # and you must be connected to internet.
54
+ #
55
+ # Test::Unit library is used for tests. see http://testunit.talbott.ws/
56
+ #
57
+ # $ cd test/
58
+ # $ ruby test_all.rb
59
+ #
60
+ # = ToDo
61
+ # * CD-ROM access under Win32
62
+ #
63
+ # = Changelog
64
+ #
65
+ # [0.5 07/02/2003]
66
+ #
67
+ # * submission (http or mail) added
68
+ # * fetching from disk in Unix or Windows format added
69
+ # * "raw_response" attribute added (raw response from the server) [Fernando Arbeiza <arbeizaf@ono.com>]
70
+ # * "tracks" removed (however it can be redefined with 'tracks.collect { |h| h["title"] }'
71
+ # * "tracks_ext" renamed to "tracks"
72
+ # * "genre" renamed to "category"
73
+ # * "exact_genre" renamed to "genre"
74
+ # * "get_result(index)": index can be a String that represents the freedb category
75
+ # * FetchCGI: does not rely on cgi.rb anymore
76
+ # * documentation written with "rdoc"
77
+ #
78
+ #
79
+ # [0.4.2 10/01/2003]
80
+ #
81
+ # * Fixed a bug in track length computation [Fernando Arbeiza <arbeizaf@ono.com>]
82
+ #
83
+ #
84
+ # [0.4.1 13/10/2002]
85
+ #
86
+ # * Improved cddb parser [Akinori MUSHA <knu@iDaemons.org>]
87
+ # * Many bugs fixed in freedb_cdrom.c [Akinori MUSHA <knu@iDaemons.org>]
88
+ #
89
+ #
90
+ # [0.4 28/09/2002]
91
+ #
92
+ # * length attribute added
93
+ # * tracks_ext attribute added
94
+ # * fixed a bug in discid computation [Akinori MUSHA <knu@iDaemons.org>]
95
+ # * protocol level handling
96
+ # * test suite
97
+ # * code refactoring
98
+ # * file renaming (change nothing for end users)
99
+ #
100
+ #
101
+ # [0.3.1 30/08/2002]
102
+ #
103
+ # * genre read-only attribute added,
104
+ # * fixes syntax error due to a change in the Ruby interpreter. [Akinori MUSHA <knu@iDaemons.org>]
105
+ # * debianization
106
+ #
107
+ #
108
+ # [0.3 07/04/2002]
109
+ #
110
+ # * fetch() replaced by fetch_net() however i created an alias to fetch()
111
+ # * fetch_cgi() added
112
+ # * discid read-only attribute added
113
+ # * free() bug on FreeBSD fixed in get_cdrom() [Stephane D'Alu <sdalu@loria.fr>]
114
+ # * get_cdrom() buffer overrun fixed [OGAWA Takaya <t-ogawa@triaez.kaisei.org>]
115
+ #
116
+ #
117
+ # [0.2 19/01/2002]
118
+ #
119
+ # * Big cleaning of code.
120
+ # * Minimum code ( just the CDROM access ) written in C. Other is in pure Ruby.
121
+ # * Module now called 'freedb' instead of 'Freedb'.
122
+ # * Deleted specific exceptions. There is only one now (FreedbError).
123
+ #
124
+ #
125
+ # [0.1 18/12/2001]
126
+ #
127
+ # * Initial version
128
+ #
129
+ # License:: GPL
130
+ # Author:: Guillaume Pierronnet (mailto:moumar@netcourrier.com)
131
+ # Website:: http://davedd.free.fr/ruby-freedb/
132
+
133
+ # Raised on any kind of error related to ruby-freedb (cd-rom, network, protocol)
134
+ class FreedbError < StandardError ; end
135
+
136
+ class Freedb
137
+
138
+ VERSION = "0.6"
139
+ PROTO_LEVEL = 5
140
+ CD_FRAME = 75
141
+ VALID_CATEGORIES = [ "blues", "classical", "country", "data", "folk", "jazz", "misc", "newage", "reggae", "rock", "soundtrack" ]
142
+
143
+ # cddbid of the CD
144
+ attr_reader(:discid)
145
+
146
+ # the complete string used to query the database
147
+ attr_reader(:query)
148
+
149
+ # total length of the CD
150
+ attr_reader(:length)
151
+
152
+ # an array with all possible results for this CD
153
+ attr_reader(:results)
154
+
155
+ # string containing raw entry from freedb database
156
+ attr_reader(:raw_response)
157
+
158
+ # artist of the CD, must not be empty
159
+ attr_accessor(:artist)
160
+
161
+ # title of the CD, must not be empty
162
+ attr_accessor(:title)
163
+
164
+ # freedb category, must be one of +Freedb::VALID_CATEGORIES+
165
+ attr_accessor(:category)
166
+
167
+ # arbitraty string for the genre
168
+ attr_accessor(:genre)
169
+
170
+ # year of the cd (0 if not known)
171
+ attr_accessor(:year)
172
+
173
+ # an array of hashs containing following keys:
174
+ # "title" (must not be empty), "length", "ext" (for extended infos)
175
+ attr_accessor(:tracks)
176
+
177
+ # extended infos of the CD
178
+ attr_accessor(:ext_infos)
179
+
180
+ # If +is_query+ is false, the discid of the CD in +param+ is dumped.
181
+ # Else +param+ is considered as a valid freedb query string and is used directly.
182
+ def initialize(param = "/dev/cdrom", is_query = false)
183
+ @query =
184
+ if is_query
185
+ param
186
+ else
187
+ require "freedb_cdrom/freedb_cdrom"
188
+ get_cdrom(param)
189
+ end
190
+ q = @query.split(" ")
191
+ @discid = q[0]
192
+ nb_tracks = q[1].to_i
193
+ @length = q[-1].to_i
194
+ @offsets = q[2...-1] << @length*CD_FRAME
195
+ @offsets.collect! { |x| x.to_i }
196
+
197
+ @tracks = Array.new
198
+
199
+ nb_tracks.times { |i|
200
+ t = Hash.new
201
+ t["length"] = ((@offsets[i+1]-@offsets[i]).to_f/CD_FRAME).round
202
+ @tracks << t
203
+ }
204
+ @revision = 0
205
+ @raw_response = ""
206
+ end
207
+
208
+
209
+ # Query database using network
210
+ # Fill the +results+ array with multiple results.
211
+ # return nil if no match found
212
+ def fetch_net(server = "freedb.org", port = 8880)
213
+ @handler = FetchNet.new(server, port)
214
+ _fetch
215
+ end
216
+
217
+ alias :fetch :fetch_net
218
+
219
+ # Query database using CGI (HTTP) method.
220
+ # Fill the +results+ array with multiple results.
221
+ # return nil if no match found
222
+ def fetch_cgi(server = "www.freedb.org", port = 80, proxy = nil, proxy_port = nil, path = "/~cddb/cddb.cgi")
223
+ @handler = FetchCGI.new(server, port, proxy, proxy_port, path)
224
+ _fetch
225
+ end
226
+
227
+ # Query database using local directory. Set +win_format+ to true
228
+ # if the database has windows format (see freedb howto in "misc/" for details)
229
+ # return nil if no match found
230
+ def fetch_disk(directory, win_format = false)
231
+ @handler = FetchDisk.new(directory, win_format)
232
+ _fetch
233
+ end
234
+
235
+ # submit the current Freedb object using http
236
+ # +from+ is an email adress used to return submissions errors
237
+ # +submit_mode+ can be set to "test" to check submission validity (for developpers)
238
+ # return nil
239
+ def submit_http(from = "user@localhost", server = "freedb.org", port = 80, path = "/~cddb/submit.cgi", submit_mode = "submit")
240
+ require "net/http"
241
+ headers = {
242
+ "Category" => @category,
243
+ "Discid" => @discid,
244
+ "User-Email" => from,
245
+ "Submit-Mode" => submit_mode,
246
+ "Charset" => "ISO-8859-1",
247
+ "X-Cddbd-Note" => "Sent by ruby-freedb #{VERSION}"
248
+ }
249
+ Net::HTTP.start(server, port) { |http|
250
+ reply, body = http.post(path, submit_body(), headers)
251
+ if reply.code != 200
252
+ raise(FreedbError, "Bad response from server: '#{body.chop}'")
253
+ end
254
+ }
255
+ nil
256
+ end
257
+ alias :submit :submit_http
258
+
259
+ # submit the current Freedb object using smtp
260
+ # return +nil+
261
+ def submit_mail(smtp_server, from = "localuser@localhost", port = 25, to = "freedb-submit@freedb.org")
262
+ # +to+ can be set to "test-submit@freedb.org" to check validity (for
263
+ # developpers)
264
+ require "net/smtp"
265
+ header = {
266
+ "From" => from,
267
+ "To" => to,
268
+ "Subject" => "cddb #{@category} #{@discid}",
269
+ "MIME-Version" => "1.0",
270
+ "Content-Type" => "text/plain",
271
+ "Content-Transfer-Encoding" => "quoted-printable",
272
+ "X-Cddbd-Note" => "Sent by ruby-freedb #{VERSION}"
273
+ }
274
+ msg = ""
275
+ header.each { |k, v|
276
+ msg << "#{k}: #{v}\r\n"
277
+ }
278
+ msg << "\r\n"
279
+ msg << submit_body
280
+ Net::SMTP.start(smtp_server, port) { |smtp| smtp.send_mail(msg, from, to) }
281
+ nil
282
+ end
283
+
284
+ # Retrieve full result from the database.
285
+ # If +index+ is a Fixnum, get the +index+'th result in the +result+ array
286
+ # If +index+ is a String, +index+ is the freedb category
287
+ def get_result(index)
288
+
289
+ if index.is_a?(String)
290
+ idx = nil
291
+ @results.each_with_index { |r, i|
292
+ if r =~ /^#{index}/
293
+ idx = i
294
+ end
295
+ }
296
+ else
297
+ idx = index
298
+ end
299
+
300
+ md = /^\S+ [0-9a-fA-F]{8}/.match(@results[idx])
301
+ @handler.send_cmd("read", md[0])
302
+
303
+ # swallow the whole response into a hash
304
+ response = Hash.new
305
+
306
+ each_line(@handler) { |line|
307
+ @raw_response << line + "\n"
308
+ case line
309
+ when /^(\d+) (\S+)/, /^([A-Za-z0-9_]+)=(.*)/
310
+ key = $1.upcase
311
+
312
+ val = $2.gsub(/\\(.)/) {
313
+ case $1
314
+ when "t"
315
+ "\t"
316
+ when "n"
317
+ "\n"
318
+ else
319
+ $1
320
+ end
321
+ }
322
+
323
+ (response[key] ||= '') << val
324
+ when /^# Revision: (\d+)/
325
+ @revision = $1.to_i
326
+ end
327
+ }
328
+ @category = response['210']
329
+ @genre = response['DGENRE']
330
+ @year = response['DYEAR'].to_i
331
+ @ext_infos = response['EXTD']
332
+
333
+ # Use a regexp instead of a bare string to avoid ruby >= 1.7 warning
334
+ @artist, @title = response['DTITLE'].split(/ \/ /, 2)
335
+ # A self-titled album may not have a title part
336
+ @title ||= @artist
337
+
338
+ response.each { |key, val|
339
+ case key
340
+ when /^4\d\d$/
341
+ raise(FreedbError, val)
342
+ when /^TTITLE(\d+)$/
343
+ i = $1.to_i
344
+ @tracks[i]["title"] = val
345
+ when /^EXTT(\d+)$/
346
+ i = $1.to_i
347
+ @tracks[i]["ext"] = val
348
+ end
349
+ }
350
+ self
351
+ end
352
+
353
+ # close all pending connections
354
+ def close
355
+ @handler.close if @handler
356
+ @handler = nil
357
+ end
358
+
359
+ private
360
+
361
+ def _fetch
362
+ @handler.gets #banner
363
+ #@handler.send_cmd("hello", "#{ENV['USER']} #{`hostname`.chop} ruby-freedb #{VERSION}")
364
+ @handler.send_cmd("hello", "user localhost ruby-freedb #{VERSION}")
365
+ if @handler.gets.chop =~ /^4\d\d (.+)/ #welcome
366
+ raise(FreedbError, $1)
367
+ end
368
+ set_proto_level(PROTO_LEVEL)
369
+ @handler.send_cmd("query", @query)
370
+ resp = @handler.gets.chop
371
+ @results = []
372
+ case resp
373
+ when /^200 (.+)/ #single result
374
+ @results << $1
375
+ when /^211/ #multiple results
376
+ each_line(@handler) { |l|
377
+ @results << l
378
+ }
379
+ when /^202/ #no match found
380
+ return nil
381
+ end
382
+ self
383
+ end
384
+
385
+ def set_proto_level(l)
386
+ if l < 1
387
+ raise(FreedbError, "Server doesn't support level 1!")
388
+ end
389
+ @handler.send_cmd("proto", l.to_s)
390
+ if @handler.gets =~ /^501/
391
+ set_proto_level(l-1)
392
+ end
393
+ end
394
+
395
+ def each_line(handler)
396
+ until (l = handler.gets) =~ /^\./
397
+ yield l.chop
398
+ end
399
+ end
400
+
401
+ def submit_body
402
+ if @tracks.detect { |h| h["title"].empty? }
403
+ raise(FreedbError, "Some tracks title are empty")
404
+ elsif not VALID_CATEGORIES.include?(@category)
405
+ raise(FreedbError, "Category is not valid")
406
+ elsif @artist.empty?
407
+ raise(FreedbError, "Artist field must not be empty")
408
+ elsif @title.empty?
409
+ raise(FreedbError, "Title field must not be empty")
410
+ end
411
+ body = <<EOF
412
+ # xmcd CD database file
413
+ #
414
+ # Track frame offsets:
415
+ EOF
416
+ @offsets[0..-2].each { |o|
417
+ body << "# #{o}\n"
418
+ }
419
+ body << <<EOF
420
+ #
421
+ # Disc length: #{@length} seconds
422
+ #
423
+ # Revision: #{@revision}
424
+ # Submitted via: ruby-freedb #{VERSION}
425
+ #
426
+ DISCID=#{discid}
427
+ DTITLE=#{artist.gsub(/ \/ /, "/")} / #{title.gsub(/ \/ /, "/")}
428
+ DYEAR=#{@year.to_i == 0 ? "" : "%04d" % @year}
429
+ DGENRE=#{(@genre || "").split(" ").collect do |w| w.capitalize end.join(" ")}
430
+ EOF
431
+ @tracks.each_with_index { |t, i|
432
+ body << "TTITLE#{i}=#{escape(t["title"])}\n"
433
+ }
434
+ body << "EXTD=#{escape(@ext_infos)}\n"
435
+ @tracks.each_with_index { |t, i|
436
+ body << "EXTT#{i}=#{escape(t["ext"])}\n"
437
+ }
438
+ body << "PLAYORDER=\n"
439
+ body
440
+ end
441
+
442
+ #FIXME optimize that, this is UGLY!
443
+ def escape(str)
444
+ str.gsub(/\t/, '\t').gsub(/\n/, '\n').gsub(/\\/, "\\\\\\")
445
+ end
446
+
447
+ class FetchCGI #:nodoc:
448
+
449
+ def initialize(server, port, proxy, proxy_port, path)
450
+ require "net/http"
451
+ @session = Net::HTTP.new(server, port, proxy, proxy_port)
452
+ @path = path
453
+ @proto_level = 1
454
+ @res = []
455
+ end
456
+
457
+ def send_cmd(cmd, args)
458
+ if cmd == "hello"
459
+ @hello_str = "hello=" + cgi_escape(args)
460
+ @res << "201" #necessary for the next call to gets
461
+ elsif cmd == "proto"
462
+ @proto_level = args
463
+ @res << "200" #necessary for the next call to gets
464
+ else
465
+ request = "?cmd=cddb+#{cmd}+#{cgi_escape(args)}&#{@hello_str}&proto=#{@proto_level}"
466
+ resp, data = @session.get(@path + request)
467
+ raise(FreedbError, "Bad HTTP response: #{resp.code} #{resp.message} while querying server") unless resp.code == "200"
468
+ @res.concat( data.split("\n") )
469
+ end
470
+ end
471
+
472
+ def gets
473
+ #(@res.nil? ? "" : @res.shift)
474
+ @res.shift
475
+ end
476
+
477
+ def close; end
478
+
479
+ private
480
+
481
+ #stolen from cgi.rb
482
+ def cgi_escape(str)
483
+ str.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
484
+ '%' + $1.unpack('H2' * $1.size).join('%').upcase
485
+ end.tr(' ', '+')
486
+ end
487
+
488
+ end
489
+
490
+ class FetchNet #:nodoc:
491
+
492
+ def initialize(server, port)
493
+ require "socket"
494
+ @socket = TCPSocket.new(server, port)
495
+ end
496
+
497
+ def send_cmd(cmd, args)
498
+ @socket.puts("cddb #{cmd} #{args}")
499
+ end
500
+
501
+ def gets
502
+ @socket.gets
503
+ end
504
+
505
+ def close
506
+ @socket.close
507
+ end
508
+ end
509
+
510
+ class FetchDisk #:nodoc:
511
+ def initialize(basedir, win_format)
512
+ raise(FreedbError, "#{basedir} is not a directory") if not File.directory?(basedir)
513
+ @basedir = File.expand_path(basedir)
514
+ @win = win_format
515
+ @res = ["201"]
516
+
517
+ # used to store results to avoid rescanning files when getting result
518
+ # hash key if the name of the category
519
+ @temp_results = {}
520
+
521
+ # storing full directory and name of differents categories ( each
522
+ # represented by a directory)
523
+ @categs = Dir.entries(@basedir).collect do |d|
524
+ dir = File.join(@basedir, d)
525
+ if File.directory?(dir) and d !~ /^\.\.?$/
526
+ @temp_results[d] = []
527
+ [dir, d]
528
+ end
529
+ end
530
+ @categs.compact!
531
+ end
532
+
533
+ def send_cmd(cmd, args)
534
+ case cmd
535
+ when "hello"
536
+ a = args.split(" ")
537
+ @res << "200 Hello and welcome #{a[0]}@#{a[1]} running #{a[2]} #{a[3]}."
538
+ when "query"
539
+ discid = args.split(" ")[0]
540
+ match = []
541
+ ####################
542
+ #WINDOWS DB FORMAT
543
+ ####################
544
+ if @win
545
+ good_line = "#FILENAME=#{discid}\n"
546
+ find_files_win(discid).each do |f, categ|
547
+ content = []
548
+ catch(:finish) do
549
+ started = false
550
+ File.foreach(f) do |line|
551
+ if line == good_line
552
+ started = true
553
+ elsif started
554
+ if line =~ /^#FILENAME=/
555
+ match << categ + " " + discid + " " + disc_name(content)
556
+ @temp_results[categ] = content
557
+ throw(:finish)
558
+ end
559
+ content << line
560
+ end
561
+ end
562
+ end
563
+ end
564
+ ####################
565
+ #CLASSIC DB FORMAT
566
+ ####################
567
+ else
568
+ @categs.each do |dir, categ|
569
+ filename = File.join(dir, discid)
570
+ #if file exists, we've got a match
571
+ if File.file?(filename)
572
+ @temp_results[categ] = File.readlines(filename)
573
+ match << categ + " " + discid + " " + disc_name(@temp_results[categ])
574
+ end
575
+ end
576
+ end
577
+ if match.size == 1
578
+ @res << "200 #{match[0]}"
579
+ elsif match.size > 1
580
+ @res << "211 Multiple match found"
581
+ match.each { |m|
582
+ @res << m
583
+ }
584
+ @res << "."
585
+ else
586
+ @res << "202 No match found"
587
+ end
588
+ when "read"
589
+ categ, discid = args.split(" ")
590
+ @res << "210 #{categ} #{discid}"
591
+ if @win
592
+ lines = @temp_results[categ]
593
+ else
594
+ filename = File.join(@basedir, categ, discid)
595
+ lines = File.readlines(filename)
596
+ end
597
+ @res.concat(lines.collect { |l| l.chop })
598
+ @res << "."
599
+ when "proto"
600
+ @res << "200 CDDB protocol level: current #{PROTO_LEVEL}, supported #{PROTO_LEVEL}"
601
+ else
602
+ @res << "501"
603
+ #$stderr.puts "#{self.class} unsupported command #{cmd}"
604
+ end
605
+ end
606
+
607
+ def gets
608
+ @res.shift + "\n"
609
+ end
610
+
611
+ def close; end
612
+
613
+ private
614
+
615
+ def disc_name(content)
616
+ disc_name = nil
617
+ content.each { |line|
618
+ if md = /DTITLE=(.+)/.match(line)
619
+ disc_name = $1
620
+ end
621
+ }
622
+ disc_name
623
+ end
624
+
625
+ def find_files_win(discid)
626
+ ret = []
627
+ head = discid[0, 2]
628
+ @categs.each do |dir, categ|
629
+ Dir.foreach(dir) do |filename|
630
+ if filename =~ /^([0-9a-fA-f]{2})to([0-9a-fA-F]{2})$/ and head >= $1 and head <= $2
631
+ ret << [File.join(dir, filename), categ]
632
+ end
633
+ end
634
+ end
635
+ ret
636
+ end
637
+ end
638
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-freedb
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.6'
5
+ platform: ruby
6
+ authors:
7
+ - Guillaume Pierronnet
8
+ - Patric Mueller
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-07-10 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A Ruby library which provides dumping CD info, fetching from and submitting
15
+ data to cddb/freedb servers.
16
+ email: bhaak@gmx.net
17
+ executables: []
18
+ extensions:
19
+ - ext/freedb_cdrom/extconf.rb
20
+ extra_rdoc_files: []
21
+ files:
22
+ - ext/freedb_cdrom/extconf.rb
23
+ - ext/freedb_cdrom/freedb_cdrom.c
24
+ - lib/freedb.rb
25
+ homepage: http://ruby-freedb.rubyforge.org/
26
+ licenses:
27
+ - Artistic
28
+ - GPL-2
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.2.2
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: A Ruby library for accessing cddb/freedb servers.
50
+ test_files: []