Updated Icon generation and Settings

This commit is contained in:
itdominator 2021-04-24 16:43:45 -05:00
parent 511d05a8a7
commit e864cce741
17 changed files with 143 additions and 132 deletions

View File

@ -1,7 +1,6 @@
# Python Imports
import os, subprocess, hashlib, threading
from os.path import isdir, isfile, join
import os, subprocess, threading, hashlib
from os.path import isfile, join
# Gtk imports
import gi
@ -24,118 +23,111 @@ def threaded(fn):
return wrapper
class Icon:
def __init__(self):
self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__)) + "/"
self.INTERNAL_ICON_PTH = self.SCRIPT_PTH + "./utils/icons/text.png"
def create_icon(self, dir, file):
full_path = dir + "/" + file
return self.get_icon_image(file, full_path)
def createIcon(self, dir, file):
fullPath = dir + "/" + file
return self.getIconImage(file, fullPath)
def createThumbnail(self, dir, file):
fullPath = dir + "/" + file
def create_thumbnail(self, dir, file):
full_path = dir + "/" + file
try:
fileHash = hashlib.sha256(str.encode(fullPath)).hexdigest()
hashImgPth = self.get_home() + "/.thumbnails/normal/" + fileHash + ".png"
file_hash = hashlib.sha256(str.encode(full_path)).hexdigest()
hash_img_pth = ABS_THUMBS_PTH + "/" + file_hash + ".jpg"
if isfile(hash_img_pth) == False:
self.generate_video_thumbnail(full_path, hash_img_pth)
thumbnl = self.createScaledImage(hashImgPth, self.viIconWH)
thumbnl = self.create_scaled_image(hash_img_pth, self.VIDEO_ICON_WH)
if thumbnl == None: # If no icon whatsoever, return internal default
thumbnl = Gtk.Image.new_from_file(self.SCRIPT_PTH + "./utils/icons/video.png")
thumbnl = Gtk.Image.new_from_file(self.DEFAULT_ICONS + "/video.png")
return thumbnl
except Exception as e:
print("Thumbnail generation issue:")
print( repr(e) )
return Gtk.Image.new_from_file(self.SCRIPT_PTH + "./utils/icons/video.png")
return Gtk.Image.new_from_file(self.DEFAULT_ICONS + "/video.png")
def getIconImage(self, file, fullPath):
def get_icon_image(self, file, full_path):
try:
thumbnl = None
# Video icon
if file.lower().endswith(self.fvideos):
thumbnl = Gtk.Image.new_from_file(self.SCRIPT_PTH + "./utils/icons/video.png")
thumbnl = Gtk.Image.new_from_file(self.DEFAULT_ICONS + "/video.png")
# Image Icon
elif file.lower().endswith(self.fimages):
thumbnl = self.createScaledImage(fullPath, self.viIconWH)
thumbnl = self.create_scaled_image(full_path, self.VIDEO_ICON_WH)
# .desktop file parsing
elif fullPath.lower().endswith( ('.desktop',) ):
thumbnl = self.parseDesktopFiles(fullPath)
elif full_path.lower().endswith( ('.desktop',) ):
thumbnl = self.parse_desktop_files(full_path)
# System icons
else:
thumbnl = self.getSystemThumbnail(fullPath, self.systemIconImageWH[0])
thumbnl = self.get_system_thumbnail(full_path, self.SYS_ICON_WH[0])
if thumbnl == None: # If no icon whatsoever, return internal default
thumbnl = Gtk.Image.new_from_file(self.INTERNAL_ICON_PTH)
thumbnl = Gtk.Image.new_from_file(self.DEFAULT_ICON)
return thumbnl
except Exception as e:
print("Icon generation issue:")
print( repr(e) )
return Gtk.Image.new_from_file(self.INTERNAL_ICON_PTH)
return Gtk.Image.new_from_file(self.DEFAULT_ICON)
def parseDesktopFiles(self, fullPath):
def parse_desktop_files(self, full_path):
try:
xdgObj = DesktopEntry(fullPath)
xdgObj = DesktopEntry(full_path)
icon = xdgObj.getIcon()
altIconPath = ""
alt_icon_path = ""
if "steam" in icon:
steamIconsDir = self.get_home() + "/.thumbnails/steam_icons/"
name = xdgObj.getName()
fileHash = hashlib.sha256(str.encode(name)).hexdigest()
name = xdgObj.getName()
file_hash = hashlib.sha256(str.encode(name)).hexdigest()
hash_img_pth = self.STEAM_ICONS_PTH + "/" + file_hash + ".jpg"
if isdir(steamIconsDir) == False:
os.mkdir(steamIconsDir)
hashImgPth = steamIconsDir + fileHash + ".jpg"
if isfile(hashImgPth) == True:
if isfile(hash_img_pth) == True:
# Use video sizes since headers are bigger
return self.createScaledImage(hashImgPth, self.viIconWH)
return self.create_scaled_image(hash_img_pth, self.VIDEO_ICON_WH)
execStr = xdgObj.getExec()
parts = execStr.split("steam://rungameid/")
exec_str = xdgObj.getExec()
parts = exec_str.split("steam://rungameid/")
id = parts[len(parts) - 1]
imageLink = "https://steamcdn-a.akamaihd.net/steam/apps/" + id + "/header.jpg"
proc = subprocess.Popen(["wget", "-O", hashImgPth, imageLink])
imageLink = self.STEAM_BASE_URL + id + "/header.jpg"
proc = subprocess.Popen(["wget", "-O", hash_img_pth, imageLink])
proc.wait()
# Use video thumbnail sizes since headers are bigger
return self.createScaledImage(hashImgPth, self.viIconWH)
return self.create_scaled_image(hash_img_pth, self.VIDEO_ICON_WH)
elif os.path.exists(icon):
return self.createScaledImage(icon, self.systemIconImageWH)
return self.create_scaled_image(icon, self.SYS_ICON_WH)
else:
iconsDirs = ["/usr/share/pixmaps", "/usr/share/icons", self.get_home() + "/.icons" ,]
altIconPath = ""
alt_icon_path = ""
for iconsDir in iconsDirs:
altIconPath = self.traverseIconsFolder(iconsDir, icon)
if altIconPath is not "":
for dir in self.ICON_DIRS:
alt_icon_path = self.traverse_icons_folder(dir, icon)
if alt_icon_path is not "":
break
return self.createScaledImage(altIconPath, self.systemIconImageWH)
return self.create_scaled_image(alt_icon_path, self.SYS_ICON_WH)
except Exception as e:
print(self.DEFAULT_ICON)
print(".desktop icon generation issue:")
print( repr(e) )
return None
def traverseIconsFolder(self, path, icon):
altIconPath = ""
def traverse_icons_folder(self, path, icon):
alt_icon_path = ""
for (dirpath, dirnames, filenames) in os.walk(path):
for file in filenames:
appNM = "application-x-" + icon
if icon in file or appNM in file:
altIconPath = dirpath + "/" + file
alt_icon_path = dirpath + "/" + file
break
return altIconPath
return alt_icon_path
def getSystemThumbnail(self, filename, size):
def get_system_thumbnail(self, filename, size):
try:
if os.path.exists(filename):
gioFile = Gio.File.new_for_path(filename)
@ -156,17 +148,63 @@ class Icon:
return None
def createScaledImage(self, path, wxh):
def generate_video_thumbnail(self, full_path, hash_img_pth):
try:
pixbuf = Gtk.Image.new_from_file(path).get_pixbuf()
scaledPixBuf = pixbuf.scale_simple(wxh[0], wxh[1], 2) # 2 = BILINEAR and is best by default
return Gtk.Image.new_from_pixbuf(scaledPixBuf)
proc = subprocess.Popen([self.FFMPG_THUMBNLR, "-t", "65%", "-s", "300", "-c", "jpg", "-i", full_path, "-o", hash_img_pth])
proc.wait()
except Exception as e:
self.logger.debug(repr(e))
self.ffprobe_generate_video_thumbnail(full_path, hash_img_pth)
def ffprobe_generate_video_thumbnail(self, full_path, hash_img_pth):
proc = None
try:
# Stream duration
command = ["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries", "stream=duration", "-of", "default=noprint_wrappers=1:nokey=1", full_path]
data = subprocess.run(command, stdout=subprocess.PIPE)
duration = data.stdout.decode('utf-8')
# Format (container) duration
if "N/A" in duration:
command = ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", full_path]
data = subprocess.run(command , stdout=subprocess.PIPE)
duration = data.stdout.decode('utf-8')
# Stream duration type: image2
if "N/A" in duration:
command = ["ffprobe", "-v", "error", "-select_streams", "v:0", "-f", "image2", "-show_entries", "stream=duration", "-of", "default=noprint_wrappers=1:nokey=1", full_path]
data = subprocess.run(command, stdout=subprocess.PIPE)
duration = data.stdout.decode('utf-8')
# Format (container) duration type: image2
if "N/A" in duration:
command = ["ffprobe", "-v", "error", "-f", "image2", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", full_path]
data = subprocess.run(command , stdout=subprocess.PIPE)
duration = data.stdout.decode('utf-8')
# Get frame roughly 35% through video
grabTime = str( int( float( duration.split(".")[0] ) * 0.35) )
command = ["ffmpeg", "-ss", grabTime, "-an", "-i", full_path, "-s", "320x180", "-vframes", "1", hash_img_pth]
proc = subprocess.Popen(command, stdout=subprocess.PIPE)
proc.wait()
except Exception as e:
print("Video thumbnail generation issue in thread:")
print( repr(e) )
self.logger.debug(repr(e))
def create_scaled_image(self, path, wxh):
try:
pixbuf = Gtk.Image.new_from_file(path).get_pixbuf()
scaled_pixbuf = pixbuf.scale_simple(wxh[0], wxh[1], 2) # 2 = BILINEAR and is best by default
return Gtk.Image.new_from_pixbuf(scaled_pixbuf)
except Exception as e:
print("Image Scaling Issue:")
print( repr(e) )
return None
def createFromFile(self, path):
def create_from_file(self, path):
try:
return Gtk.Image.new_from_file(path)
except Exception as e:
@ -174,5 +212,5 @@ class Icon:
print( repr(e) )
return None
def returnGenericIcon(self):
return Gtk.Image.new_from_file(self.INTERNAL_ICON_PTH)
def return_generic_icon(self):
return Gtk.Image.new_from_file(self.DEFAULT_ICON)

View File

@ -17,6 +17,7 @@ from . import Path, Icon
class View(Settings, Launcher, Icon, Path):
def __init__(self):
self.id = ""
self. logger = None
self.files = []
self.dirs = []
self.vids = []
@ -157,16 +158,7 @@ class View(Settings, Launcher, Icon, Path):
return self.hashSet(self.dirs)
def get_videos(self):
videos_set = self.hashSet(self.vids)
current_directory = self.get_current_directory()
for video in videos_set:
hashImgPth = join(self.ABS_THUMBS_PTH, video[1]) + ".jpg"
if not os.path.exists(hashImgPth) :
fullPath = join(current_directory, video[0])
self.logger.debug(f"Hash Path: {hashImgPth}\nFile Path: {fullPath}")
self.generate_video_thumbnail(fullPath, hashImgPth)
return videos_set
return self.hashSet(self.vids)
def get_images(self):
return self.hashSet(self.images)

View File

@ -9,7 +9,7 @@ import os, subprocess, threading
class Launcher:
def openFilelocally(self, file):
def open_file_locally(self, file):
lowerName = file.lower()
command = []
@ -38,7 +38,7 @@ class Launcher:
subprocess.Popen(command, start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True)
def remuxVideo(self, hash, file):
def remux_video(self, hash, file):
remux_vid_pth = self.REMUX_FOLDER + "/" + hash + ".mp4"
self.logger.debug(remux_vid_pth)
@ -66,53 +66,6 @@ class Launcher:
return True
def generate_video_thumbnail(self, fullPath, hashImgPth):
try:
proc = subprocess.Popen([self.FFMPG_THUMBNLR, "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPath, "-o", hashImgPth])
proc.wait()
except Exception as e:
self.logger.debug(repr(e))
self.ffprobe_generate_video_thumbnail(fullPath, hashImgPth)
def generate_video_thumbnail(self, fullPath, hashImgPth):
proc = None
try:
# Stream duration
command = ["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries", "stream=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath]
data = subprocess.run(command, stdout=subprocess.PIPE)
duration = data.stdout.decode('utf-8')
# Format (container) duration
if "N/A" in duration:
command = ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath]
data = subprocess.run(command , stdout=subprocess.PIPE)
duration = data.stdout.decode('utf-8')
# Stream duration type: image2
if "N/A" in duration:
command = ["ffprobe", "-v", "error", "-select_streams", "v:0", "-f", "image2", "-show_entries", "stream=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath]
data = subprocess.run(command, stdout=subprocess.PIPE)
duration = data.stdout.decode('utf-8')
# Format (container) duration type: image2
if "N/A" in duration:
command = ["ffprobe", "-v", "error", "-f", "image2", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath]
data = subprocess.run(command , stdout=subprocess.PIPE)
duration = data.stdout.decode('utf-8')
# Get frame roughly 35% through video
grabTime = str( int( float( duration.split(".")[0] ) * 0.35) )
command = ["ffmpeg", "-ss", grabTime, "-an", "-i", fullPath, "-s", "320x180", "-vframes", "1", hashImgPth]
proc = subprocess.Popen(command, stdout=subprocess.PIPE)
proc.wait()
except Exception as e:
print("Video thumbnail generation issue in thread:")
print( repr(e) )
self.logger.debug(repr(e))
def check_remux_space(self):
limit = self.remux_folder_max_disk_usage
try:
@ -121,7 +74,7 @@ class Launcher:
self.logger.debug(e)
return
usage = self.getRemuxFolderUsage(self.REMUX_FOLDER)
usage = self.get_remux_folder_usage(self.REMUX_FOLDER)
if usage > limit:
files = os.listdir(self.REMUX_FOLDER)
for file in files:
@ -129,7 +82,7 @@ class Launcher:
os.unlink(fp)
def getRemuxFolderUsage(self, start_path = "."):
def get_remux_folder_usage(self, start_path = "."):
total_size = 0
for dirpath, dirnames, filenames in os.walk(start_path):
for f in filenames:

View File

@ -1,7 +1,7 @@
# System import
import os
from os import path
# Lib imports
@ -11,19 +11,33 @@ from os import path
class Settings:
logger = None
GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1)
lock_folder = False
go_past_home = True
GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1)
ABS_THUMBS_PTH = None # Used for thumbnail generation and is set by passing in
REMUX_FOLDER = None # Used for Remuxed files and is set by passing in
FFMPG_THUMBNLR = None # Used for thumbnail generator binary and is set by passing in
HIDE_HIDDEN_FILES = True
lock_folder = False
go_past_home = True
iconContainerWH = [128, 128]
systemIconImageWH = [56, 56]
viIconWH = [256, 128]
USER_HOME = path.expanduser('~')
CONFIG_PATH = USER_HOME + "/.config/pyfm"
DEFAULT_ICONS = CONFIG_PATH + "/icons"
DEFAULT_ICON = DEFAULT_ICONS + "/text.png"
FFMPG_THUMBNLR = CONFIG_PATH + "/ffmpegthumbnailer" # Thumbnail generator binary
REMUX_FOLDER = USER_HOME + "/.remuxs" # Remuxed files folder
subpath = "" # modify 'home' folder path
STEAM_BASE_URL = "https://steamcdn-a.akamaihd.net/steam/apps/"
ICON_DIRS = ["/usr/share/pixmaps", "/usr/share/icons", USER_HOME + "/.icons" ,]
BASE_THUMBS_PTH = USER_HOME + "/.thumbnails" # Used for thumbnail generation
ABS_THUMBS_PTH = BASE_THUMBS_PTH + "/normal" # Used for thumbnail generation
STEAM_ICONS_PTH = BASE_THUMBS_PTH + "/steam_icons"
CONTAINER_ICON_WH = [128, 128]
VIDEO_ICON_WH = [256, 128]
SYS_ICON_WH = [56, 56]
subpath = "/LazyShare/Movies-TV-Music/TV/Anime/Barakamon" # modify 'home' folder path
# subpath = "/Desktop" # modify 'home' folder path
locked_folders = "venv::::flasks".split("::::")
mplayer_options = "-quiet -really-quiet -xy 1600 -geometry 50%:50%".split()
music_app = "/opt/deadbeef/bin/deadbeef"
@ -35,10 +49,24 @@ class Settings:
file_manager_app = "spacefm"
remux_folder_max_disk_usage = "8589934592"
# Filters
fvideos = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm')
foffice = ('.doc', '.docx', '.xls', '.xlsx', '.xlt', '.xltx', '.xlm', '.ppt', 'pptx', '.pps', '.ppsx', '.odt', '.rtf')
fimages = ('.png', '.jpg', '.jpeg', '.gif', '.ico', '.tga')
ftext = ('.txt', '.text', '.sh', '.cfg', '.conf')
fmusic = ('.psf', '.mp3', '.ogg', '.flac', '.m4a')
fpdf = ('.pdf')
# Dire structure check
if path.isdir(REMUX_FOLDER) == False:
os.mkdir(REMUX_FOLDER)
if path.isdir(BASE_THUMBS_PTH) == False:
os.mkdir(BASE_THUMBS_PTH)
if path.isdir(ABS_THUMBS_PTH) == False:
os.mkdir(ABS_THUMBS_PTH)
if path.isdir(STEAM_ICONS_PTH) == False:
os.mkdir(STEAM_ICONS_PTH)

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 858 B

After

Width:  |  Height:  |  Size: 858 B

View File

Before

Width:  |  Height:  |  Size: 850 B

After

Width:  |  Height:  |  Size: 850 B

View File

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 702 B

View File

Before

Width:  |  Height:  |  Size: 925 B

After

Width:  |  Height:  |  Size: 925 B

View File

Before

Width:  |  Height:  |  Size: 882 B

After

Width:  |  Height:  |  Size: 882 B

View File

Before

Width:  |  Height:  |  Size: 707 B

After

Width:  |  Height:  |  Size: 707 B

View File

Before

Width:  |  Height:  |  Size: 798 B

After

Width:  |  Height:  |  Size: 798 B

View File

Before

Width:  |  Height:  |  Size: 989 B

After

Width:  |  Height:  |  Size: 989 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB