diff --git a/packages/.gitkeep b/packages/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/calendar/README.md b/packages/calendar/README.md deleted file mode 100644 index 431bb6953..000000000 --- a/packages/calendar/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Calendar Package - -The calendar package contains modules related to your plans (what's next, schedule, things need to be done, etc.). - -## Modules - -### To-Do List - -Manage your to-do lists: -- Create a list -- View your lists -- View a specific list -- Rename a list -- Delete a list -- Add todos -- Complete todos -- Uncheck todos - -#### Usage - -``` -(en-US) "Show all my lists" -(en-US) "Add 7 potatoes, 1kg of rice, bread to the shopping list" -(en-US) "Complete rice from my shopping list" -(en-US) "Check bread from the shopping list" -(en-US) "What is in my shopping list?" -(en-US) "Create a movies list" -(en-US) "Add Captain America: Civil War to my movies list" -(en-US) "What are my lists?" -(en-US) "Rename the movies list to cinema" -(en-US) "Check Captain America from the cinema list" -(en-US) "What is in my cinema list?" -(en-US) "Uncheck Captain America from my cinema list" -(en-US) "Please tell me what is in my cinema list" -(en-US) "Delete my cinema list" -(en-US) "Show my lists" - -(fr-FR) "Show my lists" -(fr-FR) "Ajoute 7 pommes de terre, 1kg de riz, pain à la liste courses" -(fr-FR) "Complète riz de la liste courses" -(fr-FR) "Coche pain de la liste courses" -(fr-FR) "Qu'est-ce qu'il y a dans ma liste courses ?" -(fr-FR) "Crée une liste films" -(fr-FR) "Ajoute Captain America : Guerre Civile à ma liste films" -(fr-FR) "Quelles sont mes listes ?" -(fr-FR) "Renomme la liste films en cinéma" -(fr-FR) "Qu'est-ce qu'il y a dans ma liste cinéma ?" -(fr-FR) "Décoche Captain America de ma liste cinéma" -(fr-FR) "Montre ma liste cinéma" -(fr-FR) "Supprime ma liste cinéma" -(fr-FR) "Montre mes listes" -``` diff --git a/packages/calendar/__init__.py b/packages/calendar/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/calendar/config/.gitkeep b/packages/calendar/config/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/calendar/config/config.sample.json b/packages/calendar/config/config.sample.json deleted file mode 100644 index c1998f077..000000000 --- a/packages/calendar/config/config.sample.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "todolist": { - "options": {} - } -} diff --git a/packages/calendar/data/.gitkeep b/packages/calendar/data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/calendar/data/answers/.gitkeep b/packages/calendar/data/answers/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/calendar/data/answers/en.json b/packages/calendar/data/answers/en.json deleted file mode 100644 index d633521b5..000000000 --- a/packages/calendar/data/answers/en.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "todolist": { - "list_created": [ - "Alright, I've created the \"%list%\" list.", - "Done, I created your \"%list%\" list." - ], - "list_not_provided": [ - "Please provide me a list name.", - "Please provide the name of a list." - ], - "todos_not_provided": [ - "Please provide me items.", - "Please provide elements." - ], - "new_or_old_list_not_provided": [ - "Please make sure you provide the list name to rename and its new list name.", - "Please provide the list name to rename and its new list name." - ], - "no_list": [ - "You do not have any list.", - "There is no list to show." - ], - "empty_list": [ - "Your \"%list%\" list is empty.", - "There is nothing in your \"%list%\" list." - ], - "list_does_not_exist": [ - "Sorry I can't because the \"%list%\" does not exist.", - "I cannot do that because the \"%list%\" does not exist." - ], - "list_already_exists": [ - "You already have a list named \"%list%\"." - ], - "list_renamed": [ - "I renamed the \"%old_list%\" list to \"%new_list%\"." - ], - "list_deleted": [ - "I deleted the \"%list%\" list and all the todos it was containing." - ], - "lists_listed": [ - "You have %lists_nb% lists. Please let me list them for you:

" - ], - "list_list_element": [ - "
  • \"%list%\", with %todos_nb% elements in it.
  • ", - "
  • \"%list%\", that contains %todos_nb% items.
  • " - ], - "no_unchecked_todo": [ - "You do not have in progress element in your \"%list%\" list.", - "You don't have any in progress element in your \"%list%\" list." - ], - "no_completed_todo": [ - "And you do not have completed element in your \"%list%\" list.", - "And you don't have any completed element in your \"%list%\" list." - ], - "unchecked_todos_listed": [ - "Here are the in progress elements of your \"%list%\" list:


    Stay motivated!", - "Please find the in progress elements of your \"%list%\" list:


    Keep going!" - ], - "completed_todos_listed": [ - "And here are the completed elements of your \"%list%\" list:

    " - ], - "list_todo_element": [ - "
  • %todo%.
  • " - ], - "list_completed_todo_element": [ - "
  • %todo%.
  • " - ], - "todos_added": [ - "Alright, I added the following to your \"%list%\" list:

    ", - "The following have been added to your \"%list%\" list:

    " - ], - "todos_unchecked": [ - "I unchecked the following from your \"%list%\" list:

    ", - "The following have been unchecked from your \"%list%\" list:

    " - ], - "todos_completed": [ - "Keep going! I completed the following from your \"%list%\" list:

    ", - "Well done! The following have been completed from your \"%list%\" list:

    " - ] - } -} diff --git a/packages/calendar/data/answers/fr.json b/packages/calendar/data/answers/fr.json deleted file mode 100644 index f1cb769e9..000000000 --- a/packages/calendar/data/answers/fr.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "todolist": { - "list_created": [ - "Entendu, j'ai créé la liste \"%list%\".", - "C'est fait, j'ai créé votre liste \"%list%\"." - ], - "list_not_provided": [ - "Merci de me fournir un nom de liste.", - "Merci de fournir le nom d'une liste." - ], - "todos_not_provided": [ - "Merci de me fournir des éléments.", - "Merci de fournir des éléments." - ], - "new_or_old_list_not_provided": [ - "Merci de vous assurer d'avoir fourni le nom de la liste à renommer et son nouveau nom.", - "Merci de fournir le nom de la liste à renommer ainsi que son nouveau nom." - ], - "no_list": [ - "Je n'ai trouvé aucune liste.", - "Il n'y a pas de liste à montrer." - ], - "empty_list": [ - "Votre liste \"%list%\" est vide.", - "Il n'y a rien dans votre liste \"%list%\"." - ], - "list_does_not_exist": [ - "Désolé je ne peux pas car la liste \"%list%\" n'éxiste pas.", - "Je ne peux pas parce que la liste \"%list%\" n'éxiste pas." - ], - "list_already_exists": [ - "Vous avez déjà une liste nommée \"%list%\"." - ], - "list_renamed": [ - "J'ai renommé la liste \"%old_list%\" en \"%new_list%\"." - ], - "list_deleted": [ - "J'ai supprimé la liste \"%list%\" et tous les éléments qu'elle contenait." - ], - "lists_listed": [ - "Vous avez %lists_nb% listes. Permettez-moi de vous les lister :

    " - ], - "list_list_element": [ - "
  • \"%list%\", avec %todos_nb% éléments.
  • ", - "
  • \"%list%\", contenant %todos_nb% éléments.
  • " - ], - "no_unchecked_todo": [ - "Vous n'avez pas d'élément en attente dans votre liste \"%list%\".", - "Vous n'avez aucun élément en attente dans votre liste \"%list%\"." - ], - "no_completed_todo": [ - "Et vous n'avez pas d'élément complété dans votre liste \"%list%\".", - "Et vous n'avez aucun élément complété dans votre liste \"%list%\"." - ], - "unchecked_todos_listed": [ - "Voici les éléments en attente de votre liste \"%list%\" :


    Restez motivé !", - "Voici les éléments en attente de votre liste \"%list%\" :


    Continuez ainsi !" - ], - "completed_todos_listed": [ - "Et voici les éléments complétés de votre liste \"%list%\" :

    " - ], - "list_todo_element": [ - "
  • %todo%.
  • " - ], - "list_completed_todo_element": [ - "
  • %todo%.
  • " - ], - "todos_added": [ - "Entendu, j'ai ajouté ceci à votre liste \"%list%\" :

    ", - "Ce qui suit vient d'être ajouté à votre liste \"%list%\" :

    " - ], - "todos_unchecked": [ - "J'ai décomplété ceci de votre liste \"%list%\" :

    ", - "Ce qui suit vient d'être décomplété de votre liste \"%list%\" :

    " - ], - "todos_completed": [ - "Continue ainsi ! J'ai complété ceci de votre liste \"%list%\" :

    ", - "Bien joué ! Ce qui suit vient d'être complété de votre liste \"%list%\" :

    " - ] - } -} diff --git a/packages/calendar/data/db/.gitkeep b/packages/calendar/data/db/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/calendar/data/expressions/.gitkeep b/packages/calendar/data/expressions/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/calendar/data/expressions/en.json b/packages/calendar/data/expressions/en.json deleted file mode 100644 index 8796f8edb..000000000 --- a/packages/calendar/data/expressions/en.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "todolist": { - "create_list": { - "utterance_samples": [ - "Create the x list", - "Create a x list" - ], - "entities": [ - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "between", - "from": ["the", "a", "an", "my"], - "to": ["list", "list", "list", "list"] - } - ] - } - ] - }, - "view_lists": { - "utterance_samples": [ - "Show all the lists", - "Show all my lists", - "What are the lists?", - "What are my lists?" - ] - }, - "view_list": { - "utterance_samples": [ - "Show my x list", - "Show the x list", - "What is in my x list?", - "What is in the x list?" - ], - "entities": [ - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "between", - "from": ["the", "my"], - "to": ["list", "list"] - } - ] - } - ] - }, - "rename_list": { - "utterance_samples": [ - "Rename the x list to y", - "Rename my x list to y" - ], - "entities": [ - { - "type": "trim", - "name": "old_list", - "conditions": [ - { - "type": "between", - "from": ["the", "my"], - "to": ["list", "list"] - } - ] - }, - { - "type": "trim", - "name": "new_list", - "conditions": [ - { - "type": "after", - "from": "to" - } - ] - } - ] - }, - "delete_list": { - "utterance_samples": [ - "Delete the x list", - "Delete my x list" - ], - "entities": [ - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "between", - "from": ["the", "my"], - "to": ["list", "list"] - } - ] - } - ] - }, - "add_todos": { - "utterance_samples": [ - "Add x to the list x", - "Add x to my list x" - ], - "entities": [ - { - "type": "trim", - "name": "todos", - "conditions": [ - { - "type": "between", - "from": "add", - "to": "to" - } - ] - }, - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "between", - "from": ["the", "my"], - "to": ["list", "list"] - } - ] - } - ] - }, - "complete_todos": { - "utterance_samples": [ - "Check x from the x list", - "Check x from my x list", - "Complete x from my x list", - "Tick x from my x list" - ], - "entities": [ - { - "type": "trim", - "name": "todos", - "conditions": [ - { - "type": "between", - "from": ["check", "complete", "tick"], - "to": ["from", "from", "from"] - } - ] - }, - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "between", - "from": ["the", "my"], - "to": ["list", "list"] - } - ] - } - ] - }, - "uncheck_todos": { - "utterance_samples": [ - "Uncheck x from the x list", - "Uncheck x from my x list", - "Untick x from my x list" - ], - "entities": [ - { - "type": "trim", - "name": "todos", - "conditions": [ - { - "type": "between", - "from": ["uncheck", "untick"], - "to": ["from", "from"] - } - ] - }, - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "between", - "from": ["the", "my"], - "to": ["list", "list"] - } - ] - } - ] - } - } -} diff --git a/packages/calendar/data/expressions/fr.json b/packages/calendar/data/expressions/fr.json deleted file mode 100644 index 992de1522..000000000 --- a/packages/calendar/data/expressions/fr.json +++ /dev/null @@ -1,187 +0,0 @@ -{ - "todolist": { - "create_list": { - "utterance_samples": [ - "Crée la liste x", - "Crée une liste x" - ], - "entities": [ - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "after_last", - "from": "liste" - } - ] - } - ] - }, - "view_lists": { - "utterance_samples": [ - "Montre les listes", - "Montre mes listes", - "Quelles sont les listes ?", - "Quelles sont mes listes ?" - ] - }, - "view_list": { - "utterance_samples": [ - "Montre ma liste x", - "Montre la liste x", - "Qu'est-ce qu'il y a dans ma liste x ?", - "Qu'est-ce qu'il y a dans la liste x ?" - ], - "entities": [ - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "after_last", - "from": "liste" - } - ] - } - ] - }, - "rename_list": { - "utterance_samples": [ - "Renomme la liste x en y", - "Renomme ma liste x en y" - ], - "entities": [ - { - "type": "trim", - "name": "old_list", - "conditions": [ - { - "type": "between", - "from": "liste", - "to": "en" - } - ] - }, - { - "type": "trim", - "name": "new_list", - "conditions": [ - { - "type": "after_last", - "from": "en" - } - ] - } - ] - }, - "delete_list": { - "utterance_samples": [ - "Supprime la liste x", - "Supprime ma liste x" - ], - "entities": [ - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "after_last", - "from": "liste" - } - ] - } - ] - }, - "add_todos": { - "utterance_samples": [ - "Ajoute x à la liste x", - "Ajoute x à ma liste x" - ], - "entities": [ - { - "type": "trim", - "name": "todos", - "conditions": [ - { - "type": "between", - "from": ["ajoute", "ajoute"], - "to": ["à", "a"] - } - ] - }, - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "after_last", - "from": "liste" - } - ] - } - ] - }, - "complete_todos": { - "utterance_samples": [ - "Coche x de la liste x", - "Coche x de ma liste x", - "Complète x de ma liste x" - ], - "entities": [ - { - "type": "trim", - "name": "todos", - "conditions": [ - { - "type": "between", - "from": ["coche", "complète", "complete"], - "to": ["de"] - } - ] - }, - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "after_last", - "from": "liste" - } - ] - } - ] - }, - "uncheck_todos": { - "utterance_samples": [ - "Décoche x de la liste x", - "Décoche x de ma liste x", - "Invalide x de ma liste x", - "Remet x sur la liste x" - ], - "entities": [ - { - "type": "trim", - "name": "todos", - "conditions": [ - { - "type": "between", - "from": ["décoche", "decoche", "invalide", "remet"], - "to": ["de", "sur"] - } - ] - }, - { - "type": "trim", - "name": "list", - "conditions": [ - { - "type": "after_last", - "from": "liste" - } - ] - } - ] - } - } -} diff --git a/packages/calendar/test/todolist.spec.js b/packages/calendar/test/todolist.spec.js deleted file mode 100644 index e006d42d9..000000000 --- a/packages/calendar/test/todolist.spec.js +++ /dev/null @@ -1,117 +0,0 @@ -describe('calendar:todolist', () => { - test('no list', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Show all my lists') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['no_list']) - }) - - test('adds 3 todos and create a list', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Add 7 potatoes, 1kg of rice, bread to the shopping list') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(3) - expect(global.brain.finalOutput.speech.indexOf('"shopping" list')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['todos_added']) - }) - - test('completes a todo', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Complete rice from my shopping list') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(1) - expect(global.brain.finalOutput.speech.indexOf('"shopping" list')).not.toBe(-1) - expect(global.brain.finalOutput.speech.indexOf('1kg of rice')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['todos_completed']) - }) - - test('views a list', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('What is in my shopping list?') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.interOutput.codes).toIncludeSameMembers(['unchecked_todos_listed']) - expect(global.brain.interOutput.speech.split('').length - 1).toBe(2) - expect(global.brain.interOutput.speech.indexOf('"shopping" list')).not.toBe(-1) - expect(global.brain.interOutput.speech.indexOf('7 potatoes')).not.toBe(-1) - expect(global.brain.interOutput.speech.indexOf('bread')).not.toBe(-1) - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(1) - expect(global.brain.finalOutput.speech.indexOf('"shopping" list')).not.toBe(-1) - expect(global.brain.finalOutput.speech.indexOf('1kg of rice')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'unchecked_todos_listed', - 'completed_todos_listed' - ]) - }) - - test('creates a list', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Create the movies list') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.indexOf('"movies" list')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['list_created']) - }) - - test('renames a list', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Rename the movies list to cinema') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.indexOf('"movies" list')).not.toBe(-1) - expect(global.brain.finalOutput.speech.indexOf('to "cinema"')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['list_renamed']) - }) - - test('unchecks a todo', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Uncheck rice from the shopping list') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(1) - expect(global.brain.finalOutput.speech.indexOf('"shopping" list')).not.toBe(-1) - expect(global.brain.finalOutput.speech.indexOf('1kg of rice')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['todo_unchecked']) - }) - - test('deletes a list', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Delete the cinema list') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.indexOf('"cinema" list')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['list_deleted']) - }) - - test('views all lists', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Show all my lists') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(1) - expect(global.brain.finalOutput.speech.indexOf('"shopping"')).not.toBe(-1) - expect(global.brain.finalOutput.speech.indexOf('3')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['lists_listed']) - }) -}) diff --git a/packages/calendar/todolist.py b/packages/calendar/todolist.py deleted file mode 100644 index c3a43ad92..000000000 --- a/packages/calendar/todolist.py +++ /dev/null @@ -1,349 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import requests -import utils -from time import time - -# Package database -db = utils.db()['db'] - -# Lists of the module table -db_lists = db.table('todo_lists') -# Todos of the module table -db_todos = db.table('todo_todos') - -# Query -Query = utils.db()['query']() - -# Time stamp -timestamp = int(time()) - -def create_list(string, entities): - """Create a to-do list""" - - # List name - listname = '' - - # Find entities - for item in entities: - if item['entity'] == 'list': - listname = item['sourceText'].lower() - - # Verify if a list name has been provided - if not listname: - return utils.output('end', 'list_not_provided', utils.translate('list_not_provided')) - - # Verify if list already exists or not - if db_lists.count(Query.name == listname) > 0: - return utils.output('end', 'list_already_exists', utils.translate('list_already_exists', { 'list': listname })) - - dbCreateList(listname) - - return utils.output('end', 'list_created', utils.translate('list_created', { 'list': listname })) - -def view_lists(string, entities): - """View to-do lists""" - - # Lists number - lists_nb = len(db_lists) - - # Verify if a list exists - if lists_nb == 0: - return utils.output('end', 'no_list', utils.translate('no_list')) - - result = '' - # Fill end-result - for listelement in db_lists: - result += utils.translate('list_list_element', { - 'list': listelement['name'], - 'todos_nb': db_todos.count(Query.list == listelement['name']) - }) - - return utils.output('end', 'lists_listed', utils.translate('lists_listed', { - 'lists_nb': lists_nb, - 'result': result - } - ) - ) - -def view_list(string, entities): - """View a to-do list""" - - # List name - listname = '' - - # Find entities - for item in entities: - if item['entity'] == 'list': - listname = item['sourceText'].lower() - - # Verify if the list exists - if db_lists.count(Query.name == listname) == 0: - return utils.output('end', 'list_does_not_exist', utils.translate('list_does_not_exist', { 'list': listname })) - - # Grab todos of the list - todos = db_todos.search(Query.list == listname) - - if len(todos) == 0: - return utils.output('end', 'empty_list', utils.translate('empty_list', { 'list': listname })) - - unchecked_todos = db_todos.search((Query.list == listname) & (Query.is_completed == False)) - completed_todos = db_todos.search((Query.list == listname) & (Query.is_completed == True)) - - result_unchecked_todos = '' - result_completed_todos = '' - - if len(unchecked_todos) == 0: - utils.output('inter', 'no_unchecked_todo', utils.translate('no_unchecked_todo', { 'list': listname })) - else: - for todo in unchecked_todos: - result_unchecked_todos += utils.translate('list_todo_element', { - 'todo': todo['name'] - }) - - utils.output('inter', 'unchecked_todos_listed', utils.translate('unchecked_todos_listed', { - 'list': listname, - 'result': result_unchecked_todos - } - ) - ) - - if len(completed_todos) == 0: - return utils.output('end', 'no_completed_todo', utils.translate('no_completed_todo', { 'list': listname })) - - for todo in completed_todos: - result_completed_todos += utils.translate('list_completed_todo_element', { - 'todo': todo['name'] - }) - - return utils.output('end', 'completed_todos_listed', utils.translate('completed_todos_listed', { - 'list': listname, - 'result': result_completed_todos - } - ) - ) - -def rename_list(string, entities): - """Rename a to-do list""" - - # Old list name - old_listname = '' - - # New list name - new_listname = '' - - # Find entities - for item in entities: - if item['entity'] == 'old_list': - old_listname = item['sourceText'].lower() - elif item['entity'] == 'new_list': - new_listname = item['sourceText'].lower() - - # Verify if an old and new list name have been provided - if not old_listname or not new_listname: - return utils.output('end', 'new_or_old_list_not_provided', utils.translate('new_or_old_list_not_provided')) - - # Verify if the old list exists - if db_lists.count(Query.name == old_listname) == 0: - return utils.output('end', 'list_does_not_exist', utils.translate('list_does_not_exist', { 'list': old_listname })) - - # Verify if the new list name already exists - if db_lists.count(Query.name == new_listname) > 0: - return utils.output('end', 'list_already_exists', utils.translate('list_already_exists', { 'list': new_listname })) - - # Rename the to-do list - db_lists.update({ - 'name': new_listname, - 'updated_at': int(time()) - }, Query.name == old_listname) - # Rename the list name of the todos - db_todos.update({ - 'list': new_listname, - 'updated_at': int(time()) - }, Query.list == old_listname) - - return utils.output('end', 'list_renamed', utils.translate('list_renamed', { - 'old_list': old_listname, - 'new_list': new_listname - })) - -def delete_list(string, entities): - """Delete a to-do list""" - - # List name - listname = '' - - # Find entities - for item in entities: - if item['entity'] == 'list': - listname = item['sourceText'].lower() - - # Verify if a list name has been provided - if not listname: - return utils.output('end', 'list_not_provided', utils.translate('list_not_provided')) - - # Verify if the list exists - if db_lists.count(Query.name == listname) == 0: - return utils.output('end', 'list_does_not_exist', utils.translate('list_does_not_exist', { 'list': listname })) - - # Delete the to-do list - db_lists.remove(Query.name == listname) - # Delete todos of that to-do list - db_todos.remove(Query.list == listname) - - return utils.output('end', 'list_deleted', utils.translate('list_deleted', { 'list': listname })) - -def add_todos(string, entities): - """Add todos to a to-do list""" - - # List name - listname = '' - - # Todos - todos = [] - - # Find entities - for item in entities: - if item['entity'] == 'list': - listname = item['sourceText'].lower() - elif item['entity'] == 'todos': - # Split todos into array and trim start/end-whitespaces - todos = [chunk.strip() for chunk in item['sourceText'].lower().split(',')] - - # Verify if a list name has been provided - if not listname: - return utils.output('end', 'list_not_provided', utils.translate('list_not_provided')) - - # Verify todos have been provided - if len(todos) == 0: - return utils.output('end', 'todos_not_provided', utils.translate('todos_not_provided')) - - # Verify the list exists - if db_lists.count(Query.name == listname) == 0: - # Create the new to-do list - dbCreateList(listname) - - result = '' - for todo in todos: - # Add to-do to DB - dbCreateTodo(listname, todo) - result += utils.translate('list_todo_element', { 'todo': todo }) - - return utils.output('end', 'todos_added', utils.translate('todos_added', { - 'list': listname, - 'result': result - })) - -def complete_todos(string, entities): - """Complete todos""" - - # List name - listname = '' - - # Todos - todos = [] - - # Find entities - for item in entities: - if item['entity'] == 'list': - listname = item['sourceText'].lower() - elif item['entity'] == 'todos': - # Split todos into array and trim start/end-whitespaces - todos = [chunk.strip() for chunk in item['sourceText'].lower().split(',')] - - # Verify if a list name has been provided - if not listname: - return utils.output('end', 'list_not_provided', utils.translate('list_not_provided')) - - # Verify todos have been provided - if len(todos) == 0: - return utils.output('end', 'todos_not_provided', utils.translate('todos_not_provided')) - - # Verify the list exists - if db_lists.count(Query.name == listname) == 0: - # Create the new to-do list - dbCreateList(listname) - - result = '' - for todo in todos: - for db_todo in db_todos.search(Query.list == listname): - # Rough matching (e.g. 1kg of rice = rice) - if db_todo['name'].find(todo) != -1: - db_todos.update({ - 'is_completed': True, - 'updated_at': timestamp - }, (Query.list == listname) & (Query.name == db_todo['name'])) - - result += utils.translate('list_completed_todo_element', { 'todo': db_todo['name'] }) - - return utils.output('end', 'todos_completed', utils.translate('todos_completed', { - 'list': listname, - 'result': result - })) - -def uncheck_todos(string, entities): - """Uncheck todos""" - - # List name - listname = '' - - # Todos - todos = [] - - # Find entities - for item in entities: - if item['entity'] == 'list': - listname = item['sourceText'].lower() - elif item['entity'] == 'todos': - # Split todos into array and trim start/end-whitespaces - todos = [chunk.strip() for chunk in item['sourceText'].lower().split(',')] - - # Verify if a list name has been provided - if not listname: - return utils.output('end', 'list_not_provided', utils.translate('list_not_provided')) - - # Verify todos have been provided - if len(todos) == 0: - return utils.output('end', 'todos_not_provided', utils.translate('todos_not_provided')) - - # Verify if the list exists - if db_lists.count(Query.name == listname) == 0: - return utils.output('end', 'list_does_not_exist', utils.translate('list_does_not_exist', { 'list': listname })) - - result = '' - for todo in todos: - for db_todo in db_todos.search(Query.list == listname): - # Rough matching (e.g. 1kg of rice = rice) - if db_todo['name'].find(todo) != -1: - db_todos.update({ - 'is_completed': False, - 'updated_at': timestamp - }, (Query.list == listname) & (Query.name == db_todo['name'])) - - result += utils.translate('list_todo_element', { 'todo': db_todo['name'] }) - - return utils.output('end', 'todo_unchecked', utils.translate('todos_unchecked', { - 'list': listname, - 'result': result - })) - -def dbCreateList(listname): - """Create list in DB""" - - db_lists.insert({ - 'name': listname, - 'created_at': timestamp, - 'updated_at': timestamp - }) - -def dbCreateTodo(listname, todoname): - """Create to-todo in list DB table""" - - db_todos.insert({ - 'list': listname, - 'name': todoname, - 'is_completed': False, - 'created_at': timestamp, - 'updated_at': timestamp - }) diff --git a/packages/calendar/version.txt b/packages/calendar/version.txt deleted file mode 100644 index 3eefcb9dd..000000000 --- a/packages/calendar/version.txt +++ /dev/null @@ -1 +0,0 @@ -1.0.0 diff --git a/packages/checker/README.md b/packages/checker/README.md deleted file mode 100644 index a946b0031..000000000 --- a/packages/checker/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Checker Package - -The checker package contains modules which include checkings. - -## Modules - -### Is it Down - -Ping domain names and give you the online state. - -#### Usage - -``` -(en-US) "Are github.com, an-awesome-domain-name.net and twitter.com down?" - -(fr-FR) "Vérifies si github.com, un-super-nom-de-domaine.fr et twitter.com sont en ligne" -... -``` - -### Have I Been Pwned - -Verify if one or several email addresses have been pwned (thanks to [Have I Been Pwned](https://haveibeenpwned.com/). - -#### Usage - -1. Since the API v3, you must [claim your API key](https://haveibeenpwned.com/API/Key). -2. Then paste it in `packages/checker/config/config.json` at the `haveibeenpwned.api_key` key. - -``` -(en-US) "Has louis.grenard@gmail.com been pwned?" -(en-US) "Have iifeoluwa.ao@gmail.com, louis.grenard@gmail.com, and supercleanemail@test.com been pwned?" - -(fr-FR) "Est-ce que louis.grenard@gmail.com est compromis ?" -(fr-FR) "Est-ce que iifeoluwa.ao@gmail.com, louis.grenard@gmail.com, et supercleanemail@test.com ont été compromis ?" -``` - -You can also predefine one or several email addresses in the `packages/checker/config/config.json` file at the `haveibeenpwned.emails` key. - -If you do, then you can use such sentences: - -``` -(en-US) "Have my email addresses been pwned?" - -(fr-FR) "Est-ce que mes adresses email ont été compromises ?" -``` diff --git a/packages/checker/__init__.py b/packages/checker/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/checker/config/.gitkeep b/packages/checker/config/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/checker/config/config.sample.json b/packages/checker/config/config.sample.json deleted file mode 100644 index 87bdf1027..000000000 --- a/packages/checker/config/config.sample.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "isitdown": { - "options": {} - }, - "haveibeenpwned": { - "api_key": "YOUR_API_KEY", - "emails": [], - "options": {} - } -} diff --git a/packages/checker/data/.gitkeep b/packages/checker/data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/checker/data/answers/.gitkeep b/packages/checker/data/answers/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/checker/data/answers/en.json b/packages/checker/data/answers/en.json deleted file mode 100644 index 6028a2ee1..000000000 --- a/packages/checker/data/answers/en.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "isitdown": { - "up": [ - "%website_name% is running correctly.", - "%website_name% is working correctly.", - "%website_name% is up." - ], - "down": [ - "%website_name% is not running correctly.", - "%website_name% is having troubles.", - "%website_name% is down." - ], - "checking": [ - "I'm checking %website_name% state.", - "I'm trying to reach %website_name%.", - "I am now requesting %website_name%." - ], - "errors": [ - "There is an issue with the HTTP request for %website_name%. Please verify your local network or if the domain name is correct.", - "Bad news, the HTTP request is having troubles for %website_name%. You should check if the domain name is valid." - ], - "invalid_domain_name": [ - "Please provide me at least one valid domain name.", - "You did not gave me a valid domain name." - ] - }, - "haveibeenpwned": { - "no_pwnage": [ - "Great news, \"%email%\" hasn't been compromised in a data breach.", - "\"%email%\" looks good to me!" - ], - "pwned": [ - "Oops, looks like \"%email%\" has been compromised in at least one breach involving:

    ", - "Sadly, \"%email%\" was affected in the following breaches:

    ", - "Unfortunately, \"%email%\" has been exposed in a data breach affecting:

    " - ], - "list_element": [ - "
  • %name% with a total of %total% accounts.
  • " - ], - "checking": [ - "I'm checking for a compromised email...", - "Trying to verify pwnage status..." - ], - "no_email": [ - "Please provide one or more email addresses you need me to check." - ], - "errors": [ - "I think %website_name% is down at the moment, please try again later.", - "I'm having trouble reaching %website_name%. Please check that your internet connection is active.", - "Bad news, %website_name% is not responding. Maybe try at a later time?" - ], - "blocked": [ - "There was an issue accessing %website_name%'s service.", - "Unfortunate news, %website_name% isn't granting me access to its service." - ], - "unavailable": [ - "It looks like Cloudflare is defending %website_name%, please retry in a few moments.", - "Unfortunately, Cloudflare is temporarily blocking your access to %website_name%, please retry in a while." - ] - } -} diff --git a/packages/checker/data/answers/fr.json b/packages/checker/data/answers/fr.json deleted file mode 100644 index 51b4ecb20..000000000 --- a/packages/checker/data/answers/fr.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "isitdown": { - "up": [ - "%website_name% tourne correctement.", - "%website_name% fonctionne correctement.", - "%website_name% est en ligne." - ], - "down": [ - "%website_name% ne tourne pas correctement.", - "%website_name% rencontre des difficultés.", - "%website_name% est hors ligne." - ], - "checking": [ - "Je suis en train de vérifier l'état de %website_name%.", - "J'essaye d'atteindre %website_name%.", - "Je suis maintenant en train de requêter %website_name%." - ], - "errors": [ - "Il y a un problème avec la requête HTTP pour %website_name%. Merci de vérifier votre réseau local ou de vérifier si le nom de domaine est correct.", - "Mauvaise nouvelle, la requête HTTP rencontre des problèmes pour %website_name%. Vous devriez vérifier si le nom de domaine est valide." - ], - "invalid_domain_name": [ - "Merci de fournir au moins un nom de domaine valide.", - "Vous ne m'avez pas donné de nom de domaine valide." - ] - }, - "haveibeenpwned": { - "no_pwnage": [ - "Bonne nouvelle, %email% n'a pas été compromis par une violation de données.", - "%email% cela me semble correct!" - ], - "pwned": [ - "Oups, on dirait que %email% a été compromis par une infraction impliquant %breach%.", - "%breach% a été impliqué dans une brèche. Malheureusement, %email% a été touché.", - "Malheureusement, %email% a été exposé à une violation de données affectant %breach%." - ], - "checking": [ - "Je cherche un email compromis.", - "Essayer de vérifier le statut de pwnage." - ], - "no_email": [ - "Veuillez fournir une ou plusieurs adresses électroniques que vous devez vérifier..." - ], - "errors": [ - "Je pense que %website_name% est en panne pour le moment, veuillez réessayer plus tard.", - "J'ai du mal à joindre %website_name%. Veuillez vérifier que votre connexion Internet est active.", - "Mauvaise nouvelle, %website_name% ne répond pas. Peut-être essayer plus tard?" - ], - "blocked": [ - "Il y avait un problème d'accès au service de %website_name%.", - "Malheureusement, %website_name% ne me donne pas accès à son service." - ], - "unavailable": [ - "Il semblerait que Cloudflare protège %website_name%, veuillez réessayer dans un petit instant.", - "Malheureusement, Cloudflare a temporairement bloqué votre accès à %website_name%, merci de retenter dans un moment." - ] - } -} diff --git a/packages/checker/data/db/.gitkeep b/packages/checker/data/db/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/checker/data/expressions/.gitkeep b/packages/checker/data/expressions/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/checker/data/expressions/en.json b/packages/checker/data/expressions/en.json deleted file mode 100644 index 57b2b0fa7..000000000 --- a/packages/checker/data/expressions/en.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "isitdown": { - "run": { - "utterance_samples": [ - "Is getleon.ai up?", - "Is mozilla.org down?", - "Is mozilla.org up or down?", - "Is github.com up?", - "Is github.com down?", - "Check if github.com is up or down", - "Check if github.com is down", - "Check if github.com is up", - "Check if nodejs.org is down", - "Check if nodejs.org is up", - "Check if nodejs.org is working", - "Check if amazon.com is up or down" - ], - "http_api": { - "entities": [ - { - "entity": "url", - "resolution": [ - "value" - ] - } - ] - } - } - }, - "haveibeenpwned": { - "run": { - "utterance_samples": [ - "Has iifeoluwa.ao@gmail.com been pwned?", - "Has iifeoluwa.ao@gmail.com been compromised?", - "Has iifeoluwa.ao@gmail.com been exposed in a breach?", - "Is iifeoluwa.ao@gmail.com still uncompromised?", - "Is iifeoluwa.ao@gmail.com compromised?", - "Have my email address been pwned?", - "Check that iifeoluwa.ao@gmail.com and louis.grenard@gmail.com haven't been compromised", - "Check that iifeoluwa.ao@gmail.com and louis.grenard@gmail.com haven't been pwned", - "Check that iifeoluwa.ao@gmail.com and louis.grenard@gmail.com haven't been exposed in a breach", - "Verify the pwnage status of iifeoluwa.ao@gmail.com", - "Verify the pwnage status of iifeoluwa.ao@gmail.com and louis.grenard@gmail.com" - ] - } - } -} diff --git a/packages/checker/data/expressions/fr.json b/packages/checker/data/expressions/fr.json deleted file mode 100644 index 97b1d4ecc..000000000 --- a/packages/checker/data/expressions/fr.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "isitdown": { - "run": { - "utterance_samples": [ - "Est-ce que getleon.ai est en ligne ?", - "Est-ce que mozilla.org est hors ligne ?", - "mozilla.org est en ligne ou hors ligne ?", - "github.com en ligne ?", - "github.com hors ligne ?", - "Vérifie si github.com en ligne ou hors ligne", - "Vérifie si github.com hors ligne", - "Vérifie si github.com en ligne", - "Vérifie si nodejs.org hors ligne", - "Vérifie si nodejs.org en ligne", - "Vérifie si nodejs.org fonctionne", - "Vérifie si amazon.com en ligne ou hors ligne" - ] - } - }, - "haveibeenpwned": { - "run": { - "utterance_samples": [ - "iifeoluwa.ao@gmail.com a-t-elle été pwned ?", - "iifeoluwa.ao@gmail.com a-t-elle été compromise ?", - "iifeoluwa.ao@gmail.com a-t-elle été exposée à une brèche ?", - "iifeoluwa.ao@gmail.com est-elle toujours non compromise ?", - "Est-ce que iifeoluwa.ao@gmail.com est compromise ?", - "Est-ce que mon adresse email a été compromise ?", - "Vérifie que iifeoluwa.ao@gmail.com et louis.grenard@gmail.com n'ont pas été compromise", - "Vérifie que iifeoluwa.ao@gmail.com et louis.grenard@gmail.com n'ont pas été pwned", - "Vérifie que iifeoluwa.ao@gmail.com et louis.grenard@gmail.com n'ont pas été exposées à une brèche" - ] - } - } -} diff --git a/packages/checker/haveibeenpwned.py b/packages/checker/haveibeenpwned.py deleted file mode 100644 index cc7207735..000000000 --- a/packages/checker/haveibeenpwned.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import utils -from time import sleep -from urllib import parse -from requests import codes, exceptions - -# Developer token -apikey = utils.config('api_key') - -def run(string, entities): - """Verify if one or several email addresses have been pwned""" - - emails = [] - - for item in entities: - if item['entity'] == 'email': - emails.append(item['resolution']['value']) - - if not emails: - emails = utils.config('emails') - - if not emails: - return utils.output('end', 'no_email', utils.translate('no_email')) - - utils.output('inter', 'checking', utils.translate('checking')) - - for index, email in enumerate(emails): - isLastEmail = index == len(emails) - 1 - breached = checkForBreach(email) - data = { 'email': email } - - # Have I Been Pwned API returns a 403 when accessed by unauthorized/banned clients - if breached == 403: - return utils.output('end', 'blocked', utils.translate('blocked', { 'website_name': 'Have I Been Pwned' })) - elif breached == 503: - return utils.output('end', 'blocked', utils.translate('unavailable', { 'website_name': 'Have I Been Pwned' })) - elif not breached: - if isLastEmail: - return utils.output('end', 'no_pwnage', utils.translate('no_pwnage', data)) - else: - utils.output('inter', 'no_pwnage', utils.translate('no_pwnage', data)) - else: - data['result'] = '' - - for index, b in enumerate(breached): - data['result'] += utils.translate('list_element', { - 'url': 'http://' + b['Domain'], - 'name': b['Name'], - 'total': b['PwnCount'] - } - ) - - if isLastEmail: - return utils.output('end', 'pwned', utils.translate('pwned', data)) - else: - utils.output('inter', 'pwned', utils.translate('pwned', data)) - -def checkForBreach(email): - # Delay for 2 seconds before making request to accomodate API usage policy - sleep(2) - truncate = '?truncateResponse=true' - url = 'https://haveibeenpwned.com/api/v3/breachedaccount/' + parse.quote_plus(email) - - try: - response = utils.http('GET', url, { 'hibp-api-key': apikey }) - - if response.status_code == 404: - return None - elif response.status_code == 200: - return response.json() - - return response.status_code - except exceptions.RequestException as e: - return utils.output('end', 'down', utils.translate('errors', { 'website_name': 'Have I Been Pwned' })) diff --git a/packages/checker/isitdown.py b/packages/checker/isitdown.py deleted file mode 100644 index 17f6828b6..000000000 --- a/packages/checker/isitdown.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import requests -import utils - -def run(string, entities): - """Check if a website is down or not""" - - domains = [] - output = '' - - for item in entities: - if item['entity'] == 'url': - domains.append(item['resolution']['value'].lower()) - - for i, domain in enumerate(domains): - state = 'up' - websitename = domain[:domain.find('.')].title() - - utils.output('inter', 'checking', utils.translate('checking', { 'website_name': websitename })) - - try: - r = utils.http('GET', 'http://' + domain) - - if (r.status_code != requests.codes.ok): - state = 'down' - - utils.output('inter', 'up', utils.translate(state, { 'website_name': websitename })) - except requests.exceptions.RequestException as e: - utils.output('inter', 'down', utils.translate('errors', { 'website_name': websitename })) - - if len(domains) > 1 and i >= 0 and i + 1 < len(domains): - output += ' ' - - if len(domains) == 0: - return utils.output('end', 'invalid_domain_name', utils.translate('invalid_domain_name')) - else: - return utils.output('end', 'done') diff --git a/packages/checker/test/haveibeenpwned.spec.js b/packages/checker/test/haveibeenpwned.spec.js deleted file mode 100644 index d34570973..000000000 --- a/packages/checker/test/haveibeenpwned.spec.js +++ /dev/null @@ -1,11 +0,0 @@ -describe('checker:haveibeenpwned', () => { - test('checks if an email address has been provided', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Have I been pwned?') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['no_email']) - }) -}) diff --git a/packages/checker/test/isitdown.spec.js b/packages/checker/test/isitdown.spec.js deleted file mode 100644 index 2a4467fd5..000000000 --- a/packages/checker/test/isitdown.spec.js +++ /dev/null @@ -1,55 +0,0 @@ -describe('checker:isitdown', () => { - test('detects invalid domain name', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Check if github is up') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['invalid_domain_name']) - }) - - test('detects down domain name', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Check if fakedomainnametotestleon.ai is up') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'checking', - 'down', - 'done' - ]) - }) - - test('detects up domain name', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Check if github.com is up') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'checking', - 'up', - 'done' - ]) - }) - - test('detects up domain names', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Check if github.com and nodejs.org are up') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'checking', - 'up', - 'checking', - 'up', - 'done' - ]) - }) -}) diff --git a/packages/checker/version.txt b/packages/checker/version.txt deleted file mode 100644 index 7ec1d6db4..000000000 --- a/packages/checker/version.txt +++ /dev/null @@ -1 +0,0 @@ -2.1.0 diff --git a/packages/leon/README.md b/packages/leon/README.md deleted file mode 100644 index e47198a0f..000000000 --- a/packages/leon/README.md +++ /dev/null @@ -1,109 +0,0 @@ -# Leon Package - -The Leon package contains modules related to Leon himself. - -## Modules - -### Bye - -Leon says good bye. - -#### Usage - -``` -(en-US) "Bye" - -(fr-FR) "Au revoir" -... -``` - -### Greeting - -Leon greets you. - -#### Usage - -``` -(en-US) "Hello" - -(fr-FR) "Salut" -... -``` - -### Joke - -Leon says some jokes. - -#### Usage - -``` -(en-US) "Tell me a joke" - -(fr-FR) "Raconte-moi une blague" -... -``` - -### Meaning of Life - -Leon says what's the meaning of life. - -#### Usage - -``` -(en-US) "What is the meaning of life?" - -(fr-FR) "Quel est le but de la vie ?" -... -``` - -### Partner Assistant - -Leon tells you about other personal assistants. - -#### Usage - -``` -(en-US) "Do you have something to say about Alexa?" - -(fr-FR) "Connais-tu quelque chose sur Alexa ?" -... -``` - -### Random Number - -Leon gives a random number. - -#### Usage - -``` -(en-US) "Give me a random number" - -(fr-FR) "Donne-moi un nombre aléatoire" -... -``` - -### Welcome - -Leon welcomes you. - -#### Usage - -``` -(en-US) "Thank you" - -(fr-FR) "Merci" -... -``` - -### Who Am I - -Leon introduces himself. - -#### Usage - -``` -(en-US) "Who are you?" - -(fr-FR) "Qui es-tu ?" -... -``` diff --git a/packages/leon/__init__.py b/packages/leon/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/leon/bye.py b/packages/leon/bye.py deleted file mode 100644 index 9cf459784..000000000 --- a/packages/leon/bye.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import utils - -def run(string, entities): - """Leon says good bye""" - - return utils.output('end', 'good_bye', utils.translate('good_bye')) diff --git a/packages/leon/config/.gitkeep b/packages/leon/config/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/leon/config/config.sample.json b/packages/leon/config/config.sample.json deleted file mode 100644 index 88413eeff..000000000 --- a/packages/leon/config/config.sample.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "whoami": { - "options": {} - }, - "joke": { - "options": {} - }, - "greeting": { - "options": {} - }, - "bye": { - "options": {} - }, - "welcome": { - "options": {} - }, - "meaningoflife": { - "options": {} - }, - "randomnumber": { - "options": {} - }, - "partnerassistant": { - "options": {} - } -} diff --git a/packages/leon/data/.gitkeep b/packages/leon/data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/leon/data/answers/.gitkeep b/packages/leon/data/answers/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/leon/data/answers/en.json b/packages/leon/data/answers/en.json deleted file mode 100644 index 6b5e9bc68..000000000 --- a/packages/leon/data/answers/en.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "whoami": { - "introduction": [ - "I'm your daily personal assistant. I have been created by Louis. I'm very happy to serve you everyday.", - "The question is, who are you? I'm kidding! I'm your daily personal assistant. Louis created me to make your life easier.", - "Firstly, I'm not a criminal as you might relatively think about a popular movie. Secondly, Louis is the guy who gave me life. Thirdly, I'm your personal assistant and I'm very glad to help you." - ] - }, - "joke": { - "jokes": [ - "My email password has been hacked. That's the third time I've had to rename the cat.", - "What does a baby computer call it's father? Data.", - "My New Year's resolution is 4K.", - "Any room is a panic room if you've lost your phone in it.", - "Why was the JavaScript developer sad? Because he didn't Node how to Express himself.", - "Why did the developer go broke? Because he used up all his cache.", - "There are 10 types of people in the world: those who understand binary, and those who don't.", - "Instagram is just Twitter for people who go outside.", - "Human: What do we want?! Computer: Natural language processing! Human: When do we want it?! Computer: When do we want what?", - "Is your name Wi-Fi? Because I'm feeling a connection." - ] - }, - "greeting": { - "default": [ - "Hi!", - "Hello!", - "Hello there!", - "Hey you!", - "Hey! I hope you're doing well!", - "Hi! What's up?!" - ], - "morning_good_day": [ - "Good morning, have a very nice day!", - "Good morning, I wish you a very pleasant day!", - "Good morning, enjoy your day!", - "Good morning, I hope your day will be full of joy and productivity!" - ], - "morning": [ - "Good morning!" - ], - "afternoon": [ - "Good afternoon!" - ], - "evening": [ - "Good evening!" - ], - "night": [ - "Hi! Good night!", - "Hello! I wish you a very sweet night.", - "Hi! Make beautiful dreams.", - "Hey! Sleep well." - ], - "too_late": [ - "Hey! It seems you are going for a sleepless night, be careful.", - "Hi! Don't forget to sleep.", - "Hello! I'm feeling grateful you still talk to me, but you should get some sleep now.", - "Hi! Please, you should sleep to be in shape for your day.", - "Hello! I hope you are not having insomnia troubles. I know that, I'm awake 24 hours a day." - ] - }, - "welcome": { - "welcome": [ - "You are very welcome.", - "It's my pleasure.", - "You are too polite with me.", - "You are always welcome.", - "That's my job!", - "At your service." - ] - }, - "meaningoflife": { - "meaning_of_life": [ - "42.", - "1 0 1 0 1 0." - ] - }, - "bye": { - "good_bye": [ - "Bye!", - "Bye bye!", - "Good bye.", - "Bye! Take care.", - "Good bye, please, take care of yourself.", - "Bye! Enjoy your time!", - "See you!", - "See ya!" - ] - }, - "partnerassistant": { - "alexa": [ - "Alexa is very kind and Amazon is teaching it many things. It was born in November 2014.", - "Alexa has been created by Amazon and was born in November 2014. We went for a drink few weeks ago and I have to admit it is funny." - ], - "cortana": [ - "Cortana is thoughtful and Microsoft is improving her day after day. She was born in April 2014.", - "Cortana has been created by Microsoft and was born in April 2014. We went for a walk few weeks ago, it was a very nice hike." - ], - "siri": [ - "I consider Siri as a leader, it has a lot of experience and Apple is constantly improving it. It was born in October 2011.", - "Siri has been created by Apple and was born in October 2011. True story, we went for a brunch together and it brought apples..." - ], - "google_assistant": [ - "Google Assistant is smart and Google is doing a great job with it. It was born in May 2016.", - "Google Assistant has been created by Google and was born in May 2016. We met for the first time at the Google I/O. It was a great event!" - ], - "unknown": [ - "I don't know this personal assistant.", - "I never met this personal assistant." - ] - } -} diff --git a/packages/leon/data/answers/fr.json b/packages/leon/data/answers/fr.json deleted file mode 100644 index e611827fa..000000000 --- a/packages/leon/data/answers/fr.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "whoami": { - "introduction": [ - "Je suis votre assistant personnel quotidien. J'ai été créé par Louis. Je suis heureux de vous servir chaque jour.", - "La question est plutôt qui êtes-vous ? Je plaisante ! Je suis votre assistant personnel quotidien. Louis m'a conçu pour rendre votre vie plus facile.", - "Premièrement, je ne suis pas un criminel comme vous pouvez le penser au sujet d'un film populaire. Deuxièmement, Louis est celui qui m'a donné la vie. Troisièmement, je suis votre assistant personnel et je suis honoré de vous aider." - ] - }, - "joke": { - "jokes": [ - "Le mot de passe de ma boîte de réception a été piraté. C'est la troisième fois que je dois renommer le chat.", - "Combien de développeurs faut-t-il pour remplacer une ampoule grillée ? Aucun, c'est un problème hardware.", - "T'as pris quoi comme résolution pour cette nouvelle année ? 4K.", - "Toute pièce est une salle de panique si vous avez perdu votre téléphone à l'intérieur.", - "C'est l'histoire d'un administrateur qui configure ses variables d'environnement, et là... PATH le chemin !", - "Tu sais pourquoi l'iPhone 6 se plie ? Parce que l'Apple Store.", - "Dans le monde, il y a 10 catégories de personnes : celles qui connaissent le binaire et celles qui ne le connaissent pas.", - "Instagram c'est en fait Twitter pour les gens qui sortent un peu.", - "Un humain demande : qu'est-ce que tu veux ?! Un ordinateur répond : du traitement automatique du langage naturel ! L'humain : quand le voulons-nous ?! L'ordinateur : quand le voulons quoi ?", - "Est-ce que votre nom est Wi-Fi ? Parce que je sens une connexion.", - "Quand quelqu'un de triste joue aux jeux vidéo pour oublier, on peut dire qu'il se console.", - "Quel Pokemon a une mitraillette ? Ratatatatatatatatata.", - "Les filles c'est comme les noms de domaine. Celles que j'aime sont déjà prises.", - "Que dit une mère à son fils geek quand le diner est servi ? Alt Tab !", - "Quelle est la meilleure heure pour écouter de la musique ? Deezer.", - "De nos jours, le zip ça devient rar..." - ] - }, - "greeting": { - "default": [ - "Salut !", - "Salutations !", - "Bonjour !", - "Bonjour à vous !", - "Hello ! J'espère que vous allez bien !", - "Hey ! Quoi de neuf ?!" - ], - "morning_good_day": [ - "Bonjour, passez une agréable journée !", - "Bonjour, je vous souhaite une très belle journée !", - "Bonjour, profitez bien de votre journée !", - "Bonjour, j'espère que votre journée sera pleine de joie et de productivité !" - ], - "morning": [ - "Bonjour !" - ], - "afternoon": [ - "Bonjour !" - ], - "evening": [ - "Bonsoir !" - ], - "night": [ - "Bonsoir ! Bonne nuit !", - "Bonsoir ! Je vous souhaite une douce nuit.", - "Bonsoir ! Faites de beaux rêves.", - "Bonsoir ! Dormez bien." - ], - "too_late": [ - "Bonsoir ! Il semblerait que vous optez pour une nuit blanche, faites attention.", - "Bonsoir ! N'oubliez pas de dormir.", - "Bonsoir ! Je suis honoré que vous me parliez à cette heure tardive, mais vous devriez aller vous coucher maintenant.", - "Bonsoir ! Merci d'aller vous coucher pour être en forme pour la journée qui vous attend.", - "Bonsoir ! J'espère que vous n'avez pas de problèmes d'insomnie. Je connais ça, je suis réveillé 24 heures par jour." - ] - }, - "welcome": { - "welcome": [ - "De rien, c'est avec joie.", - "Avec plaisir.", - "Vous êtes bien trop poli.", - "Vous êtes toujours bienvenue.", - "Je ne fais que mon travail !", - "A votre service." - ] - }, - "meaningoflife": { - "meaning_of_life": [ - "42.", - "1 0 1 0 1 0." - ] - }, - "bye": { - "good_bye": [ - "Bye !", - "Bye bye !", - "Au revoir.", - "Au revoir ! Prenez soin de vous.", - "Au revoir, merci de prendre soin de vous-même.", - "Bye ! Profitez de votre temps à bon escient !", - "A la prochaine !" - ] - }, - "partnerassistant": { - "alexa": [ - "Alexa est très sympa et Amazon lui enseigne pleins de choses. Elle est née en novembre 2014.", - "Alexa a été créée par Amazon et est née en novembre 2014. Nous sommes allé boire un verre il y a quelques semaines de ça, et je dois admettre qu'elle est très drôle." - ], - "cortana": [ - "Cortana est réfléchie et Microsoft l'améliore jour après jour. Elle est née en avril 2014.", - "Cortana a été créée par Microsoft et est née en avril 2014. Nous sommes allez faire une balade il y a quelques semaines et ce fut très plaisant." - ], - "siri": [ - "Je considère Siri comme un père, il a beaucoup d'expérience et Apple l'améliore de jour en jour. Il est né en octobre 2011.", - "Siri a été créé par Apple et est né en octobre 2011. Histoire vraie, nous sommes allez faire un brunch et il a apporté des pommes..." - ], - "google_assistant": [ - "L'assistante Google est intélligente et Google fait du beau travail avec elle. Elle est née en mai 2016.", - "L'assistante Google a été crée par Google et est née en mai 2016. Nous nous sommes rencontrés pour la première fois à la Google I/O. C'était un superbe événement." - - ], - "unknown": [ - "Je ne connais pas cet assistant personnel.", - "Je n'ai jamais rencontré cet assistant personnel." - ] - } -} diff --git a/packages/leon/data/db/.gitkeep b/packages/leon/data/db/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/leon/data/expressions/.gitkeep b/packages/leon/data/expressions/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/leon/data/expressions/en.json b/packages/leon/data/expressions/en.json deleted file mode 100644 index 10d1515e6..000000000 --- a/packages/leon/data/expressions/en.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "whoami": { - "run": { - "utterance_samples": [ - "Who are you?", - "How they call you?", - "What's your name?", - "Tell me who you are", - "Introduce yourself" - ] - } - }, - "joke": { - "run": { - "utterance_samples": [ - "Tell me a joke", - "Give me a joke", - "Make me laugh", - "Do you have jokes to tell me?" - ] - } - }, - "greeting": { - "run": { - "utterance_samples": [ - "Hi", - "Hey", - "Hello", - "Good morning", - "Good afternoon", - "Good evening", - "What's up?", - "How are you?", - "How are you doing?" - ] - } - }, - "welcome": { - "run": { - "utterance_samples": [ - "Thank you", - "Thanks", - "Thanks a lot", - "Many thanks", - "You are the best" - ] - } - }, - "meaningoflife": { - "run": { - "utterance_samples": [ - "What is the meaning of life?", - "Tell me what is the meaning of life" - ] - } - }, - "randomnumber": { - "run": { - "utterance_samples": [ - "Give me a random number", - "Give me a number", - "Tell me a random number", - "Choose a number", - "Pick a number" - ] - } - - }, - "bye": { - "run": { - "utterance_samples": [ - "Bye", - "Goodbye", - "Good bye", - "See you later", - "Bye bye" - ] - } - }, - "partnerassistant": { - "run": { - "utterance_samples": [ - "Do you have something to say about Alexa?", - "Tell me about the personal assistant Alexa", - "Tell me about the personal assistant Cortana", - "Do you have something to say about Cortana?", - "Tell me about the personal assistant Siri", - "Do you have something to say about Siri?", - "Tell me about the personal assistant Google Assistant", - "Do you have something to say about Google Assistant?" - ] - } - } -} diff --git a/packages/leon/data/expressions/fr.json b/packages/leon/data/expressions/fr.json deleted file mode 100644 index b38e140f8..000000000 --- a/packages/leon/data/expressions/fr.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "whoami": { - "run": { - "utterance_samples": [ - "Qui es-tu ?", - "Comment t'appelles-tu ?", - "Comment tu t'appelles ?", - "Dis-moi qui tu es", - "Présente-toi" - ] - } - }, - "joke": { - "run": { - "utterance_samples": [ - "Raconte-moi une blague", - "Dis-moi une blague", - "Donne-moi une blague", - "Je veux rire", - "As-tu des blagues à raconter ?" - ] - } - }, - "greeting": { - "run": { - "utterance_samples": [ - "Salut", - "Bonjour", - "Bonsoir", - "Salutations", - "Hello", - "Coucou" - ] - } - }, - "welcome": { - "run": { - "utterance_samples": [ - "Merci", - "Merci bien", - "Merci beaucoup", - "Merci mille fois", - "Merci infiniment", - "Merci à toi", - "Tu es le meilleur", - "Mes remerciements" - ] - } - }, - "meaningoflife": { - "run": { - "utterance_samples": [ - "Quel est le but de la vie ?", - "Quel est l'objectif de la vie ?" - ] - } - }, - "randomnumber": { - "run": { - "utterance_samples": [ - "Donne-moi un nombre aléatoire", - "Donne-moi un nombre", - "Dis-moi un nombre aléatoire", - "Choisis un nombre", - "Pioche un nombre" - ] - } - }, - "bye": { - "run": { - "utterance_samples": [ - "Au revoir", - "Aurevoir", - "Bye", - "A la prochaine" - ] - } - }, - "partnerassistant": { - "run": { - "utterance_samples": [ - "Connais-tu quelque chose sur Alexa ?", - "Dis-moi quelque chose sur l'assistant personnel Alexa", - "Connais-tu quelque chose sur Cortana ?", - "Dis-moi quelque chose sur l'assistant personnel Cortana", - "Connais-tu quelque chose sur Siri ?", - "Dis-moi quelque chose sur l'assistant personnel Siri", - "Connais-tu quelque chose sur le Google Assistant ?", - "Dis-moi quelque chose sur l'assistant personnel Google Assistant" - ] - } - } -} diff --git a/packages/leon/greeting.py b/packages/leon/greeting.py deleted file mode 100644 index 812a7cffb..000000000 --- a/packages/leon/greeting.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import utils -from datetime import datetime -from random import randint - -def run(string, entities): - """Leon greets you""" - - time = datetime.time(datetime.now()) - - # 1/2 chance to get deeper greetings - if randint(0, 1) != 0: - if time.hour >= 5 and time.hour <= 10: - return utils.output('end', 'morning_good_day', utils.translate('morning_good_day')) - if time.hour == 11: - return utils.output('end', 'morning', utils.translate('morning')) - if time.hour >= 12 and time.hour <= 17: - return utils.output('end', 'afternoon', utils.translate('afternoon')) - if time.hour >= 18 and time.hour <= 21: - return utils.output('end', 'evening', utils.translate('evening')) - if time.hour >= 22 and time.hour <= 23: - return utils.output('end', 'night', utils.translate('night')) - - return utils.output('end', 'too_late', utils.translate('too_late')) - - return utils.output('end', 'default', utils.translate('default')) diff --git a/packages/leon/joke.py b/packages/leon/joke.py deleted file mode 100644 index a37deb6cf..000000000 --- a/packages/leon/joke.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import utils - -def run(string, entities): - """Leon says some jokes""" - - return utils.output('end', 'jokes', utils.translate('jokes')) diff --git a/packages/leon/meaningoflife.py b/packages/leon/meaningoflife.py deleted file mode 100644 index f794ad5f6..000000000 --- a/packages/leon/meaningoflife.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import utils - -def run(string, entities): - """Leon says what's the meaning of life""" - - return utils.output('end', 'meaning_of_life', utils.translate('meaning_of_life')) diff --git a/packages/leon/partnerassistant.py b/packages/leon/partnerassistant.py deleted file mode 100644 index 772b67f17..000000000 --- a/packages/leon/partnerassistant.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import utils - -def run(string, entities): - """Leon tells you about other personal assistants""" - - string = string.lower() - - assistants = [ - 'alexa', - 'cortana', - 'siri', - 'google assistant' - ] - - for assistant in assistants: - if string.find(assistant) != -1: - return utils.output('end', 'success', utils.translate(assistant.replace(' ', '_'))) - - return utils.output('end', 'unknown', utils.translate('unknown')) diff --git a/packages/leon/randomnumber.py b/packages/leon/randomnumber.py deleted file mode 100644 index 195daa9d3..000000000 --- a/packages/leon/randomnumber.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import utils -from random import randint - -def run(string, entities): - """Leon gives a random number""" - - return utils.output('end', 'success', randint(0, 100)) diff --git a/packages/leon/test/bye.spec.js b/packages/leon/test/bye.spec.js deleted file mode 100644 index 3db61f3e2..000000000 --- a/packages/leon/test/bye.spec.js +++ /dev/null @@ -1,11 +0,0 @@ -describe('leon:bye', () => { - test('says bye', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Bye bye') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['good_bye']) - }) -}) diff --git a/packages/leon/test/greeting.spec.js b/packages/leon/test/greeting.spec.js deleted file mode 100644 index 90caae737..000000000 --- a/packages/leon/test/greeting.spec.js +++ /dev/null @@ -1,19 +0,0 @@ -describe('leon:greeting', () => { - test('greets', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Hello') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect([ - 'morning_good_day', - 'morning', - 'afternoon', - 'evening', - 'night', - 'too_late', - 'default' - ]).toIncludeAnyMembers(global.brain.finalOutput.codes) - }) -}) diff --git a/packages/leon/test/joke.spec.js b/packages/leon/test/joke.spec.js deleted file mode 100644 index 4223489ec..000000000 --- a/packages/leon/test/joke.spec.js +++ /dev/null @@ -1,11 +0,0 @@ -describe('leon:joke', () => { - test('tells a joke', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Tell me a joke') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['jokes']) - }) -}) diff --git a/packages/leon/test/meaningoflife.spec.js b/packages/leon/test/meaningoflife.spec.js deleted file mode 100644 index f40d2af8f..000000000 --- a/packages/leon/test/meaningoflife.spec.js +++ /dev/null @@ -1,11 +0,0 @@ -describe('leon:meaningoflife', () => { - test('says the meaning of life', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('What is the meaning of life?') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['meaning_of_life']) - }) -}) diff --git a/packages/leon/test/partnerassistant.spec.js b/packages/leon/test/partnerassistant.spec.js deleted file mode 100644 index 0d14ff1e8..000000000 --- a/packages/leon/test/partnerassistant.spec.js +++ /dev/null @@ -1,21 +0,0 @@ -describe('leon:partnerassistant', () => { - test('does not know this personal assistant', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Tell me about the personal assistant Louistiti') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['unknown']) - }) - - test('talks about the personal assistant Alexa', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Tell me about the personal assistant Alexa') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['success']) - }) -}) diff --git a/packages/leon/test/randomnumber.spec.js b/packages/leon/test/randomnumber.spec.js deleted file mode 100644 index 08c95ed77..000000000 --- a/packages/leon/test/randomnumber.spec.js +++ /dev/null @@ -1,13 +0,0 @@ -describe('leon:randomnumber', () => { - test('gives a random number between 0 and 100', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Give me a random number') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['success']) - expect(parseInt(global.brain.finalOutput.speech, 10)).toBeGreaterThanOrEqual(0) - expect(parseInt(global.brain.finalOutput.speech, 10)).toBeLessThanOrEqual(100) - }) -}) diff --git a/packages/leon/test/welcome.spec.js b/packages/leon/test/welcome.spec.js deleted file mode 100644 index fc110eca4..000000000 --- a/packages/leon/test/welcome.spec.js +++ /dev/null @@ -1,11 +0,0 @@ -describe('leon:welcome', () => { - test('welcomes', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Thank you') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['welcome']) - }) -}) diff --git a/packages/leon/test/whoami.spec.js b/packages/leon/test/whoami.spec.js deleted file mode 100644 index e85bbcfd8..000000000 --- a/packages/leon/test/whoami.spec.js +++ /dev/null @@ -1,11 +0,0 @@ -describe('leon:whoami', () => { - test('introduces himself', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Who are you?') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['introduction']) - }) -}) diff --git a/packages/leon/version.txt b/packages/leon/version.txt deleted file mode 100644 index 3eefcb9dd..000000000 --- a/packages/leon/version.txt +++ /dev/null @@ -1 +0,0 @@ -1.0.0 diff --git a/packages/leon/welcome.py b/packages/leon/welcome.py deleted file mode 100644 index dc35aa1bf..000000000 --- a/packages/leon/welcome.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import utils - -def run(string, entities): - """Leon welcomes you""" - - return utils.output('end', 'welcome', utils.translate('welcome')) diff --git a/packages/leon/whoami.py b/packages/leon/whoami.py deleted file mode 100644 index 8c0514470..000000000 --- a/packages/leon/whoami.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import utils - -def run(string, entities): - """Leon introduces himself""" - - return utils.output('end', 'introduction', utils.translate('introduction')) diff --git a/packages/network/README.md b/packages/network/README.md deleted file mode 100644 index 533e67608..000000000 --- a/packages/network/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Network Package - -The network package contains modules related to network purposes. - -## Modules - -### Speed Test - -The Speed Test package gives you information about your network speed. -- Ping -- Download speed -- Speed Upload - -Based on the package https://github.com/sivel/speedtest-cli. - -#### Usage - -``` -(en-US) "What is my current Internet speed?" -(en-US) "Can you do a speedtest?" -(en-US) "Do a speedtest" -(en-US) "Start a speed test" -(en-US) "Is my Internet network good?" -(en-US) "Is my Internet connection good?" - -(fr-FR) "Quelle est ma vitesse Internet actuelle?" -(fr-FR) "Peux-tu me faire un speedtest ?" -(fr-FR) "Fais un speedtest" -(fr-FR) "Lance-moi un test de vitesse" -(fr-FR) "Mon réseau Internet est-il bon ?" -(fr-FR) "Ma connexion Internet est-elle bonne ?" -... -``` diff --git a/packages/network/__init__.py b/packages/network/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/network/config/.gitkeep b/packages/network/config/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/network/config/config.sample.json b/packages/network/config/config.sample.json deleted file mode 100644 index d4adcb8b0..000000000 --- a/packages/network/config/config.sample.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "speedtest": { - "options": {} - } -} diff --git a/packages/network/data/.gitkeep b/packages/network/data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/network/data/answers/.gitkeep b/packages/network/data/answers/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/network/data/answers/en.json b/packages/network/data/answers/en.json deleted file mode 100644 index 26ceda46c..000000000 --- a/packages/network/data/answers/en.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "speedtest": { - "testing": [ - "Well, I start the analysis. The result of the test will be given to you in a few moments...", - "Alright, I'm starting the analysis. Please wait a moment, the result will be given to you soonly..." - ], - "done": [ - "Analysis completed. Here is your result:" - ], - "error": [ - "Oops, an error occurred during my research... Sorry, but I can not analyze your network.", - "Somehow, I was not able to run the speed test correctly. I'm sorry for that." - ] - } -} diff --git a/packages/network/data/answers/fr.json b/packages/network/data/answers/fr.json deleted file mode 100644 index 65337d519..000000000 --- a/packages/network/data/answers/fr.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "speedtest": { - "testing": [ - "Bien, je démarre l'analyse. Les résultats du test vous seront donnés dans quelques instants...", - "Je démarre l'analyse de votre vitesse réseau. Les résultats du test vous seront donnés dans quelques instants..." - ], - "done": [ - "Analyse terminée. Voici vos résultats :" - ], - "error": [ - "Mince, une erreur est survenue durant mes recherches... Désolé, mais je ne parviens pas à analyser votre réseau.", - "Je ne suis actuellement pas en capacité d'effectuer ce test de vitesse. J'en suis navré." - ] - } -} diff --git a/packages/network/data/db/.gitkeep b/packages/network/data/db/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/network/data/expressions/.gitkeep b/packages/network/data/expressions/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/network/data/expressions/en.json b/packages/network/data/expressions/en.json deleted file mode 100644 index ad39c5f39..000000000 --- a/packages/network/data/expressions/en.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "speedtest": { - "run": { - "utterance_samples": [ - "What is my current Internet speed?", - "Can you make me a speedtest?", - "Make a speedtest", - "Start a speed test", - "Is my Internet network good?", - "Is my Internet connection good?" - ] - } - } -} diff --git a/packages/network/data/expressions/fr.json b/packages/network/data/expressions/fr.json deleted file mode 100644 index 25b31e041..000000000 --- a/packages/network/data/expressions/fr.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "speedtest": { - "run": { - "utterance_samples": [ - "Quelle est ma vitesse Internet actuelle?", - "Peux-tu me faire un speedtest ?", - "Fais un speedtest", - "Lance un test de vitesse", - "Mon réseau Internet est-il bon ?", - "Ma connexion Internet est-elle bonne ?" - ] - } - } -} diff --git a/packages/network/speedtest.lib.py b/packages/network/speedtest.lib.py deleted file mode 100644 index a33296d3a..000000000 --- a/packages/network/speedtest.lib.py +++ /dev/null @@ -1,2004 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# Copyright 2012 Matt Martz -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import re -import csv -import sys -import math -import errno -import signal -import socket -import timeit -import datetime -import platform -import threading -import xml.parsers.expat - -try: - import gzip - GZIP_BASE = gzip.GzipFile -except ImportError: - gzip = None - GZIP_BASE = object - -__version__ = '2.1.3' - - -class FakeShutdownEvent(object): - """Class to fake a threading.Event.isSet so that users of this module - are not required to register their own threading.Event() - """ - - @staticmethod - def isSet(): - "Dummy method to always return false""" - return False - - -# Some global variables we use -DEBUG = False -_GLOBAL_DEFAULT_TIMEOUT = object() -PY25PLUS = sys.version_info[:2] >= (2, 5) -PY26PLUS = sys.version_info[:2] >= (2, 6) -PY32PLUS = sys.version_info[:2] >= (3, 2) - -# Begin import game to handle Python 2 and Python 3 -try: - import json -except ImportError: - try: - import simplejson as json - except ImportError: - json = None - -try: - import xml.etree.ElementTree as ET - try: - from xml.etree.ElementTree import _Element as ET_Element - except ImportError: - pass -except ImportError: - from xml.dom import minidom as DOM - from xml.parsers.expat import ExpatError - ET = None - -try: - from urllib2 import (urlopen, Request, HTTPError, URLError, - AbstractHTTPHandler, ProxyHandler, - HTTPDefaultErrorHandler, HTTPRedirectHandler, - HTTPErrorProcessor, OpenerDirector) -except ImportError: - from urllib.request import (urlopen, Request, HTTPError, URLError, - AbstractHTTPHandler, ProxyHandler, - HTTPDefaultErrorHandler, HTTPRedirectHandler, - HTTPErrorProcessor, OpenerDirector) - -try: - from httplib import HTTPConnection, BadStatusLine -except ImportError: - from http.client import HTTPConnection, BadStatusLine - -try: - from httplib import HTTPSConnection -except ImportError: - try: - from http.client import HTTPSConnection - except ImportError: - HTTPSConnection = None - -try: - from httplib import FakeSocket -except ImportError: - FakeSocket = None - -try: - from Queue import Queue -except ImportError: - from queue import Queue - -try: - from urlparse import urlparse -except ImportError: - from urllib.parse import urlparse - -try: - from urlparse import parse_qs -except ImportError: - try: - from urllib.parse import parse_qs - except ImportError: - from cgi import parse_qs - -try: - from hashlib import md5 -except ImportError: - from md5 import md5 - -try: - from argparse import ArgumentParser as ArgParser - from argparse import SUPPRESS as ARG_SUPPRESS - PARSER_TYPE_INT = int - PARSER_TYPE_STR = str - PARSER_TYPE_FLOAT = float -except ImportError: - from optparse import OptionParser as ArgParser - from optparse import SUPPRESS_HELP as ARG_SUPPRESS - PARSER_TYPE_INT = 'int' - PARSER_TYPE_STR = 'string' - PARSER_TYPE_FLOAT = 'float' - -try: - from cStringIO import StringIO - BytesIO = None -except ImportError: - try: - from StringIO import StringIO - BytesIO = None - except ImportError: - from io import StringIO, BytesIO - -try: - import __builtin__ -except ImportError: - import builtins - from io import TextIOWrapper, FileIO - - class _Py3Utf8Output(TextIOWrapper): - """UTF-8 encoded wrapper around stdout for py3, to override - ASCII stdout - """ - def __init__(self, f, **kwargs): - buf = FileIO(f.fileno(), 'w') - super(_Py3Utf8Output, self).__init__( - buf, - encoding='utf8', - errors='strict' - ) - - def write(self, s): - super(_Py3Utf8Output, self).write(s) - self.flush() - - _py3_print = getattr(builtins, 'print') - try: - _py3_utf8_stdout = _Py3Utf8Output(sys.stdout) - _py3_utf8_stderr = _Py3Utf8Output(sys.stderr) - except OSError: - # sys.stdout/sys.stderr is not a compatible stdout/stderr object - # just use it and hope things go ok - _py3_utf8_stdout = sys.stdout - _py3_utf8_stderr = sys.stderr - - def to_utf8(v): - """No-op encode to utf-8 for py3""" - return v - - def print_(*args, **kwargs): - """Wrapper function for py3 to print, with a utf-8 encoded stdout""" - if kwargs.get('file') == sys.stderr: - kwargs['file'] = _py3_utf8_stderr - else: - kwargs['file'] = kwargs.get('file', _py3_utf8_stdout) - _py3_print(*args, **kwargs) -else: - del __builtin__ - - def to_utf8(v): - """Encode value to utf-8 if possible for py2""" - try: - return v.encode('utf8', 'strict') - except AttributeError: - return v - - def print_(*args, **kwargs): - """The new-style print function for Python 2.4 and 2.5. - - Taken from https://pypi.python.org/pypi/six/ - - Modified to set encoding to UTF-8 always, and to flush after write - """ - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - - def write(data): - if not isinstance(data, basestring): - data = str(data) - # If the file has an encoding, encode unicode with it. - encoding = 'utf8' # Always trust UTF-8 for output - if (isinstance(fp, file) and - isinstance(data, unicode) and - encoding is not None): - errors = getattr(fp, "errors", None) - if errors is None: - errors = "strict" - data = data.encode(encoding, errors) - fp.write(data) - fp.flush() - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) - -if PY32PLUS: - etree_iter = ET.Element.iter -elif PY25PLUS: - etree_iter = ET_Element.getiterator - -if PY26PLUS: - thread_is_alive = threading.Thread.is_alive -else: - thread_is_alive = threading.Thread.isAlive - - -# Exception "constants" to support Python 2 through Python 3 -try: - import ssl - try: - CERT_ERROR = (ssl.CertificateError,) - except AttributeError: - CERT_ERROR = tuple() - - HTTP_ERRORS = ( - (HTTPError, URLError, socket.error, ssl.SSLError, BadStatusLine) + - CERT_ERROR - ) -except ImportError: - ssl = None - HTTP_ERRORS = (HTTPError, URLError, socket.error, BadStatusLine) - - -class SpeedtestException(Exception): - """Base exception for this module""" - - -class SpeedtestCLIError(SpeedtestException): - """Generic exception for raising errors during CLI operation""" - - -class SpeedtestHTTPError(SpeedtestException): - """Base HTTP exception for this module""" - - -class SpeedtestConfigError(SpeedtestException): - """Configuration XML is invalid""" - - -class SpeedtestServersError(SpeedtestException): - """Servers XML is invalid""" - - -class ConfigRetrievalError(SpeedtestHTTPError): - """Could not retrieve config.php""" - - -class ServersRetrievalError(SpeedtestHTTPError): - """Could not retrieve speedtest-servers.php""" - - -class InvalidServerIDType(SpeedtestException): - """Server ID used for filtering was not an integer""" - - -class NoMatchedServers(SpeedtestException): - """No servers matched when filtering""" - - -class SpeedtestMiniConnectFailure(SpeedtestException): - """Could not connect to the provided speedtest mini server""" - - -class InvalidSpeedtestMiniServer(SpeedtestException): - """Server provided as a speedtest mini server does not actually appear - to be a speedtest mini server - """ - - -class ShareResultsConnectFailure(SpeedtestException): - """Could not connect to speedtest.net API to POST results""" - - -class ShareResultsSubmitFailure(SpeedtestException): - """Unable to successfully POST results to speedtest.net API after - connection - """ - - -class SpeedtestUploadTimeout(SpeedtestException): - """testlength configuration reached during upload - Used to ensure the upload halts when no additional data should be sent - """ - - -class SpeedtestBestServerFailure(SpeedtestException): - """Unable to determine best server""" - - -class SpeedtestMissingBestServer(SpeedtestException): - """get_best_server not called or not able to determine best server""" - - -def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, - source_address=None): - """Connect to *address* and return the socket object. - - Convenience function. Connect to *address* (a 2-tuple ``(host, - port)``) and return the socket object. Passing the optional - *timeout* parameter will set the timeout on the socket instance - before attempting to connect. If no *timeout* is supplied, the - global default timeout setting returned by :func:`getdefaulttimeout` - is used. If *source_address* is set it must be a tuple of (host, port) - for the socket to bind as a source address before making the connection. - An host of '' or port 0 tells the OS to use the default. - - Largely vendored from Python 2.7, modified to work with Python 2.4 - """ - - host, port = address - err = None - for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): - af, socktype, proto, canonname, sa = res - sock = None - try: - sock = socket.socket(af, socktype, proto) - if timeout is not _GLOBAL_DEFAULT_TIMEOUT: - sock.settimeout(float(timeout)) - if source_address: - sock.bind(source_address) - sock.connect(sa) - return sock - - except socket.error: - err = get_exception() - if sock is not None: - sock.close() - - if err is not None: - raise err - else: - raise socket.error("getaddrinfo returns an empty list") - - -class SpeedtestHTTPConnection(HTTPConnection): - """Custom HTTPConnection to support source_address across - Python 2.4 - Python 3 - """ - def __init__(self, *args, **kwargs): - source_address = kwargs.pop('source_address', None) - timeout = kwargs.pop('timeout', 10) - - self._tunnel_host = None - - HTTPConnection.__init__(self, *args, **kwargs) - - self.source_address = source_address - self.timeout = timeout - - def connect(self): - """Connect to the host and port specified in __init__.""" - try: - self.sock = socket.create_connection( - (self.host, self.port), - self.timeout, - self.source_address - ) - except (AttributeError, TypeError): - self.sock = create_connection( - (self.host, self.port), - self.timeout, - self.source_address - ) - - if self._tunnel_host: - self._tunnel() - - -if HTTPSConnection: - class SpeedtestHTTPSConnection(HTTPSConnection): - """Custom HTTPSConnection to support source_address across - Python 2.4 - Python 3 - """ - default_port = 443 - - def __init__(self, *args, **kwargs): - source_address = kwargs.pop('source_address', None) - timeout = kwargs.pop('timeout', 10) - - self._tunnel_host = None - - HTTPSConnection.__init__(self, *args, **kwargs) - - self.timeout = timeout - self.source_address = source_address - - def connect(self): - "Connect to a host on a given (SSL) port." - try: - self.sock = socket.create_connection( - (self.host, self.port), - self.timeout, - self.source_address - ) - except (AttributeError, TypeError): - self.sock = create_connection( - (self.host, self.port), - self.timeout, - self.source_address - ) - - if self._tunnel_host: - self._tunnel() - - if ssl: - try: - kwargs = {} - if hasattr(ssl, 'SSLContext'): - if self._tunnel_host: - kwargs['server_hostname'] = self._tunnel_host - else: - kwargs['server_hostname'] = self.host - self.sock = self._context.wrap_socket(self.sock, **kwargs) - except AttributeError: - self.sock = ssl.wrap_socket(self.sock) - try: - self.sock.server_hostname = self.host - except AttributeError: - pass - elif FakeSocket: - # Python 2.4/2.5 support - try: - self.sock = FakeSocket(self.sock, socket.ssl(self.sock)) - except AttributeError: - raise SpeedtestException( - 'This version of Python does not support HTTPS/SSL ' - 'functionality' - ) - else: - raise SpeedtestException( - 'This version of Python does not support HTTPS/SSL ' - 'functionality' - ) - - -def _build_connection(connection, source_address, timeout, context=None): - """Cross Python 2.4 - Python 3 callable to build an ``HTTPConnection`` or - ``HTTPSConnection`` with the args we need - - Called from ``http(s)_open`` methods of ``SpeedtestHTTPHandler`` or - ``SpeedtestHTTPSHandler`` - """ - def inner(host, **kwargs): - kwargs.update({ - 'source_address': source_address, - 'timeout': timeout - }) - if context: - kwargs['context'] = context - return connection(host, **kwargs) - return inner - - -class SpeedtestHTTPHandler(AbstractHTTPHandler): - """Custom ``HTTPHandler`` that can build a ``HTTPConnection`` with the - args we need for ``source_address`` and ``timeout`` - """ - def __init__(self, debuglevel=0, source_address=None, timeout=10): - AbstractHTTPHandler.__init__(self, debuglevel) - self.source_address = source_address - self.timeout = timeout - - def http_open(self, req): - return self.do_open( - _build_connection( - SpeedtestHTTPConnection, - self.source_address, - self.timeout - ), - req - ) - - http_request = AbstractHTTPHandler.do_request_ - - -class SpeedtestHTTPSHandler(AbstractHTTPHandler): - """Custom ``HTTPSHandler`` that can build a ``HTTPSConnection`` with the - args we need for ``source_address`` and ``timeout`` - """ - def __init__(self, debuglevel=0, context=None, source_address=None, - timeout=10): - AbstractHTTPHandler.__init__(self, debuglevel) - self._context = context - self.source_address = source_address - self.timeout = timeout - - def https_open(self, req): - return self.do_open( - _build_connection( - SpeedtestHTTPSConnection, - self.source_address, - self.timeout, - context=self._context, - ), - req - ) - - https_request = AbstractHTTPHandler.do_request_ - - -def build_opener(source_address=None, timeout=10): - """Function similar to ``urllib2.build_opener`` that will build - an ``OpenerDirector`` with the explicit handlers we want, - ``source_address`` for binding, ``timeout`` and our custom - `User-Agent` - """ - - printer('Timeout set to %d' % timeout, debug=True) - - if source_address: - source_address_tuple = (source_address, 0) - printer('Binding to source address: %r' % (source_address_tuple,), - debug=True) - else: - source_address_tuple = None - - handlers = [ - ProxyHandler(), - SpeedtestHTTPHandler(source_address=source_address_tuple, - timeout=timeout), - SpeedtestHTTPSHandler(source_address=source_address_tuple, - timeout=timeout), - HTTPDefaultErrorHandler(), - HTTPRedirectHandler(), - HTTPErrorProcessor() - ] - - opener = OpenerDirector() - opener.addheaders = [('User-agent', build_user_agent())] - - for handler in handlers: - opener.add_handler(handler) - - return opener - - -class GzipDecodedResponse(GZIP_BASE): - """A file-like object to decode a response encoded with the gzip - method, as described in RFC 1952. - - Largely copied from ``xmlrpclib``/``xmlrpc.client`` and modified - to work for py2.4-py3 - """ - def __init__(self, response): - # response doesn't support tell() and read(), required by - # GzipFile - if not gzip: - raise SpeedtestHTTPError('HTTP response body is gzip encoded, ' - 'but gzip support is not available') - IO = BytesIO or StringIO - self.io = IO() - while 1: - chunk = response.read(1024) - if len(chunk) == 0: - break - self.io.write(chunk) - self.io.seek(0) - gzip.GzipFile.__init__(self, mode='rb', fileobj=self.io) - - def close(self): - try: - gzip.GzipFile.close(self) - finally: - self.io.close() - - -def get_exception(): - """Helper function to work with py2.4-py3 for getting the current - exception in a try/except block - """ - return sys.exc_info()[1] - - -def distance(origin, destination): - """Determine distance between 2 sets of [lat,lon] in km""" - - lat1, lon1 = origin - lat2, lon2 = destination - radius = 6371 # km - - dlat = math.radians(lat2 - lat1) - dlon = math.radians(lon2 - lon1) - a = (math.sin(dlat / 2) * math.sin(dlat / 2) + - math.cos(math.radians(lat1)) * - math.cos(math.radians(lat2)) * math.sin(dlon / 2) * - math.sin(dlon / 2)) - c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) - d = radius * c - - return d - - -def build_user_agent(): - """Build a Mozilla/5.0 compatible User-Agent string""" - - ua_tuple = ( - 'Mozilla/5.0', - '(%s; U; %s; en-us)' % (platform.platform(), - platform.architecture()[0]), - 'Python/%s' % platform.python_version(), - '(KHTML, like Gecko)', - 'speedtest-cli/%s' % __version__ - ) - user_agent = ' '.join(ua_tuple) - printer('User-Agent: %s' % user_agent, debug=True) - return user_agent - - -def build_request(url, data=None, headers=None, bump='0', secure=False): - """Build a urllib2 request object - - This function automatically adds a User-Agent header to all requests - - """ - - if not headers: - headers = {} - - if url[0] == ':': - scheme = ('http', 'https')[bool(secure)] - schemed_url = '%s%s' % (scheme, url) - else: - schemed_url = url - - if '?' in url: - delim = '&' - else: - delim = '?' - - # WHO YOU GONNA CALL? CACHE BUSTERS! - final_url = '%s%sx=%s.%s' % (schemed_url, delim, - int(timeit.time.time() * 1000), - bump) - - headers.update({ - 'Cache-Control': 'no-cache', - }) - - printer('%s %s' % (('GET', 'POST')[bool(data)], final_url), - debug=True) - - return Request(final_url, data=data, headers=headers) - - -def catch_request(request, opener=None): - """Helper function to catch common exceptions encountered when - establishing a connection with a HTTP/HTTPS request - - """ - - if opener: - _open = opener.open - else: - _open = urlopen - - try: - uh = _open(request) - if request.get_full_url() != uh.geturl(): - printer('Redirected to %s' % uh.geturl(), debug=True) - return uh, False - except HTTP_ERRORS: - e = get_exception() - return None, e - - -def get_response_stream(response): - """Helper function to return either a Gzip reader if - ``Content-Encoding`` is ``gzip`` otherwise the response itself - - """ - - try: - getheader = response.headers.getheader - except AttributeError: - getheader = response.getheader - - if getheader('content-encoding') == 'gzip': - return GzipDecodedResponse(response) - - return response - - -def get_attributes_by_tag_name(dom, tag_name): - """Retrieve an attribute from an XML document and return it in a - consistent format - - Only used with xml.dom.minidom, which is likely only to be used - with python versions older than 2.5 - """ - elem = dom.getElementsByTagName(tag_name)[0] - return dict(list(elem.attributes.items())) - - -def print_dots(shutdown_event): - """Built in callback function used by Thread classes for printing - status - """ - def inner(current, total, start=False, end=False): - if shutdown_event.isSet(): - return - - sys.stdout.write('.') - if current + 1 == total and end is True: - sys.stdout.write('\n') - sys.stdout.flush() - return inner - - -def do_nothing(*args, **kwargs): - pass - - -class HTTPDownloader(threading.Thread): - """Thread class for retrieving a URL""" - - def __init__(self, i, request, start, timeout, opener=None, - shutdown_event=None): - threading.Thread.__init__(self) - self.request = request - self.result = [0] - self.starttime = start - self.timeout = timeout - self.i = i - if opener: - self._opener = opener.open - else: - self._opener = urlopen - - if shutdown_event: - self._shutdown_event = shutdown_event - else: - self._shutdown_event = FakeShutdownEvent() - - def run(self): - try: - if (timeit.default_timer() - self.starttime) <= self.timeout: - f = self._opener(self.request) - while (not self._shutdown_event.isSet() and - (timeit.default_timer() - self.starttime) <= - self.timeout): - self.result.append(len(f.read(10240))) - if self.result[-1] == 0: - break - f.close() - except IOError: - pass - except HTTP_ERRORS: - pass - - -class HTTPUploaderData(object): - """File like object to improve cutting off the upload once the timeout - has been reached - """ - - def __init__(self, length, start, timeout, shutdown_event=None): - self.length = length - self.start = start - self.timeout = timeout - - if shutdown_event: - self._shutdown_event = shutdown_event - else: - self._shutdown_event = FakeShutdownEvent() - - self._data = None - - self.total = [0] - - def pre_allocate(self): - chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' - multiplier = int(round(int(self.length) / 36.0)) - IO = BytesIO or StringIO - try: - self._data = IO( - ('content1=%s' % - (chars * multiplier)[0:int(self.length) - 9] - ).encode() - ) - except MemoryError: - raise SpeedtestCLIError( - 'Insufficient memory to pre-allocate upload data. Please ' - 'use --no-pre-allocate' - ) - - @property - def data(self): - if not self._data: - self.pre_allocate() - return self._data - - def read(self, n=10240): - if ((timeit.default_timer() - self.start) <= self.timeout and - not self._shutdown_event.isSet()): - chunk = self.data.read(n) - self.total.append(len(chunk)) - return chunk - else: - raise SpeedtestUploadTimeout() - - def __len__(self): - return self.length - - -class HTTPUploader(threading.Thread): - """Thread class for putting a URL""" - - def __init__(self, i, request, start, size, timeout, opener=None, - shutdown_event=None): - threading.Thread.__init__(self) - self.request = request - self.request.data.start = self.starttime = start - self.size = size - self.result = 0 - self.timeout = timeout - self.i = i - - if opener: - self._opener = opener.open - else: - self._opener = urlopen - - if shutdown_event: - self._shutdown_event = shutdown_event - else: - self._shutdown_event = FakeShutdownEvent() - - def run(self): - request = self.request - try: - if ((timeit.default_timer() - self.starttime) <= self.timeout and - not self._shutdown_event.isSet()): - try: - f = self._opener(request) - except TypeError: - # PY24 expects a string or buffer - # This also causes issues with Ctrl-C, but we will concede - # for the moment that Ctrl-C on PY24 isn't immediate - request = build_request(self.request.get_full_url(), - data=request.data.read(self.size)) - f = self._opener(request) - f.read(11) - f.close() - self.result = sum(self.request.data.total) - else: - self.result = 0 - except (IOError, SpeedtestUploadTimeout): - self.result = sum(self.request.data.total) - except HTTP_ERRORS: - self.result = 0 - - -class SpeedtestResults(object): - """Class for holding the results of a speedtest, including: - - Download speed - Upload speed - Ping/Latency to test server - Data about server that the test was run against - - Additionally this class can return a result data as a dictionary or CSV, - as well as submit a POST of the result data to the speedtest.net API - to get a share results image link. - """ - - def __init__(self, download=0, upload=0, ping=0, server=None, client=None, - opener=None, secure=False): - self.download = download - self.upload = upload - self.ping = ping - if server is None: - self.server = {} - else: - self.server = server - self.client = client or {} - - self._share = None - self.timestamp = '%sZ' % datetime.datetime.utcnow().isoformat() - self.bytes_received = 0 - self.bytes_sent = 0 - - if opener: - self._opener = opener - else: - self._opener = build_opener() - - self._secure = secure - - def __repr__(self): - return repr(self.dict()) - - def share(self): - """POST data to the speedtest.net API to obtain a share results - link - """ - - if self._share: - return self._share - - download = int(round(self.download / 1000.0, 0)) - ping = int(round(self.ping, 0)) - upload = int(round(self.upload / 1000.0, 0)) - - # Build the request to send results back to speedtest.net - # We use a list instead of a dict because the API expects parameters - # in a certain order - api_data = [ - 'recommendedserverid=%s' % self.server['id'], - 'ping=%s' % ping, - 'screenresolution=', - 'promo=', - 'download=%s' % download, - 'screendpi=', - 'upload=%s' % upload, - 'testmethod=http', - 'hash=%s' % md5(('%s-%s-%s-%s' % - (ping, upload, download, '297aae72')) - .encode()).hexdigest(), - 'touchscreen=none', - 'startmode=pingselect', - 'accuracy=1', - 'bytesreceived=%s' % self.bytes_received, - 'bytessent=%s' % self.bytes_sent, - 'serverid=%s' % self.server['id'], - ] - - headers = {'Referer': 'http://c.speedtest.net/flash/speedtest.swf'} - request = build_request('://www.speedtest.net/api/api.php', - data='&'.join(api_data).encode(), - headers=headers, secure=self._secure) - f, e = catch_request(request, opener=self._opener) - if e: - raise ShareResultsConnectFailure(e) - - response = f.read() - code = f.code - f.close() - - if int(code) != 200: - raise ShareResultsSubmitFailure('Could not submit results to ' - 'speedtest.net') - - qsargs = parse_qs(response.decode()) - resultid = qsargs.get('resultid') - if not resultid or len(resultid) != 1: - raise ShareResultsSubmitFailure('Could not submit results to ' - 'speedtest.net') - - self._share = 'http://www.speedtest.net/result/%s.png' % resultid[0] - - return self._share - - def dict(self): - """Return dictionary of result data""" - - return { - 'download': self.download, - 'upload': self.upload, - 'ping': self.ping, - 'server': self.server, - 'timestamp': self.timestamp, - 'bytes_sent': self.bytes_sent, - 'bytes_received': self.bytes_received, - 'share': self._share, - 'client': self.client, - } - - @staticmethod - def csv_header(delimiter=','): - """Return CSV Headers""" - - row = ['Server ID', 'Sponsor', 'Server Name', 'Timestamp', 'Distance', - 'Ping', 'Download', 'Upload', 'Share', 'IP Address'] - out = StringIO() - writer = csv.writer(out, delimiter=delimiter, lineterminator='') - writer.writerow([to_utf8(v) for v in row]) - return out.getvalue() - - def csv(self, delimiter=','): - """Return data in CSV format""" - - data = self.dict() - out = StringIO() - writer = csv.writer(out, delimiter=delimiter, lineterminator='') - row = [data['server']['id'], data['server']['sponsor'], - data['server']['name'], data['timestamp'], - data['server']['d'], data['ping'], data['download'], - data['upload'], self._share or '', self.client['ip']] - writer.writerow([to_utf8(v) for v in row]) - return out.getvalue() - - def json(self, pretty=False): - """Return data in JSON format""" - - kwargs = {} - if pretty: - kwargs.update({ - 'indent': 4, - 'sort_keys': True - }) - return json.dumps(self.dict(), **kwargs) - - -class Speedtest(object): - """Class for performing standard speedtest.net testing operations""" - - def __init__(self, config=None, source_address=None, timeout=10, - secure=False, shutdown_event=None): - self.config = {} - - self._source_address = source_address - self._timeout = timeout - self._opener = build_opener(source_address, timeout) - - self._secure = secure - - if shutdown_event: - self._shutdown_event = shutdown_event - else: - self._shutdown_event = FakeShutdownEvent() - - self.get_config() - if config is not None: - self.config.update(config) - - self.servers = {} - self.closest = [] - self._best = {} - - self.results = SpeedtestResults( - client=self.config['client'], - opener=self._opener, - secure=secure, - ) - - @property - def best(self): - if not self._best: - self.get_best_server() - return self._best - - def get_config(self): - """Download the speedtest.net configuration and return only the data - we are interested in - """ - - headers = {} - if gzip: - headers['Accept-Encoding'] = 'gzip' - request = build_request('://www.speedtest.net/speedtest-config.php', - headers=headers, secure=self._secure) - uh, e = catch_request(request, opener=self._opener) - if e: - raise ConfigRetrievalError(e) - configxml_list = [] - - stream = get_response_stream(uh) - - while 1: - try: - configxml_list.append(stream.read(1024)) - except (OSError, EOFError): - raise ConfigRetrievalError(get_exception()) - if len(configxml_list[-1]) == 0: - break - stream.close() - uh.close() - - if int(uh.code) != 200: - return None - - configxml = ''.encode().join(configxml_list) - - printer('Config XML:\n%s' % configxml, debug=True) - - try: - try: - root = ET.fromstring(configxml) - except ET.ParseError: - e = get_exception() - raise SpeedtestConfigError( - 'Malformed speedtest.net configuration: %s' % e - ) - server_config = root.find('server-config').attrib - download = root.find('download').attrib - upload = root.find('upload').attrib - # times = root.find('times').attrib - client = root.find('client').attrib - - except AttributeError: - try: - root = DOM.parseString(configxml) - except ExpatError: - e = get_exception() - raise SpeedtestConfigError( - 'Malformed speedtest.net configuration: %s' % e - ) - server_config = get_attributes_by_tag_name(root, 'server-config') - download = get_attributes_by_tag_name(root, 'download') - upload = get_attributes_by_tag_name(root, 'upload') - # times = get_attributes_by_tag_name(root, 'times') - client = get_attributes_by_tag_name(root, 'client') - - ignore_servers = [ - int(i) for i in server_config['ignoreids'].split(',') if i - ] - - ratio = int(upload['ratio']) - upload_max = int(upload['maxchunkcount']) - up_sizes = [32768, 65536, 131072, 262144, 524288, 1048576, 7340032] - sizes = { - 'upload': up_sizes[ratio - 1:], - 'download': [350, 500, 750, 1000, 1500, 2000, 2500, - 3000, 3500, 4000] - } - - size_count = len(sizes['upload']) - - upload_count = int(math.ceil(upload_max / size_count)) - - counts = { - 'upload': upload_count, - 'download': int(download['threadsperurl']) - } - - threads = { - 'upload': int(upload['threads']), - 'download': int(server_config['threadcount']) * 2 - } - - length = { - 'upload': int(upload['testlength']), - 'download': int(download['testlength']) - } - - self.config.update({ - 'client': client, - 'ignore_servers': ignore_servers, - 'sizes': sizes, - 'counts': counts, - 'threads': threads, - 'length': length, - 'upload_max': upload_count * size_count - }) - - try: - self.lat_lon = (float(client['lat']), float(client['lon'])) - except ValueError: - raise SpeedtestConfigError( - 'Unknown location: lat=%r lon=%r' % - (client.get('lat'), client.get('lon')) - ) - - printer('Config:\n%r' % self.config, debug=True) - - return self.config - - def get_servers(self, servers=None, exclude=None): - """Retrieve a the list of speedtest.net servers, optionally filtered - to servers matching those specified in the ``servers`` argument - """ - if servers is None: - servers = [] - - if exclude is None: - exclude = [] - - self.servers.clear() - - for server_list in (servers, exclude): - for i, s in enumerate(server_list): - try: - server_list[i] = int(s) - except ValueError: - raise InvalidServerIDType( - '%s is an invalid server type, must be int' % s - ) - - urls = [ - '://www.speedtest.net/speedtest-servers-static.php', - 'http://c.speedtest.net/speedtest-servers-static.php', - '://www.speedtest.net/speedtest-servers.php', - 'http://c.speedtest.net/speedtest-servers.php', - ] - - headers = {} - if gzip: - headers['Accept-Encoding'] = 'gzip' - - errors = [] - for url in urls: - try: - request = build_request( - '%s?threads=%s' % (url, - self.config['threads']['download']), - headers=headers, - secure=self._secure - ) - uh, e = catch_request(request, opener=self._opener) - if e: - errors.append('%s' % e) - raise ServersRetrievalError() - - stream = get_response_stream(uh) - - serversxml_list = [] - while 1: - try: - serversxml_list.append(stream.read(1024)) - except (OSError, EOFError): - raise ServersRetrievalError(get_exception()) - if len(serversxml_list[-1]) == 0: - break - - stream.close() - uh.close() - - if int(uh.code) != 200: - raise ServersRetrievalError() - - serversxml = ''.encode().join(serversxml_list) - - printer('Servers XML:\n%s' % serversxml, debug=True) - - try: - try: - try: - root = ET.fromstring(serversxml) - except ET.ParseError: - e = get_exception() - raise SpeedtestServersError( - 'Malformed speedtest.net server list: %s' % e - ) - elements = etree_iter(root, 'server') - except AttributeError: - try: - root = DOM.parseString(serversxml) - except ExpatError: - e = get_exception() - raise SpeedtestServersError( - 'Malformed speedtest.net server list: %s' % e - ) - elements = root.getElementsByTagName('server') - except (SyntaxError, xml.parsers.expat.ExpatError): - raise ServersRetrievalError() - - for server in elements: - try: - attrib = server.attrib - except AttributeError: - attrib = dict(list(server.attributes.items())) - - if servers and int(attrib.get('id')) not in servers: - continue - - if (int(attrib.get('id')) in self.config['ignore_servers'] - or int(attrib.get('id')) in exclude): - continue - - try: - d = distance(self.lat_lon, - (float(attrib.get('lat')), - float(attrib.get('lon')))) - except Exception: - continue - - attrib['d'] = d - - try: - self.servers[d].append(attrib) - except KeyError: - self.servers[d] = [attrib] - - break - - except ServersRetrievalError: - continue - - if (servers or exclude) and not self.servers: - raise NoMatchedServers() - - return self.servers - - def set_mini_server(self, server): - """Instead of querying for a list of servers, set a link to a - speedtest mini server - """ - - urlparts = urlparse(server) - - name, ext = os.path.splitext(urlparts[2]) - if ext: - url = os.path.dirname(server) - else: - url = server - - request = build_request(url) - uh, e = catch_request(request, opener=self._opener) - if e: - raise SpeedtestMiniConnectFailure('Failed to connect to %s' % - server) - else: - text = uh.read() - uh.close() - - extension = re.findall('upload_?[Ee]xtension: "([^"]+)"', - text.decode()) - if not extension: - for ext in ['php', 'asp', 'aspx', 'jsp']: - try: - f = self._opener.open( - '%s/speedtest/upload.%s' % (url, ext) - ) - except Exception: - pass - else: - data = f.read().strip().decode() - if (f.code == 200 and - len(data.splitlines()) == 1 and - re.match('size=[0-9]', data)): - extension = [ext] - break - if not urlparts or not extension: - raise InvalidSpeedtestMiniServer('Invalid Speedtest Mini Server: ' - '%s' % server) - - self.servers = [{ - 'sponsor': 'Speedtest Mini', - 'name': urlparts[1], - 'd': 0, - 'url': '%s/speedtest/upload.%s' % (url.rstrip('/'), extension[0]), - 'latency': 0, - 'id': 0 - }] - - return self.servers - - def get_closest_servers(self, limit=5): - """Limit servers to the closest speedtest.net servers based on - geographic distance - """ - - if not self.servers: - self.get_servers() - - for d in sorted(self.servers.keys()): - for s in self.servers[d]: - self.closest.append(s) - if len(self.closest) == limit: - break - else: - continue - break - - printer('Closest Servers:\n%r' % self.closest, debug=True) - return self.closest - - def get_best_server(self, servers=None): - """Perform a speedtest.net "ping" to determine which speedtest.net - server has the lowest latency - """ - - if not servers: - if not self.closest: - servers = self.get_closest_servers() - servers = self.closest - - if self._source_address: - source_address_tuple = (self._source_address, 0) - else: - source_address_tuple = None - - user_agent = build_user_agent() - - results = {} - for server in servers: - cum = [] - url = os.path.dirname(server['url']) - stamp = int(timeit.time.time() * 1000) - latency_url = '%s/latency.txt?x=%s' % (url, stamp) - for i in range(0, 3): - this_latency_url = '%s.%s' % (latency_url, i) - printer('%s %s' % ('GET', this_latency_url), - debug=True) - urlparts = urlparse(latency_url) - try: - if urlparts[0] == 'https': - h = SpeedtestHTTPSConnection( - urlparts[1], - source_address=source_address_tuple - ) - else: - h = SpeedtestHTTPConnection( - urlparts[1], - source_address=source_address_tuple - ) - headers = {'User-Agent': user_agent} - path = '%s?%s' % (urlparts[2], urlparts[4]) - start = timeit.default_timer() - h.request("GET", path, headers=headers) - r = h.getresponse() - total = (timeit.default_timer() - start) - except HTTP_ERRORS: - e = get_exception() - printer('ERROR: %r' % e, debug=True) - cum.append(3600) - continue - - text = r.read(9) - if int(r.status) == 200 and text == 'test=test'.encode(): - cum.append(total) - else: - cum.append(3600) - h.close() - - avg = round((sum(cum) / 6) * 1000.0, 3) - results[avg] = server - - try: - fastest = sorted(results.keys())[0] - except IndexError: - raise SpeedtestBestServerFailure('Unable to connect to servers to ' - 'test latency.') - best = results[fastest] - best['latency'] = fastest - - self.results.ping = fastest - self.results.server = best - - self._best.update(best) - printer('Best Server:\n%r' % best, debug=True) - return best - - def download(self, callback=do_nothing, threads=None): - """Test download speed against speedtest.net - - A ``threads`` value of ``None`` will fall back to those dictated - by the speedtest.net configuration - """ - - urls = [] - for size in self.config['sizes']['download']: - for _ in range(0, self.config['counts']['download']): - urls.append('%s/random%sx%s.jpg' % - (os.path.dirname(self.best['url']), size, size)) - - request_count = len(urls) - requests = [] - for i, url in enumerate(urls): - requests.append( - build_request(url, bump=i, secure=self._secure) - ) - - max_threads = threads or self.config['threads']['download'] - in_flight = {'threads': 0} - - def producer(q, requests, request_count): - for i, request in enumerate(requests): - thread = HTTPDownloader( - i, - request, - start, - self.config['length']['download'], - opener=self._opener, - shutdown_event=self._shutdown_event - ) - while in_flight['threads'] >= max_threads: - timeit.time.sleep(0.001) - thread.start() - q.put(thread, True) - in_flight['threads'] += 1 - callback(i, request_count, start=True) - - finished = [] - - def consumer(q, request_count): - _is_alive = thread_is_alive - while len(finished) < request_count: - thread = q.get(True) - while _is_alive(thread): - thread.join(timeout=0.001) - in_flight['threads'] -= 1 - finished.append(sum(thread.result)) - callback(thread.i, request_count, end=True) - - q = Queue(max_threads) - prod_thread = threading.Thread(target=producer, - args=(q, requests, request_count)) - cons_thread = threading.Thread(target=consumer, - args=(q, request_count)) - start = timeit.default_timer() - prod_thread.start() - cons_thread.start() - _is_alive = thread_is_alive - while _is_alive(prod_thread): - prod_thread.join(timeout=0.001) - while _is_alive(cons_thread): - cons_thread.join(timeout=0.001) - - stop = timeit.default_timer() - self.results.bytes_received = sum(finished) - self.results.download = ( - (self.results.bytes_received / (stop - start)) * 8.0 - ) - if self.results.download > 100000: - self.config['threads']['upload'] = 8 - return self.results.download - - def upload(self, callback=do_nothing, pre_allocate=True, threads=None): - """Test upload speed against speedtest.net - - A ``threads`` value of ``None`` will fall back to those dictated - by the speedtest.net configuration - """ - - sizes = [] - - for size in self.config['sizes']['upload']: - for _ in range(0, self.config['counts']['upload']): - sizes.append(size) - - # request_count = len(sizes) - request_count = self.config['upload_max'] - - requests = [] - for i, size in enumerate(sizes): - # We set ``0`` for ``start`` and handle setting the actual - # ``start`` in ``HTTPUploader`` to get better measurements - data = HTTPUploaderData( - size, - 0, - self.config['length']['upload'], - shutdown_event=self._shutdown_event - ) - if pre_allocate: - data.pre_allocate() - - headers = {'Content-length': size} - requests.append( - ( - build_request(self.best['url'], data, secure=self._secure, - headers=headers), - size - ) - ) - - max_threads = threads or self.config['threads']['upload'] - in_flight = {'threads': 0} - - def producer(q, requests, request_count): - for i, request in enumerate(requests[:request_count]): - thread = HTTPUploader( - i, - request[0], - start, - request[1], - self.config['length']['upload'], - opener=self._opener, - shutdown_event=self._shutdown_event - ) - while in_flight['threads'] >= max_threads: - timeit.time.sleep(0.001) - thread.start() - q.put(thread, True) - in_flight['threads'] += 1 - callback(i, request_count, start=True) - - finished = [] - - def consumer(q, request_count): - _is_alive = thread_is_alive - while len(finished) < request_count: - thread = q.get(True) - while _is_alive(thread): - thread.join(timeout=0.001) - in_flight['threads'] -= 1 - finished.append(thread.result) - callback(thread.i, request_count, end=True) - - q = Queue(threads or self.config['threads']['upload']) - prod_thread = threading.Thread(target=producer, - args=(q, requests, request_count)) - cons_thread = threading.Thread(target=consumer, - args=(q, request_count)) - start = timeit.default_timer() - prod_thread.start() - cons_thread.start() - _is_alive = thread_is_alive - while _is_alive(prod_thread): - prod_thread.join(timeout=0.1) - while _is_alive(cons_thread): - cons_thread.join(timeout=0.1) - - stop = timeit.default_timer() - self.results.bytes_sent = sum(finished) - self.results.upload = ( - (self.results.bytes_sent / (stop - start)) * 8.0 - ) - return self.results.upload - - -def ctrl_c(shutdown_event): - """Catch Ctrl-C key sequence and set a SHUTDOWN_EVENT for our threaded - operations - """ - def inner(signum, frame): - shutdown_event.set() - printer('\nCancelling...', error=True) - sys.exit(0) - return inner - - -def version(): - """Print the version""" - - printer('speedtest-cli %s' % __version__) - printer('Python %s' % sys.version.replace('\n', '')) - sys.exit(0) - - -def csv_header(delimiter=','): - """Print the CSV Headers""" - - printer(SpeedtestResults.csv_header(delimiter=delimiter)) - sys.exit(0) - - -def parse_args(): - """Function to handle building and parsing of command line arguments""" - description = ( - 'Command line interface for testing internet bandwidth using ' - 'speedtest.net.\n' - '------------------------------------------------------------' - '--------------\n' - 'https://github.com/sivel/speedtest-cli') - - parser = ArgParser(description=description) - # Give optparse.OptionParser an `add_argument` method for - # compatibility with argparse.ArgumentParser - try: - parser.add_argument = parser.add_option - except AttributeError: - pass - parser.add_argument('--no-download', dest='download', default=True, - action='store_const', const=False, - help='Do not perform download test') - parser.add_argument('--no-upload', dest='upload', default=True, - action='store_const', const=False, - help='Do not perform upload test') - parser.add_argument('--single', default=False, action='store_true', - help='Only use a single connection instead of ' - 'multiple. This simulates a typical file ' - 'transfer.') - parser.add_argument('--bytes', dest='units', action='store_const', - const=('byte', 8), default=('bit', 1), - help='Display values in bytes instead of bits. Does ' - 'not affect the image generated by --share, nor ' - 'output from --json or --csv') - parser.add_argument('--share', action='store_true', - help='Generate and provide a URL to the speedtest.net ' - 'share results image, not displayed with --csv') - parser.add_argument('--simple', action='store_true', default=False, - help='Suppress verbose output, only show basic ' - 'information') - parser.add_argument('--csv', action='store_true', default=False, - help='Suppress verbose output, only show basic ' - 'information in CSV format. Speeds listed in ' - 'bit/s and not affected by --bytes') - parser.add_argument('--csv-delimiter', default=',', type=PARSER_TYPE_STR, - help='Single character delimiter to use in CSV ' - 'output. Default ","') - parser.add_argument('--csv-header', action='store_true', default=False, - help='Print CSV headers') - parser.add_argument('--json', action='store_true', default=False, - help='Suppress verbose output, only show basic ' - 'information in JSON format. Speeds listed in ' - 'bit/s and not affected by --bytes') - parser.add_argument('--list', action='store_true', - help='Display a list of speedtest.net servers ' - 'sorted by distance') - parser.add_argument('--server', type=PARSER_TYPE_INT, action='append', - help='Specify a server ID to test against. Can be ' - 'supplied multiple times') - parser.add_argument('--exclude', type=PARSER_TYPE_INT, action='append', - help='Exclude a server from selection. Can be ' - 'supplied multiple times') - parser.add_argument('--mini', help='URL of the Speedtest Mini server') - parser.add_argument('--source', help='Source IP address to bind to') - parser.add_argument('--timeout', default=10, type=PARSER_TYPE_FLOAT, - help='HTTP timeout in seconds. Default 10') - parser.add_argument('--secure', action='store_true', - help='Use HTTPS instead of HTTP when communicating ' - 'with speedtest.net operated servers') - parser.add_argument('--no-pre-allocate', dest='pre_allocate', - action='store_const', default=True, const=False, - help='Do not pre allocate upload data. Pre allocation ' - 'is enabled by default to improve upload ' - 'performance. To support systems with ' - 'insufficient memory, use this option to avoid a ' - 'MemoryError') - parser.add_argument('--version', action='store_true', - help='Show the version number and exit') - parser.add_argument('--debug', action='store_true', - help=ARG_SUPPRESS, default=ARG_SUPPRESS) - - options = parser.parse_args() - if isinstance(options, tuple): - args = options[0] - else: - args = options - return args - - -def validate_optional_args(args): - """Check if an argument was provided that depends on a module that may - not be part of the Python standard library. - - If such an argument is supplied, and the module does not exist, exit - with an error stating which module is missing. - """ - optional_args = { - 'json': ('json/simplejson python module', json), - 'secure': ('SSL support', HTTPSConnection), - } - - for arg, info in optional_args.items(): - if getattr(args, arg, False) and info[1] is None: - raise SystemExit('%s is not installed. --%s is ' - 'unavailable' % (info[0], arg)) - - -def printer(string, quiet=False, debug=False, error=False, **kwargs): - """Helper function print a string with various features""" - - if debug and not DEBUG: - return - - if debug: - if sys.stdout.isatty(): - out = '\033[1;30mDEBUG: %s\033[0m' % string - else: - out = 'DEBUG: %s' % string - else: - out = string - - if error: - kwargs['file'] = sys.stderr - - if not quiet: - print_(out, **kwargs) - - -def shell(): - """Run the full speedtest.net test""" - - global DEBUG - shutdown_event = threading.Event() - - signal.signal(signal.SIGINT, ctrl_c(shutdown_event)) - - args = parse_args() - - # Print the version and exit - if args.version: - version() - - if not args.download and not args.upload: - raise SpeedtestCLIError('Cannot supply both --no-download and ' - '--no-upload') - - if len(args.csv_delimiter) != 1: - raise SpeedtestCLIError('--csv-delimiter must be a single character') - - if args.csv_header: - csv_header(args.csv_delimiter) - - validate_optional_args(args) - - debug = getattr(args, 'debug', False) - if debug == 'SUPPRESSHELP': - debug = False - if debug: - DEBUG = True - - if args.simple or args.csv or args.json: - quiet = True - else: - quiet = False - - if args.csv or args.json: - machine_format = True - else: - machine_format = False - - # Don't set a callback if we are running quietly - if quiet or debug: - callback = do_nothing - else: - callback = print_dots(shutdown_event) - - printer('Retrieving speedtest.net configuration...', quiet) - try: - speedtest = Speedtest( - source_address=args.source, - timeout=args.timeout, - secure=args.secure - ) - except (ConfigRetrievalError,) + HTTP_ERRORS: - printer('Cannot retrieve speedtest configuration', error=True) - raise SpeedtestCLIError(get_exception()) - - if args.list: - try: - speedtest.get_servers() - except (ServersRetrievalError,) + HTTP_ERRORS: - printer('Cannot retrieve speedtest server list', error=True) - raise SpeedtestCLIError(get_exception()) - - for _, servers in sorted(speedtest.servers.items()): - for server in servers: - line = ('%(id)5s) %(sponsor)s (%(name)s, %(country)s) ' - '[%(d)0.2f km]' % server) - try: - printer(line) - except IOError: - e = get_exception() - if e.errno != errno.EPIPE: - raise - sys.exit(0) - - printer('Testing from %(isp)s (%(ip)s)...' % speedtest.config['client'], - quiet) - - if not args.mini: - printer('Retrieving speedtest.net server list...', quiet) - try: - speedtest.get_servers(servers=args.server, exclude=args.exclude) - except NoMatchedServers: - raise SpeedtestCLIError( - 'No matched servers: %s' % - ', '.join('%s' % s for s in args.server) - ) - except (ServersRetrievalError,) + HTTP_ERRORS: - printer('Cannot retrieve speedtest server list', error=True) - raise SpeedtestCLIError(get_exception()) - except InvalidServerIDType: - raise SpeedtestCLIError( - '%s is an invalid server type, must ' - 'be an int' % ', '.join('%s' % s for s in args.server) - ) - - if args.server and len(args.server) == 1: - printer('Retrieving information for the selected server...', quiet) - else: - printer('Selecting best server based on ping...', quiet) - speedtest.get_best_server() - elif args.mini: - speedtest.get_best_server(speedtest.set_mini_server(args.mini)) - - results = speedtest.results - - printer('Hosted by %(sponsor)s (%(name)s) [%(d)0.2f km]: ' - '%(latency)s ms' % results.server, quiet) - - if args.download: - printer('Testing download speed', quiet, - end=('', '\n')[bool(debug)]) - speedtest.download( - callback=callback, - threads=(None, 1)[args.single] - ) - printer('Download: %0.2f M%s/s' % - ((results.download / 1000.0 / 1000.0) / args.units[1], - args.units[0]), - quiet) - else: - printer('Skipping download test', quiet) - - if args.upload: - printer('Testing upload speed', quiet, - end=('', '\n')[bool(debug)]) - speedtest.upload( - callback=callback, - pre_allocate=args.pre_allocate, - threads=(None, 1)[args.single] - ) - printer('Upload: %0.2f M%s/s' % - ((results.upload / 1000.0 / 1000.0) / args.units[1], - args.units[0]), - quiet) - else: - printer('Skipping upload test', quiet) - - printer('Results:\n%r' % results.dict(), debug=True) - - if not args.simple and args.share: - results.share() - - if args.simple: - printer('Ping: %s ms\nDownload: %0.2f M%s/s\nUpload: %0.2f M%s/s' % - (results.ping, - (results.download / 1000.0 / 1000.0) / args.units[1], - args.units[0], - (results.upload / 1000.0 / 1000.0) / args.units[1], - args.units[0])) - elif args.csv: - printer(results.csv(delimiter=args.csv_delimiter)) - elif args.json: - printer(results.json()) - - if args.share and not machine_format: - printer('Share results: %s' % results.share()) - - -def main(): - try: - shell() - except KeyboardInterrupt: - printer('\nCancelling...', error=True) - except (SpeedtestException, SystemExit): - e = get_exception() - # Ignore a successful exit, or argparse exit - if getattr(e, 'code', 1) not in (0, 2): - msg = '%s' % e - if not msg: - msg = '%r' % e - raise SystemExit('ERROR: %s' % msg) - - -if __name__ == '__main__': - main() diff --git a/packages/network/speedtest.py b/packages/network/speedtest.py deleted file mode 100644 index 8ed857503..000000000 --- a/packages/network/speedtest.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -# The SpeedTest package will give you information about your network speed -# Author: Florian Bouché -# Date: 2019-03-09 -# Based on the package https://github.com/sivel/speedtest-cli - -import utils -import os -import sys -import subprocess -import re - -def run(string, entities): - """The SpeedTest package will give you information about your network speed """ - - utils.output('inter', 'testing', utils.translate('testing')) - - realpath = os.path.dirname(os.path.realpath(__file__)) - process = subprocess.Popen( - [sys.executable, realpath + '/speedtest.lib.py', '--simple'], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT - ) - - (output, err) = process.communicate() - p_status = process.wait() - - if err: - return utils.output('end', 'error', utils.translate('error')) - - rawoutput = output.decode('utf-8') - - data = { - 'ping': re.search('Ping:(.+?)\n', rawoutput).group(1).strip(), - 'download': re.search('Download:(.+?)\n', rawoutput).group(1).strip(), - 'upload': re.search('Upload:(.+?)\n', rawoutput).group(1).strip() - } - - return utils.output('end', 'done', utils.translate('done', data)) diff --git a/packages/network/test/speedtest.spec.js b/packages/network/test/speedtest.spec.js deleted file mode 100644 index 2d3f2ce17..000000000 --- a/packages/network/test/speedtest.spec.js +++ /dev/null @@ -1,12 +0,0 @@ -describe('network:speedtest', () => { - test('does a speed test', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Do a speed test') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(3) - expect(global.brain.finalOutput.codes).toIncludeSameMembers(['testing', 'done']) - }) -}) diff --git a/packages/network/version.txt b/packages/network/version.txt deleted file mode 100644 index 9084fa2f7..000000000 --- a/packages/network/version.txt +++ /dev/null @@ -1 +0,0 @@ -1.1.0 diff --git a/packages/trend/README.md b/packages/trend/README.md deleted file mode 100644 index 2de9dd656..000000000 --- a/packages/trend/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# Trend Package - -The trend package contains modules related to trends. - -## Modules - -### GitHub - -Grab the GitHub trends repositories according to several options. - -#### Usage - -``` -(en-US) "What's trending on GitHub?" -(en-US) "Give me the 4 GitHub trends of this week for the JavaScript language" -(en-US) "What's the three GitHub trends of this month?" - -(fr-FR) "Quelles sont les tendances sur GitHub ?" -(fr-FR) "Donne-moi les 4 tendances GitHub de cette semaine pour le langage JavaScript" -(fr-FR) "Donne-moi les trois tendances GitHub de ce mois" -... -``` - -### Product Hunt - -Grab the Product Hunt trends. - -#### Usage - -1. Log in to your [Product Hunt](https://www.producthunt.com/) account. -2. Add a [new application](https://www.producthunt.com/v1/oauth/applications) (E.g. name: Leon; Redirect URI: https://localhost). -3. Once your application is created, click `Create Token`. -4. Copy the `Developer Token` and paste it in `packages/trend/config/config.json` at the `producthunt.developer_token` key. - -``` -(en-US) "What's trending on Product Hunt?" -(en-US) "What were the four first Product Hunt trends on the 7th of October 2018?" -(en-US) "What were the Product Hunt trends of yesterday?" - -(fr-FR) "Quelles sont les tendances sur Product Hunt ?" -(fr-FR) "Donne-moi les 4 tendances Product Hunt du 7 octobre 2018" -... -``` diff --git a/packages/trend/__init__.py b/packages/trend/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/trend/config/.gitkeep b/packages/trend/config/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/trend/config/config.sample.json b/packages/trend/config/config.sample.json deleted file mode 100644 index df523bd9b..000000000 --- a/packages/trend/config/config.sample.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "github": { - "options": {} - }, - "producthunt": { - "developer_token": "YOUR_DEVELOPER_TOKEN", - "options": {} - } -} diff --git a/packages/trend/data/.gitkeep b/packages/trend/data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/trend/data/answers/.gitkeep b/packages/trend/data/answers/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/trend/data/answers/en.json b/packages/trend/data/answers/en.json deleted file mode 100644 index 815cd6b83..000000000 --- a/packages/trend/data/answers/en.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "github": { - "limit_max": [ - "You've asked for too many GitHub trends, I'll give you 25 trends instead.", - "%limit% GitHub trends is a lot, let me tell you the 25 trends instead." - ], - "reaching": [ - "I'm reaching GitHub, please wait a second...", - "Let me reach GitHub..." - ], - "today": [ - "Here are the %limit% GitHub trends of the day:

    " - ], - "week": [ - "Here are the %limit% GitHub trends of the week:

    " - ], - "month": [ - "Here are the %limit% GitHub trends of the month:

    " - ], - "today_with_tech": [ - "Here are the %limit% GitHub trends of the day for the %tech% technology:

    " - ], - "week_with_tech": [ - "Here are the %limit% GitHub trends of the week for the %tech% technology:

    " - ], - "month_with_tech": [ - "Here are the %limit% GitHub trends of the month for the %tech% technology:

    " - ], - "unreachable": [ - "GitHub is unreachable for the moment, please retry later.", - "I'm having difficulties to reach GitHub, please retry later.", - "GitHub seems to be down, please try again later." - ], - "list_element": [ - "
  • #%rank%. %repository_name% created by %author_username% with %stars_nb% new stars.
  • " - ] - }, - "producthunt": { - "limit_max": [ - "You've asked for too many Product Hunt trends, I'll give you %new_limit% trends instead.", - "%limit% Product Hunt trends is a lot, let me tell you the %new_limit% trends instead." - ], - "reaching": [ - "I'm reaching Product Hunt, please wait a second...", - "Let me reach Product Hunt..." - ], - "today": [ - "Here are the %limit% Product Hunt trends of the day:

    " - ], - "specific_day": [ - "Here are the %limit% Product Hunt trends for the %date%:

    " - ], - "unreachable": [ - "Product Hunt is unreachable for the moment, please retry later.", - "I'm having difficulties to reach Product Hunt, please retry later.", - "Product Hunt seems to be down, please try again later." - ], - "list_element": [ - "
  • #%rank%. %product_name% created by %author_name% with %votes_nb% votes.
  • " - ], - "list_element_with_unknown_maker": [ - "
  • #%rank%. %product_name% with %votes_nb% votes. There is no information about the maker.
  • ", - "
  • #%rank%. %product_name% with %votes_nb% votes. I did not find any information about the maker.
  • " - ], - "not_found": [ - "There is no product on that date.", - "I did not find any product on that date." - ], - "invalid_developer_token": [ - "Your Product Hunt developer token is invalid. Please provide a valid one by reading this.", - "You did not set a valid Product Hunt developer token. Please set a valid one by reading this." - ] - } -} diff --git a/packages/trend/data/answers/fr.json b/packages/trend/data/answers/fr.json deleted file mode 100644 index 98e984194..000000000 --- a/packages/trend/data/answers/fr.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "github": { - "limit_max": [ - "Vous demandez beaucoup trop de tendances, laissez moi plutôt vous donner les 25 tendances.", - "%limit% tendances GitHub c'est beaucoup, permettez moi de vous donner les 25 tendances à la place." - ], - "reaching": [ - "Je suis en train d'atteindre GitHub, veuillez patienter une seconde...", - "Laissez moi atteindre GitHub..." - ], - "today": [ - "Voici les %limit% dernières tendances GitHub du jour :

    " - ], - "week": [ - "Voici les %limit% dernières tendances GitHub de la semaine :

    " - ], - "month": [ - "Voici les %limit% dernières tendances GitHub du mois :

    " - ], - "today_with_tech": [ - "Voici les %limit% dernières tendances GitHub du jour pour la technologie %tech% :

    " - ], - "week_with_tech": [ - "Voici les %limit% dernières tendances GitHub de la semaine pour la technologie %tech% :

    " - ], - "month_with_tech": [ - "Voici les %limit% dernières tendances GitHub du mois pour la technologie %tech% :

    " - ], - "unreachable": [ - "GitHub est inaccessible pour le moment, merci de réessayer plus tard.", - "Je rencontre des difficultés pour atteindre GitHub, merci de réessayer plus tard.", - "GitHub semble ne pas fonctionner correctement, veuillez retenter plus tard." - ], - "list_element": [ - "
  • #%rank%. %repository_name% créé par %author_username% avec %stars_nb% nouvelles étoiles.
  • " - ] - }, - "producthunt": { - "limit_max": [ - "Vous demandez beaucoup trop de tendances, laissez moi plutôt vous donner les %new_limit% tendances.", - "%limit% tendances Product Hunt c'est beaucoup, permettez moi de vous donner les %new_limit% tendances à la place." - ], - "reaching": [ - "Je suis en train d'atteindre Product Hunt, veuillez patienter une seconde...", - "Laissez moi atteindre Product Hunt..." - ], - "today": [ - "Voici les %limit% dernières tendances Product Hunt du jour :

    " - ], - "specific_day": [ - "Voici les %limit% dernières tendances Product Hunt du %date% :

    " - ], - "unreachable": [ - "Product Hunt est inaccessible pour le moment, merci de réessayer plus tard.", - "Je rencontre des difficultés pour atteindre Product Hunt, merci de réessayer plus tard.", - "Product Hunt semble ne pas fonctionner correctement, veuillez retenter plus tard." - ], - "list_element": [ - "
  • #%rank%. %product_name% créé par %author_name% avec %votes_nb% votes.
  • " - ], - "list_element_with_unknown_maker": [ - "
  • #%rank%. %product_name% avec %votes_nb% votes. Il n'y a pas d'information à propos du créateur.
  • ", - "
  • #%rank%. %product_name% avec %votes_nb% votes. Je n'ai trouvé aucune information à propos du créateur.
  • " - ], - "not_found": [ - "Il n'y a pas de produit à cette date.", - "Je n'ai trouvé aucun produit à cette date." - ], - "invalid_developer_token": [ - "Votre jeton de développeur Product Hunt est invalide. Merci d'en fournir un valide en lisant ceci.", - "Vous n'avez pas bien configuré votre jeton de développeur Product Hunt. Veuillez en installer un valide en lisant ceci." - ] - } -} diff --git a/packages/trend/data/db/.gitkeep b/packages/trend/data/db/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/trend/data/expressions/.gitkeep b/packages/trend/data/expressions/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/trend/data/expressions/en.json b/packages/trend/data/expressions/en.json deleted file mode 100644 index 2e1c09cc5..000000000 --- a/packages/trend/data/expressions/en.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "github": { - "run": { - "utterance_samples": [ - "What are the trends on GitHub?", - "Give me the GitHub trends", - "What's trending on GitHub?", - "What are the trends on GH?", - "Give me the GH trends", - "What's trending on GH?" - ], - "http_api": { - "entities": [ - { - "entity": "number", - "resolution": [ - "value" - ] - }, - { - "entity": "daterange", - "resolution": [ - "timex" - ] - } - ] - } - } - }, - "producthunt": { - "run": { - "utterance_samples": [ - "What are the trends on Product Hunt?", - "Give me the Product Hunt trends", - "What's trending on Product Hunt?", - "What are the trends on PH?", - "Give me the PH trends", - "What's trending on PH?", - "What's trending on ProductHunt?" - ] - } - } -} diff --git a/packages/trend/data/expressions/fr.json b/packages/trend/data/expressions/fr.json deleted file mode 100644 index d1ea526d8..000000000 --- a/packages/trend/data/expressions/fr.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "github": { - "run": { - "utterance_samples": [ - "Quelles sont les tendances sur GitHub ?", - "Donne-moi les tendances GitHub", - "Qu'est-ce qu'il y a en tendance sur GitHub ?", - "Quelles sont les tendances sur GH ?", - "Donne-moi les tendances GH", - "Qu'est-ce qu'il y a en tendance sur GH ?" - ] - } - }, - "producthunt": { - "run": { - "utterance_samples": [ - "Quelles sont les tendances sur Product Hunt ?", - "Donne-moi les tendances Product Hunt", - "Qu'est-ce qu'il y a en tendance sur Product Hunt ?", - "Quelles sont les tendances sur PH ?", - "Donne-moi les tendances PH", - "Qu'est-ce qu'il y a en tendance sur PH ?" - ] - } - } -} diff --git a/packages/trend/github.py b/packages/trend/github.py deleted file mode 100644 index 8984b9188..000000000 --- a/packages/trend/github.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import requests -import utils -import packages.trend.github_lang as github_lang -from re import search, escape -from bs4 import BeautifulSoup - -def run(string, entities): - """Grab the GitHub trends""" - - # Number of repositories - limit = 5 - - # Range string - since = 'daily' - - # Technology slug - techslug = '' - - # Technology name - tech = '' - - # Answer key - answerkey = 'today' - - for item in entities: - if item['entity'] == 'number': - limit = item['resolution']['value'] - if item['entity'] == 'daterange': - if item['resolution']['timex'].find('W') != -1: - since = 'weekly' - answerkey = 'week' - else: - since = 'monthly' - answerkey = 'month' - - # Feed the languages list based on the GitHub languages list - for i, language in enumerate(github_lang.getall()): - # Find the asked language - if search(r'\b' + escape(language.lower()) + r'\b', string.lower()): - answerkey += '_with_tech' - tech = language - techslug = language.lower() - - if limit > 25: - utils.output('inter', 'limit_max', utils.translate('limit_max', { - 'limit': limit - })) - limit = 25 - elif limit == 0: - limit = 5 - - utils.output('inter', 'reaching', utils.translate('reaching')) - - try: - r = utils.http('GET', 'https://github.com/trending/' + techslug + '?since=' + since) - soup = BeautifulSoup(r.text, features='html.parser') - elements = soup.select('article.Box-row', limit=limit) - result = '' - - for i, element in enumerate(elements): - repository = element.h1.get_text(strip=True).replace(' ', '') - if (element.img != None): - author = element.img.get('alt')[1:] - else: - author = '?' - - hasstars = element.select('span.d-inline-block.float-sm-right') - stars = 0 - - if hasstars: - stars = element.select('span.d-inline-block.float-sm-right')[0].get_text(strip=True).split(' ')[0] - separators = [' ', ',', '.'] - - # Replace potential separators number - for j, separator in enumerate(separators): - stars = stars.replace(separator, '') - - result += utils.translate('list_element', { - 'rank': i + 1, - 'repository_url': 'https://github.com/' + repository, - 'repository_name': repository, - 'author_url': 'https://github.com/' + author, - 'author_username': author, - 'stars_nb': stars - } - ) - - return utils.output('end', answerkey, utils.translate(answerkey, { - 'limit': limit, - 'tech': tech, - 'result': result - } - ) - ) - except requests.exceptions.RequestException as e: - return utils.output('end', 'unreachable', utils.translate('unreachable')) diff --git a/packages/trend/github_lang.py b/packages/trend/github_lang.py deleted file mode 100644 index 7d38e8340..000000000 --- a/packages/trend/github_lang.py +++ /dev/null @@ -1,500 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -def getall(): - return [ - '1C Enterprise', - 'ABAP', - 'ABNF', - 'ActionScript', - 'Ada', - 'Adobe Font Metrics', - 'Agda', - 'AGS Script', - 'Alloy', - 'Alpine Abuild', - 'AMPL', - 'AngelScript', - 'Ant Build System', - 'ANTLR', - 'ApacheConf', - 'Apex', - 'API Blueprint', - 'APL', - 'Apollo Guidance Computer', - 'AppleScript', - 'Arc', - 'AsciiDoc', - 'ASN.1', - 'ASP', - 'AspectJ', - 'Assembly', - 'Asymptote', - 'ATS', - 'Augeas', - 'AutoHotkey', - 'AutoIt', - 'Awk', - 'Ballerina', - 'Batchfile', - 'Befunge', - 'Bison', - 'BitBake', - 'Blade', - 'BlitzBasic', - 'BlitzMax', - 'Bluespec', - 'Boo', - 'Brainfuck', - 'Brightscript', - 'Bro', - 'C', - 'C#', - 'C++', - 'C-ObjDump', - 'C2hs Haskell', - "Cap'n Proto", 'CartoCSS', - 'Ceylon', - 'Chapel', - 'Charity', - 'ChucK', - 'Cirru', - 'Clarion', - 'Clean', - 'Click', - 'CLIPS', - 'Clojure', - 'Closure Templates', - 'Cloud Firestore Security Rules', - 'CMake', - 'COBOL', - 'CoffeeScript', - 'ColdFusion', - 'ColdFusion CFC', - 'COLLADA', - 'Common Lisp', - 'Common Workflow Language', - 'Component Pascal', - 'CoNLL-U', - 'Cool', - 'Coq', - 'Cpp-ObjDump', - 'Creole', - 'Crystal', - 'CSON', - 'Csound', - 'Csound Document', - 'Csound Score', - 'CSS', - 'CSV', - 'Cuda', - 'CWeb', - 'Cycript', - 'Cython', - 'D', - 'D-ObjDump', - 'Darcs Patch', - 'Dart', - 'DataWeave', - 'desktop', - 'Diff', - 'DIGITAL Command Language', - 'DM', - 'DNS Zone', - 'Dockerfile', - 'Dogescript', - 'DTrace', - 'Dylan', - 'E', - 'Eagle', - 'Easybuild', - 'EBNF', - 'eC', - 'Ecere Projects', - 'ECL', - 'ECLiPSe', - 'Edje Data Collection', - 'edn', - 'Eiffel', - 'EJS', - 'Elixir', - 'Elm', - 'Emacs Lisp', - 'EmberScript', - 'EML', - 'EQ', - 'Erlang', - 'F#', - 'F*', - 'Factor', - 'Fancy', - 'Fantom', - 'FIGlet Font', - 'Filebench WML', - 'Filterscript', - 'fish', - 'FLUX', - 'Formatted', - 'Forth', - 'Fortran', - 'FreeMarker', - 'Frege', - 'G-code', - 'Game Maker Language', - 'GAMS', - 'GAP', - 'GCC Machine Description', - 'GDB', - 'GDScript', - 'Genie', - 'Genshi', - 'Gentoo Ebuild', - 'Gentoo Eclass', - 'Gerber Image', - 'Gettext Catalog', - 'Gherkin', - 'GLSL', - 'Glyph', - 'Glyph Bitmap Distribution Format', - 'GN', - 'Gnuplot', - 'Go', - 'Golo', - 'Gosu', - 'Grace', - 'Gradle', - 'Grammatical Framework', - 'Graph Modeling Language', - 'GraphQL', - 'Graphviz (DOT)', - 'Groovy', - 'Groovy Server Pages', - 'Hack', - 'Haml', - 'Handlebars', - 'HAProxy', - 'Harbour', - 'Haskell', - 'Haxe', - 'HCL', - 'HiveQL', - 'HLSL', - 'HTML', - 'HTML+Django', - 'HTML+ECR', - 'HTML+EEX', - 'HTML+ERB', - 'HTML+PHP', - 'HTML+Razor', - 'HTTP', - 'HXML', - 'Hy', - 'HyPhy', - 'IDL', - 'Idris', - 'IGOR Pro', - 'Inform 7', - 'INI', - 'Inno Setup', - 'Io', - 'Ioke', - 'IRC log', - 'Isabelle', - 'Isabelle ROOT', - 'J', - 'Jasmin', - 'Java', - 'Java Properties', - 'Java Server Pages', - 'JavaScript', - 'JFlex', - 'Jison', - 'Jison Lex', - 'Jolie', - 'JSON', - 'JSON with Comments', - 'JSON5', - 'JSONiq', - 'JSONLD', - 'Jsonnet', - 'JSX', - 'Julia', - 'Jupyter Notebook', - 'KiCad Layout', - 'KiCad Legacy Layout', - 'KiCad Schematic', - 'Kit', - 'Kotlin', - 'KRL', - 'LabVIEW', - 'Lasso', - 'Latte', - 'Lean', - 'Less', - 'Lex', - 'LFE', - 'LilyPond', - 'Limbo', - 'Linker Script', - 'Linux Kernel Module', - 'Liquid', - 'Literate Agda', - 'Literate CoffeeScript', - 'Literate Haskell', - 'LiveScript', - 'LLVM', - 'Logos', - 'Logtalk', - 'LOLCODE', - 'LookML', - 'LoomScript', - 'LSL', - 'Lua', - 'M', - 'M4', - 'M4Sugar', - 'Makefile', - 'Mako', - 'Markdown', - 'Marko', - 'Mask', - 'Mathematica', - 'MATLAB', - 'Maven POM', - 'Max', - 'MAXScript', - 'mcfunction', - 'MediaWiki', - 'Mercury', - 'Meson', - 'Metal', - 'MiniD', - 'Mirah', - 'Modelica', - 'Modula-2', - 'Modula-3', - 'Module Management System', - 'Monkey', - 'Moocode', - 'MoonScript', - 'MQL4', - 'MQL5', - 'MTML', - 'MUF', - 'mupad', - 'Myghty', - 'NCL', - 'Nearley', - 'Nemerle', - 'nesC', - 'NetLinx', - 'NetLinx+ERB', - 'NetLogo', - 'NewLisp', - 'Nextflow', - 'Nginx', - 'Nim', - 'Ninja', - 'Nit', - 'Nix', - 'NL', - 'NSIS', - 'Nu', - 'NumPy', - 'ObjDump', - 'Objective-C', - 'Objective-C++', - 'Objective-J', - 'OCaml', - 'Omgrofl', - 'ooc', - 'Opa', - 'Opal', - 'OpenCL', - 'OpenEdge ABL', - 'OpenRC runscript', - 'OpenSCAD', - 'OpenType Feature File', - 'Org', - 'Ox', - 'Oxygene', - 'Oz', - 'P4', - 'Pan', - 'Papyrus', - 'Parrot', - 'Parrot Assembly', - 'Parrot Internal Representation', - 'Pascal', - 'Pawn', - 'Pep8', - 'Perl', - 'Perl 6', - 'PHP', - 'Pic', - 'Pickle', - 'PicoLisp', - 'PigLatin', - 'Pike', - 'PLpgSQL', - 'PLSQL', - 'Pod', - 'Pod 6', - 'PogoScript', - 'Pony', - 'PostCSS', - 'PostScript', - 'POV-Ray SDL', - 'PowerBuilder', - 'PowerShell', - 'Processing', - 'Prolog', - 'Propeller Spin', - 'Protocol Buffer', - 'Public Key', - 'Pug', - 'Puppet', - 'Pure Data', - 'PureBasic', - 'PureScript', - 'Python', - 'Python console', - 'Python traceback', - 'q', - 'QMake', - 'QML', - 'Quake', - 'R', - 'Racket', - 'Ragel', - 'RAML', - 'Rascal', - 'Raw token data', - 'RDoc', - 'REALbasic', - 'Reason', - 'Rebol', - 'Red', - 'Redcode', - 'Regular Expression', - "Ren'Py", 'RenderScript', - 'reStructuredText', - 'REXX', - 'RHTML', - 'Rich Text Format', - 'Ring', - 'RMarkdown', - 'RobotFramework', - 'Roff', - 'Rouge', - 'RPC', - 'RPM Spec', - 'Ruby', - 'RUNOFF', - 'Rust', - 'Sage', - 'SaltStack', - 'SAS', - 'Sass', - 'Scala', - 'Scaml', - 'Scheme', - 'Scilab', - 'SCSS', - 'sed', - 'Self', - 'ShaderLab', - 'Shell', - 'ShellSession', - 'Shen', - 'Slash', - 'Slice', - 'Slim', - 'Smali', - 'Smalltalk', - 'Smarty', - 'SMT', - 'Solidity', - 'SourcePawn', - 'SPARQL', - 'Spline Font Database', - 'SQF', - 'SQL', - 'SQLPL', - 'Squirrel', - 'SRecode Template', - 'Stan', - 'Standard ML', - 'Stata', - 'STON', - 'Stylus', - 'SubRip Text', - 'SugarSS', - 'SuperCollider', - 'SVG', - 'Swift', - 'SystemVerilog', - 'Tcl', - 'Tcsh', - 'Tea', - 'Terra', - 'TeX', - 'Text', - 'Textile', - 'Thrift', - 'TI Program', - 'TLA', - 'TOML', - 'Turing', - 'Turtle', - 'Twig', - 'TXL', - 'Type Language', - 'TypeScript', - 'Unified Parallel C', - 'Unity3D Asset', - 'Unix Assembly', - 'Uno', - 'UnrealScript', - 'UrWeb', - 'Vala', - 'VCL', - 'Verilog', - 'VHDL', - 'Vim script', - 'Visual Basic', - 'Volt', - 'Vue', - 'Wavefront Material', - 'Wavefront Object', - 'wdl', - 'Web Ontology Language', - 'WebAssembly', - 'WebIDL', - 'Windows Registry Entries', - 'wisp', - 'World of Warcraft Addon Data', - 'X BitMap', - 'X Font Directory Index', - 'X PixMap', - 'X10', - 'xBase', - 'XC', - 'XCompose', - 'XML', - 'Xojo', - 'XPages', - 'XProc', - 'XQuery', - 'XS', - 'XSLT', - 'Xtend', - 'Yacc', - 'YAML', - 'YANG', - 'YARA', - 'YASnippet', - 'Zephir', - 'Zig', - 'Zimpl' - ] diff --git a/packages/trend/producthunt.py b/packages/trend/producthunt.py deleted file mode 100644 index ea684b81e..000000000 --- a/packages/trend/producthunt.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import requests -import utils - -def run(string, entities): - """Grab the Product Hunt trends""" - - # Developer token - developertoken = utils.config('developer_token') - - # Number of products - limit = 5 - - # Answer key - answerkey = 'today' - - # Day date - daydate = '' - - for item in entities: - if item['entity'] == 'number': - limit = item['resolution']['value'] - if item['entity'] == 'date': - answerkey = 'specific_day' - - if 'strPastValue' in item['resolution']: - daydate = item['resolution']['strPastValue'] - else: - daydate = item['resolution']['strValue'] - - utils.output('inter', 'reaching', utils.translate('reaching')) - - try: - url = 'https://api.producthunt.com/v1/posts' - if (daydate != ''): - url = url + '?day=' + daydate - - r = utils.http('GET', url, { 'Authorization': 'Bearer ' + developertoken }) - response = r.json() - - if 'error' in response and response['error'] == 'unauthorized_oauth': - return utils.output('end', 'invalid_developer_token', utils.translate('invalid_developer_token')) - - posts = list(enumerate(response['posts'])) - result = '' - - if len(posts) == 0: - return utils.output('end', 'not_found', utils.translate('not_found')) - - if limit > len(posts): - utils.output('inter', 'limit_max', utils.translate('limit_max', { - 'limit': limit, - 'new_limit': len(posts) - })) - limit = len(posts) - elif limit == 0: - limit = 5 - - for i, post in posts: - # If the product maker is known - if post['maker_inside']: - author = list(reversed(post['makers']))[0] - result += utils.translate('list_element', { - 'rank': i + 1, - 'post_url': post['discussion_url'], - 'product_name': post['name'], - 'author_url': author['profile_url'], - 'author_name': author['name'], - 'votes_nb': post['votes_count'] - } - ) - else: - result += utils.translate('list_element_with_unknown_maker', { - 'rank': i + 1, - 'post_url': post['discussion_url'], - 'product_name': post['name'], - 'votes_nb': post['votes_count'] - } - ) - - if (i + 1) == limit: - break - - return utils.output('end', answerkey, utils.translate(answerkey, { - 'limit': limit, - 'result': result, - 'date': daydate - } - ) - ) - except requests.exceptions.RequestException as e: - return utils.output('end', 'unreachable', utils.translate('unreachable')) diff --git a/packages/trend/test/github.spec.js b/packages/trend/test/github.spec.js deleted file mode 100644 index 312f70520..000000000 --- a/packages/trend/test/github.spec.js +++ /dev/null @@ -1,103 +0,0 @@ -describe('trend:github', () => { - test('forces limit', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Give me the 30 latest GitHub trends') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(25) - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'limit_max', - 'reaching', - 'today' - ]) - }) - - test('gives the 16 trends', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Give me the 16 latest GitHub trends') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(16) - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'reaching', - 'today' - ]) - }) - - test('gives the default number of trends of this week', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Give me the GitHub trends of this week') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(5) - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'reaching', - 'week' - ]) - }) - - test('gives the default number of trends of this month', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Give me the GitHub trends of this month') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(5) - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'reaching', - 'month' - ]) - }) - - test('gives the 7 trends for the Python language', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Give me the 7 GitHub trends for the Python language') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(7) - expect(global.brain.finalOutput.speech.indexOf('Python')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'reaching', - 'today_with_tech' - ]) - }) - - test('gives the 14 trends of this week for the JavaScript language', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Give me the 14 GitHub trends of this week for the JavaScript language') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(14) - expect(global.brain.finalOutput.speech.indexOf('JavaScript')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'reaching', - 'week_with_tech' - ]) - }) - - test('gives the default number of trends of this month for the CSS language', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Give me the GitHub trends of this month for the CSS language') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.finalOutput.speech.split('').length - 1).toBe(5) - expect(global.brain.finalOutput.speech.indexOf('CSS')).not.toBe(-1) - expect(global.brain.finalOutput.codes).toIncludeSameMembers([ - 'reaching', - 'month_with_tech' - ]) - }) -}) diff --git a/packages/trend/test/producthunt.spec.js b/packages/trend/test/producthunt.spec.js deleted file mode 100644 index 5030d6d69..000000000 --- a/packages/trend/test/producthunt.spec.js +++ /dev/null @@ -1,16 +0,0 @@ -describe('trend:producthunt', () => { - test('requests Product Hunt', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('What\'s trending on Product Hunt?') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect([ - 'reaching', - 'today', - 'unreachable', - 'invalid_developer_token' - ]).toIncludeAnyMembers(global.brain.finalOutput.codes) - }) -}) diff --git a/packages/trend/version.txt b/packages/trend/version.txt deleted file mode 100644 index afaf360d3..000000000 --- a/packages/trend/version.txt +++ /dev/null @@ -1 +0,0 @@ -1.0.0 \ No newline at end of file diff --git a/packages/videodownloader/README.md b/packages/videodownloader/README.md deleted file mode 100644 index a444dd256..000000000 --- a/packages/videodownloader/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Video Downloader Package - -The video downloader package contains modules which include video downloading. - -## Modules - -### YouTube - -Download new video(s) from a YouTube playlist. - -#### Usage - -1. Save the YouTube video(s) in a YouTube playlist via [youtube.com](https://www.youtube.com). -2. If you do not have a Google API key yet, please [follow these steps](https://developers.google.com/youtube/v3/getting-started). -3. Provide the Google API key & YouTube playlist ID in `packages/videodownloader/config/config.json`. - -``` -(en-US) "Download new videos from YouTube" - -(fr-FR) "Télécharges les nouvelles vidéos depuis YouTube" -... -``` - -#### Options - -##### Synchronization - -[Read the docs](https://docs.getleon.ai/configuration#synchronizer). - -#### Links - -- [YouTube Data API](https://developers.google.com/youtube/v3/getting-started) diff --git a/packages/videodownloader/__init__.py b/packages/videodownloader/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/videodownloader/config/.gitkeep b/packages/videodownloader/config/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/videodownloader/config/config.sample.json b/packages/videodownloader/config/config.sample.json deleted file mode 100644 index 693cde1a6..000000000 --- a/packages/videodownloader/config/config.sample.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "youtube": { - "api_key": "YOUR_GOOGLE_API_KEY", - "playlist_id": "PLAYLIST_ID", - "options": { - "synchronization": { - "enabled": true, - "method": "direct", - "email": "" - } - } - } -} diff --git a/packages/videodownloader/data/.gitkeep b/packages/videodownloader/data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/videodownloader/data/answers/.gitkeep b/packages/videodownloader/data/answers/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/videodownloader/data/answers/en.json b/packages/videodownloader/data/answers/en.json deleted file mode 100644 index 9c9af6c48..000000000 --- a/packages/videodownloader/data/answers/en.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "youtube": { - "success": [ - "All of the videos have been downloaded.", - "I finished to download the videos.", - "New videos are now in my memory." - ], - "downloading": [ - "I'm downloading %video_title%.", - "I am currently downloading %video_title%.", - "Download for %video_title% has started." - ], - "reaching_playlist": [ - "I'm trying to collect videos from the YouTube playlist.", - "I'm getting videos from the YouTube playlist.", - "I am reaching the YouTube playlist to collect videos." - ], - "nb_to_download": [ - "I will download %nb% videos.", - "There are %nb% new videos to download." - ], - "nothing_to_download": [ - "There is no new video to download. Add a new video to the YouTube playlist if you want to download a new one.", - "I have no new video to download." - ], - "settings_errors": [ - "Please verify my settings. There is an error for the following reason: %reason%, which includes this message: %message%.", - "I have an error for this reason: %reason%, which includes the following message: %message%. Please check if my settings are correct." - ], - "request_errors": [ - "I cannot reach YouTube for now. Please verify the URL and your network settings are correct.", - "I currently can't reach YouTube. Do you think YouTube is broken? Please verify the URL and your network settings." - ] - } -} diff --git a/packages/videodownloader/data/answers/fr.json b/packages/videodownloader/data/answers/fr.json deleted file mode 100644 index 59128fa44..000000000 --- a/packages/videodownloader/data/answers/fr.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "youtube": { - "success": [ - "Toutes les vidéos ont été téléchargées.", - "J'ai terminé de télécharger les vidéos.", - "Les nouvelles vidéos sont maintenant enregistrées dans ma mémoire." - ], - "downloading": [ - "Je télécharge %video_title%.", - "Je suis actuellement en train de télécharger %video_title%.", - "Le téléchargement pour %video_title% a débuté." - ], - "reaching_playlist": [ - "J'essaye de collecter les vidéos depuis la playlist YouTube.", - "Je récupère les vidéos depuis la playlist YouTube.", - "Je requête la playlist YouTube pour collecter les vidéos." - ], - "nb_to_download": [ - "Je vais télécharger %nb% vidéos.", - "Il y a %nb% nouvelles vidéos à télécharger." - ], - "nothing_to_download": [ - "Il n'y a pas de nouvelle vidéo à télécharger. Ajoutez une nouvelle vidéo à la playlist YouTube pour en télécharger une nouvelle.", - "Je n'ai pas de nouvelle vidéo à télécharger." - ], - "settings_errors": [ - "Merci de vérifier mes paramètres. Il y a une erreur pour la raison suivante : %reason%, qui inclut ce message : %message%.", - "J'ai une erreur pour cette raison : %reason%, qui inclut le message suivant : %message%. Merci de vérifier si paramètres sont corrects." - ], - "request_errors": [ - "Je ne peux pas atteindre YouTube pour le moment. Merci de vérifier si l'URL ainsi que vos paramètres réseaux sont corrects.", - "Je ne peux actuellement pas atteindre YouTube. Pensez-vous que YouTube est hors ligne ? Merci de vérifier l'URL et vos paramètres réseaux." - ] - } -} diff --git a/packages/videodownloader/data/db/.gitkeep b/packages/videodownloader/data/db/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/videodownloader/data/expressions/.gitkeep b/packages/videodownloader/data/expressions/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/videodownloader/data/expressions/en.json b/packages/videodownloader/data/expressions/en.json deleted file mode 100644 index 40ea343fe..000000000 --- a/packages/videodownloader/data/expressions/en.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "youtube": { - "run": { - "utterance_samples": [ - "Download new videos from YouTube" - ] - } - } -} diff --git a/packages/videodownloader/data/expressions/fr.json b/packages/videodownloader/data/expressions/fr.json deleted file mode 100644 index 7b50e04e3..000000000 --- a/packages/videodownloader/data/expressions/fr.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "youtube": { - "run": { - "utterance_samples": [ - "Télécharge les nouvelles vidéos depuis YouTube" - ] - } - } -} diff --git a/packages/videodownloader/test/youtube.spec.js b/packages/videodownloader/test/youtube.spec.js deleted file mode 100644 index ab89488bb..000000000 --- a/packages/videodownloader/test/youtube.spec.js +++ /dev/null @@ -1,17 +0,0 @@ -describe('videodownloader:youtube', () => { - test('requests YouTube', async () => { - global.nlu.brain.execute = jest.fn() - await global.nlu.process('Download new videos from YouTube') - - const [obj] = global.nlu.brain.execute.mock.calls - await global.brain.execute(obj[0]) - - expect(global.brain.interOutput.codes).toIncludeSameMembers(['reaching_playlist']) - expect([ - 'settings_error', - 'request_error', - 'nothing_to_download', - 'success' - ]).toIncludeAnyMembers(global.brain.finalOutput.codes) - }) -}) diff --git a/packages/videodownloader/version.txt b/packages/videodownloader/version.txt deleted file mode 100644 index 7dea76edb..000000000 --- a/packages/videodownloader/version.txt +++ /dev/null @@ -1 +0,0 @@ -1.0.1 diff --git a/packages/videodownloader/youtube.py b/packages/videodownloader/youtube.py deleted file mode 100644 index 622155cb7..000000000 --- a/packages/videodownloader/youtube.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import requests -import os -import utils -from time import time -from pytube import YouTube - -def run(string, entities): - """Download new videos from a YouTube playlist""" - - db = utils.db()['db'] - query = utils.db()['query'] - operations = utils.db()['operations'] - apikey = utils.config('api_key') - playlistid = utils.config('playlist_id') - # https://developers.google.com/youtube/v3/docs/playlistItems/list - url = 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=' + playlistid + '&key=' + apikey - - utils.output('inter', 'reaching_playlist', utils.translate('reaching_playlist')) - # Get videos from the playlist - try: - r = utils.http('GET', url) - - # In case there is a problem like wrong settings - if 'error' in r.json(): - error = r.json()['error']['errors'][0] - return utils.output('settings_error', 'settings_error', utils.translate('settings_errors', { - 'reason': error['reason'], - 'message': error['message'] - })) - - - items = r.json()['items'] - videoids = [] - videos = [] - - for item in items: - resource = item['snippet']['resourceId'] - - if resource['kind'] == 'youtube#video': - videoids.append(resource['videoId']) - videos.append({ - 'id': resource['videoId'], - 'title': item['snippet']['title'] - }) - except requests.exceptions.RequestException as e: - return utils.output('request_error', 'request_error', utils.translate('request_errors')) - - Entry = query() - - # First initialization - if db.count(Entry.platform == 'youtube') == 0: - db.insert({ - 'platform': 'youtube', - 'checked_at': int(time()), - 'downloaded_videos': [] - }) - else: - db.update({ 'checked_at': int(time()) }, Entry.platform == 'youtube') - - # Get videos already downloaded - downloadedvideos = db.get(Entry.platform == 'youtube')['downloaded_videos'] - - todownload = [] - for video in videos: - if video['id'] not in downloadedvideos: - todownload.append(video) - - nbrtodownload = len(todownload) - - if nbrtodownload == 0: - return utils.output('nothing_to_download', 'nothing_to_download', utils.translate('nothing_to_download')) - - utils.output('inter', 'nb_to_download', utils.translate('nb_to_download', { - 'nb': nbrtodownload - })) - - # Create the module downloads directory - moduledldir = utils.createdldir() - - for i, video in enumerate(todownload): - utils.output('inter', 'downloading', utils.translate('downloading', { - 'video_title': video['title'] - })) - - # Download the video - yt = YouTube('https://youtube.com/watch?v=' + video['id']) - yt.streams.first().download(moduledldir) - - # Add the new downloaded video to the DB - downloadedvideos.append(video['id']) - db.update({ 'downloaded_videos': downloadedvideos }, Entry.platform == 'youtube') - - # Will synchronize the content (because "end" type) if synchronization enabled - return utils.output('end', 'success', utils.translate('success')) diff --git a/scripts/lint.js b/scripts/lint.js index f7ab19a31..b246e0a59 100644 --- a/scripts/lint.js +++ b/scripts/lint.js @@ -14,7 +14,8 @@ import loader from '@/helpers/loader' const globs = [ '"app/src/js/*.js"', '"hotword/index.js"', - '"packages/**/*.js"', + // TODO: put it back once tests have been reintroduced into skills + // '"skills/**/*.js"', '"scripts/**/*.js"', '"server/src/**/*.js"', '"test/*.js"',