reddit-image-wall-getter/reddit_imgs/system/downloader/downloadedData.py

148 lines
4.8 KiB
Python

#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import json
import os
import shutil
import tkinter
from concurrent.futures import ThreadPoolExecutor
from io import BytesIO
from pathlib import Path
import filetype
from PIL import Image, ImageTk
class DownloadedData(object):
def __init__(self, loadfrom=None):
self.initialize()
self.loadfrom(loadfrom)
def initialize(self):
self.control = list()
self.fb = dict()
def loadfrom(self, loadfrom):
if loadfrom:
with open(os.path.join(loadfrom, 'meta.json')) as f:
self.control = json.loads(f.read())
for ctrl in self.control:
fnm = ctrl['dname']
cnt = b''
with open(os.path.join(loadfrom, fnm), 'rb') as f:
cnt = f.read()
self.fb[fnm] = cnt
def storedLinks(self):
return [ctrl['link'] for ctrl in self.control]
def put(self, link, downloaded, ext=None):
global rootWindow
if ext is None:
try:
ext = link.rsplit('/', 1)[-1].rsplit('.', 1)[-1]
if ext not in ['jpg', 'png', 'gif', 'webp']:
raise Exception
except:
ext = filetype.guess_extension(downloaded)
if ext is None:
ext = 'unk'
fnm = '%04d.%s' % (len(self.control), ext)
self.control.append({
'dname': fnm,
'link': link,
'ext': ext,
})
self.fb[fnm] = downloaded
if userWantsPreview and rootWindow is None:
rootWindow = MainApp()
if rootWindow is not None and downloaded is not None:
try:
rootWindow.update_image(Image.open(BytesIO(downloaded)), link)
except:
pass
if (pth := Path('latest_put_image.file')).exists():
pth.unlink()
Path('latest_put_image.url').write_text(link)
Path('latest_put_image.file').write_bytes(downloaded)
def remove(self, directory):
directory = os.path.abspath(directory)
if os.path.exists(directory):
shutil.rmtree(directory)
def into(self, directory):
self.remove(directory)
directory = os.path.abspath(directory)
os.makedirs(directory)
try:
with open(os.path.join(directory, 'meta.json'), 'w') as f:
f.write(json.dumps(self.control, sort_keys=True, indent=2))
for seq, (fnm, dtb) in enumerate(self.fb.items()):
with open(os.path.join(directory, fnm), 'wb') as f:
f.write(dtb)
print(' '*50, end='', flush=True)
print('\r', end='', flush=True)
print(f' `--> Saving image {seq+1} of {len(self.fb)}', end='', flush=True)
print('\r', end='', flush=True)
except KeyboardInterrupt as e:
shutil.rmtree(directory)
raise e
def merge(self, other):
for oitem in other.control:
self.put(oitem['link'], other.fb[oitem['dname']], oitem['ext'])
def bulk_merge(self, others):
for other in others:
self.merge(other)
class MainApp(tkinter.Tk):
def __init__(self):
super().__init__()
self.geometry('500x500')
self.known_width = 500
self.known_height = 500
self.resizable(width=True, height=True)
self.photo = Image.new('RGB', (256,256), (0,0,0))
self.display_photo = self.photo.copy()
self.image = ImageTk.PhotoImage(self.display_photo)
self.frame = tkinter.Frame(self)
self.frame.pack(fill=tkinter.BOTH, expand=tkinter.YES)
self.panel = tkinter.Label(self.frame)
self.panel.pack(fill=tkinter.BOTH, expand=tkinter.YES)
self.panel.bind('<Configure>', self._resize_image)
self.panel.configure(image=self.image)
self.update()
self._resize_image2()
self.update()
def _resize_image(self, event):
self.known_width = event.width
self.known_height = event.height
self._resize_image2()
def _resize_image2(self):
size_tuple = (self.known_width, self.known_height)
self.display_photo = self.photo.copy()
self.display_photo.thumbnail(size_tuple)
if self.display_photo is None:
self.display_photo = self.photo
self.image = ImageTk.PhotoImage(self.display_photo)
self.panel.configure(image=self.image)
def update_image(self, image, windowTile=None):
if windowTile is not None:
self.winfo_toplevel().title(str(windowTile))
self.photo = image
self._resize_image2()
self.update()
userWantsPreview = False
rootWindow = None
if 'REDDITGETTER_PREVIEW' in os.environ and os.environ['REDDITGETTER_PREVIEW'] != '':
userWantsPreview = True