media-optimization-engine 1.4.0__tar.gz → 1.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. {media_optimization_engine-1.4.0/media_optimization_engine.egg-info → media_optimization_engine-1.4.1}/PKG-INFO +23 -1
  2. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/README.md +22 -0
  3. media_optimization_engine-1.4.1/media_engine/adapters/flutter/README.md +63 -0
  4. media_optimization_engine-1.4.1/media_engine/adapters/flutter/standard_images.dart +106 -0
  5. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1/media_optimization_engine.egg-info}/PKG-INFO +23 -1
  6. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_optimization_engine.egg-info/SOURCES.txt +1 -0
  7. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/pyproject.toml +1 -1
  8. media_optimization_engine-1.4.0/media_engine/adapters/flutter/README.md +0 -10
  9. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/LICENSE +0 -0
  10. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/__init__.py +0 -0
  11. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/adapters/__init__.py +0 -0
  12. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/adapters/flutter/__init__.py +0 -0
  13. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/adapters/flutter/models.dart +0 -0
  14. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/adapters/marzipano/__init__.py +0 -0
  15. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/adapters/marzipano/manifest.py +0 -0
  16. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/adapters/pannellum/__init__.py +0 -0
  17. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/adapters/pannellum/manifest.py +0 -0
  18. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/adapters/threejs/__init__.py +0 -0
  19. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/adapters/threejs/manifest.py +0 -0
  20. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/admin.py +0 -0
  21. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/apps.py +0 -0
  22. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/auth.py +0 -0
  23. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/autoregister.py +0 -0
  24. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/control_plane.py +0 -0
  25. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/doctor.py +0 -0
  26. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/focal_detectors.py +0 -0
  27. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/health.py +0 -0
  28. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/image_ops.py +0 -0
  29. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/integration.py +0 -0
  30. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/locks.py +0 -0
  31. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/__init__.py +0 -0
  32. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/__init__.py +0 -0
  33. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/audit_media_engine.py +0 -0
  34. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/audit_panorama_media.py +0 -0
  35. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/backfill_panorama_media.py +0 -0
  36. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/backfill_registered_media.py +0 -0
  37. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/backfill_responsive_images.py +0 -0
  38. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/cleanup_image_derivatives.py +0 -0
  39. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/media_engine_doctor.py +0 -0
  40. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/media_engine_node_report.py +0 -0
  41. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/rollback_media_engine_config.py +0 -0
  42. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/management/commands/sync_media_engine_hub.py +0 -0
  43. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/manifest.py +0 -0
  44. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/metrics.py +0 -0
  45. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/migrations/0001_initial.py +0 -0
  46. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/migrations/0002_panorama_multires.py +0 -0
  47. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/migrations/0003_panorama_cube_tiles.py +0 -0
  48. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/migrations/__init__.py +0 -0
  49. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/models.py +0 -0
  50. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/node.py +0 -0
  51. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/__init__.py +0 -0
  52. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/base.py +0 -0
  53. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/image/__init__.py +0 -0
  54. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/image/standard.py +0 -0
  55. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/panorama/__init__.py +0 -0
  56. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/panorama/cube_tiles.py +0 -0
  57. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/panorama/cubemap.py +0 -0
  58. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/panorama/detect.py +0 -0
  59. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/panorama/equirectangular.py +0 -0
  60. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/panorama/manifest.py +0 -0
  61. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/panorama/tiles.py +0 -0
  62. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/processors/registry.py +0 -0
  63. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/profiles.py +0 -0
  64. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/queueing.py +0 -0
  65. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/registry.py +0 -0
  66. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/runtime_config.py +0 -0
  67. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/serializers.py +0 -0
  68. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/services.py +0 -0
  69. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/signals.py +0 -0
  70. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/spec/openapi.yaml +0 -0
  71. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/static/media_engine/adaptive-media.js +0 -0
  72. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/static/media_engine/media-cache-sw.js +0 -0
  73. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/storage_paths.py +0 -0
  74. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/system_views.py +0 -0
  75. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/tasks.py +0 -0
  76. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/templatetags/__init__.py +0 -0
  77. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/templatetags/responsive_media.py +0 -0
  78. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/tests/__init__.py +0 -0
  79. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/tests/test_distributed_node.py +0 -0
  80. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/tests/test_image_ops.py +0 -0
  81. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/tests/test_panorama.py +0 -0
  82. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/tests/test_paths.py +0 -0
  83. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/tests/test_profiles.py +0 -0
  84. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/tests/test_responsive_media.py +0 -0
  85. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/urls.py +0 -0
  86. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/validators.py +0 -0
  87. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_engine/views.py +0 -0
  88. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_optimization_engine.egg-info/dependency_links.txt +0 -0
  89. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_optimization_engine.egg-info/entry_points.txt +0 -0
  90. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_optimization_engine.egg-info/requires.txt +0 -0
  91. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/media_optimization_engine.egg-info/top_level.txt +0 -0
  92. {media_optimization_engine-1.4.0 → media_optimization_engine-1.4.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: media-optimization-engine
3
- Version: 1.4.0
3
+ Version: 1.4.1
4
4
  Summary: Media Optimization Engineer for Django/Python: automatic model-field optimization, responsive picture/srcset rendering, AVIF/WebP derivatives, 360 media, autonomous nodes, and CDN-ready storage.
5
5
  Author-email: Achille Kabasele <pepexykabasele@gmail.com>
6
6
  Maintainer-email: Achille Kabasele <pepexykabasele@gmail.com>
@@ -233,6 +233,28 @@ JavaScript is not required for normal responsive images.
233
233
 
234
234
  Runtime measurement is appropriate only for highly dynamic components whose rendered width cannot be described reliably with sizes, such as resizable editors, canvas-like builders, or asynchronously mounted panels.
235
235
 
236
+ ## Flutter / native clients
237
+
238
+ MOE also ships reference Dart adapters for native applications.
239
+
240
+ Standard Flutter clients should fetch the image manifest, measure the rendered widget width, multiply it by device pixel ratio, and select the first derivative at or above that physical width.
241
+
242
+ ~~~dart
243
+ final variant = manifest.select(
244
+ logicalWidth: constraints.maxWidth,
245
+ devicePixelRatio: MediaQuery.devicePixelRatioOf(context),
246
+ preferredFormat: 'webp',
247
+ );
248
+ ~~~
249
+
250
+ Reference adapters are packaged under:
251
+
252
+ ~~~text
253
+ media_engine/adapters/flutter/
254
+ ~~~
255
+
256
+ This keeps optimization and derivative generation on the Django/Python backend while allowing Flutter to select and cache the most appropriate immutable URL. Panorama manifests use the same principle at tile/level granularity.
257
+
236
258
  ## Backfill
237
259
 
238
260
  Historical media can be ingested with maintenance commands:
@@ -177,6 +177,28 @@ JavaScript is not required for normal responsive images.
177
177
 
178
178
  Runtime measurement is appropriate only for highly dynamic components whose rendered width cannot be described reliably with sizes, such as resizable editors, canvas-like builders, or asynchronously mounted panels.
179
179
 
180
+ ## Flutter / native clients
181
+
182
+ MOE also ships reference Dart adapters for native applications.
183
+
184
+ Standard Flutter clients should fetch the image manifest, measure the rendered widget width, multiply it by device pixel ratio, and select the first derivative at or above that physical width.
185
+
186
+ ~~~dart
187
+ final variant = manifest.select(
188
+ logicalWidth: constraints.maxWidth,
189
+ devicePixelRatio: MediaQuery.devicePixelRatioOf(context),
190
+ preferredFormat: 'webp',
191
+ );
192
+ ~~~
193
+
194
+ Reference adapters are packaged under:
195
+
196
+ ~~~text
197
+ media_engine/adapters/flutter/
198
+ ~~~
199
+
200
+ This keeps optimization and derivative generation on the Django/Python backend while allowing Flutter to select and cache the most appropriate immutable URL. Panorama manifests use the same principle at tile/level granularity.
201
+
180
202
  ## Backfill
181
203
 
182
204
  Historical media can be ingested with maintenance commands:
@@ -0,0 +1,63 @@
1
+ # Flutter adapter
2
+
3
+ Media Optimization Engineer can be consumed by Flutter through the same immutable manifest API used by other native clients.
4
+
5
+ The Python package ships Dart reference models under this directory. They are framework-neutral examples that consuming Flutter applications can copy or wrap in their own networking/cache layer.
6
+
7
+ ## Standard images
8
+
9
+ \`standard_images.dart\` parses a standard MOE manifest and selects a derivative from:
10
+
11
+ ~~~text
12
+ target physical width = rendered logical width × devicePixelRatio
13
+ ~~~
14
+
15
+ Recommended policy:
16
+
17
+ 1. fetch the asset manifest once;
18
+ 2. cache the manifest in memory;
19
+ 3. measure the actual widget width with \`LayoutBuilder\`;
20
+ 4. multiply by \`MediaQuery.devicePixelRatioOf(context)\`;
21
+ 5. select the first WebP derivative at or above that physical width;
22
+ 6. if none is large enough, use the largest available derivative;
23
+ 7. cache the selected immutable URL with the application's normal image cache;
24
+ 8. fall back to the manifest fallback/original URL if needed.
25
+
26
+ Example:
27
+
28
+ ~~~dart
29
+ final targetLogicalWidth = constraints.maxWidth;
30
+ final dpr = MediaQuery.devicePixelRatioOf(context);
31
+
32
+ final variant = manifest.select(
33
+ logicalWidth: targetLogicalWidth,
34
+ devicePixelRatio: dpr,
35
+ preferredFormat: 'webp',
36
+ );
37
+ ~~~
38
+
39
+ WebP is a conservative default for broad Android/iOS compatibility. Applications may prefer AVIF on platforms where their Flutter image stack reliably supports it.
40
+
41
+ ## Panorama 360
42
+
43
+ \`models.dart\` parses the generic panorama manifest.
44
+
45
+ Recommended panorama policy:
46
+
47
+ - show \`preview\` immediately;
48
+ - select a level from viewport width × DPR;
49
+ - request only tiles intersecting the current field of view;
50
+ - keep adjacent tiles warm for smooth panning;
51
+ - use AVIF where supported, otherwise WebP.
52
+
53
+ ## API
54
+
55
+ A standard image manifest is available from the REST viewset:
56
+
57
+ ~~~text
58
+ GET /api/v1/images/<asset-id>/manifest/?profile=<profile>
59
+ ~~~
60
+
61
+ When MOE is mounted under another prefix in a Django project, keep the same route relative to that prefix.
62
+
63
+ The native client should never upload or process an image merely to render it. Processing stays server-side; Flutter only chooses among READY immutable derivatives.
@@ -0,0 +1,106 @@
1
+ class MediaVariant {
2
+ final int width;
3
+ final int height;
4
+ final String url;
5
+ final int bytes;
6
+ final int quality;
7
+
8
+ const MediaVariant({
9
+ required this.width,
10
+ required this.height,
11
+ required this.url,
12
+ this.bytes = 0,
13
+ this.quality = 0,
14
+ });
15
+
16
+ factory MediaVariant.fromJson(Map<String, dynamic> json) => MediaVariant(
17
+ width: (json['width'] as num?)?.toInt() ?? 0,
18
+ height: (json['height'] as num?)?.toInt() ?? 0,
19
+ url: (json['url'] ?? '').toString(),
20
+ bytes: (json['bytes'] as num?)?.toInt() ?? 0,
21
+ quality: (json['quality'] as num?)?.toInt() ?? 0,
22
+ );
23
+ }
24
+
25
+ class MediaManifest {
26
+ final String id;
27
+ final String status;
28
+ final int width;
29
+ final int height;
30
+ final String profile;
31
+ final String dominantColor;
32
+ final String blurhash;
33
+ final String placeholderDataUrl;
34
+ final String originalUrl;
35
+ final MediaVariant? fallback;
36
+ final Map<String, List<MediaVariant>> variants;
37
+
38
+ const MediaManifest({
39
+ required this.id,
40
+ required this.status,
41
+ required this.width,
42
+ required this.height,
43
+ required this.profile,
44
+ required this.variants,
45
+ this.dominantColor = '',
46
+ this.blurhash = '',
47
+ this.placeholderDataUrl = '',
48
+ this.originalUrl = '',
49
+ this.fallback,
50
+ });
51
+
52
+ factory MediaManifest.fromJson(Map<String, dynamic> json) {
53
+ final rawVariants =
54
+ Map<String, dynamic>.from(json['variants'] as Map? ?? const {});
55
+ final parsed = <String, List<MediaVariant>>{};
56
+ for (final entry in rawVariants.entries) {
57
+ final items = (entry.value as List? ?? const [])
58
+ .whereType<Map>()
59
+ .map((item) => MediaVariant.fromJson(
60
+ Map<String, dynamic>.from(item),
61
+ ))
62
+ .toList()
63
+ ..sort((a, b) => a.width.compareTo(b.width));
64
+ parsed[entry.key] = items;
65
+ }
66
+
67
+ return MediaManifest(
68
+ id: (json['id'] ?? '').toString(),
69
+ status: (json['status'] ?? '').toString(),
70
+ width: (json['width'] as num?)?.toInt() ?? 0,
71
+ height: (json['height'] as num?)?.toInt() ?? 0,
72
+ profile: (json['profile'] ?? '').toString(),
73
+ dominantColor: (json['dominant_color'] ?? '').toString(),
74
+ blurhash: (json['blurhash'] ?? '').toString(),
75
+ placeholderDataUrl: (json['placeholder_data_url'] ?? '').toString(),
76
+ originalUrl: (json['original_url'] ?? '').toString(),
77
+ fallback: json['fallback'] is Map
78
+ ? MediaVariant.fromJson(
79
+ Map<String, dynamic>.from(json['fallback'] as Map),
80
+ )
81
+ : null,
82
+ variants: parsed,
83
+ );
84
+ }
85
+
86
+ MediaVariant? select({
87
+ required double logicalWidth,
88
+ required double devicePixelRatio,
89
+ String preferredFormat = 'webp',
90
+ }) {
91
+ final target = (logicalWidth * devicePixelRatio).ceil().clamp(1, 10000);
92
+ final order = <String>[preferredFormat, 'webp', 'avif'];
93
+
94
+ for (final format in order.toSet()) {
95
+ final candidates = variants[format];
96
+ if (candidates == null || candidates.isEmpty) continue;
97
+
98
+ for (final candidate in candidates) {
99
+ if (candidate.width >= target) return candidate;
100
+ }
101
+ return candidates.last;
102
+ }
103
+
104
+ return fallback;
105
+ }
106
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: media-optimization-engine
3
- Version: 1.4.0
3
+ Version: 1.4.1
4
4
  Summary: Media Optimization Engineer for Django/Python: automatic model-field optimization, responsive picture/srcset rendering, AVIF/WebP derivatives, 360 media, autonomous nodes, and CDN-ready storage.
5
5
  Author-email: Achille Kabasele <pepexykabasele@gmail.com>
6
6
  Maintainer-email: Achille Kabasele <pepexykabasele@gmail.com>
@@ -233,6 +233,28 @@ JavaScript is not required for normal responsive images.
233
233
 
234
234
  Runtime measurement is appropriate only for highly dynamic components whose rendered width cannot be described reliably with sizes, such as resizable editors, canvas-like builders, or asynchronously mounted panels.
235
235
 
236
+ ## Flutter / native clients
237
+
238
+ MOE also ships reference Dart adapters for native applications.
239
+
240
+ Standard Flutter clients should fetch the image manifest, measure the rendered widget width, multiply it by device pixel ratio, and select the first derivative at or above that physical width.
241
+
242
+ ~~~dart
243
+ final variant = manifest.select(
244
+ logicalWidth: constraints.maxWidth,
245
+ devicePixelRatio: MediaQuery.devicePixelRatioOf(context),
246
+ preferredFormat: 'webp',
247
+ );
248
+ ~~~
249
+
250
+ Reference adapters are packaged under:
251
+
252
+ ~~~text
253
+ media_engine/adapters/flutter/
254
+ ~~~
255
+
256
+ This keeps optimization and derivative generation on the Django/Python backend while allowing Flutter to select and cache the most appropriate immutable URL. Panorama manifests use the same principle at tile/level granularity.
257
+
236
258
  ## Backfill
237
259
 
238
260
  Historical media can be ingested with maintenance commands:
@@ -34,6 +34,7 @@ media_engine/adapters/__init__.py
34
34
  media_engine/adapters/flutter/README.md
35
35
  media_engine/adapters/flutter/__init__.py
36
36
  media_engine/adapters/flutter/models.dart
37
+ media_engine/adapters/flutter/standard_images.dart
37
38
  media_engine/adapters/marzipano/__init__.py
38
39
  media_engine/adapters/marzipano/manifest.py
39
40
  media_engine/adapters/pannellum/__init__.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "media-optimization-engine"
7
- version = "1.4.0"
7
+ version = "1.4.1"
8
8
  description = "Media Optimization Engineer for Django/Python: automatic model-field optimization, responsive picture/srcset rendering, AVIF/WebP derivatives, 360 media, autonomous nodes, and CDN-ready storage."
9
9
  requires-python = ">=3.11"
10
10
  authors = [{ name = "Achille Kabasele", email = "pepexykabasele@gmail.com" }]
@@ -1,10 +0,0 @@
1
- # Flutter panorama adapter
2
-
3
- `models.dart` parses the generic MOE panorama manifest. A Flutter viewer can select the lowest level that satisfies current viewport width and devicePixelRatio, then request only visible tiles.
4
-
5
- Recommended policy:
6
- - show `preview` immediately;
7
- - select a level from viewport width x DPR;
8
- - request only tiles intersecting the current field of view;
9
- - keep adjacent tiles warm for smooth panning;
10
- - use AVIF where the Flutter image stack supports it, otherwise WebP.