Browse Source

Do complete rewrite and orientate gnusrss to objects

drymer 2 years ago
parent
commit
7ac337061a
2 changed files with 440 additions and 457 deletions
  1. 2
    0
      .gitignore
  2. 438
    457
      gnusrss.py

+ 2
- 0
.gitignore View File

@@ -4,3 +4,5 @@ gnusrss.db
4 4
 dist
5 5
 MANIFEST
6 6
 *.egg-info
7
+todo.org
8
+__pycache__

+ 438
- 457
gnusrss.py View File

@@ -71,7 +71,7 @@ class Database:
71 71
         self.connection.close()
72 72
 
73 73
 
74
-class myParser(HTMLParser):
74
+class StupidParser(HTMLParser):
75 75
     """Just a HTML parser."""
76 76
     def __init__(self):
77 77
         HTMLParser.__init__(self, convert_charrefs=True)
@@ -84,483 +84,464 @@ class myParser(HTMLParser):
84 84
         return ''.join(self.data)
85 85
 
86 86
 
87
-def rss(feed, post_format):
88
-    """
89
-    Request the feed, parse it and return requested values on a list
90
-    of lists.
91
-
92
-    Keyword arguments:
93
-    feed -- string containing the url or the filepath of the feed
94
-    post_format -- string containing RSS keywords surrounded by {}
95
-    """
96
-
97
-    foo = []
98
-    xml = feedparser.parse(feed)
99
-    entries_keys = list(xml.entries[0].keys())
100
-    feed_keys = list(xml.feed.keys())
101
-
102
-    # Very ugly way to test existence, but seems to be the only way
103
-    if 'published' in entries_keys:
104
-        lastbuild = xml.entries[0].published
105
-    elif 'published' in feed_keys:
106
-        lastbuild = xml.feed.published
107
-    elif 'updated' in entries_keys:
108
-        lastbuild = xml.entries[0].updated
109
-    elif 'updated' in feed_keys:
110
-        lastbuild = xml.feed.updated
111
-    else:
112
-        # Since the feed doesn't have a date, I'll create it
113
-        lastbuild = time.strftime("%a, %d %b %Y %H:%M:%S GMT")
114
-
115
-    if 'link' in feed_keys:
116
-        rss_link = xml.feed.link
117
-    else:
118
-        rss_link = 'http://' + xml.entries[0].link.split('/')[2]
119
-
120
-    for item in xml['items']:
121
-        values = {}
122
-        for i in entries_keys:
123
-            if i in post_format:
124
-                values[i] = item[i]
125
-        post = post_format.format(**values)
126
-
127
-        # Stupid HTML code adding to make it complete to parse it
128
-        post = '<html>' + post + '</html>'
129
-        parser = myParser()
130
-        parser.feed(post)
131
-        post = parser.return_value()
132
-
133
-        if 'guid' in entries_keys:
134
-            guid = item['guid']
87
+class GNUsrss:
88
+    def parse_feed(self, feed, post_format):
89
+        """
90
+        Request the feed, parse it and return requested values on a list
91
+        of lists.
92
+
93
+        Keyword arguments:
94
+        feed -- string containing the url or the filepath of the feed
95
+        post_format -- string containing RSS keywords surrounded by {}
96
+
97
+        Comment:
98
+        Here it's saved way more tags that aren't necessary. They're added just
99
+        to add more metadata just because it's clearer when viewing the sqlite.
100
+        """
101
+
102
+        article = []
103
+        xml = feedparser.parse(feed)
104
+        entries_keys = list(xml.entries[0].keys())
105
+        feed_keys = list(xml.feed.keys())
106
+
107
+        # Very ugly way to test existence, but seems to be the only way
108
+        if 'published' in entries_keys:
109
+            lastbuild = xml.entries[0].published
110
+        elif 'published' in feed_keys:
111
+            lastbuild = xml.feed.published
112
+        elif 'updated' in entries_keys:
113
+            lastbuild = xml.entries[0].updated
114
+        elif 'updated' in feed_keys:
115
+            lastbuild = xml.feed.updated
135 116
         else:
136
-            # Since the feed doesn't have a guid, I'll create it
137
-            guid = hashlib.sha1(post.encode()).hexdigest()
138
-
139
-        foo.append([rss_link, post, item['link'], lastbuild,
140
-                    guid])
141
-    return foo
142
-
143
-
144
-def post(article, gs_node, username, password):
145
-    """
146
-    Post the articles to GNU Social.
147
-
148
-    Keyword arguments:
149
-    article -- list containing a most of what is necessary on the
150
-        insert
151
-    gs_node -- string containing the url of the GNU Social node
152
-    username -- string containing the user of GNU Social
153
-    password -- string containing the password of GNU Social
154
-    """
155
-
156
-    msg = article[1].split()
157
-    api = (gs_node + '/api/statuses/update.xml')
158
-
159
-    # Check for twitter images and call post_image if required
160
-    for word in msg:
161
-        if 'pic.twitter.com/' in word:
162
-            image = post_image(word, gs_node, username, password)
163
-            if image is not None:
164
-                index = msg.index(word)
165
-                msg[index] = image
117
+            # Since the feed doesn't have a date, I'll create it
118
+            lastbuild = time.strftime("%a, %d %b %Y %H:%M:%S GMT")
119
+
120
+        if 'link' in feed_keys:
121
+            rss_link = xml.feed.link
122
+        else:
123
+            rss_link = 'http://' + xml.entries[0].link.split('/')[2]
124
+
125
+        for item in xml['items']:
126
+            values = {}
127
+            for i in entries_keys:
128
+                if i in post_format:
129
+                    values[i] = item[i]
130
+            post = post_format.format(**values)
131
+
132
+            # Stupid HTML code adding to complete the post to parse it
133
+            post = '<html>' + post + '</html>'
134
+            parser = StupidParser()
135
+            parser.feed(post)
136
+            post = parser.return_value()
137
+
138
+            if 'guid' in entries_keys:
139
+                guid = item['guid']
166 140
             else:
167
-                pass
168
-    msg = ' '.join(msg)
169
-
170
-    buffer = BytesIO()
171
-    post_data = {'status': msg, 'source': 'gnusrss'}
172
-    postfields = urllib.parse.urlencode(post_data)
173
-
174
-    curl = pycurl.Curl()
175
-    curl.setopt(pycurl.URL, api)
176
-    curl.setopt(pycurl.USERPWD, username + ':' + password)
177
-    curl.setopt(pycurl.VERBOSE, False)
178
-    curl.setopt(curl.POSTFIELDS, postfields)
179
-    curl.setopt(pycurl.WRITEDATA, buffer)
180
-    curl.perform()
181
-    curl.close
182
-
183
-    response = curl.getinfo(curl.RESPONSE_CODE)
184
-
185
-    return response
186
-
187
-
188
-def post_image(picture, gs_node, username, password):
189
-    """
190
-    Upload a picture to GNU Social hosting and return a string with the
191
-    new url.
192
-
193
-    Keyword arguments:
194
-    picture -- string containing the twitter url of a picture
195
-    gs_node -- string containing the url of the GNU Social node
196
-    username -- string containing the user of GNU Social
197
-    password -- string containing the password of GNU Social
198
-    """
199
-    # If the picture doesn't exist, just go on
200
-    try:
201
-        html = urllib.request.urlopen('https://' + picture).read().decode(
202
-            'utf-8').splitlines()
203
-    except:
204
-        return picture
205
-
206
-    api = gs_node + '/api/statusnet/media/upload'
207
-    pic = ""
208
-    found = False
209
-
210
-    # Search the hardcoded tag name of the picture
211
-    for part in html:
212
-        if picture in part:
213
-            found == True
214
-        if 'data-image-url' in part and found:
215
-            pic = part.split('"')[1]
216
-            break
217
-
218
-    # If there's a video instead of a picture, just exit
219
-    if not pic:
220
-        return None
221
-    buffer = BytesIO()
222
-
223
-    # Pick the image and put it in the buffer
224
-    curl = pycurl.Curl()
225
-    curl.setopt(pycurl.URL, pic)
226
-    curl.setopt(pycurl.VERBOSE, False)
227
-    curl.setopt(pycurl.WRITEDATA, buffer)
228
-    curl.perform()
229
-
230
-    pic = buffer.getvalue()
231
-    buffer = BytesIO()
232
-
233
-    # Upload the buffer's image
234
-    curl.setopt(pycurl.URL, api)
235
-    curl.setopt(pycurl.USERPWD, username + ':' + password)
236
-    curl.setopt(curl.HTTPPOST,
237
-                [('media', (curl.FORM_BUFFER, 'useless.jpg',
238
-                            curl.FORM_BUFFERPTR, pic))])
239
-    curl.setopt(pycurl.WRITEDATA, buffer)
240
-    curl.perform()
241
-    curl.close()
242
-
243
-    buffer = buffer.getvalue().decode()
244
-    xmldoc = minidom.parseString(buffer)
245
-    item = xmldoc.getElementsByTagName('rsp')
246
-    url = item.item(0).getElementsByTagName(
247
-        'mediaurl')[0].firstChild.data
248
-
249
-    return url
250
-
251
-
252
-def shortener(post):
253
-    """
254
-    Return a shortened url.
255
-
256
-    Keyword argument:
257
-    post -- string containing a url to be shortened
258
-    """
259
-
260
-    api = ('http://qttr.at/yourls-api.php?format=xml&action=shorturl'
261
-           '&signature=b6afeec983&url=' + post)
262
-    buffer = BytesIO()
263
-
264
-    curl = pycurl.Curl()
265
-    curl.setopt(pycurl.URL, api)
266
-    curl.setopt(pycurl.VERBOSE, False)
267
-    curl.setopt(pycurl.WRITEDATA, buffer)
268
-    curl.perform()
269
-
270
-    buffer = buffer.getvalue().decode('utf-8')
271
-
272
-    xmldoc = minidom.parseString(buffer)
273
-    item = xmldoc.getElementsByTagName('result')
274
-    url = item.item(0).getElementsByTagName('shorturl')[0].\
275
-      firstChild.data
276
-
277
-    return url
278
-
279
-
280
-def compare(feeds):
281
-    """
282
-    Compare the picked feed to the saved on the database and return
283
-    list of lists if new.
284
-
285
-    Keyword argument:
286
-    feeds -- list of lists containing all actual feeds on the RSS file
287
-    """
288
-
289
-    db = Database()
290
-    old = db.select('select guid from items;')
291
-    new_feed = []
292
-    posted = []
293
-
294
-    # make the list accesible
295
-    for x in old:
296
-        posted.append(x[0])
297
-
298
-    for feed in feeds:
299
-        if feed[4] not in posted:
300
-            new_feed.append(feed)
301
-
302
-    return new_feed
303
-
304
-
305
-def shorten_all(post):
306
-    """
307
-    Short all the urls from a notice.
308
-
309
-    Keyword arguments:
310
-    post - list containing all the data related to the post to GS
311
-    """
312
-    # Regex taken from stackoverflow, thanks guys
313
-    # It doesn't identify pic.twitter.com url, which is good
314
-    urls = findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]'
315
-                       '|(?:%[0-9a-fA-F][0-9a-fA-F]))+', post[1])
316
-
317
-    separate = post[1].split(' ')
318
-
319
-    # Clean unicode carriage return
320
-    tmp = ''
321
-    for i in separate:
322
-        i = i.replace(u'\xa0', u'') + ' '
323
-        tmp += i
324
-    separate = tmp.split(' ')
325
-
326
-    for i in urls:
327
-        shortened = shortener(i)
328
-        position = separate.index(i)
329
-        separate[position] = shortened
330
-
331
-    post[1] = ' '.join(separate)
332
-
333
-    return post
334
-
335
-
336
-def get_config(name, option):
337
-    """
338
-    Parse config file and return it on a list.
339
-
340
-    Keyword arguments:
341
-    name -- string containing the config's name
342
-    option -- string containin the section of the config to be parsed
343
-    """
344
-
345
-    config = []
346
-    parser = configparser.SafeConfigParser()
347
-    parser.read(name)
141
+                # Since the feed doesn't have a guid, I'll create it
142
+                guid = hashlib.sha1(post.encode()).hexdigest()
348 143
 
349
-    for name, value in parser.items(option):
350
-        config.append(value)
351
-
352
-    return config
353
-
354
-
355
-def create_config(config_name):
356
-    """
357
-    Create config file.
358
-
359
-    Keyword argument:
360
-    config_name -- string containing the config's name to be created
361
-    """
362
-
363
-    print('Hi! Now we\'ll create de config file!')
364
-    feed = input('Please introduce the feed\'s url: ')
365
-    username = input('Please introduce your username '
366
-                     '(user@server.com): ')
367
-    password = input('Please introduce your password: ')
368
-    shorten = input('Do you need to shorten the urls that you '
369
-                    'post? Please take in account \nthat you '
370
-                    'should only use it if your node only has 140'
371
-                    ' characters. \nAnswer with "yes" or just press '
372
-                    'enter if you don\'t want to use it: ')
373
-    fallback_feed = input('Please introduce your feed\'s fallback'
374
-                          'url. If you don\'t want or have one,\n'
375
-                          'just press enter: ')
376
-    print('Now we\'re gona fetch the feed. Please wait...')
377
-    feed_file = feedparser.parse(feed)
378
-    keys = list(feed_file.entries[0].keys())
379
-    print('Done! The tags are: ')
380
-    for tag in keys:
381
-        print('\t' + tag)
382
-    post_format = input('The XML has been parsed. Choose wich '
383
-                        'format you want:\nPlease put the tags '
384
-                        'inside the square brackets\nEx: {title}'
385
-                        ' - {link} by @{author}: ')
386
-
387
-    config = configparser.ConfigParser()
388
-    config['feeds'] = {}
389
-    config['feeds']['feed'] = feed
390
-    config['feeds']['user'] = username
391
-    config['feeds']['password'] = password
392
-    config['feeds']['shorten'] = shorten
393
-    config['feeds']['fallback_feed'] = fallback_feed
394
-    config['feeds']['format'] = post_format
395
-
396
-    with open(config_name + '.ini', 'w') as configfile:
397
-        config.write(configfile)
398
-
399
-
400
-def parse_options():
401
-    """Parse command line options of this program."""
144
+            article.append([rss_link, post, item['link'], lastbuild, guid])
402 145
 
403
-    parser = argparse.ArgumentParser(description='Post feeds to GNU '
404
-                                     'Social', prog='gnusrss')
405
-    parser.add_argument('-c', '--create-config', metavar='file_name',
406
-                        dest='create_config', help='creates a config '
407
-                        'file')
408
-    parser.add_argument('-C', '--create-db', dest='create_database',
409
-                        action='store_true', help='creates the database')
410
-    parser.add_argument('-p', '--post', metavar='config_file',
411
-                        dest='post', help='posts feeds')
412
-    parser.add_argument('-P', '--post-all', dest='post_all',
413
-                        action='store_true', help='posts all feeds')
414
-    parser.add_argument('-k', '--populate-database', metavar='file_name',
415
-                        dest='populate_database', help='fetch the RSS and'
416
-                        ' save it in the database')
417
-    args = parser.parse_args()
418
-
419
-    if args.create_database:
420
-        if os.path.exists('gnusrss.db'):
421
-            overwrite = input('The database already exists. Are you '
422
-                              'sure you want to overwrite it? (y/n)')
423
-            if overwrite == 'y':
424
-                db = Database()
425
-                db.create_tables()
426
-                db.close
427
-                print('Database created!')
428
-        else:
429
-            db = Database()
430
-            db.create_tables()
431
-            db.close()
432
-            print('Database created!')
146
+        return article
147
+
148
+    def post(self, article, gs_node, username, password):
149
+        """
150
+        Post the articles to GNU Social.
151
+
152
+        Keyword arguments:
153
+        article -- list containing a most of what is necessary on the insert
154
+        gs_node -- string containing the url of the GNU Social node
155
+        username -- string containing the user of GNU Social
156
+        password -- string containing the password of GNU Social
157
+        """
158
+
159
+        msg = article[1].split()
160
+        api = (gs_node + '/api/statuses/update.xml')
161
+
162
+        # Check for twitter images and call post_image if required
163
+        for word in msg:
164
+            if 'pic.twitter.com/' in word:
165
+                image = self.post_image(word, gs_node, username, password)
166
+                if image is not None:
167
+                    index = msg.index(word)
168
+                    msg[index] = image
169
+                else:
170
+                    pass
171
+
172
+        msg = ' '.join(msg)
173
+
174
+        buffer = BytesIO()
175
+        post_data = {'status': msg, 'source': 'gnusrss'}
176
+        postfields = urllib.parse.urlencode(post_data)
177
+
178
+        curl = pycurl.Curl()
179
+        curl.setopt(pycurl.URL, api)
180
+        curl.setopt(pycurl.USERPWD, username + ':' + password)
181
+        curl.setopt(pycurl.VERBOSE, False)
182
+        curl.setopt(curl.POSTFIELDS, postfields)
183
+        curl.setopt(pycurl.WRITEDATA, buffer)
184
+        curl.perform()
185
+        curl.close
186
+
187
+        response = curl.getinfo(curl.RESPONSE_CODE)
188
+
189
+        return response
190
+
191
+    def post_image(self, picture, gs_node, username, password):
192
+        """
193
+        Upload a picture to GNU Social hosting and return a string with the
194
+        new url.
195
+
196
+        Keyword arguments:
197
+        picture -- string containing the twitter url of a picture
198
+        gs_node -- string containing the url of the GNU Social node
199
+        username -- string containing the user of GNU Social
200
+        password -- string containing the password of GNU Social
201
+        """
202
+
203
+        pic = ""
204
+        found = False
205
+        api = gs_node + '/api/statusnet/media/upload'
206
+
207
+        # If the picture doesn't exist or is not well written, show must go on
208
+        try:
209
+            html = urllib.request.urlopen('https://' + picture).read().decode(
210
+                'utf-8').splitlines()
211
+        except:
212
+            return picture
213
+
214
+        # Search the hardcoded tag name of the picture
215
+        for part in html:
216
+            if picture in part:
217
+                found = True
218
+                if 'data-image-url' in part and found:
219
+                    pic = part.split('"')[1]
220
+                    break
221
+
222
+        # If there's a video instead of a picture, just exit
223
+        if not pic:
224
+            return None
225
+
226
+        # Pick the image and put it in the buffer
227
+        buffer = BytesIO()
228
+        curl = pycurl.Curl()
229
+        curl.setopt(pycurl.URL, pic)
230
+        curl.setopt(pycurl.VERBOSE, False)
231
+        curl.setopt(pycurl.WRITEDATA, buffer)
232
+        curl.perform()
233
+
234
+        pic = buffer.getvalue()
235
+        buffer = BytesIO()
236
+
237
+        # Upload the buffer's image
238
+        curl.setopt(pycurl.URL, api)
239
+        curl.setopt(pycurl.USERPWD, username + ':' + password)
240
+        curl.setopt(curl.HTTPPOST,[('media', (curl.FORM_BUFFER, 'useless.jpg',
241
+                                            curl.FORM_BUFFERPTR, pic))])
242
+        curl.setopt(pycurl.WRITEDATA, buffer)
243
+        curl.perform()
244
+        curl.close()
245
+
246
+        buffer = buffer.getvalue().decode()
247
+        xmldoc = minidom.parseString(buffer)
248
+        item = xmldoc.getElementsByTagName('rsp')
249
+        url = item.item(0).getElementsByTagName('mediaurl')[0].firstChild.data
250
+
251
+        return url
252
+
253
+    def compare(self, feeds):
254
+        """
255
+        Compare the picked feed to the saved on the database and return
256
+        list of lists if new.
257
+
258
+        Keyword argument:
259
+        feeds -- list of lists containing all actual feeds on the RSS file
260
+        """
433 261
 
434
-    if args.create_config:
435 262
         db = Database()
436
-        create_config(args.create_config)
437
-        config = get_config(args.create_config + '.ini', 'feeds')
438
-        feed = config[0]
439
-        post_format = config[5]
440
-        posts = rss(feed, post_format)
441
-
442
-        for article in posts:
443
-            if config[3] is 'yes':
444
-                shortened = shortener(article[2])
445
-                article[2] = shortened
446
-            db.insert_data([article[0], article[1], 1, article[2],
447
-                            article[3], article[4]])
448
-        db.close
449
-
450
-    elif args.post:
451
-        config = get_config(args.post, 'feeds')
452
-        feed = config[0]
453
-        fallback_feed = config[4]
454
-        gs_node = 'https://' + config[1].split('@')[1]
455
-        username = config[1].split('@')[0]
456
-        password = config[2]
457
-        post_format = config[5]
263
+        old = db.select('select guid from items;')
264
+        new_feed = []
265
+        posted = []
266
+
267
+        # make the list accesible
268
+        for x in old:
269
+            posted.append(x[0])
270
+
271
+        for feed in feeds:
272
+            if feed[4] not in posted:
273
+                new_feed.append(feed)
274
+
275
+        db.close()
276
+        return new_feed
277
+
278
+    def shortener(self, post):
279
+        """
280
+        Return a shortened url.
281
+
282
+        Keyword argument:
283
+        post -- string containing a url to be shortened
284
+        """
285
+
286
+        api = ('http://qttr.at/yourls-api.php?format=xml&action=shorturl'
287
+                   '&signature=b6afeec983&url=' + post)
288
+        buffer = BytesIO()
289
+        curl = pycurl.Curl()
290
+        curl.setopt(pycurl.URL, api)
291
+        curl.setopt(pycurl.VERBOSE, False)
292
+        curl.setopt(pycurl.WRITEDATA, buffer)
293
+        curl.perform()
294
+
295
+        buffer = buffer.getvalue().decode('utf-8')
296
+
297
+        xmldoc = minidom.parseString(buffer)
298
+        item = xmldoc.getElementsByTagName('result')
299
+        url = item.item(0).getElementsByTagName('shorturl')[0].firstChild.data
300
+
301
+        return url
302
+
303
+    def shorten_all(self, post):
304
+        """
305
+        Short all the urls from a notice.
306
+
307
+        Keyword arguments:
308
+        post - list containing all the data related to the post to GS
309
+        """
310
+
311
+        # Regex taken from stackoverflow, thanks guys
312
+        # It doesn't identify pic.twitter.com url, which is good
313
+        urls = findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&~#=+]|[!*\(\),]'
314
+                           '|(?:%[0-9a-fA-F][0-9a-fA-F]))+', post[1])
315
+
316
+        separate = post[1].split(' ')
317
+        # Clean shitty carriage return
318
+        tmp = ''
319
+        for i in separate:
320
+            i = i.replace(u'\xa0', u'') + ' '
321
+            i = i.replace('\n', '')
322
+            tmp += i
323
+
324
+        separate = tmp.split(' ')
325
+
326
+        for i in urls:
327
+            shortened = self.shortener(i)
328
+            position = separate.index(i)
329
+            separate[position] = shortened
330
+
331
+        post[1] = ' '.join(separate)
332
+
333
+        return post
334
+
335
+
336
+class Config:
337
+    def create(self, config_name):
338
+        """
339
+        Create config file.
340
+
341
+        Keyword argument:
342
+        config_name -- string containing the config's name to be created
343
+        """
344
+
345
+        print('Hi! Now we\'ll create de config file!')
346
+        feed = input('Please introduce the feed\'s url: ')
347
+        username = input('Please introduce your username '
348
+                             '(user@server.com): ')
349
+        password = input('Please introduce your password: ')
350
+        shorten = input('Do you need to shorten the urls that you '
351
+                            'post? Please take in account \nthat you '
352
+                            'should only use it if your node only has 140'
353
+                            ' characters. \nAnswer with "yes" or just press '
354
+                            'enter if you don\'t want to use it: ')
355
+        fallback_feed = input('Please introduce your feed\'s fallback'
356
+                                  'url. If you don\'t want or have one,\n'
357
+                                  'just press enter: ')
358
+        print('Now we\'re going to fetch the feed. Please wait...')
359
+        feed_file = feedparser.parse(feed)
360
+        keys = list(feed_file.entries[0].keys())
361
+        print('Done! The tags are: ')
362
+        for tag in keys:
363
+            print('\t' + tag)
364
+        post_format = input('The XML has been parsed. Choose wich '
365
+                            'format you want:\nPlease put the tags '
366
+                            'inside the square brackets\nEx: {title}'
367
+                            ' - {link} by @{author}: ')
368
+
369
+        config = configparser.ConfigParser()
370
+        config['feeds'] = {}
371
+        config['feeds']['feed'] = feed
372
+        config['feeds']['user'] = username
373
+        config['feeds']['password'] = password
374
+        config['feeds']['shorten'] = shorten
375
+        config['feeds']['fallback_feed'] = fallback_feed
376
+        config['feeds']['format'] = post_format
377
+
378
+        with open(config_name + '.ini', 'w') as configfile:
379
+            config.write(configfile)
380
+
381
+    def get(self, name):
382
+        """
383
+        Parse config file and return it on a list.
384
+
385
+        Keyword arguments:
386
+        name -- string containing the config's name
387
+        """
388
+
389
+        config = []
390
+        parser = configparser.SafeConfigParser()
391
+        parser.read(name)
392
+
393
+        for name, value in parser.items('feeds'):
394
+            config.append(value)
395
+
396
+        return config
458 397
 
398
+
399
+class ParseOptions():
400
+    """Parse command line options of this program."""
401
+    def __init__(self):
402
+        parser = argparse.ArgumentParser(description='Post feeds to GNU '
403
+                                             'Social', prog='gnusrss')
404
+        parser.add_argument('-c', '--create-config', metavar='file_name',
405
+                            dest='create_config', help='creates a config file')
406
+        parser.add_argument('-C', '--create-db', dest='create_database',
407
+                            action='store_true', help='creates the database')
408
+        parser.add_argument('-p', '--post', metavar='config_file',
409
+                            dest='post', help='posts feeds')
410
+        parser.add_argument('-P', '--post-all', dest='post_all',
411
+                            action='store_true', help='posts all feeds')
412
+        parser.add_argument('-k', '--populate-database', metavar='file_name',
413
+                            dest='populate_database', help='fetch the RSS and'
414
+                            ' save it in the database')
415
+        self.db = Database()
416
+        self.gs = GNUsrss()
417
+        self.cnf = Config()
418
+
419
+        self.args = parser.parse_args()
420
+        # Make all options accesible within self
421
+        self.create_database = self.args.create_database
422
+        self.create_config = self.args.create_config
423
+        self.post = self.args.post
424
+        self.post_all = self.args.post_all
425
+        self.populate_database = self.args.populate_database
426
+
427
+    def declare_config(self):
428
+        """Assign all config file parameters to a self object."""
429
+
430
+        config = self.cnf.get(self.config_name)
431
+        self.feed = config[0]
432
+        self.user = config[1].split('@')[0]
433
+        self.password = config[2]
434
+        self.shorten = config[3]
435
+        self.fallback_feed = config[4]
436
+        self.format = config[5]
437
+        self.server = 'https://' + config[1].split('@')[1]
438
+
439
+    def post_notice(self):
440
+        """Post notice to GNU social."""
441
+
442
+        file_name = self.config_name
443
+
444
+        # If first feed and fallback feed aren't available, fail gracefully
459 445
         try:
460
-            posts = rss(feed, post_format)
446
+            posts = self.gs.parse_feed(self.feed, self.format)
461 447
         except:
462
-            if fallback_feed:
463
-                posts = rss(fallback_feed, post_format)
448
+            if self.fallback_feed:
449
+                posts = self.gs.parse_feed(self.fallback_feed, self.format)
464 450
             else:
465
-                print('There\'s been a problem with ' + args.post
466
-                          + ' file.')
467
-                exit()
451
+                print('There\'s been a problem with ' + file_name + ' file.')
452
+                return None
468 453
 
469 454
         posts = list(reversed(posts))
470
-        new = compare(posts)
455
+        new = self.gs.compare(posts)
471 456
 
472 457
         if new:
473 458
             # Post only the older item
474
-            to_post = new[0]
475
-            db = Database()
476
-            if config[3] == 'yes':
477
-                to_post = shorten_all(to_post)
478
-
479
-            posted = post(to_post, gs_node, username, password)
480
-
481
-            if int(posted) == int('200'):
482
-                db.insert_data([to_post[0], to_post[1], 1, to_post[2],
483
-                                to_post[3], to_post[4]])
484
-                db.close()
485
-
486
-    elif args.post_all:
487
-        for config in listdir('.'):
488
-            if config.endswith('.ini'):
489
-                file_name = config
490
-                config = get_config(config, 'feeds')
491
-                feed = config[0]
492
-                fallback_feed = config[4]
493
-                gs_node = 'https://' + config[1].split('@')[1]
494
-                username = config[1].split('@')[0]
495
-                password = config[2]
496
-                post_format = config[5]
497
-
498
-                try:
499
-                    posts = rss(feed, post_format)
500
-                except:
501
-                    if fallback_feed:
502
-                        posts = rss(fallback_feed, post_format)
503
-                    else:
504
-                        print('Something went wrong in ' + file_name + 'file.')
505
-                        pass
506
-
507
-                posts = list(reversed(posts))
508
-                new = compare(posts)
509
-
510
-                if new:
511
-                    # Post the first posted
512
-                    to_post = new[0]
513
-                    db = Database()
514
-                    if config[3] == 'yes':
515
-                        shortened = shorten_all(to_post)
516
-
517
-                    try:
518
-                        posted = post(to_post, gs_node, username, password)
519
-                    except:
520
-                        print('Something went wrong in ' + config + 'file.')
521
-                        print('I\'ll continue with the next feeds.')
522
-                        pass
523
-
524
-                    if int(posted) == int('200'):
525
-                        db.insert_data([to_post[0], to_post[1], 1,
526
-                                        to_post[2], to_post[3], to_post[4]])
527
-                        db.close()
528
-
529
-    elif args.populate_database:
530
-        config = get_config(args.populate_database, 'feeds')
531
-        feed = config[0]
532
-        fallback_feed = config[4]
533
-        post_format = config[5]
459
+            self.to_post = new[0]
460
+            if self.shorten == 'yes':
461
+                self.to_post = self.gs.shorten_all(self.to_post)
534 462
 
535
-        try:
536
-            posts = rss(feed, post_format)
537
-        except:
538
-            posts = rss(fallback_feed, post_format)
463
+            if not self.populate_database:
464
+                code = self.gs.post(self.to_post, self.server, self.user,
465
+                                        self.password)
466
+                self.save_in_database(code)
539 467
 
540
-        new = compare(posts)
541 468
 
542
-        if new:
543
-            db = Database()
544
-            for n in new:
545
-                if config[3] == 'yes':
546
-                    shortened = shortener(n[2])
547
-                    temp = n[1].split()
548
-                    try:
549
-                        temp[temp.index(n[2])] = shortened
550
-                    except:
551
-                        print('There\'s not url in the message. Please'
552
-                            ' fix the config.')
553
-                        exit()
469
+    def save_in_database(self, code):
470
+        """
471
+        Save posts in database
472
+
473
+        Keyword arguments:
474
+        code -- HTML code of the notice's post to GNU social
475
+        """
476
+
477
+        if self.create_config or self.populate_database or int(code) == \
478
+                int(200):
479
+            self.db.insert_data([self.to_post[0], self.to_post[1], 1,
480
+                                     self.to_post[2], self.to_post[3],
481
+                                     self.to_post[4]])
482
+
483
+    def pointers(self):
484
+        """This are the options of the program."""
485
+
486
+        if self.create_database:
487
+            if os.path.exists('gnusrss.db'):
488
+                overwrite = input('The database already exists. Are you '
489
+                                'sure you want to overwrite it? (y/n) ')
490
+
491
+                if overwrite == 'y':
492
+                    self.db.create_tables()
493
+            else:
494
+                self.db.create_tables()
495
+
496
+            if not self.create_config and not self.populate_database and \
497
+                    not self.post and not self.post_all:
498
+                self.db.close()
499
+
500
+        if self.create_config:
501
+            self.config_name = self.create_config + '.ini'
502
+            self.cnf.create(self.create_config)
503
+
504
+            populate = input('Do you want to populate the database? (y) Or you'
505
+                                 ' prefer to post old items? (n) ')
506
+
507
+            if populate == 'y':
508
+                self.declare_config()
509
+                posts = self.gs.parse_feed(self.feed, self.format)
510
+
511
+                for post in posts:
512
+                    self.to_post = post
513
+                    self.save_in_database(0)
514
+                self.db.close()
515
+
516
+        elif self.post:
517
+            self.config_name = self.post
518
+            self.declare_config()
519
+            self.post_notice()
520
+            self.db.close()
521
+
522
+        elif self.post_all:
523
+            for config in listdir('.'):
524
+                if config.endswith('.ini'):
525
+                    self.config_name = config
526
+                    self.declare_config()
527
+                    self.post_notice()
528
+            self.db.close()
529
+
530
+        elif self.populate_database:
531
+            self.config_name = self.populate_database
532
+            self.declare_config()
533
+            posts = self.gs.parse_feed(self.feed, self.format)
554 534
 
555
-                    n[1] = ' '.join(temp)
556
-                    n[2] = shortened
535
+            for post in posts:
536
+                self.to_post = post
537
+                self.save_in_database(0)
557 538
 
558
-                db.insert_data([n[0], n[1], 1, n[2], n[3], n[4]])
559
-            db.close()
539
+            self.db.close()
560 540
 
561
-    if len(argv) == 1:
562
-        parser.print_help()
541
+        if len(argv) == 1:
542
+            self.parser.print_help()
563 543
 
564 544
 
565 545
 if __name__ == "__main__":
566
-    parse_options()
546
+    options = ParseOptions()
547
+    options.pointers()