План был такой:
- Выбрать папку для разбора бардака
- Программа будет по очереди показывать оттуда файлы (фотки, видео и т.д.)
- Пользователь через пробел вводит теги для просмотренного файла (например «фото машина зима» или просто «trash»)
- программа переходит к следующему файлу, пока список не кончится
- В результате формируется база данных по файлам (sqlite files.db)
- Тэги привязываются не к пути файла, а к его контрольной сумме MD5, если копия папки попадётся где-то ещё — программа файлы узнает
- В результате файлы любого типа можно находить по тегам
- Для удаления мусора можно составить список файлов например с тегом «trash» и передать список например команде «del»
Главное меню:
Программа для разбора бардака с файлами
1. Выбор папки
2. Анализ
3. Разбор
4. Сохранить списки
0. Выход
Исходный код черновика (написано за 2 дня):
#! -*- coding: utf-8 -*-
'''
Программа для разбора бардака на дисках
LOG:
добавил ввод нескольких тэгов через пробел
добавил таблицу с путями к файлам
добавил просмотр видео
добавил разбор по выбранному тэгу, можно для просмотра
добавил вывод текущих тегов
добавил удаление тегов через -...
'''
import os
import sqlite3
import hashlib
import time
# просмотрщики
IMAGE_PROGRAM = "eog"
VIDEO_PROGRAM = "vlc"
MUSIC_PROGRAM = "vlc"
TEXT_PROGRAM = "gedit"
CREATE_TABLES_QUERY = """
CREATE TABLE `FILES_INFO` ( `FILES_INFO_ID` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `PATH` TEXT NOT NULL, `FILE_MD5` TEXT NOT NULL, `LAST_MODIFIED` TEXT )
CREATE TABLE `FILES_TAGS` ( `FILES_TAGS_ID` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `FILE_MD5` TEXT NOT NULL, `TAG` TEXT NOT NULL )
"""
class FilesAnalyzer:
def __init__(self):
self.db_connection = sqlite3.connect('files.db')
self.path = ''
self.count_by_tags = {}
self.files_by_tags = {}
def analyze(self):
'''
1. Статистика по количеству файлов по каждому тегу
и неразмеченных
2. Сохранение списков файлов по каждому тегу
и неразмеченных
'''
# Счётчики файлов по тегам
self.count_by_tags = {}
self.count_by_tags[""] = 0
# списки файлов по тегам
self.files_by_tags = {}
self.files_by_tags[""] = []
for root, dirs, files in os.walk(self.path):
for f in files:
f_full = '%s/%s' % (root, f)
f_md5 = self.get_md5(f_full)
f_tags = self.get_tags(f_md5)
''' DEBUG
print('Файл: %s' % f_full)
print('MD5: %s' % f_md5)
print('Тэги: %s' % ', '.join(f_tags))
'''
if len(f_tags) > 0:
for tag in f_tags:
if tag not in self.count_by_tags.keys():
self.count_by_tags[tag] = 1
self.files_by_tags[tag] = []
self.files_by_tags[tag].append(f_full)
else:
self.count_by_tags[tag] += 1
self.files_by_tags[tag].append(f_full)
else:
self.count_by_tags[''] += 1
self.files_by_tags[''].append(f_full)
for key in self.count_by_tags.keys():
print("Тэг '%s': %s" % (key, self.count_by_tags[key]))
''' DEBUG
for key in self.files_by_tags.keys():
print("Файлы '%s':" % key)
for f in self.files_by_tags[key]:
print(f)
'''
def manual_sort(self, selected_tag=""):
'''
Ручная маркировка тегами неразмеченных файлов
'''
if selected_tag in self.files_by_tags.keys():
for f in self.files_by_tags[selected_tag]:
# проверить что новый md5
md5 = self.get_md5(f)
tags = self.get_tags(md5)
if (selected_tag == "" and len(tags) == 0) \
or selected_tag in tags:
print("Файл: '%s'" % f)
print("Текущие тэги: %s" % \
self.get_tags(md5))
# пердосмотр или открыть файл
self.try_preview(f)
new_tags_text = input("Введи тэги для файла: ")
if len(new_tags_text) > 0:
new_tags = new_tags_text.split()
for new_tag in new_tags:
self.save_tag(f, new_tag)
self.save_info(f)
# теперь прошлый анализ бесполезен
self.files_by_tags = {}
self.count_by_tags = {}
else:
print('Ошибка: файлов с тегом "%s" не найдено' % selected_tag)
def save_info(self, f):
'''
сохранение информации о файле в БД
/param[in] f - имя файла
'''
# приготовить информацию
md5 = self.get_md5(f)
mtime = os.path.getmtime(f)
last_modified = time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime(mtime))
# проверить, что в базе такого ещё нет
cur = self.db_connection.cursor()
check_query = """SELECT *
FROM FILES_INFO
WHERE PATH = '%s'
AND FILE_MD5 = '%s'
AND LAST_MODIFIED = '%s'""" % (
f, md5, last_modified)
is_new = True
for row in cur.execute(check_query):
is_new = False
if is_new:
# сохранение в БД
query = """INSERT INTO FILES_INFO
(PATH, FILE_MD5, LAST_MODIFIED)
VALUES ('%s', '%s', '%s')""" % (
f, md5, last_modified)
cur.execute(query)
self.db_connection.commit()
def try_preview(self, f):
if f.lower()[-4:] in ('.png', '.bmp', '.gif', '.jpg', 'jpeg'):
#os.system('eog "%s"' % f)
os.system('%s "%s"' % (IMAGE_PROGRAM, f))
elif f.lower()[-4:] in ('.avi', '.mpg', '.3gp', '.mov'):
os.system('%s "%s"' % (VIDEO_PROGRAM, f))
elif f.lower()[-4:] in ('.mp3', '.wav', '.ogg'):
os.system('%s "%s"' % (MUSIC_PROGRAM, f))
def save_tag(self, f, tag):
md5 = self.get_md5(f)
cur = self.db_connection.cursor()
if tag[0] == "-":
# TODO: УДАЛИТЬ ТЕГ
del_query = """DELETE FROM FILES_TAGS
WHERE FILE_MD5 = '%s'
AND TAG = '%s'""" % (md5, tag[1:])
cur.execute(del_query)
self.db_connection.commit()
else:
# Сначала проверить что тега у файла ещё нет
check_query = """SELECT * FROM FILES_TAGS
WHERE FILE_MD5 = '%s'
AND TAG = '%s'""" % (md5, tag)
is_new = True
for row in cur.execute(check_query):
is_new = False
break
if is_new:
# Добавить файлу тег
query = """INSERT INTO FILES_TAGS
(FILE_MD5, TAG) VALUES ('%s', '%s')""" % (
md5, tag)
cur.execute(query)
self.db_connection.commit()
def show_main_menu(self):
while True:
print('\n' * 3 + '''
Программа для разбора бардака с файлами
1. Выбор папки
2. Анализ
3. Разбор
4. Сохранить списки
0. Выход
''')
selected = input("Что делать? > ")
if selected == "0":
self.close()
elif selected == "1":
self.show_select_path_menu()
elif selected == "2":
self.show_analyze_menu()
elif selected == "3":
self.show_manual_sort_menu()
elif selected == "4":
self.show_save_lists_menu()
def close(self):
self.db_connection.close()
print("Выход из программы")
quit()
def show_save_lists_menu(self):
print("Сохранение списков файлов")
self.save_lists()
def save_lists(self):
for key in self.files_by_tags.keys():
file_name = "%s.txt" % key
if key == "":
file_name = "_unsorted.txt"
if len(self.files_by_tags[key]) > 0:
f = open(file_name, 'w')
for item in self.files_by_tags[key]:
f.write(item)
f.write('\n')
f.close()
print(file_name)
def show_select_path_menu(self):
selected = input('Введите имя папки для разбора: ')
if self.is_valid_path(selected):
self.path = selected
print("Выбрана папка: '%s'" % selected)
else:
print("Ошибка: не удалось выбрать папку: '%s'" % selected)
def show_analyze_menu(self):
print("Анализ файлов в %s:" % self.path)
self.analyze()
def show_manual_sort_menu(self):
print("Ручной разбор файлов")
selected_tag = input("Выбери тег для разбора (по умолчанию без тегов): ")
self.manual_sort(selected_tag)
def is_valid_path(self, str_path):
if os.path.exists(str_path):
return True
else:
return False
def get_md5(self, file_path):
result = ''
f = open(file_path, 'rb')
content = f.read()
f.close()
result = hashlib.md5(content).hexdigest()
return result
def get_tags(self, md5):
result = []
cur = self.db_connection.cursor()
query = "SELECT TAG FROM FILES_TAGS WHERE FILE_MD5 = '%s'" % md5
for row in cur.execute(query):
result.append(row[0])
return result
if __name__ == "__main__":
fa = FilesAnalyzer()
fa.show_main_menu()