Créez votre propre bibliothèque de liens
J’aime lire beaucoup d’articles sur beaucoup de sujets différents. Comme c’est souvent le cas chez les techniciens, je veux apprendre plus de choses que je n’en ai le temps. Par conséquent, j’ai besoin de sauvegarder des articles quelque part pour y revenir et les lire quand j’ai le temps.
Le matin, je scanne habituellement Hacker New, mon Medium Daily Digest, mon fil Twitter et éventuellement quelques newsletters Substack. Je vais lire quelques articles et mettre en signet beaucoup d’articles à lire plus tard. J’avais l’habitude d’utiliser les signets du navigateur, mais cela est rapidement devenu incontrôlable.
Ma solution actuelle consiste à utiliser l’extension de navigateur Obsidian Clipper qui enregistre les articles dans une note quotidienne dans mon Obsidian Vault. Cela fonctionne bien car je peux les étiqueter avec un sujet et les rechercher plus tard. Mon problème avec cela est qu’il est difficile de voir une vue récapitulative des articles et de faire la distinction entre lus et non lus. C’est ce qui m’a motivé à mettre en place ma solution.
Cet article suppose que le lecteur est familiarisé avec Python, AWS et SQL et expliquera comment enregistrer des signets d’URL dans votre base de données à l’aide d’un bookmarklet. Plus précisément, l’implémentation utilise Flask, AWS Elastic Beanstalk et MySQL.
La première étape consiste à déployer une application Flask sur Beanstalk. La documentation AWS est plutôt bonne si vous n’en avez pas déjà une. Soyez averti cependant, l’installation de l’interface de ligne de commande Elastic Beanstalk peut être un peu délicate selon le type de machine que vous utilisez.
Une fois que vous avez une application fonctionnelle et que vous avez modifié les itinéraires et les modèles de base pour répondre à vos besoins, vous souhaiterez configurer la base de données. La première étape ici consiste à accéder au tableau de bord Elastic Beanstalk et à rechercher l’environnement dans lequel votre application Flask s’exécute. Dans le panneau latéral, cliquez sur Configuration. Faites défiler vers le bas où il est écrit « Base de données ».
Pour vous assurer que vous restez (très probablement) dans l’offre gratuite d’AWS-RDS, sélectionnez MySQL sur un db.t2.micro
instance avec une faible disponibilité. À l’étape suivante, vous aurez besoin du point de terminaison, du nom d’utilisateur et du mot de passe de la base de données. Prenez donc note de ceux-ci. De plus, pendant que vous êtes ici, vous devez accéder au groupe de sécurité et autoriser le trafic entrant à partir de votre adresse IP afin de pouvoir vous connecter à la base de données tout en exécutant le serveur localement.
Nous allons maintenant créer la base de données et la table qui seront utilisées pour stocker vos favoris. Vous devrez installer MySQL sur votre ordinateur local. Pour moi, c’était fait avec.
brew install mysql-client
export PATH=”/usr/local/opt/mysql-client/bin:$PATH”
brew install mysql
Une fois cela fait, vous pouvez vous connecter à votre point de terminaison et créer la base de données et la table. Après la première commande, vous serez invité à entrer votre mot de passe.
mysql -h <YOUR-ENDPOINT> -u <USERNAME> -p
CREATE DATABASE MyDB;
USE MyDB;
CREATE TABLE bookmarks (id INT NOT NULL PRIMARY KEY, url VARCHAR(64), category VARCHAR(40), is_read BOOL, created_date DATETIME);
Nous sommes maintenant prêts à commencer à travailler dans un IDE !
La toute première chose à faire ici est la dernière étape de la configuration de votre base de données. Dans le même répertoire que application.py et le .elasticbeanstalk
répertoire, créez un nouveau répertoire appelé .ebextensions
. Pour faire fonctionner MySQL sur votre instance de calcul élastique, créez un nouveau fichier appelé 01_packages.config
et ajoutez ce qui suit :
packages:
yum:
python3-devel: []
mariadb-devel: []
Bon, maintenant nous pouvons commencer à utiliser Python. Activez votre environnement virtuel et
pip install flask-mysqldb
Dans application.py
vous aurez besoin d’avoir quelque chose comme ça :
from flask_mysqldb import MySQL
# Create Flask Application
application = Flask(__name__)
application.secret_key = dotenv_values(‘.env’)[‘APP_SECRET’]# initialize the db
application.config['MYSQL_HOST'] = dotenv_values('.env')['DB_ENDPOINT']
application.config['MYSQL_USER'] = dotenv_values('.env')['DB_USERNAME']
application.config['MYSQL_PASSWORD'] = dotenv_values('.env')['DB_PASSWORD']
application.config['MYSQL_DB'] = 'MyDB'
db = MySQL(application)
import source.routes
j’aime garder routes.py
aussi propre que possible, alors commençons par bookmarks.py où nous définirons un Bookmark
class et quelques fonctions de gestion de vos marque-pages.
Le Bookmark
la classe prend une URL et une catégorie lors de son initialisation, attribue la date-heure actuelle à created_date
, et suppose que vous n’avez pas encore lu l’article. Je n’utilise pas actuellement la méthode des catégories. Je prévois de jouer avec certains modèles d’apprentissage automatique pour voir dans quelle mesure ils peuvent étiqueter ou catégoriser les articles que je les alimente.
Le Bookmark
classe a également une méthode pour insérer l’objet dans la base de données. Lorsque vous affichez les signets sur votre site Web, il y aura une case à cocher.
Si vous cochez une case et soumettez le formulaire, le update_read_bookmarks()
la fonction met à jour la base de données.
Le get_all_unread_bookmarks()
La fonction extrait les données que nous voulons afficher sur bookmarks.html.
from application import db
import datetimeclass Bookmark():
def __init__(self, url, category) -> None:
self.url = url
self.category = category
self.created_date = datetime.datetime.now()
self.is_read = False
def insert(self):
query = f"""INSERT INTO bookmarks (url, category, created_date, is_read)
VALUES ('{self.url}', '{self.category}', '{self.created_date}', {self.is_read});"""
cursor = db.connection.cursor()
cursor.execute(query)
db.connection.commit()
cursor.close()
def update_read_bookmarks(bookmarks_to_update):
query = f"""UPDATE bookmarks
SET is_read = TRUE
WHERE id IN ({bookmarks_to_update});"""
cursor = db.connection.cursor()
cursor.execute(query)
db.connection.commit()
cursor.close()
def get_all_unread_bookmarks():
query = """SELECT * FROM bookmarks
WHERE is_read = False
ORDER BY created_date DESC;"""
cursor = db.connection.cursor()
cursor.execute(query)
db.connection.commit()
bookmarks = cursor.fetchall()
cursor.close()
return bookmarks
Ok, alors maintenant toutes les pièces sont en place pour créer les itinéraires et faire fonctionner les choses !
Dans routes.py
, vous aurez quelque chose comme celui ci-dessous. La route du signet est ce qui est utilisé dans le bookmarklet, c’est pourquoi il recherche un suffixe qui ressemble à : ?url=<URL TO BOOKMARK>
. Lorsque vous utilisez le bookmarklet pour marquer une URL, il vous amènera à The /bookmark/show
route, vers laquelle vous voudrez peut-être créer un lien depuis index.html.
Tout ce qu’il fait est d’interroger la base de données pour les signets non lus et de les afficher dans un tableau. Le /update_bookmarks
route est l’action associée au formulaire sur bookmarks.html et recherchera les cases qui ont été cochées afin que la base de données soit correctement mise à jour.
from application import db
from source.bookmarks import Bookmark, get_all_unread_bookmarks, update_read_bookmarks@application.route("/bookmark", methods=["GET", "POST"])
def bookmark():
print(request.args)
if token := request.args.get("token"):
print("Found the token")
if token == dotenv_values(".env")["BOOKMARK_TOKEN"]:
if url := request.args.get("url"):
bookmark = Bookmark(url=url, category="self")
bookmark.insert()
return redirect(url)
else:
print("The token was wrong")
return welcome()
else:
print("Didnt find the token")
return welcome()
return bookmark_show()
@application.route("/bookmark/show", methods=["GET", "POST"])
@login_required
def bookmark_show():
bookmarks = get_all_unread_bookmarks()
return render_template("bookmarks.html", data=bookmarks)
@application.route("/update_bookmarks", methods=["GET", "POST"])
@login_required
def update_bookmarks():
new_read_bookmarks = [str(bookmark) for bookmark in request.form]
bookmarks_for_query = ",".join(new_read_bookmarks)
update_read_bookmarks(bookmarks_for_query)
bookmarks = get_all_unread_bookmarks()
return render_template("bookmarks.html", data=bookmarks)
J’utilise Flask-Login pour m’assurer que je suis le seul à pouvoir interagir avec la base de données. Pour l’instant, je suis le seul à pouvoir même voir les signets, mais éventuellement, je l’ouvrirai pour que d’autres personnes puissent voir ma « bibliothèque de liens ».
Pour être honnête, j’ai trouvé la documentation et les tutoriels sur l’utilisation de Flask-Login avec MySQL assez insuffisants, donc je vais écrire un autre article sur la façon d’utiliser Flask-Login avec des mots de passe cryptés sur une base de données MySQL.
Pour m’assurer que je suis le seul à pouvoir ajouter un signet, j’ai un jeton comme variable d’environnement. J’ai ce jeton dans la requête qui vient du bookmarklet ; s’ils ne correspondent pas, le signet n’est pas ajouté.
La dernière étape consiste à créer bookmarks.html. Je suis peut-être trop utilitaire pour mon bien, mais le mien ressemble à ça :
<html><body>
<form action="/update_bookmarks" method="post">
<input type="submit">
<table border="1">
<tr border="1">
<th>URL</th>
<th>Category</th>
<th>Created Date</th>
<th>Read</th>
</tr>
{% for item in data %}
<br>
<tr border="1">
<td border="1">
<a href="{{item[1]}}">
{{item[1]}}
</a>
</td>
<td border="1">{{item[2]}}</td>
<td border="1">{{item[4]}}</td>
{% if item[3] %}
<td><input type="checkbox" name="{{ item[0] }}" checked /> </td>
{% else %}
<td><input type="checkbox" name="{{ item[0] }}" /> </td>
{% endif %}
</tr>
{% endfor %}
</table>
</form>
</body>
</html>
La dernière chose dont vous aurez besoin est le bookmarklet qui est ceci :
javascript:location.href=’http://127.0.0.1:5000/bookmark?url='+location.href+'&token=<TOKEN';
Une fois que vous avez terminé les tests, utilisez votre domaine au lieu de localhost et vous aurez terminé !
J’ai de grands projets pour cette application, donc si vous êtes intéressé, suivez-moi pour lire bientôt les prochaines étapes ou rejoignez-moi sur LinkedIn!
- Donnez à l’application un numéro de téléphone pour que je puisse ajouter des signets par SMS.
- Utilisez l’apprentissage automatique et le traitement du langage naturel pour extraire des mots-clés et catégoriser les articles.
- Ajoutez la recherche, le filtrage, la pagination, etc.