SalexAI commited on
Commit
75a3f76
·
verified ·
1 Parent(s): 4a51820

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -251
app.py CHANGED
@@ -1,251 +1,39 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8">
5
- <title>CCP - Central Content Pool</title>
6
- <style>
7
- body {
8
- background-color: #ffcc00;
9
- font-family: "Comic Sans MS", cursive, sans-serif;
10
- margin: 0;
11
- padding: 0;
12
- text-align: center;
13
- }
14
- header {
15
- background-color: #003399;
16
- color: white;
17
- padding: 15px;
18
- font-size: 2em;
19
- border-bottom: 4px double #fff;
20
- }
21
- .logo {
22
- font-size: 50px;
23
- font-weight: bold;
24
- color: #ff0000;
25
- text-shadow: 3px 3px 0 #000;
26
- margin-top: 20px;
27
- }
28
- .subtext {
29
- font-size: 24px;
30
- color: black;
31
- margin-top: -10px;
32
- }
33
- .fineprint {
34
- font-size: 12px;
35
- color: gray;
36
- margin-top: -5px;
37
- font-style: italic;
38
- }
39
- .container {
40
- margin: 20px auto;
41
- width: 90%;
42
- max-width: 1200px;
43
- }
44
- .search-container {
45
- margin: 20px auto;
46
- width: 100%;
47
- display: flex;
48
- justify-content: center;
49
- }
50
- #search-input {
51
- width: 80%;
52
- padding: 10px;
53
- font-size: 18px;
54
- border: 3px solid #000;
55
- outline: none;
56
- background: #ffffff;
57
- transition: 0.3s ease-in-out;
58
- }
59
- #search-input:focus {
60
- background: #ffff99;
61
- }
62
- .videos {
63
- display: flex;
64
- flex-wrap: wrap;
65
- gap: 15px;
66
- justify-content: center;
67
- }
68
- .video-card {
69
- background-color: #fff;
70
- border: 3px solid black;
71
- padding: 10px;
72
- width: 320px;
73
- cursor: pointer;
74
- transition: transform 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
75
- animation: fadeIn 0.5s ease-in;
76
- }
77
- .video-card:hover {
78
- transform: scale(1.05);
79
- box-shadow: 5px 5px 0 #000;
80
- }
81
- .video-card img {
82
- width: 100%;
83
- height: auto;
84
- aspect-ratio: 16/9;
85
- object-fit: cover;
86
- border: 4px solid black;
87
- image-rendering: pixelated;
88
- }
89
- .video-card h2 {
90
- margin: 10px 0 0 0;
91
- font-size: 20px;
92
- color: #003399;
93
- }
94
- .modal-overlay {
95
- position: fixed;
96
- top: 0;
97
- left: 0;
98
- right: 0;
99
- bottom: 0;
100
- background: rgba(0,0,0,0.5);
101
- display: none;
102
- align-items: center;
103
- justify-content: center;
104
- animation: fadeIn 0.5s;
105
- }
106
- .modal-window {
107
- background-color: #c0c0c0;
108
- border: 2px solid #000;
109
- width: 80%;
110
- max-width: 800px;
111
- box-shadow: 5px 5px 0 #000;
112
- animation: slideDown 0.5s ease-out;
113
- }
114
- .modal-header {
115
- background: #000080;
116
- color: white;
117
- padding: 5px;
118
- display: flex;
119
- justify-content: space-between;
120
- align-items: center;
121
- }
122
- .modal-header button {
123
- background: #c0c0c0;
124
- border: 2px outset #fff;
125
- cursor: pointer;
126
- margin-left: 5px;
127
- }
128
- .modal-content {
129
- padding: 10px;
130
- background: #fff;
131
- }
132
- .modal-content video {
133
- width: 100%;
134
- height: auto;
135
- max-height: 80vh;
136
- object-fit: contain;
137
- display: block;
138
- }
139
- @keyframes fadeIn {
140
- from { opacity: 0; }
141
- to { opacity: 1; }
142
- }
143
- @keyframes slideDown {
144
- from { transform: translateY(-20px); opacity: 0; }
145
- to { transform: translateY(0); opacity: 1; }
146
- }
147
- </style>
148
- </head>
149
- <body>
150
- <header>Welcome to CCP</header>
151
- <div class="logo">CCP</div>
152
- <div class="subtext">(Central Content Pool)</div>
153
- <div class="fineprint">(not the China guys, they copied us...)</div>
154
-
155
- <div class="container">
156
- <div class="search-container">
157
- <input type="text" id="search-input" placeholder="Search for videos...">
158
- </div>
159
-
160
- <div class="videos" id="video-list"></div>
161
- </div>
162
-
163
- <div class="modal-overlay" id="modal-overlay">
164
- <div class="modal-window">
165
- <div class="modal-header">
166
- <span id="modal-title">Video Player</span>
167
- <div>
168
- <button id="fullscreen-btn">Full Screen</button>
169
- <button id="close-btn">Close</button>
170
- </div>
171
- </div>
172
- <div class="modal-content">
173
- <video id="modal-video" controls>
174
- <source id="video-source" src="" type="video/mp4">
175
- Your browser does not support the video tag.
176
- </video>
177
- </div>
178
- </div>
179
- </div>
180
-
181
- <script>
182
- let allVideos = [];
183
- const videoList = document.getElementById('video-list');
184
- const searchInput = document.getElementById('search-input');
185
-
186
- async function fetchVideos() {
187
- try {
188
- const response = await fetch('https://salexai-funserver.hf.space/album/B0p532ODWH4KDMb');
189
- const data = await response.json();
190
- allVideos = data.videos;
191
- renderVideos(allVideos);
192
- } catch (error) {
193
- console.error('Failed to fetch videos:', error);
194
- }
195
- }
196
-
197
- async function renderVideos(videoArray) {
198
- videoList.innerHTML = '';
199
- for (const vid of videoArray) {
200
- const title = vid.caption && vid.caption.trim() ? vid.caption.trim() : 'Unnamed Video';
201
- const thumb = vid.poster && vid.poster.trim() ? vid.poster : 'https://via.placeholder.com/320x180.png?text=No+Preview';
202
-
203
- const card = document.createElement('div');
204
- card.className = 'video-card';
205
- card.innerHTML = `
206
- <img src="${thumb}" alt="Thumbnail">
207
- <h2>${title}</h2>
208
- `;
209
- card.addEventListener('click', () => openModal(title, vid.url));
210
- videoList.appendChild(card);
211
- }
212
- }
213
-
214
- searchInput.addEventListener('input', (e) => {
215
- const searchVal = e.target.value.toLowerCase();
216
- const filtered = allVideos.filter(v => {
217
- const cap = v.caption && v.caption.trim() ? v.caption.trim().toLowerCase() : 'unnamed video';
218
- return cap.includes(searchVal);
219
- });
220
- renderVideos(filtered);
221
- });
222
-
223
- function openModal(title, url) {
224
- document.getElementById('modal-title').textContent = title;
225
- document.getElementById('video-source').src = url;
226
- const modalVideo = document.getElementById('modal-video');
227
- modalVideo.load();
228
- document.getElementById('modal-overlay').style.display = 'flex';
229
- }
230
-
231
- document.getElementById('close-btn').addEventListener('click', () => {
232
- const modalVideo = document.getElementById('modal-video');
233
- modalVideo.pause();
234
- document.getElementById('modal-overlay').style.display = 'none';
235
- });
236
-
237
- document.getElementById('fullscreen-btn').addEventListener('click', () => {
238
- const modalVideo = document.getElementById('modal-video');
239
- if (modalVideo.requestFullscreen) {
240
- modalVideo.requestFullscreen();
241
- } else if (modalVideo.webkitRequestFullscreen) {
242
- modalVideo.webkitRequestFullscreen();
243
- } else if (modalVideo.msRequestFullscreen) {
244
- modalVideo.msRequestFullscreen();
245
- }
246
- });
247
-
248
- fetchVideos();
249
- </script>
250
- </body>
251
- </html>
 
1
+ import httpx
2
+ from fastapi import FastAPI
3
+ from fastapi.responses import JSONResponse
4
+
5
+ app = FastAPI()
6
+
7
+ ICLOUD_API = "https://p51-sharedstreams.icloud.com/B0p532ODWH4KDMb/sharedstreams/webstream"
8
+
9
+ @app.get("/album/B0p532ODWH4KDMb")
10
+ async def get_album():
11
+ try:
12
+ async with httpx.AsyncClient(follow_redirects=True, timeout=15) as client:
13
+ response = await client.post(ICLOUD_API)
14
+ response.raise_for_status()
15
+ result = response.json()
16
+
17
+ # Transform and clean up for the frontend
18
+ cleaned = {
19
+ "videos": []
20
+ }
21
+
22
+ for item in result.get("photos", []):
23
+ video_url = item.get("videoUrl")
24
+ poster_url = item.get("posterFrameUrl")
25
+ caption = item.get("caption", "")
26
+
27
+ if video_url:
28
+ cleaned["videos"].append({
29
+ "url": video_url,
30
+ "poster": poster_url or "", # fallback
31
+ "caption": caption or ""
32
+ })
33
+
34
+ return JSONResponse(content=cleaned)
35
+
36
+ except httpx.HTTPStatusError as e:
37
+ return JSONResponse(status_code=500, content={"error": f"Status error: {e.response.status_code}"})
38
+ except Exception as e:
39
+ return JSONResponse(status_code=500, content={"error": f"Unexpected error: {str(e)}"})