reorganized files
This commit is contained in:
0
.gitattributes → app/.gitattributes
vendored
0
.gitattributes → app/.gitattributes
vendored
0
.gitignore → app/.gitignore
vendored
0
.gitignore → app/.gitignore
vendored
27
app/Dockerfile
Normal file
27
app/Dockerfile
Normal 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 / /
|
||||
BIN
app/__pycache__/models.cpython-310.pyc
Normal file
BIN
app/__pycache__/models.cpython-310.pyc
Normal file
Binary file not shown.
@@ -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¤t_weather=true"
|
||||
api_url = "https://api.open-meteo.com/v1/forecast?latitude=32.681676709461826&longitude=-97.373412014933¤t_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)
|
||||
@@ -1,3 +1,4 @@
|
||||
Flask==2.3.3
|
||||
Flask-SQLAlchemy==3.0.5
|
||||
Werkzeug==2.3.7
|
||||
youtube-transcript-api
|
||||
673
app/static/css/nationalparks.css
Normal file
673
app/static/css/nationalparks.css
Normal 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*/
|
||||
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
3
app/static/js/nationalparks.js
Normal file
3
app/static/js/nationalparks.js
Normal file
File diff suppressed because one or more lines are too long
@@ -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>
|
||||
20
app/templates/nationalparks.html
Normal file
20
app/templates/nationalparks.html
Normal 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 %}
|
||||
26
app/templates/transcript.html
Normal file
26
app/templates/transcript.html
Normal 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 %}
|
||||
@@ -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
13
compose.yaml
Normal 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
|
||||
Reference in New Issue
Block a user