Как разложить фото, видео по папкам, исходя из их дат, используя python



Всем знакомы завалы из фото и видео, кои покоятся годами после копирования с устройств.

Особенно это характерно для iphone,ipad, которые при прямом копировании (без itunes) создают
залежи медиаконтента. Как это все разложить по годам-месяцам?

Да, есть синхронизация, да, можно сразу все сортировать. Но…

Кто-то предпочитает ничего не трогать, так как соблюдается единство свалки, кто-то делает робкие попытки разложить все накопленное хотя бы по годам.

Бесспорно, через проводник, используя табличный вид, вручную не составит труда все это это раскидать, но начинаешь смотреть старые фото, и процесс затягивается.

Поэтому напишем простую программу, которая разложит файлы в папке по годам с месяцами в них:





Программа сама будет определять дату, «заглядывая» в дату изменения файла:



Почему используем дату изменения, а не дату создания файла?
Как правило, она более корректно указывает на дату файла, чем ее тезка.

Импорт модулей на старте:
import os,time
import datetime
import shutil

Предложим пользователю скопировать путь (windows) к папке с файлами:

p=input('Скопируйте сюда путь к фото. Например: E:/\1')
os.chdir(p)

Введем функцию создания папок с месяцами от 01 до 12 (да простят мне отсутствие f' строк):

#создаем папки месяцев от 01 до 12
def d():
    for x in range (1,13):
        if x>9:
            if not os.path.exists(str(x)):
                os.makedirs(str(x))
        else:
            if not os.path.exists('0'+str(x)):
                os.makedirs('0'+str(x))

Следующая функция обработает дату, полученную с фото/видео файла:

def mod_date(file):
    t = os.path.getmtime(file)
    return datetime.datetime.fromtimestamp(t)

Теперь, пройдясь по папке, программа соберет все расширения файлов, а заодно,
определит какой год у файла. Для каждого года будет создана своя папка, а в ней,
в свою очередь, будут созданы папки с месяцами:

a=[] #['AAE', 'MOV', 'JPG', 'PNG']
for root, dirs, files in os.walk(p):    
    for file in files:
        if file[-3:] not in a:
            a.append(file[-3:])
        if file[-3:] in a:
            year=str(mod_date(file))[:10][:4]            
            if not os.path.exists(year):
                os.makedirs(year)
            os.chdir(p+'/'+year)            
            d()
            os.chdir(p)

*Таким образом можно раскидать по папкам файлы с совершенно разными (любыми) расширениями, а не только jpeg,mov,mkv.

Еще раз пройдемся по папке со свалкой фото, теперь уже перенося фото в соответствующие, вновь созданные папки:

try:
    for root, dirs, files in os.walk(p):    
        for file in files:
                if file[-3:] in a:
                    year=str(mod_date(file))[:10][:4]                    
                    month=str(mod_date(file))[:10][5:7] #месяц создания фото
                    shutil.move(file, year+'/'+month+'/'+file) #перенос файла в папку
except EnvironmentError:
    ('Вроде готово')

Так как программа завершается с ошибкой, в цикле не найдя последнего файла, что не влияет на ее корректное выполнение, используется костыль из try,except, который притупляет бдительность впечатлительных особ, получающих красноту в консоль.

P.S.: Пост не претендует на научность, но, возможно, кому-то поможет победить свалки фото/видео.

Программа — скачать.
@zoldaten
01.10.2020 11:41 UTC
Первоисточник

Комментарии

@VtaliyVasilyevich
01.10.2020 07:36 UTC
0
Отличная практика для начинающих.
@Vitamus
01.10.2020 08:16 UTC
0
Как практикум по языку — хорошо. Но подобная задача прекрасно решается групповым переименованием в Total Commander.
@Stravnik
01.10.2020 08:18 UTC
0
Благодарю.
Попробую сегодня на многолетнем архиве фотографий.
@shukan
01.10.2020 12:02 UTC
0
Всё отлично, только дату лучше брать из Exif.Image.DateTime

from PIL import Image
def get_date_taken(path):
    return Image.open(path)._getexif()[36867]
@Arc_SSA
01.10.2020 12:14 UTC
0
Интересная штука. Еще бы по не системным свойствам научиться раскладывать
@Stravnik
01.10.2020 12:28 UTC
0
Если Вы про раскладывание по тому что изображено на снимках, то Вам в сторону TensorFlow надо смотреть.
@gorodnev
01.10.2020 15:13 UTC
+1
мне кажется, что на нормальном шелле (bash/zsh и прочие) такое делается в пару строк
@
01.10.2020 17:45 UTC
0
НЛО прилетело и опубликовало эту надпись здесь
@zoldaten
02.10.2020 06:40 UTC
0
С небольшими изменениями должно поехать и на Linux.
@Shtucer
01.10.2020 18:23 UTC
+1

Ужас.
'/' заменить на os.path.sep
а ещё лучше прочитать про os.path.join()

@Tihon_V
01.10.2020 20:15 UTC
+1

А еще лучше — использовать pathlib.

@GCU
01.10.2020 18:33 UTC
+2

Расширение файла это не всегда последние три символа, есть специальная функция для этого — os.path.splitext. Зачем нужно два прохода и пустые папки по месяцам — не ясно.

@Tihon_V
01.10.2020 20:16 UTC
0

Стоит опубликовать исходники на GitHub :)

@salaev
02.10.2020 05:45 UTC
0
тут прямо есть что улучшать в коде…
из того что еще не упомянули заметил отсутствие lower() или upper() для расширения файла (сравнивать все желательно в одном регистре)
ну и os.chdir(p) — прям не нужно использовать, здесь проще сформировать путь куда сохранять и делать shutil.move
вместо функции d для папок месяцев правильнее формировать путь сохранения с использованием '{0:02d}'.format(x) где x — месяц от 1 до 12

Просто для такой задачи вся элегантность и простота питона не видна, все можно сделать сильно проще и короче

@zoldaten
02.10.2020 06:43 UTC
0
Благодарю. Код не идеален бесспорно. Всего лишь лопатка для разгребания )
05.10.2020 12:23 UTC
0
так разгребать красиво можно
for i in range(1, 13):
    ... if os.path.exists(f'{i:02}') else os.makedirs(f'{i:02}')
@bugdesigner
02.10.2020 06:48 UTC
0

Можно пойти дальше и использовать EXIF метаданные для определения даты снимка. Время модификации файлов иногда не соответствуют времени снимка.

@AlexVPetrov
05.10.2020 12:22 UTC
0
#!/bin/sh

for i in 'tv-shots0' 'tv-shots1' 'tv-shots2' 'tv-shots3'
do
echo $i

cd /tank/CAMERAS/$i

find. -name "*.png" -print |
ls -lUrD %Y-%m-%d_%H:%M:%S $line |
while read line
do
echo $line
namefile=`echo "$line" | awk '{ print $7 }'`
myvar=`echo "$line" | awk '{ print $6 }'`
yearfile=`echo | awk '{ print substr("'"${myvar}"'",1,4)}'`
mounthfile=`echo | awk '{ print substr("'"${myvar}"'",6,2)}'`
dayfile=`echo | awk '{ print substr("'"${myvar}"'",9,2)}'`
echo namefile $namefile
echo yearfile $yearfile
echo mounthfile $mounthfile
echo dayfile $dayfile
if [! -f /tank/CAMERAS/$i.arch/$yearfile/$mounthfile/$dayfile ]; then
mkdir -p /tank/CAMERAS/$i.arch/$yearfile/$mounthfile/$dayfile
fi
mv $namefile /tank/CAMERAS/$i.arch/$yearfile/$mounthfile/$dayfile/
done

done