ruby-freedb 0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []