Como fiz um organizador automático de arquivos
Recentemente abrindo a minha pasta de downloads percebi o quão desorganizada ela é e o quão aleatórios são os arquivos que estão nela. Isso é um problema recorrente com 99,9999% dos usuários médios de computadores. É aquele velho assunto de "depois eu organizo", mas esse "depois" nunca chega. Eu sou usuário de Linux, mais precisamente o Arch Linux e o que mais me chama a atenção em relação à organização da minha home é o fato de a pasta de Downloads estar sempre cheia enquanto Documentos, Imagens, Vídeos e as outras pastas da home vazias.
Isso me deu uma ótima ideia: fazer um script para mover automaticamente os arquivos da pasta de downloads para a sua pasta correta na home afinal, elas existem para isso de acordo com a extenção do arquivo.
O que exatamente será feito?
- Vamos criar um arquivo de configuração onde teremos o caminho da pasta e seus tipos de arquivos
- Vamos classificar cada arquivo de acordo com a sua extenção
- Vamos mover esse arquivo para a sua determinada pasta
- Fazer com que o script seja executado automaticamente
Criando o arquivo de configuração.
No Linux nós temos muitos arquivos e pastas especiais. Se você usa um terminal bash certamente já ouviu falar sobre o arquivo .bashrc, para zsh é o .zshrc e por aí vai. Mas se você utiliza fish assim como eu, já deve estar familiarizado com a pasta .config.
Para quem não entendeu nada do que foi dito anteriormente
Arquivos e pastas que iniciam com um . são pastas e arquivos ocultos.A home no linux é uma pasta especial com o caminho /home/username
que é o equivalente à pasta C:\\users\\username
no windows.
Pegando as pastas do usuário
As pastas que estão em /home/user são geradas automaticamente no primeiro login e depois são atualizadas de acordo com o arquivo ~/.config/user-dirs.dirs
que pode ser editado diretamente ou traduzido de acordo com o locale definido em ~/.config/user-dirs.conf
. Existe um script que é rodado cada vez que você faz login no sistema para verificar possíveis mudanças nesses arquivos chamado xdg-user-dirs-update.
A melhor forma de conseguir pegar as pastas é utilizando o comando xdg-user-dir que retorna o caminho /home/username
quando chamado sem nenhum argumento. Esse comando pode receber um parâmetro chamado NAME
que tem 8 valores possíveis:
DESKTOP, DOWNLOAD, TEMPLATES, PUBLICSHARE, DOCUMENTS, MUSIC, PICTURES, VIDEOS
Para cada um desses argumentos é retornado o caminho completo até a respectiva pasta. Por exemplo:
[user]$ xdg-user-dir
>> /home/user
[user]$ xdg-user-dir DOCUMENTS # Em inglês
>> /home/user/documents
[user]$ xdg-user-dir DESKTOP # Em português
>> /home/user/'Área de trabalho'
A partir desse utilitário podemos garantir com que pegamos as pastas corretas além de que elas existem, o que irá evitar muitas dores de cabeça no futuro.
Eu fiz esse script na linguagem Python, mas você pode fazer o mesmo programa em absolutamente qualquer linguagem de programação, desde shell script até C. Linguagens são apenas ferramentas então é a parte menos importante. O mesmo serve para o arquivo de configuração, eu preferi utilizar JSON, mas você pode utilizar qualquer um de sua preferência, desde um csv até xml.
Para gerar esse arquivo eu fiz da seguinte forma:
# setup.py
import json
import os
from subprocess import check_output
USER_DIRS = [
check_output(["xdg-user-dir", "DOCUMENTS"])[:-1].decode("utf-8"),
check_output(["xdg-user-dir", "PICTURES"])[:-1].decode("utf-8"),
check_output(["xdg-user-dir", "MUSIC"])[:-1].decode("utf-8"),
check_output(["xdg-user-dir", "VIDEOS"])[:-1].decode("utf-8"),
]
FILE_EXTENSIONS = [
["pdf", "odt", "doc", "docx", "csv", "ods", "xls", "xlsx"],
["png", "jpeg", "jpg", "gif", "webp", "svg"],
["mp3", "wav", "ogg"],
["mp4", "avi", "wmv", "mov", "flv", "mkv", "webm"],
]
def setup():
HOME = check_output(["xdg-user-dir"])[:-1].decode("utf-8")
CONFIG_PATH = f"{HOME}/.config/downloads-organizer"
default_json = dict(zip(USER_DIRS, FILE_EXTENSIONS))
config_json = json.dumps(default_json, indent=2)
if not os.path.exists(CONFIG_PATH):
os.mkdir(CONFIG_PATH)
if not os.path.isfile(f"{CONFIG_PATH}/config.json"):
with open(f"{CONFIG_PATH}/config.json", "w", encoding="utf-8") as config_file:
config_file.write(config_json)
O algoritmo é muito simples:
- Criamos uma lista com as pastas do usuário, utilizando o utilitário
xdg-user-dir
- Criamos uma lista com as extenções de arquivos para cada pasta
- Juntamos as duas listas com
zip()
e transformamos em um dicionário comdict()
- Transformamos o dicionário em um JSON
- Verificamos se a pasta
~/.config/downloads-organizer
existe e, caso não exista, criamos ela - Fazemos a mesma verificação com o arquivo
~/.config/downloads-organizer/config.json
e, caso não exista, o criamos.
Depois de rodarmos essa função termos um arquivo de configuração para o nosso script salvo em ~/.config/downloads-organizer
. Nesse caso eu preferi fazer em JSON, mas poderia ser absolutamente qualquer outro formato.
Classificando os arquivos
Essa é provavelmente a parte mais simples do programa, basicamente vamos precisar pegar a extenção do arquivo e utilizando o arquivo de configuração criado verificar se ela se encaixa em alguma das pastas.
# classify_file.py
from json import load
from subprocess import check_output
HOME = check_output(["xdg-user-dir"])[:-1].decode("utf-8")
def classify_file(file: str):
file_extension = file.split(".")[-1]
with open(
f"{HOME}/.config/downloads-organizer/config.json", "r", encoding="utf-8"
) as config_file:
config = load(config_file)
for folder in config:
if file_extension in config[folder]:
return folder
return check_output(["xdg-user-dir", "DESKTOP"])[0:-1].decode("utf-8")
Como eu disse, o algoritmo é muito simples:
- Separa o nome do arquivo da sua extenção com
split(".")
e armazena apenas a extenção - Abre o arquivo de configuração e armazena como um dicionário python
- Para cada pasta no arquivo de configuração verifica se a extenção do arquivo deve estar na pasta, caso esteja retorna o caminho para a pasta
- Caso o valor não se encaixe retorna uma pasta padrão (no meu caso é a pasta Desktop)
Movendo os arquivos
Aqui cabe ressaltar o que significa objetivamente mover um arquivo. Normalmente nós fazemos isso apenas por interface gráfica, mas também é possível via linha de comando, que é o que nos mostra o que significa mover um arquivo. Em linha de comando nós temos um comando chamado mv
que move os arquivos, mas também serve para renomear os arquivos. Isso significa que mover é basicamente renomear o arquivo.
No Python existem várias maneiras para fazer isso, principalmente as seguintes:
import shutil
import os
import subprocess
shutil.move('caminho/do/arquivo', 'novo/caminho/do/arquivo')
os.rename('caminho/do/arquivo', 'novo/caminho/do/arquivo')
subprocess.run('mv', 'caminho/do/arquivo', 'novo/caminho/do/arquivo')
Independentemente da forma escolhida para mover o arquivo, o resultado será o mesmo. Nesse caso:
# move_file.py
import os
HOME = os.environ.get("HOME")
def move(file, folder):
new_file_name = file
i = 1
while os.path.exists(f"{folder}/{new_file_name}"):
new_file_name = f"[{i}]{file}"
i += 1
os.rename(f"{HOME}/Downloads/{file}", f"{folder}/{new_file_name}")
O algoritmo é o seguinte:
- verifica se o nome do arquivo já existe e, caso já exista, dá um índice antes do nome do arquivo
- move o arquivo para a pasta
main.py
Por fim, juntando todas as funções teremos o nosso script completo:
# main.py
import os
from classify_file import classify_file
from move_file import move
from setup import setup
print("Start oganizing Downloads files")
HOME = os.environ.get("HOME")
setup()
files = [
f
for f in os.listdir(f"{HOME}/Downloads")
if os.path.isfile(f"{HOME}/Downloads/{f}")
]
for file in files:
folder = classify_file(file)
move(file, folder)
print("Done oganizing Downloads files")
Fazendo o script rodar automaticamente
Cada usuário tem uma pasta que define algums programas que serão iniciados de forma automática cada vez que o usuário faz login. Essa pasta é a ~/.config/autostart
e cada programa deve ter um arquivo desktop para ser rodado. Basicamente ao invés de colocar o seu programa inteiro dentro dessa pasta você precisa de apenas um arquivo que contém alguns metadados e representa alguma rotina, mais ou menos como funcionam os atalhos do windows.
Por exemplo, eu utilizo o cliente de emails Geary que tem a funcionalidade de notificar todos os emails que eu recebo, portanto ele é iniciado sempre que faço login com o meu usuário. O seu arquivo desktop é o seguinte:
# org.gnome.Geary.desktop
[Desktop Entry]
Type=Application
Name=org.gnome.Geary
Exec=flatpak run --command=geary org.gnome.Geary --gapplication-service
X-Flatpak=org.gnome.Geary
Como pode ver é um arquivo com metadados e o mais importante é o Exec
, pois a partir dele podemos rodar qualquer script a partir desse arquivo. Vamos fazer um arquivo chamado downloads-organizer.desktop
na pasta ~/.config/autostart
:
# ~/.config/autostart/downloads-organizer.desktop
[Desktop Entry]
Type=Application
Name=downloads organizer
Exec=python3 caminho/para/o/arquivo/main.py
Terminal=false
E pronto! Agora cada vez que o usuário fizer login o script será rodado automaticamente.
Conclusão
O script que eu apresentei aqui é muito simples, mas não deixa de ser muito útil no nosso dia a dia. Se você chegou até aqui deve ter percebido que em nenhum momento eu fiz um tutorial de um programa Python, veja isso como uma oportunidade de fazer esse mesmo script na linguagem de sua preferência, garanto que será uma ótima experiência para aprender mais sobre a sua linguagem preferida.