root/trunk/rockfm.py

Revision 117, 8.3 KB (checked in by cmccurdy, 18 months ago)

fixed a bug that submitted songs out of order when errors were encountered

Line 
1#!/usr/bin/python
2
3import sys
4import datetime
5import time
6import re
7import getpass
8import os.path
9from optparse import OptionParser
10from rockfm import rockbox
11from rockfm import Scrobbler
12from rockfm import rockfm
13
14current_version = '0.4'
15
16def setup_args():
17    parser = OptionParser(usage='%prog [options]\nrock.fm -- ' +
18        'submit your songs played in rockbox to last.fm',
19        version='rock.fm %s' % current_version)
20
21    parser.add_option('-c', '--config', action='store', type='string',
22        dest='conf_file', help='Location of the configuration file')
23    parser.add_option('-n', '--no-config', action='store_true',
24        dest='no_conf', help='Do not use a configuration file')
25    parser.add_option('-d', '--directory', action='store', type='string',
26        dest='log_dir', help='Directory of the scrobbler log file',
27        default=None)
28    parser.add_option('-D', '--dry-run', '--pretend', action='store_true',
29        dest='pretend', help="Don't actually contact the servers")
30    parser.add_option('-f', '--file', action='store', type='string',
31        dest='log_file', help='Scrobbler log file', default=None)
32    parser.add_option('-u', '--username', action='store', type='string',
33        dest='username', help='Last.fm username')
34    parser.add_option('-P', '--password', action='store', type='string',
35        dest='password', help='Last.fm password (plaintext)')
36    parser.add_option('-p', '--prompt', action='store_true',
37        dest='prompt_pw', help='Prompt for a password to be entered')
38    parser.add_option('-U', '--utc-offset', action='store', type='float',
39        default=100.0, dest='utc_offset',
40        help='Override UTC offset autodetection')
41    parser.add_option('-m', '--max', action='store', type='int', default=1,
42        dest='max_subs', help='Maximum songs to submit in one request')
43    parser.add_option('-b', '--backup-dir', action='store', type='string',
44        dest='backup_dir', help='Create a backup of the log file ' +
45        'in the given directory')
46    parser.add_option('-g', '--gui', action='store_true', default=True,
47        dest='use_gui', help='Use the GUI interface')
48    parser.add_option('-N', '--no-gui', action='store_false',
49        dest='use_gui', help="Don't use the GUI interface")
50    parser.add_option('-v', '--verbose', action='count',
51        dest='verbose', help='Print status updates to the screen. ' +
52        'Use twice for extra verbosity')
53
54    return parser
55
56def show_gui(scrobbler,conf,args):
57    """Processes the logic of the GUI"""
58    # if we can't load PyQt4, exit
59    try:
60        import rockfm.ui.RockApp
61    except ImportError, error:
62        sys.stderr.write('ImportError: %s' % (error))
63        sys.exit(6)
64
65    # calling the RockApp exits the app when closed
66    app = rockfm.ui.RockApp(scrobbler,conf,args)
67
68if __name__ == '__main__':
69    # parse command line options, and exit if given a bad one
70    try:
71        parser = setup_args()
72        (options, args) = parser.parse_args()
73    except Exception, strerr:
74        sys.stderr.write('Error parsing arguments: %s' % strerr)
75        sys.exit(1)
76
77    # create the new scrobbler object
78    scrobbler = Scrobbler.Scrobbler('rb2', '0.1', options.username,
79        options.password)
80
81    # look for a conf file in standard locations
82    if options.no_conf is not False and options.conf_file is None:
83        for conf_loc in ('~/.config/rockfm', '~/.rockfm',
84            '~/rockfm/rockfm.conf', '/usr/share/rockfm/rockfm.conf',
85            '/usr/local/share/rockfm/rockfm.conf', '/etc/rockfm.conf'):
86            if os.path.exists(os.path.expanduser(conf_loc)):
87                options.conf_file = os.path.expanduser(conf_loc)
88                break
89
90    scrobbler.pretend = options.pretend
91    conf_settings = {}
92    if options.log_file is not None or options.log_dir is not None:
93        forced_log = True
94    else:
95        forced_log = False
96
97    if not options.no_conf and options.conf_file is not None:
98        conf_settings = rockfm.read_config(options.conf_file)
99
100        # set the required arguments
101        if options.username is None:
102            try:
103                scrobbler.username = conf_settings['username']
104            except KeyError: pass
105
106        if options.password is None and options.prompt_pw is not True:
107            try:
108                scrobbler.set_md5_pw(conf_settings['password'])
109            except KeyError: pass
110
111        if options.log_file is None and options.log_dir is None:
112            if not conf_settings.has_key('log_file'):
113                try:
114                    options.log_file = conf_settings['log_dir'] + \
115                                    '/.scrobbler.log'
116                except KeyError: pass
117            else:
118                options.log_file = conf_settings['log_file']
119
120        # try the rest of them. pass on exceptions, since we expect
121        # them if the key has not been set in the config function
122        if options.utc_offset is None:
123            try:
124                options.utc_offset = conf_settings['utc_offset']
125            except: pass
126
127        if options.max_subs is None:
128            try:
129                options.max_subs = int(conf_settings['max_submit'])
130            except: pass
131
132        if options.use_gui is None:
133            try:
134                if int(conf_settings['gui']) > 0:
135                    options.use_gui = True
136                else:
137                    options.use_gui = False
138            except: pass
139
140        if options.verbose is None:
141            try:
142                if int(conf_settings['verbose']) == 1:
143                    scrobbler.set_verbose(True, False, use_gui)
144                elif int(conf_settings['verbose']) > 1:
145                    scrobbler.set_verbose(True, True, use_gui)
146            except: pass
147
148    if options.log_dir is not None and options.log_file is None:
149        options.log_file = options.log_dir + '/.scrobbler.log'
150
151    # backup the log file
152    if options.backup_dir is not None and options.log_file is not None and \
153        options.use_gui is not True:
154        try:
155            if scrobbler.verbose:
156                sys.stdout.write('Copying scrobbler log file from %s to %s' %
157                    (options.log_file, options.backup_dir))
158            rockbox.backup_log(options.log_file, options.backup_dir)
159        except IOError, err:
160            sys.stderr.write('Could not backup log file: %s\n' % err)
161
162        # exit gracefully if this was the only intention
163        if scrobbler.username == None or options.prompt_pw is None:
164            sys.exit(0)
165
166    if options.use_gui:
167        conf_settings['log_file'] = options.log_file
168        conf_settings['file'] = options.conf_file
169        conf_settings['forced_log'] = forced_log
170        show_gui(scrobbler,conf_settings,[])
171
172    if options.prompt_pw:
173        while scrobbler.password == '' or scrobbler.password is None:
174            scrobbler.password = getpass.getpass('Password: ')
175
176    # show usage if log file, username, or password are not present
177    # and no configuration file exists
178    if (options.log_file is None or scrobbler.username is None or
179        scrobbler.password is None) and options.use_gui is False:
180        parser.print_help()
181        sys.exit(2)
182
183    scrobbler.set_max_submit(options.max_subs)
184    if options.verbose == 1:
185        scrobbler.set_verbose(True, False)
186    elif options.verbose > 1:
187        scrobbler.set_verbose(True, True)
188
189    # compute the utc offset, if not given
190    if options.utc_offset == 100.0:
191        local = time.time()
192        utc = time.mktime(time.gmtime(local))
193        options.utc_offset = local - utc
194        if scrobbler.verbose:
195            print 'Guessing UTC offset:', options.utc_offset, 'seconds:', \
196                options.utc_offset / 3600, 'hours'
197    else:
198        # set the utc offset to seconds
199        if options.utc_offset > -12.0 and options.utc_offset < 13.0:
200            options.utc_offset = options.utc_offset * 3600
201
202    (header,log_array) = rockbox.read_log(options.log_file)
203    for entry in log_array:
204        artist, album, track, track_num, length, status, time = entry
205        if status == 'L' and int(length) > 30:
206            corrected_time = float(time) - float(options.utc_offset)
207            if scrobbler.vv:
208                print 'changed from', datetime.datetime.utcfromtimestamp(
209                    float(time)),
210                print 'to', datetime.datetime.utcfromtimestamp(float(
211                    corrected_time))
212            scrobbler.queue_song(artist, track, album, '', length,
213                corrected_time)
214
215    handshake_succeeded = False
216    while not handshake_succeeded:
217        try:
218            handshake_succeeded = rockfm.handshake(scrobbler)
219        except Scrobbler.HandshakeFrequencyError, error:
220            sys.stderr.write('Handshake frequency error: %s\n' % error)
221            sys.exit(3)
222        except Scrobbler.UnknownHandshakeError, error:
223            sys.stderr.write('Unknown handshake error: %s\n' % error)
224            sys.exit(3)
225
226    while len(scrobbler.queue) > 0:
227        try:
228            scrobbler.submit_queue()
229        except Scrobbler.BadAuthError:
230            try:
231                sys.stderr.write('BadAuth error: attempting re-handshake\n')
232                rockfm.handshake(scrobbler)
233            except Scrobbler.HandshakeFrequencyError, error:
234                sys.stderr.write('%s\n' % error)
235                sys.exit(3)
236            except Scrobbler.UnknownHandshakeError, error:
237                sys.stderr.write('%s\n' % error)
238                sys.exit(3)
239        except Scrobbler.SubmitError, error:
240            sys.stderr.write('Error during submit phase: %s\n' % (error))
241        except IOError, error:
242            sys.stderr.write('IOError: %s\n' % (error))
243
244    if not scrobbler.pretend:
245        rockbox.reset_log(options.log_file, header, scrobbler,
246            options.utc_offset)
Note: See TracBrowser for help on using the browser.