added other sources for more variety
This commit is contained in:
parent
b684c293b0
commit
08bdfe970c
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
|||||||
keys.py
|
keys.py
|
||||||
*.pyc
|
*.pyc
|
||||||
.image-cache/
|
.cache/
|
||||||
test.png
|
test.png
|
||||||
wifi_networks.yml
|
wifi_networks.yml
|
@ -4,9 +4,12 @@
|
|||||||
# become: true
|
# become: true
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
|
# mostly fixed
|
||||||
repo_dest: /home/remy/eink
|
repo_dest: /home/remy/eink
|
||||||
code_dest: /home/remy/eink/src
|
code_dest: /home/remy/eink/src
|
||||||
service_target_dir: /etc/systemd/system/
|
service_target_dir: /etc/systemd/system/
|
||||||
|
# adapt to taste
|
||||||
|
own_image_percent: 90
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: Pull the latest version of the code
|
- name: Pull the latest version of the code
|
||||||
|
@ -6,6 +6,7 @@ Type=oneshot
|
|||||||
User={{ ansible_user }}
|
User={{ ansible_user }}
|
||||||
WorkingDirectory={{ code_dest }}
|
WorkingDirectory={{ code_dest }}
|
||||||
ExecStart=python main.py
|
ExecStart=python main.py
|
||||||
|
Environment="OWN_IMAGE_PERCENT={{ own_image_percent }}"
|
||||||
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
from .immich import ImageGetImmich
|
||||||
|
from .unsplash import ImageGetUnsplash
|
||||||
|
from .museum import ImageGetMuseum
|
||||||
|
import random
|
||||||
|
import os
|
||||||
|
|
||||||
|
igetter = ImageGetImmich()
|
||||||
|
ugettter = ImageGetUnsplash()
|
||||||
|
mgetter = ImageGetMuseum()
|
||||||
|
|
||||||
|
class ImageGetCombined:
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
own_image_percent = int(os.getenv("OWN_IMAGE_PERCENT", 90))
|
||||||
|
other_image_percent = int(100 - own_image_percent)
|
||||||
|
self.getters = [igetter] * own_image_percent \
|
||||||
|
+ [ugettter] * int(other_image_percent/2) \
|
||||||
|
+ [mgetter] * int(other_image_percent/2)
|
||||||
|
# representing weighted probabilities
|
||||||
|
print(f"Using {len(self.getters)} image sources: ~{own_image_percent}% own, ~{other_image_percent}% foreign images.")
|
||||||
|
|
||||||
|
|
||||||
|
def get_random_image(self) -> bytearray:
|
||||||
|
getter = random.choice(self.getters)
|
||||||
|
return getter.get_random_image()
|
@ -17,8 +17,9 @@ class ImageGetImmich(ImageGet):
|
|||||||
headers=headers
|
headers=headers
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_random_image_ids(self, num=1) -> str:
|
def get_random_image_ids(self, num=1) -> str:
|
||||||
url = keys.immich_api_root_url + "album/" + keys.immich_album_id
|
url = self.base_url + "album/" + keys.immich_album_id
|
||||||
headers = self.headers | {"Accept": "application/json"}
|
headers = self.headers | {"Accept": "application/json"}
|
||||||
|
|
||||||
response = h.request("GET", url, headers=headers, data={})
|
response = h.request("GET", url, headers=headers, data={})
|
||||||
@ -41,7 +42,7 @@ class ImageGetImmich(ImageGet):
|
|||||||
|
|
||||||
|
|
||||||
def get_image_file(self, image_id: str) -> bytearray:
|
def get_image_file(self, image_id: str) -> bytearray:
|
||||||
url = keys.immich_api_root_url + "asset/download/" + image_id
|
url = self.base_url + "asset/download/" + image_id
|
||||||
|
|
||||||
headers = self.headers | {"Accept": "application/octet-stream"}
|
headers = self.headers | {"Accept": "application/octet-stream"}
|
||||||
response = h.request("POST", url, headers=headers, data={})
|
response = h.request("POST", url, headers=headers, data={})
|
||||||
@ -49,9 +50,3 @@ class ImageGetImmich(ImageGet):
|
|||||||
raise ImageGetException("Error in step get_image_file: " + str(response.status_code))
|
raise ImageGetException("Error in step get_image_file: " + str(response.status_code))
|
||||||
|
|
||||||
return response.content
|
return response.content
|
||||||
|
|
||||||
|
|
||||||
# def save_cached_files(self) -> None:
|
|
||||||
# in super
|
|
||||||
# return
|
|
||||||
|
|
||||||
|
66
src/get/museum.py
Normal file
66
src/get/museum.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import httpx as h
|
||||||
|
import random
|
||||||
|
import json
|
||||||
|
|
||||||
|
from .template import ImageGet, ImageGetException
|
||||||
|
|
||||||
|
class ImageGetMuseum(ImageGet):
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
headers = {
|
||||||
|
"AIC-User-Agent": "Eink Art Display (remoll@ethz.ch)"
|
||||||
|
}
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
base_url="https://api.artic.edu/api/v1/artworks/",
|
||||||
|
headers=headers
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_random_image_ids(self, num=1) -> list[str]:
|
||||||
|
post_data = {
|
||||||
|
"resources": "artworks",
|
||||||
|
"fields": ["id","image_id"],
|
||||||
|
"boost": False,
|
||||||
|
"limit": num,
|
||||||
|
"query": {
|
||||||
|
"function_score": {
|
||||||
|
"query": {
|
||||||
|
"bool": {
|
||||||
|
"filter": [
|
||||||
|
{"term": {"is_public_domain": True}},
|
||||||
|
{"exists": {"field": "image_id"}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"boost_mode": "replace",
|
||||||
|
"random_score": {
|
||||||
|
"field": "id",
|
||||||
|
"seed": f"{random.randint(1, 1000000)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = h.post(self.base_url + "search", json=post_data, headers=self.headers)
|
||||||
|
if not response.status_code == 200:
|
||||||
|
raise ImageGetException("Error in step get_image_file: " + str(response.status_code))
|
||||||
|
|
||||||
|
response = json.loads(response.text)
|
||||||
|
images = response["data"]
|
||||||
|
ids = [img["id"] for img in images]
|
||||||
|
return ids
|
||||||
|
|
||||||
|
|
||||||
|
def get_image_file(self, image_id: str) -> bytearray:
|
||||||
|
url = self.base_url + f"{image_id}"
|
||||||
|
print(url)
|
||||||
|
response = h.get(url, headers=self.headers)
|
||||||
|
if not response.status_code == 200:
|
||||||
|
raise ImageGetException("Error in step get_image_file: " + str(response.status_code))
|
||||||
|
|
||||||
|
response = json.loads(response.text)
|
||||||
|
image_url = response["config"]["iiif_url"] + "/" + response["data"]["image_id"] + "/full/843,/0/default.jpg"
|
||||||
|
image = h.get(image_url).content
|
||||||
|
return image
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
import keys
|
|
||||||
import httpx as h
|
|
||||||
import random
|
|
||||||
import json
|
|
||||||
|
|
||||||
from image_get import ImageGet, ImageGetException
|
|
||||||
|
|
||||||
class ImageGetImmich(ImageGet):
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
headers = {
|
|
||||||
"AIC-User-Agent": "Eink Art Display (remoll@ethz.ch)"
|
|
||||||
}
|
|
||||||
|
|
||||||
super().__init__(
|
|
||||||
base_url=keys.immich_api_root_url,
|
|
||||||
headers=self.headers
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_random_image_ids(self) -> list[str]:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def get_image_file(self, image_id: str) -> bytearray:
|
|
||||||
raise NotImplementedError
|
|
@ -13,16 +13,18 @@ class ImageGet:
|
|||||||
self.base_url = base_url
|
self.base_url = base_url
|
||||||
self.headers = headers
|
self.headers = headers
|
||||||
self.cache_num = cache_num
|
self.cache_num = cache_num
|
||||||
self.cache_dir = Path("../.cache/{self.__class__.__name__}/")
|
self.cache_dir = Path(f"../.cache/{self.__class__.__name__}/")
|
||||||
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
self.save_cached_files()
|
||||||
|
|
||||||
|
|
||||||
# Main entrypoint, called externally
|
# Main entrypoint, called externally
|
||||||
def get_random_image(self) -> bytearray:
|
def get_random_image(self) -> bytearray:
|
||||||
try:
|
try:
|
||||||
id = self.get_random_image_ids()[0]
|
id = self.get_random_image_ids()[0]
|
||||||
bytes = self.get_image_file(id)
|
bytes = self.get_image_file(id)
|
||||||
# self.save_cached_files()
|
self.save_cached_files()
|
||||||
except (h.ConnectError, h.HTTPStatusError, h.NetworkError, h.RequestError, h.DecodingError, h.TransportError, ImageGetException):
|
except (h.ConnectError, h.HTTPStatusError, h.NetworkError, h.RequestError, h.DecodingError, h.TransportError, ImageGetException):
|
||||||
print("Loading image from cache")
|
print("Loading image from cache")
|
||||||
bytes = self.load_cached_file()
|
bytes = self.load_cached_file()
|
||||||
@ -33,21 +35,21 @@ class ImageGet:
|
|||||||
def save_cached_files(self) -> None:
|
def save_cached_files(self) -> None:
|
||||||
"""Ensures self.cache_num files are at self.cache_dir at any time"""
|
"""Ensures self.cache_num files are at self.cache_dir at any time"""
|
||||||
|
|
||||||
present_count = len(list(self.cached_path.glob("*")))
|
present_count = len(list(self.cache_dir.glob("*")))
|
||||||
missing = self.cached_num - present_count
|
missing = self.cache_num - present_count
|
||||||
if missing == 0:
|
if missing == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
ids = self.get_random_image_ids(missing)
|
ids = self.get_random_image_ids(num = missing)
|
||||||
for i, id in enumerate(ids):
|
for i, id in enumerate(ids):
|
||||||
print(f"Caching image {i + 1}")
|
print(f"Caching image {i + 1}")
|
||||||
new_cache = self.cached_path / f"{uuid.uuid4()}"
|
new_cache = self.cache_dir / f"{uuid.uuid4()}"
|
||||||
new_cache.write_bytes(self.get_image_file(id))
|
new_cache.write_bytes(self.get_image_file(id))
|
||||||
|
|
||||||
|
|
||||||
def load_cached_file(self) -> bytearray:
|
def load_cached_file(self) -> bytearray:
|
||||||
"""Returns a random file from self.cached_path"""
|
"""Returns a random file from self.cache_dir"""
|
||||||
files = list(self.cached_path.glob("*"))
|
files = list(self.cache_dir.glob("*"))
|
||||||
|
|
||||||
if len(files) == 0:
|
if len(files) == 0:
|
||||||
raise ImageGetException("Could not load cached file: directory empty")
|
raise ImageGetException("Could not load cached file: directory empty")
|
||||||
@ -59,7 +61,7 @@ class ImageGet:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_random_image_ids(self) -> list[str]:
|
def get_random_image_ids(self, num=1) -> list[str]:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
27
src/get/unsplash.py
Normal file
27
src/get/unsplash.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import httpx as h
|
||||||
|
|
||||||
|
from .template import ImageGet, ImageGetException
|
||||||
|
|
||||||
|
class ImageGetUnsplash(ImageGet):
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
base_url="https://source.unsplash.com/",
|
||||||
|
headers={}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_random_image_ids(self, num=1) -> list[str]:
|
||||||
|
# there are no ids since the api has a random endpoint
|
||||||
|
return [0 for i in range(num)]
|
||||||
|
|
||||||
|
|
||||||
|
def get_image_file(self, image_id: str = "doesntmatter") -> bytearray:
|
||||||
|
url = self.base_url + "random"
|
||||||
|
response = h.get(url, follow_redirects=True)
|
||||||
|
|
||||||
|
if not response.status_code == 200:
|
||||||
|
raise ImageGetException("Error in step get_image_file: " + str(response.status_code))
|
||||||
|
|
||||||
|
return response.content
|
@ -1,6 +1,6 @@
|
|||||||
import sys
|
import sys
|
||||||
from image_convert import ImageShrink
|
from image_convert import ImageShrink
|
||||||
from get import immich
|
from get.combined import ImageGetCombined
|
||||||
from image_show import ImageShow
|
from image_show import ImageShow
|
||||||
|
|
||||||
if len(sys.argv) == 2 and sys.argv[1] == "test":
|
if len(sys.argv) == 2 and sys.argv[1] == "test":
|
||||||
@ -18,7 +18,7 @@ if "noreduce" in sys.argv:
|
|||||||
print("Disabling color reduction")
|
print("Disabling color reduction")
|
||||||
shrink_kwargs["colors"] = -1
|
shrink_kwargs["colors"] = -1
|
||||||
|
|
||||||
getter = immich.ImageGetImmich()
|
getter = ImageGetCombined()
|
||||||
converter = ImageShrink(**shrink_kwargs)
|
converter = ImageShrink(**shrink_kwargs)
|
||||||
shower = ImageShow()
|
shower = ImageShow()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user