reorganized files

This commit is contained in:
Nico Melone
2025-09-18 16:59:30 -05:00
parent e5d6ed6e7e
commit 2617eade47
36 changed files with 811 additions and 4 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

27
app/Dockerfile Normal file
View File

@@ -0,0 +1,27 @@
# syntax=docker/dockerfile:1.4
FROM --platform=$BUILDPLATFORM python:3.10-alpine AS builder
WORKDIR /app
COPY requirements.txt /app
RUN --mount=type=cache,target=/root/.cache/pip \
pip3 install -r requirements.txt
COPY . /app
ENTRYPOINT ["python3"]
CMD ["app.py"]
FROM builder as dev-envs
RUN <<EOF
apk update
apk add git
EOF
RUN <<EOF
addgroup -S docker
adduser -S --shell /bin/bash --ingroup docker vscode
EOF
# install Docker tools (cli, buildx, compose)
COPY --from=gloursdocker/docker / /

Binary file not shown.

View File

@@ -1,4 +1,7 @@
from flask import Flask, render_template, request, redirect, url_for, jsonify
import tempfile
from urllib.parse import parse_qs, urlparse
from flask import Flask, render_template, request, redirect, send_file, url_for, jsonify
from youtube_transcript_api import YouTubeTranscriptApi
from models import db, Item
from datetime import datetime as dt
import requests, csv, json
@@ -66,7 +69,7 @@ def short_stories(story=1):
@app.route('/weather')
def get_weather():
# Replace with your API's URL
api_url = "https://api.open-meteo.com/v1/forecast?latitude=32.0015&longitude=-102.1394&current_weather=true"
api_url = "https://api.open-meteo.com/v1/forecast?latitude=32.681676709461826&longitude=-97.373412014933&current_weather=true"
try:
# Make the GET request to the API
@@ -128,5 +131,44 @@ def pcc():
return render_template('pcc.html', value = value_chain)
return render_template('pcc.html')
def get_video_id(url: str) -> str:
"""Extract YouTube video ID from URL."""
query = urlparse(url)
if query.hostname in ['www.youtube.com', 'youtube.com']:
return parse_qs(query.query)['v'][0]
elif query.hostname == 'youtu.be':
return query.path[1:]
else:
raise ValueError("Invalid YouTube URL")
def fetch_transcript(url: str, language: str = 'ja') -> str:
"""Fetch transcript text."""
video_id = get_video_id(url)
ytt_api = YouTubeTranscriptApi()
transcript = ytt_api.fetch(video_id, languages=[language])
return (" ".join([entry.text for entry in transcript]),transcript.video_id)
@app.route("/transcript", methods=["GET", "POST"])
def transcript():
if request.method == "POST":
yt_url = request.form["url"]
lang = request.form.get("lang", "ja")
try:
transcript, video_id = fetch_transcript(yt_url, lang)
except Exception as e:
return f"Error: {e}", 400
# Save to a temporary file and return immediately
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".txt", mode="w", encoding="utf-8")
tmp.write(transcript)
tmp.close()
return send_file(tmp.name, as_attachment=True, download_name=f"{video_id}-transcript.txt")
return render_template("transcript.html")
@app.route("/nationalparks")
def nationalparks():
return render_template("nationalparks.html")
if __name__ == '__main__':
app.run(debug=True)
app.run(debug=True, host='0.0.0.0', port=8000)

View File

@@ -1,3 +1,4 @@
Flask==2.3.3
Flask-SQLAlchemy==3.0.5
Werkzeug==2.3.7
youtube-transcript-api

View File

@@ -0,0 +1,673 @@
@import url(https://unpkg.com/leaflet@1.9.4/dist/leaflet.css);
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
margin: 0;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, Courier New, monospace;
}
.leaflet-image-layer,
.leaflet-layer,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-pane,
.leaflet-pane > canvas,
.leaflet-pane > svg,
.leaflet-tile,
.leaflet-tile-container,
.leaflet-zoom-box {
left: 0;
position: absolute;
top: 0;
}
.leaflet-container {
overflow: hidden;
}
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile {
-webkit-user-drag: none;
-webkit-user-select: none;
user-select: none;
}
.leaflet-tile::selection {
background: #0000;
}
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
}
.leaflet-safari .leaflet-tile-container {
height: 1600px;
-webkit-transform-origin: 0 0;
width: 1600px;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
.leaflet-container .leaflet-overlay-pane svg {
max-height: none !important;
max-width: none !important;
}
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer {
max-height: none !important;
max-width: none !important;
padding: 0;
width: auto;
}
.leaflet-container img.leaflet-tile {
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom {
touch-action: pan-x pan-y;
}
.leaflet-container.leaflet-touch-drag {
touch-action: none;
touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
touch-action: none;
}
.leaflet-container {
-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
box-sizing: border-box;
height: 0;
width: 0;
z-index: 800;
}
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-pane {
z-index: 400;
}
.leaflet-tile-pane {
z-index: 200;
}
.leaflet-overlay-pane {
z-index: 400;
}
.leaflet-shadow-pane {
z-index: 500;
}
.leaflet-marker-pane {
z-index: 600;
}
.leaflet-tooltip-pane {
z-index: 650;
}
.leaflet-popup-pane {
z-index: 700;
}
.leaflet-map-pane canvas {
z-index: 100;
}
.leaflet-map-pane svg {
z-index: 200;
}
.leaflet-vml-shape {
height: 1px;
width: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
.leaflet-control {
pointer-events: visiblePainted;
pointer-events: auto;
position: relative;
z-index: 800;
}
.leaflet-bottom,
.leaflet-top {
pointer-events: none;
position: absolute;
z-index: 1000;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
clear: both;
float: left;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-animated {
transform-origin: 0 0;
}
svg.leaflet-zoom-animated {
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
transition: transform 0.25s cubic-bezier(0, 0, 0.25, 1);
}
.leaflet-pan-anim .leaflet-tile,
.leaflet-zoom-anim .leaflet-tile {
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
.leaflet-interactive {
cursor: pointer;
}
.leaflet-grab {
cursor: grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
cursor: crosshair;
}
.leaflet-control,
.leaflet-popup-pane {
cursor: auto;
}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
cursor: move;
cursor: grabbing;
}
.leaflet-image-layer,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-pane > svg path,
.leaflet-tile-container {
pointer-events: none;
}
.leaflet-image-layer.leaflet-interactive,
.leaflet-marker-icon.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: visiblePainted;
pointer-events: auto;
}
.leaflet-container {
background: #ddd;
outline-offset: 1px;
}
.leaflet-container a {
color: #0078a8;
}
.leaflet-zoom-box {
background: #ffffff80;
border: 2px dotted #38f;
}
.leaflet-container {
font-family: Helvetica Neue, Arial, Helvetica, sans-serif;
font-size: 12px;
font-size: 0.75rem;
line-height: 1.5;
}
.leaflet-bar {
border-radius: 4px;
box-shadow: 0 1px 5px #000000a6;
}
.leaflet-bar a {
background-color: #fff;
border-bottom: 1px solid #ccc;
color: #000;
display: block;
height: 26px;
line-height: 26px;
text-align: center;
text-decoration: none;
width: 26px;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:focus,
.leaflet-bar a:hover {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
border-bottom: none;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.leaflet-bar a.leaflet-disabled {
background-color: #f4f4f4;
color: #bbb;
cursor: default;
}
.leaflet-touch .leaflet-bar a {
height: 30px;
line-height: 30px;
width: 30px;
}
.leaflet-touch .leaflet-bar a:first-child {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
.leaflet-touch .leaflet-bar a:last-child {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
font: 700 18px Lucida Console, Monaco, monospace;
text-indent: 1px;
}
.leaflet-touch .leaflet-control-zoom-in,
.leaflet-touch .leaflet-control-zoom-out {
font-size: 22px;
}
.leaflet-control-layers {
background: #fff;
border-radius: 5px;
box-shadow: 0 1px 5px #0006;
}
.leaflet-control-layers-toggle {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAQAAAADQ4RFAAACf0lEQVR4AY1UM3gkARTePdvdoTxXKc+qTl3aU5U6b2Kbkz3Gtq3Zw6ziLGNPzrYx7946Tr6/ee/XeCQ4D3ykPtL5tHno4n0d/h3+xfuWHGLX81cn7r0iTNzjr7LrlxCqPtkbTQEHeqOrTy4Yyt3VCi/IOB0v7rVC7q45Q3Gr5K6jt+3Gl5nCoDD4MtO+j96Wu8atmhGqcNGHObuf8OM/x3AMx38+4Z2sPqzCxRFK2aF2e5Jol56XTLyggAMTL56XOMoS1W4pOyjUcGGQdZxU6qRh7B9Zp+PfpOFlqt0zyDZckPi1ttmIp03jX8gyJ8a/PG2yutpS/Vol7peZIbZcKBAEEheEIAgFbDkz5H6Zrkm2hVWGiXKiF4Ycw0RWKdtC16Q7qe3X4iOMxruonzegJzWaXFrU9utOSsLUmrc0YjeWYjCW4PDMADElpJSSQ0vQvA1Tm6/JlKnqFs1EGyZiFCqnRZTEJJJiKRYzVYzJck2Rm6P4iH+cmSY0YzimYa8l0EtTODFWhcMIMVqdsI2uiTvKmTisIDHJ3od5GILVhBCarCfVRmo4uTjkhrhzkiBV7SsaqS+TzrzM1qpGGUFt28pIySQHR6h7F6KSwGWm97ay+Z+ZqMcEjEWebE7wxCSQwpkhJqoZA5ivCdZDjJepuJ9IQjGGUmuXJdBFUygxVqVsxFsLMbDe8ZbDYVCGKxs+W080max1hFCarCfV+C1KATwcnvE9gRRuMP2prdbWGowm1KB1y+zwMMENkM755cJ2yPDtqhTI6ED1M/82yIDtC/4j4BijjeObflpO9I9MwXTCsSX8jWAFeHr05WoLTJ5G8IQVS/7vwR6ohirYM7f6HzYpogfS3R2OAAAAAElFTkSuQmCC);
height: 36px;
width: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAA0CAQAAABvcdNgAAAEsklEQVR4AWL4TydIhpZK1kpWOlg0w3ZXP6D2soBtG42jeI6ZmQTHzAxiTbSJsYLjO9HhP+WOmcuhciVnmHVQcJnp7DFvScowZorad/+V/fVzMdMT2g9Cv9guXGv/7pYOrXh2U+RRR3dSd9JRx6bIFc/ekqHI29JC6pJ5ZEh1yWkhkbcFeSjxgx3L2m1cb1C7bceyxA+CNjT/Ifff+/kDk2u/w/33/IeCMOSaWZ4glosqT3DNnNZQ7Cs58/3Ce5HL78iZH/vKVIaYlqzfdLu8Vi7dnvUbEza5Idt36tquZFldl6N5Z/POLof0XLK61mZCmJSWjVF9tEjUluu74IUXvgttuVIHE7YxSkaYhJZam7yiM9Pv82JYfl9nptxZaxMJE4YSPty+vF0+Y2up9d3wwijfjZbabqm/3bZ9ecKHsiGmRflnn1MW4pjHf9oLufyn2z3y1D6n8g8TZhxyzipLNPnAUpsOiuWimg52psrTZYnOWYNDTMuWBWa0tJb4rgq1UvmutpaYEbZlwU3CLJm/ayYjHW5/h7xWLn9Hh1vepDkyf7dE7MtT5LR4e7yYpHrkhOUpEfssBLq2pPhAqoSWKUkk7EDqkmK6RrCEzqDjhNDWNE+XSMvkJRDWlZTmCW0l0PHQGRZY5t1L83kT0Y3l2SItk5JAWHl2dCOBm+fPu3fo5/3v61RMCO9Jx2EEYYhb0rmNQMX/vm7gqOEJLcXTGw3CAuRNeyaPWwjR8PRqKQ1PDA/dpv+on9Shox52WFnx0KY8onHayrJzm87i5h9xGw/tfkev0jGsQizqezUKjk12hBMKJ4kbCqGPVNXudyyrShovGw5CgxsRICxF6aRmSjlBnHRzg7Gx8fKqEubI2rahQYdR1YgDIRQO7JvQyD52hoIQx0mxa0ODtW2Iozn1le2iIRdzwWewedyZzewidueOGqlsn1MvcnQpuVwLGG3/IR1hIKxCjelIDZ8ldqWz25jWAsnldEnK0Zxro19TGVb2ffIZEsIO89EIEDvKMPrzmBOQcKQ+rroye6NgRRxqR4U8EAkz0CL6uSGOm6KQCdWjvjRiSP1BPalCRS5iQYiEIvxuBMJEWgzSoHADcVMuN7IuqqTeyUPq22qFimFtxDyBBJEwNyt6TM88blFHao/6tWWhuuOM4SAK4EI4QmFHA+SEyWlp4EQoJ13cYGzMu7yszEIBOm2rVmHUNqwAIQabISNMRstmdhNWcFLsSm+0tjJH1MdRxO5Nx0WDMhCtgD6OKgZeljJqJKc9po8juskR9XN0Y1lZ3mWjLR9JCO1jRDMd0fpYC2VnvjBSEFg7wBENc0R9HFlb0xvF1+TBEpF68d+DHR6IOWVv2BECtxo46hOFUBd/APU57WIoEwJhIi2CdpyZX0m93BZicktMj1AS9dClteUFAUNUIEygRZCtik5zSxI9MubTBH1GOiHsiLJ3OCoSZkILa9PxiN0EbvhsAo8tdAf9Seepd36lGWHmtNANTv5Jd0z4QYyeo/UEJqxKRpg5LZx6btLPsOaEmdMyxYdlc8LMaJnikDlhclqmPiQnTEpLUIZEwkRagjYkEibQErwhkTAKCLQEbUgkzJQWc/0PstHHcfEdQ+UAAAAASUVORK5CYII=);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
height: 44px;
width: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-expanded {
background: #fff;
color: #333;
padding: 6px 10px 6px 6px;
}
.leaflet-control-layers-scrollbar {
overflow-x: hidden;
overflow-y: scroll;
padding-right: 5px;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
font-size: 13px;
font-size: 1.08333em;
}
.leaflet-control-layers-separator {
border-top: 1px solid #ddd;
height: 0;
margin: 5px -10px 5px -6px;
}
.leaflet-default-icon-path {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQVR4Aa1XA5BjWRTN2oW17d3YaZtr2962HUzbDNpjszW24mRt28p47v7zq/bXZtrp/lWnXr337j3nPCe85NcypgSFdugCpW5YoDAMRaIMqRi6aKq5E3YqDQO3qAwjVWrD8Ncq/RBpykd8oZUb/kaJutow8r1aP9II0WmLKLIsJyv1w/kqw9Ch2MYdB++12Onxee/QMwvf4/Dk/Lfp/i4nxTXtOoQ4pW5Aj7wpici1A9erdAN2OH64x8OSP9j3Ft3b7aWkTg/Fm91siTra0f9on5sQr9INejH6CUUUpavjFNq1B+Oadhxmnfa8RfEmN8VNAsQhPqF55xHkMzz3jSmChWU6f7/XZKNH+9+hBLOHYozuKQPxyMPUKkrX/K0uWnfFaJGS1QPRtZsOPtr3NsW0uyh6NNCOkU3Yz+bXbT3I8G3xE5EXLXtCXbbqwCO9zPQYPRTZ5vIDXD7U+w7rFDEoUUf7ibHIR4y6bLVPXrz8JVZEql13trxwue/uDivd3fkWRbS6/IA2bID4uk0UpF1N8qLlbBlXs4Ee7HLTfV1j54APvODnSfOWBqtKVvjgLKzF5YdEk5ewRkGlK0i33Eofffc7HT56jD7/6U+qH3Cx7SBLNntH5YIPvODnyfIXZYRVDPqgHtLs5ABHD3YzLuespb7t79FY34DjMwrVrcTuwlT55YMPvOBnRrJ4VXTdNnYug5ucHLBjEpt30701A3Ts+HEa73u6dT3FNWwflY86eMHPk+Yu+i6pzUpRrW7SNDg5JHR4KapmM5Wv2E8Tfcb1HoqqHMHU+uWDD7zg54mz5/2BSnizi9T1Dg4QQXLToGNCkb6tb1NU+QAlGr1++eADrzhn/u8Q2YZhQVlZ5+CAOtqfbhmaUCS1ezNFVm2imDbPmPng5wmz+gwh+oHDce0eUtQ6OGDIyR0uUhUsoO3vfDmmgOezH0mZN59x7MBi++WDL1g/eEiU3avlidO671bkLfwbw5XV2P8Pzo0ydy4t2/0eu33xYSOMOD8hTf4CrBtGMSoXfPLchX+J0ruSePw3LZeK0juPJbYzrhkH0io7B3k164hiGvawhOKMLkrQLyVpZg8rHFW7E2uHOL888IBPlNZ1FPzstSJM694fWr6RwpvcJK60+0HCILTBzZLFNdtAzJaohze60T8qBzyh5ZuOg5e7uwQppofEmf2++DYvmySqGBuKaicF1blQjhuHdvCIMvp8whTTfZzI7RldpwtSzL+F1+wkdZ2TBOW2gIF88PBTzD/gpeREAMEbxnJcaJHNHrpzji0gQCS6hdkEeYt9DF/2qPcEC8RM28Hwmr3sdNyht00byAut2k3gufWNtgtOEOFGUwcXWNDbdNbpgBGxEvKkOQsxivJx33iow0Vw5S6SVTrpVq11ysA2Rp7gTfPfktc6zhtXBBC+adRLshf6sG2RfHPZ5EAc4sVZ83yCN00Fk/4kggu40ZTvIEm5g24qtU4KjBrx/BTTH8ifVASAG7gKrnWxJDcU7x8X6Ecczhm3o6YicvsLXWfh3Ch1W0k8x0nXF+0fFxgt4phz8QvypiwCCFKMqXCnqXExjq10beH+UUA7+nG6mdG/Pu0f3LgFcGrl2s0kNNjpmoJ9o4B29CMO8dMT4Q5ox8uitF6fqsrJOr8qnwNbRzv6hSnG5wP+64C7h9lp30hKNtKdWjtdkbuPA19nJ7Tz3zR/ibgARbhb4AlhavcBebmTHcFl2fvYEnW0ox9xMxKBS8btJ+KiEbq9zA4RthQXDhPa0T9TEe69gWupwc6uBUphquXgf+/FrIjweHQS4/pduMe5ERUMHUd9xv8ZR98CxkS4F2n3EUrUZ10EYNw7BWm9x1GiPssi3GgiGRDKWRYZfXlON+dfNbM+GgIwYdwAAAAASUVORK5CYII=);
}
.leaflet-container .leaflet-control-attribution {
background: #fff;
background: #fffc;
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
color: #333;
line-height: 1.4;
padding: 0 5px;
}
.leaflet-control-attribution a {
text-decoration: none;
}
.leaflet-control-attribution a:focus,
.leaflet-control-attribution a:hover {
text-decoration: underline;
}
.leaflet-attribution-flag {
display: inline !important;
height: 0.6669em;
vertical-align: initial !important;
width: 1em;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
background: #fffc;
border: 2px solid #777;
border-top: none;
box-sizing: border-box;
line-height: 1.1;
padding: 2px 5px 1px;
text-shadow: 1px 1px #fff;
white-space: nowrap;
}
.leaflet-control-scale-line:not(:first-child) {
border-bottom: none;
border-top: 2px solid #777;
margin-top: -2px;
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-bar,
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers {
box-shadow: none;
}
.leaflet-touch .leaflet-bar,
.leaflet-touch .leaflet-control-layers {
background-clip: padding-box;
border: 2px solid #0003;
}
.leaflet-popup {
margin-bottom: 20px;
position: absolute;
text-align: center;
}
.leaflet-popup-content-wrapper {
border-radius: 12px;
padding: 1px;
text-align: left;
}
.leaflet-popup-content {
font-size: 13px;
font-size: 1.08333em;
line-height: 1.3;
margin: 13px 24px 13px 20px;
min-height: 1px;
}
.leaflet-popup-content p {
margin: 1.3em 0;
}
.leaflet-popup-tip-container {
height: 20px;
left: 50%;
margin-left: -20px;
margin-top: -1px;
overflow: hidden;
pointer-events: none;
position: absolute;
width: 40px;
}
.leaflet-popup-tip {
height: 17px;
margin: -10px auto 0;
padding: 1px;
pointer-events: auto;
transform: rotate(45deg);
width: 17px;
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: #fff;
box-shadow: 0 3px 14px #0006;
color: #333;
}
.leaflet-container a.leaflet-popup-close-button {
background: #0000;
border: none;
color: #757575;
font: 16px/24px Tahoma, Verdana, sans-serif;
height: 24px;
position: absolute;
right: 0;
text-align: center;
text-decoration: none;
top: 0;
width: 24px;
}
.leaflet-container a.leaflet-popup-close-button:focus,
.leaflet-container a.leaflet-popup-close-button:hover {
color: #585858;
}
.leaflet-popup-scrolled {
overflow: auto;
}
.leaflet-oldie .leaflet-popup-content-wrapper {
-ms-zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678,M12=0.70710678,M21=-0.70710678,M22=0.70710678);
margin: 0 auto;
width: 24px;
}
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
border: 1px solid #999;
}
.leaflet-div-icon {
background: #fff;
border: 1px solid #666;
}
.leaflet-tooltip {
background-color: #fff;
border: 1px solid #fff;
border-radius: 3px;
box-shadow: 0 1px 3px #0006;
color: #222;
padding: 6px;
pointer-events: none;
position: absolute;
-webkit-user-select: none;
user-select: none;
white-space: nowrap;
}
.leaflet-tooltip.leaflet-interactive {
cursor: pointer;
pointer-events: auto;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before,
.leaflet-tooltip-top:before {
background: #0000;
border: 6px solid #0000;
content: "";
pointer-events: none;
position: absolute;
}
.leaflet-tooltip-bottom {
margin-top: 6px;
}
.leaflet-tooltip-top {
margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
left: 50%;
margin-left: -6px;
}
.leaflet-tooltip-top:before {
border-top-color: #fff;
bottom: 0;
margin-bottom: -12px;
}
.leaflet-tooltip-bottom:before {
border-bottom-color: #fff;
margin-left: -6px;
margin-top: -12px;
top: 0;
}
.leaflet-tooltip-left {
margin-left: -6px;
}
.leaflet-tooltip-right {
margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
margin-top: -6px;
top: 50%;
}
.leaflet-tooltip-left:before {
border-left-color: #fff;
margin-right: -12px;
right: 0;
}
.leaflet-tooltip-right:before {
border-right-color: #fff;
left: 0;
margin-left: -12px;
}
@media print {
.leaflet-control {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}
.App {
background: #f5f5f5;
display: flex;
flex-direction: column;
font-family: system-ui, sans-serif;
height: 100vh;
}
ul {
list-style: none;
padding: 0;
}
li {
margin-bottom: 0.5rem;
}
.main-content {
display: flex;
flex: 1 1 auto;
overflow-y: auto;
overflow: hidden;
z-index: 1;
}
.park-list {
background: #fff;
border-radius: 10px;
border-right: 1px solid #ddd;
overflow-x: hidden;
overflow-y: auto;
padding: 0 0.5rem;
width: 20%;
}
.map-section {
display: flex;
flex: 1 1 auto;
flex-direction: column;
overflow: hidden;
padding: 0 0.5rem;
}
.sticky-header {
background: #fff;
box-shadow: 0 2px 4px #0000001a;
justify-content: space-between;
padding: 0.75rem 1rem;
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 999;
}
.controls,
.sticky-header {
align-items: center;
display: flex;
}
.controls {
flex-wrap: wrap;
gap: 1rem;
}
.leaflet-container {
border-radius: 10px;
flex: 1 1 auto;
height: 100%;
width: 100%;
}
ul.park-list {
display: flex;
flex-wrap: wrap;
gap: 1rem;
list-style: none;
margin: 0;
padding: 0;
}
.park-card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 6px #0000001a;
display: flex;
flex: 1 0 250px;
flex-direction: column;
overflow: hidden;
}
.park-card__img {
display: block;
height: 140px;
object-fit: cover;
width: 100%;
}
.park-card__label {
font-size: 0.9rem;
padding: 0.75rem 0.75rem 1rem;
}
/*# sourceMappingURL=main.149f127c.css.map*/

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

File diff suppressed because one or more lines are too long

View File

@@ -24,6 +24,8 @@
<li class="nav"><a href="{{ url_for('vocabulary') }}">Vocabulary</a></li>
<li class="nav"><a href="{{ url_for('short_stories') }}">Short Stories</a></li>
<li class="nav"><a href="{{ url_for('pcc') }}">PCC</a></li>
<li class="nav"><a href="{{ url_for('transcript') }}">Transcript</a></li>
<li class="nav"><a href="{{ url_for('nationalparks') }}">National Parks</a></li>
<li class="nav"><a href="{{ url_for('about') }}">About</a></li>
</ul>
</nav>

View File

@@ -0,0 +1,20 @@
{% extends "base.html" %}
{% block content %}
<body>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<title>React App</title>
<script defer="defer" src="{{ url_for('static', filename='js/nationalparks.js') }}"></script>
<link href="{{ url_for('static', filename='css/nationalparks.css') }}" rel="stylesheet">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
{% endblock %}

View File

@@ -0,0 +1,26 @@
{% extends "base.html" %}
{% block content %}
<h1>YouTube Transcript Fetcher</h1>
<form method="post">
<label for="url">YouTube URL:</label><br>
<input type="text" id="url" name="url" style="width:70%" required>
<label for="lang">Language code:</label>
<input type="text" id="lang" name="lang" value="ja" style="width:50px">
<button type="submit">Get Transcript</button>
</form>
{% if transcript %}
<h2>Transcript</h2>
<textarea readonly>{{ transcript }}</textarea>
<form method="post" action="/download">
<input type="hidden" name="url" value="{{ url }}">
<input type="hidden" name="lang" value="{{ lang }}">
<button type="submit">Download as TXT</button>
</form>
{% endif %}
</html>
{% endblock %}

View File

@@ -2,7 +2,7 @@
{% block content %}
<!-- Display header for current weather information -->
<h1>Current Weather</h1>
<h1>Current Weather in Fort Worth</h1>
<!-- Display temperature with unit and conversion to Fahrenheit -->
<p>

13
compose.yaml Normal file
View File

@@ -0,0 +1,13 @@
services:
web:
build:
context: app
target: builder
# flask requires SIGINT to stop gracefully
# (default stop signal from Compose is SIGTERM)
stop_signal: SIGINT
restart: always
ports:
- '8000:8000'
volumes:
- /Users/nico/Documents/GitHub/flask-practice/app:/app