Merge branch 'next-gen' into unittests

This commit is contained in:
Manuel Cortez 2022-01-27 09:11:33 -06:00
commit 1262a9d784
No known key found for this signature in database
GPG Key ID: 9E0735CA15EFE790
10 changed files with 189 additions and 151 deletions

View File

@ -7,6 +7,7 @@ TWBlue Changelog
* TWBlue can display image descriptions within Tweet templates. For that, you can use the $image_description variable in your template.
* We have restored conversation and threads support powered by Twitter API V2 thanks to a set of improvements we have done in the application, as well as more generous limits to Tweet monthly cap by Twitter.
* In the Windows 11 Keymap, the default shortcut to open the keystrokes editor is now CTRL+Alt+Windows+K to avoid conflicts with the new global mute microphone shortcut.
* TWBlue show display properly HTML entities in tweet's text.
* TWBlue should no longer load old tweets in buffers.
* Fixed issue when uploading attachments (images, videos or gif files) while sending tweets or replies.
* Fixed an error that was making TWBlue to ask for a restart after saving account settings, even if such restart was not required. ([#413,](https://github.com/manuelcortez/TWBlue/issues/413))

View File

@ -125,6 +125,9 @@ class Buffer(object):
def share_item(self):
pass
def can_share(self):
pass
def destroy_status(self):
pass

View File

@ -174,9 +174,9 @@ class BaseBuffer(base.Buffer):
self.put_items_on_list(number_of_items)
if hasattr(self, "finished_timeline") and self.finished_timeline == False:
if "-timeline" in self.name:
self.username = val[0].user.screen_name
self.username = self.session.get_user(self.kwargs.get("user_id")).screen_name
elif "-favorite" in self.name:
self.username = self.session.api_call("get_user", **self.kwargs).screen_name
self.username = self.session.get_user(self.kwargs.get("user_id")).screen_name
self.finished_timeline = True
if number_of_items > 0 and self.name != "sent_tweets" and self.name != "sent_direct_messages" and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
self.session.sound.play(self.sound)
@ -391,6 +391,12 @@ class BaseBuffer(base.Buffer):
tweet = self.session.db[self.name][self.buffer.list.get_selected()]
return tweet
def can_share(self):
tweet = self.get_right_tweet()
user = self.session.get_user(tweet.user)
is_protected = user.protected
return is_protected==False
@_tweets_exist
def reply(self, *args, **kwargs):
tweet = self.get_right_tweet()
@ -442,6 +448,8 @@ class BaseBuffer(base.Buffer):
@_tweets_exist
def share_item(self, *args, **kwargs):
if self.can_share() == False:
return output.speak(_("This action is not supported on protected accounts."))
tweet = self.get_right_tweet()
id = tweet.id
if self.session.settings["general"]["retweet_mode"] == "ask":
@ -483,6 +491,9 @@ class BaseBuffer(base.Buffer):
self.session.sound.play("geo.ogg")
if self.session.settings['sound']['indicate_img'] and utils.is_media(tweet):
self.session.sound.play("image.ogg")
can_share = self.can_share()
pub.sendMessage("toggleShare", shareable=can_share)
self.buffer.retweet.Enable(can_share)
def audio(self, url='', *args, **kwargs):
if sound.URLPlayer.player.is_playing():

View File

@ -134,6 +134,7 @@ class Controller(object):
pub.subscribe(self.manage_blocked_user, "blocked-user")
pub.subscribe(self.manage_unblocked_user, "unblocked-user")
pub.subscribe(self.create_buffer, "createBuffer")
pub.subscribe(self.toggle_share_settings, "toggleShare")
if system == "Windows":
pub.subscribe(self.invisible_shorcuts_changed, "invisible-shorcuts-changed")
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.show_hide, menuitem=self.view.show_hide)
@ -1657,6 +1658,10 @@ class Controller(object):
if sound_to_play != None and buff not in buffer.session.settings["other_buffers"]["muted_buffers"]:
self.notify(buffer.session, sound_to_play)
def toggle_share_settings(self, shareable=True):
self.view.retweet.Enable(shareable)
def check_streams(self):
if self.started == False:
return

View File

@ -367,6 +367,7 @@ class viewTweet(basicTweet):
pass
def clear_text(self, text):
text = utils.StripChars(text)
urls = utils.find_urls_in_text(text)
for i in urls:
if "https://twitter.com/" in i:

View File

@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: TW Blue 0.94\n"
"POT-Creation-Date: 2021-12-22 18:18+0100\n"
"PO-Revision-Date: 2021-12-27 23:24+0100\n"
"POT-Creation-Date: 2022-01-26 18:25+0100\n"
"PO-Revision-Date: 2022-01-26 18:26+0100\n"
"Last-Translator: Corentin Bacqué-Cazenave <corentin@progaccess.net>\n"
"Language-Team: Corentin Bacqué-Cazenave <corentin@progaccess.net>\n"
"Language: fr\n"
@ -21,56 +21,56 @@ msgid "This action is not supported for this buffer"
msgstr "Cette action n'est pas supportée pour ce tampon"
#: ../src\controller\buffers\twitter\base.py:70
#: ../src\controller\mainController.py:337 ../src\controller\settings.py:323
#: ../src\controller\mainController.py:338 ../src\controller\settings.py:323
msgid "Home"
msgstr "Accueil"
#: ../src\controller\buffers\twitter\base.py:70
#: ../src\controller\mainController.py:339 ../src\controller\settings.py:324
#: ../src\controller\mainController.py:340 ../src\controller\settings.py:324
msgid "Mentions"
msgstr "Mentions"
#: ../src\controller\buffers\twitter\base.py:70
#: ../src\controller\mainController.py:341
#: ../src\controller\mainController.py:342
msgid "Direct messages"
msgstr "Messages"
#: ../src\controller\buffers\twitter\base.py:70
#: ../src\controller\mainController.py:343 ../src\controller\settings.py:326
#: ../src\controller\mainController.py:344 ../src\controller\settings.py:326
msgid "Sent direct messages"
msgstr "Messages envoyés"
#: ../src\controller\buffers\twitter\base.py:70
#: ../src\controller\mainController.py:345 ../src\controller\settings.py:327
#: ../src\controller\mainController.py:346 ../src\controller\settings.py:327
msgid "Sent tweets"
msgstr "Tweets envoyés"
#: ../src\controller\buffers\twitter\base.py:70
#: ../src\controller\mainController.py:347
#: ../src\controller\mainController.py:1390 ../src\controller\settings.py:328
#: ../src\controller\mainController.py:348
#: ../src\controller\mainController.py:1391 ../src\controller\settings.py:328
msgid "Likes"
msgstr "Favoris"
#: ../src\controller\buffers\twitter\base.py:70
#: ../src\controller\mainController.py:349
#: ../src\controller\mainController.py:1395 ../src\controller\settings.py:329
#: ../src\controller\mainController.py:350
#: ../src\controller\mainController.py:1396 ../src\controller\settings.py:329
msgid "Followers"
msgstr "Abonnés"
#: ../src\controller\buffers\twitter\base.py:70
#: ../src\controller\mainController.py:353
#: ../src\controller\mainController.py:1405 ../src\controller\settings.py:331
#: ../src\controller\mainController.py:354
#: ../src\controller\mainController.py:1406 ../src\controller\settings.py:331
msgid "Blocked users"
msgstr "Utilisateurs bloqués"
#: ../src\controller\buffers\twitter\base.py:70
#: ../src\controller\mainController.py:355
#: ../src\controller\mainController.py:1410 ../src\controller\settings.py:332
#: ../src\controller\mainController.py:356
#: ../src\controller\mainController.py:1411 ../src\controller\settings.py:332
msgid "Muted users"
msgstr "Utilisateurs masqués"
#: ../src\controller\buffers\twitter\base.py:70
#: ../src\controller\mainController.py:1400 ../src\controller\settings.py:330
#: ../src\controller\mainController.py:1401 ../src\controller\settings.py:330
msgid "Friends"
msgstr "Abonnements"
@ -129,46 +129,50 @@ msgstr "%s éléments récupérés"
msgid "This buffer is not a timeline; it can't be deleted."
msgstr "Ce tampon n'est pas une chronologie ; Impossible de le supprimé."
#: ../src\controller\buffers\twitter\base.py:404
#: ../src\controller\buffers\twitter\base.py:410
msgid "Reply to {arg0}"
msgstr "Répondre à {arg0}"
#: ../src\controller\buffers\twitter\base.py:406
#: ../src\controller\buffers\twitter\base.py:412
#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:27
msgid "Reply"
msgstr "Répondre"
#: ../src\controller\buffers\twitter\base.py:407
#: ../src\controller\buffers\twitter\base.py:413
msgid "Reply to %s"
msgstr "Répondre à %s"
#: ../src\controller\buffers\twitter\base.py:430
#: ../src\controller\buffers\twitter\base.py:436
#: ../src\controller\buffers\twitter\directMessages.py:124
msgid "New direct message"
msgstr "Nouveau message"
#: ../src\controller\buffers\twitter\base.py:430
#: ../src\controller\buffers\twitter\base.py:436
#: ../src\controller\messages.py:268
msgid "Direct message to %s"
msgstr "Message à %s"
#: ../src\controller\buffers\twitter\base.py:461
#: ../src\controller\buffers\twitter\base.py:452
msgid "This action is not supported on protected accounts."
msgstr "Cette action n'est pas supportée pour les comptes protégés."
#: ../src\controller\buffers\twitter\base.py:469
msgid "Add your comment to the tweet"
msgstr "Ajoutez votre commentaire pour le tweet"
#: ../src\controller\buffers\twitter\base.py:461
#: ../src\controller\buffers\twitter\base.py:469
msgid "Quote"
msgstr "Citer"
#: ../src\controller\buffers\twitter\base.py:522
#: ../src\controller\buffers\twitter\base.py:533
msgid "Opening URL..."
msgstr "Ouverture de l'URL..."
#: ../src\controller\buffers\twitter\base.py:559
#: ../src\controller\buffers\twitter\base.py:570
msgid "User details"
msgstr "Détails de l'utilisateur"
#: ../src\controller\buffers\twitter\base.py:580
#: ../src\controller\buffers\twitter\base.py:591
msgid "Opening item in web browser..."
msgstr "Ouverture de l'élément dans le navigateur Web..."
@ -207,85 +211,85 @@ msgstr "{0} nouvel abonné"
msgid "This action is not supported in the buffer, yet."
msgstr "Cette action n'est pas supportée pour le tampon actuel"
#: ../src\controller\mainController.py:277
#: ../src\controller\mainController.py:278
msgid "Ready"
msgstr "Prêt"
#: ../src\controller\mainController.py:351
#: ../src\controller\mainController.py:352
msgid "Following"
msgstr "Abonnements"
#: ../src\controller\mainController.py:356
#: ../src\controller\mainController.py:357
msgid "Timelines"
msgstr "Chronologies"
#: ../src\controller\mainController.py:359
#: ../src\controller\mainController.py:883
#: ../src\controller\mainController.py:1582
#: ../src\controller\mainController.py:360
#: ../src\controller\mainController.py:884
#: ../src\controller\mainController.py:1583
msgid "Timeline for {}"
msgstr "Chronologie de {}"
#: ../src\controller\mainController.py:360
#: ../src\controller\mainController.py:361
msgid "Likes timelines"
msgstr "Chronologies des favoris"
#: ../src\controller\mainController.py:363
#: ../src\controller\mainController.py:902
#: ../src\controller\mainController.py:1584
#: ../src\controller\mainController.py:364
#: ../src\controller\mainController.py:903
#: ../src\controller\mainController.py:1585
msgid "Likes for {}"
msgstr "Favoris de {}"
#: ../src\controller\mainController.py:364
#: ../src\controller\mainController.py:365
msgid "Followers timelines"
msgstr "Chronologies des abonnés"
#: ../src\controller\mainController.py:367
#: ../src\controller\mainController.py:921
#: ../src\controller\mainController.py:1586
#: ../src\controller\mainController.py:368
#: ../src\controller\mainController.py:922
#: ../src\controller\mainController.py:1587
msgid "Followers for {}"
msgstr "Abonnés de {}"
#: ../src\controller\mainController.py:368
#: ../src\controller\mainController.py:369
msgid "Following timelines"
msgstr "Chronologies des abonnements"
#: ../src\controller\mainController.py:371
#: ../src\controller\mainController.py:940
#: ../src\controller\mainController.py:1588
#: ../src\controller\mainController.py:372
#: ../src\controller\mainController.py:941
#: ../src\controller\mainController.py:1589
msgid "Friends for {}"
msgstr "Abonnements de {}"
#: ../src\controller\mainController.py:372 ../src\wxUI\dialogs\lists.py:13
#: ../src\controller\mainController.py:373 ../src\wxUI\dialogs\lists.py:13
msgid "Lists"
msgstr "Listes"
#: ../src\controller\mainController.py:375
#: ../src\controller\mainController.py:1422
#: ../src\controller\mainController.py:376
#: ../src\controller\mainController.py:1423
msgid "List for {}"
msgstr "Liste {}"
#: ../src\controller\mainController.py:376
#: ../src\controller\mainController.py:377
msgid "Searches"
msgstr "Recherches"
#: ../src\controller\mainController.py:379
#: ../src\controller\mainController.py:426
#: ../src\controller\mainController.py:431
#: ../src\controller\mainController.py:380
#: ../src\controller\mainController.py:427
#: ../src\controller\mainController.py:432
msgid "Search for {}"
msgstr "Recherche de {}"
#: ../src\controller\mainController.py:381
#: ../src\controller\mainController.py:982
#: ../src\controller\mainController.py:1590
#: ../src\controller\mainController.py:382
#: ../src\controller\mainController.py:983
#: ../src\controller\mainController.py:1591
msgid "Trending topics for %s"
msgstr "Tendances pour %s"
#: ../src\controller\mainController.py:448
#: ../src\controller\mainController.py:464
#: ../src\controller\mainController.py:1080
#: ../src\controller\mainController.py:1099
#: ../src\controller\mainController.py:1118
#: ../src\controller\mainController.py:1137
#: ../src\controller\mainController.py:449
#: ../src\controller\mainController.py:465
#: ../src\controller\mainController.py:1081
#: ../src\controller\mainController.py:1100
#: ../src\controller\mainController.py:1119
#: ../src\controller\mainController.py:1138
msgid ""
"No session is currently in focus. Focus a session with the next or previous "
"session shortcut."
@ -293,152 +297,152 @@ msgstr ""
"Aucune session n'a actuellement le focus. Sélectionnez-en une avec le "
"raccourci pour la session précédente ou suivante."
#: ../src\controller\mainController.py:452
#: ../src\controller\mainController.py:453
msgid "Empty buffer."
msgstr "Tampon vide."
#: ../src\controller\mainController.py:459
#: ../src\controller\mainController.py:460
msgid "{0} not found."
msgstr "{0} introuvable."
#: ../src\controller\mainController.py:469
#: ../src\controller\mainController.py:470
msgid "Filters cannot be applied on this buffer"
msgstr "Les filtres ne peuvent pas s'appliquer à ce tampon"
#: ../src\controller\mainController.py:522
#: ../src\controller\mainController.py:539
#: ../src\controller\mainController.py:568
#: ../src\controller\mainController.py:523
#: ../src\controller\mainController.py:540
#: ../src\controller\mainController.py:569
msgid "Select the user"
msgstr "Sélectionnez l'utilisateur"
#: ../src\controller\mainController.py:753
#: ../src\controller\mainController.py:754
msgid "Add an user alias"
msgstr "Ajoute un alias pour l'utilisateur"
#: ../src\controller\mainController.py:761
#: ../src\controller\mainController.py:762
msgid "Alias has been set correctly for {}."
msgstr "L'alias pour {} a correctement été définie"
#: ../src\controller\mainController.py:829 ../src\controller\messages.py:327
#: ../src\controller\mainController.py:830 ../src\controller\messages.py:327
msgid "MMM D, YYYY. H:m"
msgstr "D MMM YYYY à H:m"
#: ../src\controller\mainController.py:957
#: ../src\controller\mainController.py:958
msgid "Conversation with {0}"
msgstr "Conversation avec {0}"
#: ../src\controller\mainController.py:998
#: ../src\controller\mainController.py:1015
#: ../src\controller\mainController.py:999
#: ../src\controller\mainController.py:1016
msgid "There are no coordinates in this tweet"
msgstr "Il n'y a aucune coordonnée dans ce tweet"
#: ../src\controller\mainController.py:1000
#: ../src\controller\mainController.py:1019
#: ../src\controller\mainController.py:1001
#: ../src\controller\mainController.py:1020
msgid "Error decoding coordinates. Try again later."
msgstr "Erreur pendant le décodage des coordonnées. Réessayez plus tard."
#: ../src\controller\mainController.py:1004
#: ../src\controller\mainController.py:1005
msgid "Unable to find address in OpenStreetMap."
msgstr "Impossible de trouver l'adresse dans OpenStreetMap"
#: ../src\controller\mainController.py:1017
#: ../src\controller\mainController.py:1018
msgid "There are no results for the coordinates in this tweet"
msgstr "Il n'y a aucun résultat pour les coordonnées dans ce tweet"
#: ../src\controller\mainController.py:1128
#: ../src\controller\mainController.py:1147
#: ../src\controller\mainController.py:1129
#: ../src\controller\mainController.py:1148
msgid "%s, %s of %s"
msgstr "%s, %s de %s"
#: ../src\controller\mainController.py:1130
#: ../src\controller\mainController.py:1149
#: ../src\controller\mainController.py:1174
#: ../src\controller\mainController.py:1199
#: ../src\controller\mainController.py:1131
#: ../src\controller\mainController.py:1150
#: ../src\controller\mainController.py:1175
#: ../src\controller\mainController.py:1200
msgid "%s. Empty"
msgstr "%s. Vide"
#: ../src\controller\mainController.py:1162
#: ../src\controller\mainController.py:1166
#: ../src\controller\mainController.py:1187
#: ../src\controller\mainController.py:1163
#: ../src\controller\mainController.py:1167
#: ../src\controller\mainController.py:1188
msgid "{0}: This account is not logged into Twitter."
msgstr "{0}: Ce compte n'est pas connecté à twitter."
#: ../src\controller\mainController.py:1172
#: ../src\controller\mainController.py:1197
#: ../src\controller\mainController.py:1173
#: ../src\controller\mainController.py:1198
msgid "%s. %s, %s of %s"
msgstr "%s. %s, %s de %s"
#: ../src\controller\mainController.py:1191
#: ../src\controller\mainController.py:1192
msgid "{0}: This account is not logged into twitter."
msgstr "{0}: Ce compte n'est pas connecté à twitter."
#: ../src\controller\mainController.py:1416
#: ../src\controller\mainController.py:1417
msgid "This list is already opened"
msgstr "Cette liste est déjà ouverte"
#: ../src\controller\mainController.py:1446
#: ../src\controller\mainController.py:1462
#: ../src\controller\mainController.py:1447
#: ../src\controller\mainController.py:1463
msgid ""
"An error happened while trying to connect to the server. Please try later."
msgstr ""
"Une erreur s'est produite en essayant de se connecter au serveur. Veuillez "
"réessayer plus tard."
#: ../src\controller\mainController.py:1498
#: ../src\controller\mainController.py:1499
msgid "The auto-reading of new tweets is enabled for this buffer"
msgstr "La lecture automatique des nouveaux tweets est activée pour ce tampon"
#: ../src\controller\mainController.py:1501
#: ../src\controller\mainController.py:1502
msgid "The auto-reading of new tweets is disabled for this buffer"
msgstr ""
"La lecture automatique des nouveaux tweets est désactivée pour ce tampon"
#: ../src\controller\mainController.py:1508
#: ../src\controller\mainController.py:1509
msgid "Session mute on"
msgstr "Session muet"
#: ../src\controller\mainController.py:1511
#: ../src\controller\mainController.py:1512
msgid "Session mute off"
msgstr "Session non muet"
#: ../src\controller\mainController.py:1519
#: ../src\controller\mainController.py:1520
msgid "Buffer mute on"
msgstr "Tampon muet"
#: ../src\controller\mainController.py:1522
#: ../src\controller\mainController.py:1523
msgid "Buffer mute off"
msgstr "Tampon non muet"
#: ../src\controller\mainController.py:1542
#: ../src\controller\mainController.py:1543
msgid "Copied"
msgstr "Copié"
#: ../src\controller\mainController.py:1572
#: ../src\controller\mainController.py:1573
msgid "Unable to update this buffer."
msgstr "Impossible de mettre à jour ce tampon."
#: ../src\controller\mainController.py:1575
#: ../src\controller\mainController.py:1576
msgid "Updating buffer..."
msgstr "Actualisation..."
#: ../src\controller\mainController.py:1578
#: ../src\controller\mainController.py:1579
msgid "{0} items retrieved"
msgstr "{0} éléments récupérés"
#: ../src\controller\mainController.py:1597
#: ../src\controller\mainController.py:1617
#: ../src\controller\mainController.py:1598
#: ../src\controller\mainController.py:1618
msgid "Invalid buffer"
msgstr "Tampon invalide"
#: ../src\controller\mainController.py:1608
#: ../src\controller\mainController.py:1609
msgid "Picture {0}"
msgstr "Photo {0}"
#: ../src\controller\mainController.py:1609
#: ../src\controller\mainController.py:1610
msgid "Select the picture"
msgstr "Sélectionner la photo"
#: ../src\controller\mainController.py:1628
#: ../src\controller\mainController.py:1629
msgid "Unable to extract text"
msgstr "Impossible d'extraire le texte"
@ -454,7 +458,7 @@ msgstr "%s - %s/%d caractères"
msgid "View item"
msgstr "Voir l'élément"
#: ../src\controller\messages.py:379
#: ../src\controller\messages.py:380
msgid "Link copied to clipboard."
msgstr "Lien copié dans le Presse-papiers"
@ -1968,27 +1972,27 @@ msgstr ""
"elle va être détruite et recréée automatiquement. Si ce problème perciste, "
"veuillez envoyer le journal d'erreur aux développeurs de {app}."
#: ../src\sessions\twitter\compose.py:38 ../src\sessions\twitter\compose.py:81
#: ../src\sessions\twitter\compose.py:146
#: ../src\sessions\twitter\compose.py:155
#: ../src\sessions\twitter\compose.py:25 ../src\sessions\twitter\compose.py:68
#: ../src\sessions\twitter\compose.py:133
#: ../src\sessions\twitter\compose.py:142
#: ../src\sessions\twitter\templates.py:26
msgid "dddd, MMMM D, YYYY H:m:s"
msgstr "dddd D MMMM YYYY à H:m:s"
#: ../src\sessions\twitter\compose.py:89 ../src\sessions\twitter\compose.py:91
#: ../src\sessions\twitter\compose.py:76 ../src\sessions\twitter\compose.py:78
msgid "Dm to %s "
msgstr "Mp à %s"
#: ../src\sessions\twitter\compose.py:130
#: ../src\sessions\twitter\compose.py:117
msgid "{0}. Quoted tweet from @{1}: {2}"
msgstr "{0}. Tweet de @{1} cité : {2}"
#: ../src\sessions\twitter\compose.py:157
#: ../src\sessions\twitter\compose.py:159
#: ../src\sessions\twitter\compose.py:144
#: ../src\sessions\twitter\compose.py:146
msgid "Unavailable"
msgstr "Indisponible"
#: ../src\sessions\twitter\compose.py:160
#: ../src\sessions\twitter\compose.py:147
msgid ""
"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined "
"Twitter %s"
@ -1996,15 +2000,15 @@ msgstr ""
"%s (@%s). %s abonnés, %s abonnements, %s tweets. Dernier tweet envoyé %s. À "
"rejoint Twitter %s"
#: ../src\sessions\twitter\compose.py:164
#: ../src\sessions\twitter\compose.py:151
msgid "No description available"
msgstr "Aucune description disponible"
#: ../src\sessions\twitter\compose.py:168
#: ../src\sessions\twitter\compose.py:155
msgid "private"
msgstr "privé"
#: ../src\sessions\twitter\compose.py:169
#: ../src\sessions\twitter\compose.py:156
msgid "public"
msgstr "public"
@ -2018,8 +2022,8 @@ msgstr "%s erreur. Raison: %s"
msgid "%s succeeded."
msgstr "%s réussi."
#: ../src\sessions\twitter\session.py:450
#: ../src\sessions\twitter\session.py:528
#: ../src\sessions\twitter\session.py:451
#: ../src\sessions\twitter\session.py:529
msgid "Deleted account"
msgstr "Compte supprimé"
@ -2043,23 +2047,23 @@ msgstr ""
"$display_name (@$screen_name). $followers abonnés, $following abonnements, "
"$tweets tweets. À rejoint Twitter $created_at."
#: ../src\sessions\twitter\templates.py:50
#: ../src\sessions\twitter\templates.py:54
msgid "Image description: {}."
msgstr "Description de l'image: {}."
#: ../src\sessions\twitter\utils.py:229
#: ../src\sessions\twitter\utils.py:243
msgid "Sorry, you are not authorised to see this status."
msgstr "Désolé, vous n'êtes pas autorisé à voir ce Tweet."
#: ../src\sessions\twitter\utils.py:231
#: ../src\sessions\twitter\utils.py:245
msgid "No status found with that ID"
msgstr "Aucun Tweet trouvée avec cet ID"
#: ../src\sessions\twitter\utils.py:233
#: ../src\sessions\twitter\utils.py:247
msgid "Error {0}"
msgstr "Erreur {0}"
#: ../src\sessions\twitter\utils.py:260
#: ../src\sessions\twitter\utils.py:274
msgid "{user_1}, {user_2} and {all_users} more: {text}"
msgstr "{user_1}, {user_2} et {all_users} de plus : {text}"

View File

@ -3,7 +3,6 @@ import platform
system = platform.system()
from . import utils
import re
import html.entities
import time
import output
import languageHandler
@ -11,21 +10,9 @@ import arrow
import logging
import config
from .long_tweets import twishort, tweets
from .utils import StripChars
log = logging.getLogger("compose")
def StripChars(s):
"""Converts any html entities in s to their unicode-decoded equivalents and returns a string."""
entity_re = re.compile(r"&(#\d+|\w+);")
def matchFunc(match):
"""Nested function to handle a match object.
If we match &blah; and it's not found, &blah; will be returned.
if we match #\d+, unichr(digits) will be returned.
Else, a unicode string will be returned."""
if match.group(1).startswith('#'): return chr(int(match.group(1)[1:]))
replacement = html.entities.entitydefs.get(match.group(1), "&%s;" % match.group(1))
return replacement
return str(entity_re.sub(matchFunc, s))
chars = "abcdefghijklmnopqrstuvwxyz"
def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=None):

View File

@ -36,9 +36,9 @@ class Session(base.baseSession):
return self.order_direct_messages(data)
num = 0
last_id = None
if (name in self.db) == False:
if self.db.get(name) == None:
self.db[name] = []
if ("users" in self.db) == False:
if self.db.get("users") == None:
self.db["users"] = {}
objects = self.db[name]
if ignore_older and len(self.db[name]) > 0:
@ -264,13 +264,13 @@ class Session(base.baseSession):
returns a list with all items retrieved."""
results = []
if self.db.get(name) == None or self.db.get(name) == []:
last_id = None
since_id = None
else:
if self.settings["general"]["reverse_timelines"] == False:
last_id = self.db[name][0].id
since_id = self.db[name][-1].id
else:
last_id = self.db[name][-1].id
data = getattr(self.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], since_id=last_id, *args, **kwargs)
since_id = self.db[name][0].id
data = getattr(self.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], since_id=since_id, *args, **kwargs)
results.extend(data)
results.reverse()
return results

View File

@ -32,7 +32,7 @@ def process_text(tweet):
elif hasattr(tweet, "text"):
text = tweet.text
# Cleanup mentions, so we'll remove more than 2 mentions to make the tweet easier to read.
text = utils.clean_mentions(text)
text = utils.clean_mentions(utils.StripChars(text))
# Replace URLS for extended version of those.
if hasattr(tweet, "entities"):
text = utils.expand_urls(text, tweet.entities)
@ -45,11 +45,20 @@ def process_image_descriptions(entities):
for media in entities["media"]:
if media.get("ext_alt_text") != None:
image_descriptions.append(media.get("ext_alt_text"))
# Tweets retrieved via the Streaming API have a description field in media photos with image description available.
elif media.get("description") != None:
image_descriptions.append(media.get("description"))
idescriptions = ""
for image in image_descriptions:
idescriptions += _("Image description: {}.").format(image)
return idescriptions
def remove_unneeded_variables(template, variables):
for variable in variables:
template = re.sub("\$"+variable, "", template)
return template
def render_tweet(tweet, template, session, relative_times=False, offset_seconds=0):
""" Renders any given Tweet according to the passed template.
Available data for tweets will be stored in the following variables:
@ -61,6 +70,7 @@ def render_tweet(tweet, template, session, relative_times=False, offset_seconds=
$text: Tweet text.
$image_descriptions: Information regarding image descriptions added by twitter users.
"""
global tweet_variables
available_data = dict()
created_at = process_date(tweet.created_at, relative_times, offset_seconds)
available_data.update(date=created_at)
@ -89,7 +99,7 @@ def render_tweet(tweet, template, session, relative_times=False, offset_seconds=
if image_descriptions != "":
available_data.update(image_descriptions=image_descriptions)
result = Template(_(template)).safe_substitute(**available_data)
result = re.sub(r"\$\w+", "", result)
result = remove_unneeded_variables(result, tweet_variables)
return result
def render_dm(dm, template, session, relative_times=False, offset_seconds=0):
@ -102,6 +112,7 @@ def render_dm(dm, template, session, relative_times=False, offset_seconds=0):
$recipient_screen_name: User screen name for user receiving the dm, this is the same name used to reference the user in Twitter.
$text: Text of the direct message.
"""
global dm_variables
available_data = dict()
available_data.update(text=utils.expand_urls(dm.message_create["message_data"]["text"], dm.message_create["message_data"]["entities"]))
# Let's remove the last 3 digits in the timestamp string.
@ -116,7 +127,7 @@ def render_dm(dm, template, session, relative_times=False, offset_seconds=0):
recipient = session.get_user(dm.message_create["target"]["recipient_id"])
available_data.update(sender_display_name=sender.name, sender_screen_name=sender.screen_name, recipient_display_name=recipient.name, recipient_screen_name=recipient.screen_name)
result = Template(_(template)).safe_substitute(**available_data)
result = re.sub(r"\$\w+", "", result)
result = remove_unneeded_variables(result, dm_variables)
return result
# Sesion object is not used in this function but we keep compatibility across all rendering functions.
@ -134,6 +145,7 @@ def render_person(user, template, session=None, relative_times=True, offset_seco
$tweets: The number of Tweets (including retweets) issued by the user. This value might be inaccurate.
$created_at: The date and time that the user account was created on Twitter.
"""
global person_variables
available_data = dict(display_name=user.name, screen_name=user.screen_name, followers=user.followers_count, following=user.friends_count, likes=user.favourites_count, listed=user.listed_count, tweets=user.statuses_count)
# Nullable values.
nullables = ["location", "description"]
@ -143,5 +155,5 @@ def render_person(user, template, session=None, relative_times=True, offset_seco
created_at = process_date(user.created_at, relative_times=relative_times, offset_seconds=offset_seconds)
available_data.update(created_at=created_at)
result = Template(_(template)).safe_substitute(**available_data)
result = re.sub(r"\$\w+", "", result)
result = remove_unneeded_variables(result, person_variables)
return result

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import re
import html.entities
import output
import logging
import requests
@ -16,6 +17,19 @@ url_re = re.compile(r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4
url_re2 = re.compile("(?:\w+://|www\.)[^ ,.?!#%=+][^ \\n\\t]*")
bad_chars = '\'\\\n.,[](){}:;"'
def StripChars(s):
"""Converts any html entities in s to their unicode-decoded equivalents and returns a string."""
entity_re = re.compile(r"&(#\d+|\w+);")
def matchFunc(match):
"""Nested function to handle a match object.
If we match &blah; and it's not found, &blah; will be returned.
if we match #\d+, unichr(digits) will be returned.
Else, a unicode string will be returned."""
if match.group(1).startswith('#'): return chr(int(match.group(1)[1:]))
replacement = html.entities.entitydefs.get(match.group(1), "&%s;" % match.group(1))
return replacement
return str(entity_re.sub(matchFunc, s))
def find_urls_in_text(text):
return url_re2.findall(text)