get the viewer working
- ID
3b652f6- date
2023-05-13 08:58:55+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
2779ea2- message
get the viewer working- changed files
4 files, 189 additions, 17 deletions
Changed files
get_structural_metadata.swift (3944) → get_structural_metadata.swift (3963)
diff --git a/get_structural_metadata.swift b/get_structural_metadata.swift
index 57ac5de..cd52d19 100644
--- a/get_structural_metadata.swift
+++ b/get_structural_metadata.swift
@@ -30,7 +30,7 @@ PHAssetCollection
struct AssetData: Codable {
var localIdentifier: String
- var creationDate: Date?
+ var creationDate: String?
}
var allAssets: [AssetData] = []
@@ -41,7 +41,7 @@ PHAsset
allAssets.append(
AssetData(
localIdentifier: asset.localIdentifier,
- creationDate: asset.creationDate
+ creationDate: asset.creationDate?.ISO8601Format()
)
)
})
server.py (1715) → server.py (2691)
diff --git a/server.py b/server.py
index d79b08d..b4137da 100755
--- a/server.py
+++ b/server.py
@@ -11,11 +11,41 @@ app = Flask(__name__)
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 24 * 60 * 60
+class PhotosData:
+ def __init__(self):
+ data = json.loads(subprocess.check_output(['swift', 'get_structural_metadata.swift']))
+
+ all_assets = sorted(data['assets'], key=lambda a: a['creationDate'])
+
+ all_albums = data['albums']
+
+ for alb in all_albums:
+ alb['assetIdentifiers'] = set(alb['assetIdentifiers'])
+
+ for asset in all_assets:
+ asset['albums'] = [alb['localizedTitle'] for alb in all_albums if asset['localIdentifier'] in alb['assetIdentifiers']]
+
+ if 'Flagged' in asset['albums']:
+ asset['state'] = 'Flagged'
+ asset['albums'].remove('Flagged')
+ elif 'Rejected' in asset['albums']:
+ asset['state'] = 'Rejected'
+ asset['albums'].remove('Rejected')
+ else:
+ asset['state'] = 'Unknown'
+
+ assert 'Flagged' not in asset['albums']
+ assert 'Rejected' not in asset['albums']
+
+ self.all_assets = all_assets
+
+
+photos_data = PhotosData()
+
+
@app.route("/")
def index():
- data = json.load(open('out.json'))
-
- all_assets = sorted(data['assets'], key=lambda a: a['creationDate'])
+ all_assets = photos_data.all_assets
try:
local_identifier = request.args['localIdentifier']
@@ -33,7 +63,8 @@ def index():
@functools.cache
def get_thumbnail_path(local_identifier):
- return subprocess.check_output(['swift', 'get_asset_jpeg.swift', local_identifier, '65']).decode('utf8')
+ # 85 * 2x
+ return subprocess.check_output(['swift', 'get_asset_jpeg.swift', local_identifier, '170']).decode('utf8')
@app.route('/thumbnail')
templates/index.html (861) → templates/index.html (6732)
diff --git a/templates/index.html b/templates/index.html
index dd28497..049eff0 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -1,32 +1,161 @@
<style>
- .thumbnail {
+ body {
+ text-align: center;
+ padding: 0;
+ margin: 10px;
+ font-family: -apple-system;
+/* background: black;*/
+ }
+
+ a {
+ text-decoration: none;
+ }
+
+ #thumbnails {
+ margin-bottom: 1em;
+ height: 85px;
+ }
+
+ #thumbnails div.thumbnail {
+ display: inline-block;
+ border: 1px solid lightgrey;
+ margin: 1px;
+ width: 65px;
+ height: 65px;
+ padding: 1px;
+ }
+
+ #thumbnails div.thumbnail img {
+ width: 65px;
+ height: 65px;
+ }
+
+ #thumbnails div.thumbnail .state {
+ position: absolute;
+ width: 15px;
+ height: 17px;
+ color: white;
+ text-align: left;
+ padding-left: 3px;
+ padding-top: 1px;
+ font-size: 13px;
+ line-height: 16px;
+ border-bottom-right-radius: 18px;
+ margin-left: -3px;
+ margin-top: -3px;
+ font-family: serif;
+ }
+
+ #thumbnails div.this_asset div.thumbnail .state {
+ width: 19px;
+ height: 21px;
+ color: white;
+ text-align: left;
+ padding-left: 4px;
+ padding-top: 2px;
+ font-size: 17px;
+ line-height: 16px;
+ border-bottom-right-radius: 18px;
+ margin-left: -3px;
+ margin-top: -3px;
+ font-family: serif;
+ }
+
+ #thumbnails div.thumbnail.state-Flagged {
+ border-color: green;
+ border-width: 2px;
+ margin: 0;
+ }
+
+ #thumbnails div.thumbnail.state-Flagged .state {
+ background: green;
+ }
+
+ #thumbnails div.thumbnail.state-Rejected {
+ border-color: red;
+ border-width: 2px;
+ margin: 0;
+ }
+
+ #thumbnails div.thumbnail.state-Rejected .state {
+ background: red;
+ }
+
+ #thumbnails div.this_asset {
+ display: inline-block;
+ }
+
+ #thumbnails div.this_asset div.thumbnail {
+ width: 85px;
+ height: 85px;
+ }
+
+ #thumbnails div.this_asset div.thumbnail img {
+ width: 85px;
+ height: 85px;
+ }
+
+ #thumbnails img {
object-fit: cover;
aspect-ratio: 1 / 1;
- border: 2px solid red;
}
- .thumbnail_small {
+ #thumbnails .placeholder {
width: 65px;
height: 65px;
+ display: inline-block;
+ border: 2px solid lightgrey;
+ opacity: 0.5;
}
.thumbnail_big {
width: 85px;
height: 85px;
}
+
+ img#big {
+ max-width: calc(100vw - 20px);
+ /* screen height - 85px (thumbnail bar) - 20px (body padding) -1em (margin below thumbnail bar) - 18px (metadata) - 1em (margin below metadata)*/
+ max-height: calc(100vh - 85px - 20px - 1em - 18px - 1em);
+ }
</style>
-{% for a in prev_five %}
- <img src="{{ url_for('thumbnail', localIdentifier=a['localIdentifier']) }}" class="thumbnail thumbnail_small">
-{% endfor %}
+<div id="thumbnails">
+ {% set placeholder_prev_five = 5 - prev_five|length %}
+ {% for _ in range(placeholder_prev_five) %}
+ <!-- from subtle patterns -->
+ <img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIAFwAXAMBIgACEQEDEQH/xAAXAAEBAQEAAAAAAAAAAAAAAAAAAQcC/8QAMxAAAQMDAwIEBAUEAwAAAAAAAQARIQIxQSIyURJhQnGBoVJicrEDEzPR8EORssEjc4L/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A2gdt3s6fTu9u7J5RXbqw6Z0sKjnB5QB8m727sn/XfvYjsgnZFXODyyfQ1JPOQgfQ3/rjsn0QM9XCfQwzOQn0aRcvkIH0wPF1cJ5W8XVdT6dNImoHhXygDcKpKBjinxdV0/x8T3dMcUjcDdPVqRuBu6B/jkZdP+T+kwGXu6Y+XIy6NWf06mHDoA48VurlL7TqMdXPKdvFbq5KSYpLEx1csgX2lqjnnnyS+zSbvyg1FqS1R8Qyybtp6SZflAd9mnPmEvsPRkvkJfbpz5oC+09Lai2QgPD06QJIMwnlpA3C6CZp0gSQJdB20imSAgY+GkXpu6ewEGnkpYPtFN6eUHNgINIQMcU26e6dNdX6dXSBDJ38Ig0906Kq5oqNIEMEBn0vJjqym4mmxt1ZjlRnej0fPr2V3E02w+Y5QBqPSIJzn1TfAek3cX9U3aZHcX9U3xIzH+0DdbTmMoNVtLSWTfyM6f5dN2CGnT/LoAmRpaSKZdBIcQKS5FNigmbdMtTlBMzplqbFAx1WFNwLFPmsKYIFig+L4cU2KC3V8MMLFAZg+Bp6cJ+Wa5pq6QIZMdXENhPy/wAyerpaGFvRAZ9HZu6M+hm75jlIOg7bd/NLvQYFvJA3vTI+481N8GMxf1V36TAHskV6TA7Y7IG+CGzCDXgxOn7eafqbhaY54TffExE8IA1T8M6cpfU234bFN0mTTIaH7ID1ajJBhodAuOr4bNYoMVZpgNYpfXc02aAU+e5Fmse6Bjra0dvNOgfiajU2B3T58iBw3KdAr1VVdP8AtA+Q7fsOXSDpqinztwkbTs9m5dL6aop+3CBu01RSPb903OK4H9m7JfTXFP24ZN0V2HoyBvivHox4TfulrYnhN29vWJ4Tdv8AR4nhA3TVJFsOeE3ajJG3DpumoORZ4nhLzVJG14coF2qvUNuHS7VXqFsOOWS83qG18oPivVg8hA+fxY8uWTpor1fiFj90+bxY5byRqDP4hY/dAix2ezful4qGj27Ml6hSdpqIZSnUQCIJIbhkFvFcU/xmS8fiW729EGogVTSXjhlKdRAqkEEscILf9THMSl9/MdXP7KUnq3AHT1ThAX3S1PUHwUFvumoberlL7pq8PVdR4JMmkOCUJiomTTIJQXgmavD1XKDnx4e7IYFRuaWYnuhjqNzSQATdA7+PHLfuh/L/AKparzn1T7irpfLLqiimsE1ByCzoP//Z" class="placeholder">
+ {% endfor %}
+
+ {% for asset in prev_five %}
+ {% include "thumbnail.html" %}
+ {% endfor %}
+
+
+ <div class="this_asset">
+ {% set asset = this_asset %}
+ {% include "thumbnail.html" %}
+ </div>
+
+ {% for asset in next_five %}
+ {% include "thumbnail.html" %}
+ {% endfor %}
-<img src="{{ url_for('thumbnail', localIdentifier=this_asset['localIdentifier']) }}" class="thumbnail thumbnail_big">
+ {% set placeholder_next_five = 5 - next_five|length %}
+ {% for _ in range(placeholder_next_five) %}
+ <img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIAFwAXAMBIgACEQEDEQH/xAAXAAEBAQEAAAAAAAAAAAAAAAAAAQcC/8QAMxAAAQMDAwIEBAUEAwAAAAAAAQARIQIxQSIyURJhQnGBoVJicrEDEzPR8EORssEjc4L/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A2gdt3s6fTu9u7J5RXbqw6Z0sKjnB5QB8m727sn/XfvYjsgnZFXODyyfQ1JPOQgfQ3/rjsn0QM9XCfQwzOQn0aRcvkIH0wPF1cJ5W8XVdT6dNImoHhXygDcKpKBjinxdV0/x8T3dMcUjcDdPVqRuBu6B/jkZdP+T+kwGXu6Y+XIy6NWf06mHDoA48VurlL7TqMdXPKdvFbq5KSYpLEx1csgX2lqjnnnyS+zSbvyg1FqS1R8Qyybtp6SZflAd9mnPmEvsPRkvkJfbpz5oC+09Lai2QgPD06QJIMwnlpA3C6CZp0gSQJdB20imSAgY+GkXpu6ewEGnkpYPtFN6eUHNgINIQMcU26e6dNdX6dXSBDJ38Ig0906Kq5oqNIEMEBn0vJjqym4mmxt1ZjlRnej0fPr2V3E02w+Y5QBqPSIJzn1TfAek3cX9U3aZHcX9U3xIzH+0DdbTmMoNVtLSWTfyM6f5dN2CGnT/LoAmRpaSKZdBIcQKS5FNigmbdMtTlBMzplqbFAx1WFNwLFPmsKYIFig+L4cU2KC3V8MMLFAZg+Bp6cJ+Wa5pq6QIZMdXENhPy/wAyerpaGFvRAZ9HZu6M+hm75jlIOg7bd/NLvQYFvJA3vTI+481N8GMxf1V36TAHskV6TA7Y7IG+CGzCDXgxOn7eafqbhaY54TffExE8IA1T8M6cpfU234bFN0mTTIaH7ID1ajJBhodAuOr4bNYoMVZpgNYpfXc02aAU+e5Fmse6Bjra0dvNOgfiajU2B3T58iBw3KdAr1VVdP8AtA+Q7fsOXSDpqinztwkbTs9m5dL6aop+3CBu01RSPb903OK4H9m7JfTXFP24ZN0V2HoyBvivHox4TfulrYnhN29vWJ4Tdv8AR4nhA3TVJFsOeE3ajJG3DpumoORZ4nhLzVJG14coF2qvUNuHS7VXqFsOOWS83qG18oPivVg8hA+fxY8uWTpor1fiFj90+bxY5byRqDP4hY/dAix2ezful4qGj27Ml6hSdpqIZSnUQCIJIbhkFvFcU/xmS8fiW729EGogVTSXjhlKdRAqkEEscILf9THMSl9/MdXP7KUnq3AHT1ThAX3S1PUHwUFvumoberlL7pq8PVdR4JMmkOCUJiomTTIJQXgmavD1XKDnx4e7IYFRuaWYnuhjqNzSQATdA7+PHLfuh/L/AKparzn1T7irpfLLqiimsE1ByCzoP//Z" class="placeholder">
+ {% endfor %}
+</div>
-{% for a in next_five %}
- <img src="{{ url_for('thumbnail', localIdentifier=a['localIdentifier']) }}" class="thumbnail thumbnail_small">
-{% endfor %}
+<p class="metadata">
+ {% if this_asset['albums'] %}
+ <strong>albums:</strong> {{ this_asset['albums'] | join(', ') }} /
+ {% endif %}
+ <strong>state:</strong> {{ this_asset['state'] }} /
+ <strong>creation date:</strong> {{ this_asset['creationDate'] }}
+</p>
-<img src="{{ url_for('image', localIdentifier=this_asset['localIdentifier']) }}">
+<img id="big" src="{{ url_for('image', localIdentifier=this_asset['localIdentifier']) }}">
<!--{% for a in assets %}
templates/thumbnail.html (0) → templates/thumbnail.html (455)
diff --git a/templates/thumbnail.html b/templates/thumbnail.html
new file mode 100644
index 0000000..143e700
--- /dev/null
+++ b/templates/thumbnail.html
@@ -0,0 +1,12 @@
+<a href="{{ url_for('index', localIdentifier=asset['localIdentifier'])}}">
+ <div class="thumbnail state-{{ asset['state'] }}">
+ {% if asset['state'] == 'Flagged' %}
+ <div class="state">✓</div>
+ {% elif asset['state'] == 'Rejected' %}
+ <div class="state">✘</div>
+ {% endif %}
+ <img
+ src="{{ url_for('thumbnail', localIdentifier=asset['localIdentifier']) }}"
+ class="thumbnail state-{{ asset['state'] }}">
+ </div>
+</a>