vault backup: 2025-12-22 14:32:30
All checks were successful
Deploy Quartz site to GitHub Pages / build (push) Successful in 2m47s
All checks were successful
Deploy Quartz site to GitHub Pages / build (push) Successful in 2m47s
This commit is contained in:
16
content/.obsidian/workspace.json
vendored
16
content/.obsidian/workspace.json
vendored
@@ -26,12 +26,15 @@
|
|||||||
"id": "b6de1b6650c09ff3",
|
"id": "b6de1b6650c09ff3",
|
||||||
"type": "leaf",
|
"type": "leaf",
|
||||||
"state": {
|
"state": {
|
||||||
"type": "pdf",
|
"type": "markdown",
|
||||||
"state": {
|
"state": {
|
||||||
"file": "Anatomi & Histologi 2/1 Öga anatomi/Slides.pdf.pdf"
|
"file": "Anatomi & Histologi 2/Schema.md",
|
||||||
|
"mode": "source",
|
||||||
|
"source": false,
|
||||||
|
"backlinks": false
|
||||||
},
|
},
|
||||||
"icon": "lucide-file-text",
|
"icon": "lucide-file",
|
||||||
"title": "Slides.pdf"
|
"title": "Schema"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -206,6 +209,8 @@
|
|||||||
},
|
},
|
||||||
"active": "b6de1b6650c09ff3",
|
"active": "b6de1b6650c09ff3",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
|
"Anatomi & Histologi 2/Statistik.md",
|
||||||
|
"Anatomi & Histologi 2/1 Öga anatomi/Slides.pdf.pdf",
|
||||||
"Anatomi & Histologi 2/1 Öga anatomi/Slides.md",
|
"Anatomi & Histologi 2/1 Öga anatomi/Slides.md",
|
||||||
"Anatomi & Histologi 2/1 Öga anatomi/Målbeskrivning.md",
|
"Anatomi & Histologi 2/1 Öga anatomi/Målbeskrivning.md",
|
||||||
"Anatomi & Histologi 2/1 Öga anatomi/Instuderingsfrågor.md",
|
"Anatomi & Histologi 2/1 Öga anatomi/Instuderingsfrågor.md",
|
||||||
@@ -221,7 +226,6 @@
|
|||||||
"Anatomi & Histologi 2/Gamla tentor/2024-01-10/21.md",
|
"Anatomi & Histologi 2/Gamla tentor/2024-01-10/21.md",
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2025-01-15/17.md",
|
"Anatomi & Histologi 2/Gamla tentor/2025-01-15/17.md",
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2025-02-08/10.md",
|
"Anatomi & Histologi 2/Gamla tentor/2025-02-08/10.md",
|
||||||
"Anatomi & Histologi 2/1 Öga anatomi/Slides.pdf.pdf",
|
|
||||||
"Anatomi & Histologi 2/1 Öga anatomi/Studietips.md",
|
"Anatomi & Histologi 2/1 Öga anatomi/Studietips.md",
|
||||||
"Anatomi & Histologi 2/Demokompendium.md",
|
"Anatomi & Histologi 2/Demokompendium.md",
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2024-01-10/20.md",
|
"Anatomi & Histologi 2/Gamla tentor/2024-01-10/20.md",
|
||||||
@@ -233,12 +237,10 @@
|
|||||||
"Anatomi & Histologi 2/1 Öga anatomi/Oculus.md.md",
|
"Anatomi & Histologi 2/1 Öga anatomi/Oculus.md.md",
|
||||||
"Anatomi & Histologi 2/2 Öra anatomi/Slides.pdf.pdf",
|
"Anatomi & Histologi 2/2 Öra anatomi/Slides.pdf.pdf",
|
||||||
"Anatomi & Histologi 2/2 Öra anatomi/Instuderingsfrågor.md",
|
"Anatomi & Histologi 2/2 Öra anatomi/Instuderingsfrågor.md",
|
||||||
"Anatomi & Histologi 2/Statistik.md",
|
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2022-01-15/20.md",
|
"Anatomi & Histologi 2/Gamla tentor/2022-01-15/20.md",
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2022-06-01/21.md",
|
"Anatomi & Histologi 2/Gamla tentor/2022-06-01/21.md",
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2025-06-03/26.md",
|
"Anatomi & Histologi 2/Gamla tentor/2025-06-03/26.md",
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2025-08-08/10.md",
|
"Anatomi & Histologi 2/Gamla tentor/2025-08-08/10.md",
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2025-08-08/8.md",
|
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2023-01-11/!2023-01-11-0044-PRX.pdf",
|
"Anatomi & Histologi 2/Gamla tentor/2023-01-11/!2023-01-11-0044-PRX.pdf",
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2022-06-01/!2022-06-01-0101-MGY.pdf",
|
"Anatomi & Histologi 2/Gamla tentor/2022-06-01/!2022-06-01-0101-MGY.pdf",
|
||||||
"Anatomi & Histologi 2/Gamla tentor/2022-01-15/!2022-01-15-0032-BWD.pdf",
|
"Anatomi & Histologi 2/Gamla tentor/2022-01-15/!2022-01-15-0032-BWD.pdf",
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
| 2026-01-14 | 10:00–12:00 2h | Frågestund inför skriftliga tentamen | [Zoom](https://app.zoom.us/wc/join/62993534868?fromPWA=1&pwd=dmVuVXc0NXRoRnFqdXR1dEVSc2Urdz09) | Anne Uv, Helena Carén, Magnus Rudenholm |
|
| 2026-01-14 | 10:00–12:00 2h | Frågestund inför skriftliga tentamen | [Zoom](https://app.zoom.us/wc/join/62993534868?fromPWA=1&pwd=dmVuVXc0NXRoRnFqdXR1dEVSc2Urdz09) | Anne Uv, Helena Carén, Magnus Rudenholm |
|
||||||
| 2026-01-15 | 08:00–16:00 8h | Förberedelse vetenskaplig artikel | Distansundervisning/Online Självstudier | |
|
| 2026-01-15 | 08:00–16:00 8h | Förberedelse vetenskaplig artikel | Distansundervisning/Online Självstudier | |
|
||||||
| 2026-01-15 | 19:00–21:00 2h | [Skriftig tentamen anatomi/histologi del 2](https://canvas.gu.se/courses/91586/pages/f-tentamen?module_item_id=1418976) | [Andra Långgatan 19](https://www.google.com/maps/place/Andra+L%C3%A5nggatan+19,+413+28+G%C3%B6teborg/@57.6992557,11.9457214,478m/data=!3m2!1e3!4b1!4m6!3m5!1s0x464ff3415f98b55d:0x652d07c9960bd44b!8m2!3d57.6992557!4d11.9482963!16s%2Fg%2F11c2gks9gc?entry=ttu&g_ep=EgoyMDI1MTIwOS4wIKXMDSoKLDEwMDc5MjA3M0gBUAM%3D) | |
|
| 2026-01-15 | 19:00–21:00 2h | [Skriftig tentamen anatomi/histologi del 2](https://canvas.gu.se/courses/91586/pages/f-tentamen?module_item_id=1418976) | [Andra Långgatan 19](https://www.google.com/maps/place/Andra+L%C3%A5nggatan+19,+413+28+G%C3%B6teborg/@57.6992557,11.9457214,478m/data=!3m2!1e3!4b1!4m6!3m5!1s0x464ff3415f98b55d:0x652d07c9960bd44b!8m2!3d57.6992557!4d11.9482963!16s%2Fg%2F11c2gks9gc?entry=ttu&g_ep=EgoyMDI1MTIwOS4wIKXMDSoKLDEwMDc5MjA3M0gBUAM%3D) | |
|
||||||
| 2026-01-16 | 09:15–12:00 3h | TBL vetenskaplig artikel: B1-B10 - Obligatorisk | 2045 T Bjurström | Joan Camuñas, Abhishek Niroula |
|
| 2026-01-16 | 09:15–12:00 3h | TBL vetenskaplig artikel: B1-B10 - **Obligatorisk** | 2045 T Bjurström | Joan Camuñas, Abhishek Niroula |
|
||||||
| 2026-01-16 | 13:15–16:00 3h | TBL vetenskaplig artikel: A1-A10 - Obligatorisk | 2045 T Bjurström | Joan Camuñas, Abhishek Niroula |
|
| 2026-01-16 | 13:15–16:00 3h | TBL vetenskaplig artikel: A1-A10 - **Obligatorisk** | 2045 T Bjurström | Joan Camuñas, Abhishek Niroula |
|
||||||
| 2026-01-31 | 08:30–12:30 4h | Digital omtentamen - biokemi med skannat papper | Första Långgatan 16 | |
|
| 2026-01-31 | 08:30–12:30 4h | Digital omtentamen - biokemi med skannat papper | Första Långgatan 16 | |
|
||||||
| 2026-02-07 | 08:30–10:30 2h | Digital omtentamen anatomi/histologi del 2 | [Andra Långgatan 19](https://www.google.com/maps/place/Andra+L%C3%A5nggatan+19,+413+28+G%C3%B6teborg/@57.6992557,11.9457214,478m/data=!3m2!1e3!4b1!4m6!3m5!1s0x464ff3415f98b55d:0x652d07c9960bd44b!8m2!3d57.6992557!4d11.9482963!16s%2Fg%2F11c2gks9gc?entry=ttu&g_ep=EgoyMDI1MTIwOS4wIKXMDSoKLDEwMDc5MjA3M0gBUAM%3D) | |
|
| 2026-02-07 | 08:30–10:30 2h | Digital omtentamen anatomi/histologi del 2 | [Andra Långgatan 19](https://www.google.com/maps/place/Andra+L%C3%A5nggatan+19,+413+28+G%C3%B6teborg/@57.6992557,11.9457214,478m/data=!3m2!1e3!4b1!4m6!3m5!1s0x464ff3415f98b55d:0x652d07c9960bd44b!8m2!3d57.6992557!4d11.9482963!16s%2Fg%2F11c2gks9gc?entry=ttu&g_ep=EgoyMDI1MTIwOS4wIKXMDSoKLDEwMDc5MjA3M0gBUAM%3D) | |
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,13 @@
|
|||||||
|
|
||||||
<div class="options-container">
|
<div class="options-container">
|
||||||
{% for option in question.options.all %}
|
{% for option in question.options.all %}
|
||||||
<div class="option-item" id="option-{{ option.letter }}" onclick="toggleOption('{{ option.letter }}')">
|
<label class="option-item" for="checkbox-{{ option.letter }}" id="option-{{ option.letter }}">
|
||||||
<input type="checkbox" id="checkbox-{{ option.letter }}\" value="{{ option.letter }}"
|
<input type="checkbox" id="checkbox-{{ option.letter }}" value="{{ option.letter }}"
|
||||||
|
onchange="toggleOption('{{ option.letter }}')"
|
||||||
style="margin-right: 0.5rem; width: 1.2rem; height: 1.2rem; cursor: pointer;">
|
style="margin-right: 0.5rem; width: 1.2rem; height: 1.2rem; cursor: pointer;">
|
||||||
<span class="option-letter">{{ option.letter }}</span>
|
<span class="option-letter">{{ option.letter }}</span>
|
||||||
<span>{{ option.text }}</span>
|
<span>{{ option.text }}</span>
|
||||||
</div>
|
</label>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,80 +1,161 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Download Swedish auto-generated subtitles from YouTube videos using yt-dlp.
|
||||||
|
"""
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import os
|
import platform
|
||||||
import glob
|
|
||||||
|
|
||||||
def get_clipboard():
|
|
||||||
result = subprocess.run(['pbpaste'], capture_output=True, text=True)
|
|
||||||
return result.stdout.strip()
|
|
||||||
|
|
||||||
def set_clipboard(text):
|
|
||||||
subprocess.run(['pbcopy'], input=text, text=True)
|
|
||||||
|
|
||||||
def get_url_from_dialog():
|
def get_url_from_dialog():
|
||||||
|
"""
|
||||||
|
Show a macOS dialog to get the YouTube URL.
|
||||||
|
Uses osascript (AppleScript) - similar to zenity on Linux or prompt() in HTML.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The URL entered by the user, or None if cancelled
|
||||||
|
"""
|
||||||
|
if platform.system() != 'Darwin':
|
||||||
|
print("Error: Dialog is only supported on macOS", file=sys.stderr)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# AppleScript to show a text input dialog
|
||||||
applescript = '''
|
applescript = '''
|
||||||
display dialog "Enter YouTube URL:" default answer "" with title "Download Swedish Subtitles" buttons {"Cancel", "OK"} default button "OK"
|
display dialog "Enter YouTube URL:" default answer "" with title "Download Swedish Subtitles" buttons {"Cancel", "OK"} default button "OK"
|
||||||
set userInput to text returned of result
|
set userInput to text returned of result
|
||||||
return userInput
|
return userInput
|
||||||
'''
|
'''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(['osascript', '-e', applescript], capture_output=True, text=True, check=True)
|
result = subprocess.run(
|
||||||
|
['osascript', '-e', applescript],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=True
|
||||||
|
)
|
||||||
return result.stdout.strip()
|
return result.stdout.strip()
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
|
# User cancelled or error occurred
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def clean_subtitles(srt_content):
|
def clean_subtitles(srt_content):
|
||||||
|
"""
|
||||||
|
Clean SRT subtitle content by removing timestamps, unwrapping lines, and removing duplicates.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
srt_content: Raw SRT subtitle content
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Cleaned text content with timestamps removed and duplicates filtered
|
||||||
|
"""
|
||||||
lines = srt_content.strip().split('\n')
|
lines = srt_content.strip().split('\n')
|
||||||
text_lines = []
|
text_lines = []
|
||||||
seen_lines = set()
|
seen_lines = set()
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if not line or line.isdigit() or '-->' in line:
|
|
||||||
|
# Skip empty lines, sequence numbers, and timestamp lines
|
||||||
|
if not line:
|
||||||
continue
|
continue
|
||||||
|
if line.isdigit():
|
||||||
|
continue
|
||||||
|
if '-->' in line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Skip duplicate lines (auto-generated subtitles often repeat)
|
||||||
if line in seen_lines:
|
if line in seen_lines:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
seen_lines.add(line)
|
seen_lines.add(line)
|
||||||
text_lines.append(line)
|
text_lines.append(line)
|
||||||
|
|
||||||
|
# Join all lines with spaces to unwrap
|
||||||
return ' '.join(text_lines)
|
return ' '.join(text_lines)
|
||||||
|
|
||||||
def download_subtitles(url):
|
def download_subtitles(url):
|
||||||
cmd = [
|
"""
|
||||||
'yt-dlp',
|
Download auto-generated Swedish subtitles from a YouTube video or playlist.
|
||||||
'--write-auto-sub',
|
|
||||||
'--sub-lang', 'sv',
|
|
||||||
'--skip-download',
|
|
||||||
'--convert-subs', 'srt',
|
|
||||||
'-o', '%(id)s.%(ext)s',
|
|
||||||
url
|
|
||||||
]
|
|
||||||
|
|
||||||
subprocess.run(cmd, capture_output=True, text=True, check=True)
|
Args:
|
||||||
|
url: YouTube video or playlist URL
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
|
||||||
srt_files = glob.glob('*.sv.srt')
|
try:
|
||||||
|
# Get video ID to construct subtitle filename
|
||||||
|
# Download subtitles to current directory, then read and delete
|
||||||
|
cmd = [
|
||||||
|
'yt-dlp',
|
||||||
|
'--write-auto-sub',
|
||||||
|
'--sub-lang', 'sv',
|
||||||
|
'--skip-download',
|
||||||
|
'--convert-subs', 'srt',
|
||||||
|
'-o', '%(id)s.%(ext)s',
|
||||||
|
url
|
||||||
|
]
|
||||||
|
|
||||||
if srt_files:
|
print(f"Downloading subtitles...", file=sys.stderr)
|
||||||
subtitle_file = srt_files[0]
|
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
||||||
with open(subtitle_file, 'r', encoding='utf-8') as f:
|
|
||||||
raw_content = f.read()
|
|
||||||
cleaned_content = clean_subtitles(raw_content)
|
|
||||||
os.remove(subtitle_file)
|
|
||||||
return cleaned_content
|
|
||||||
|
|
||||||
sys.exit(1)
|
# Find the generated .srt file
|
||||||
|
srt_files = glob.glob('*.sv.srt')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if srt_files:
|
||||||
url = get_clipboard()
|
subtitle_file = srt_files[0]
|
||||||
|
print(f"Reading subtitles from: {subtitle_file}", file=sys.stderr)
|
||||||
|
|
||||||
if not url or 'youtube.com' not in url and 'youtu.be' not in url:
|
# Read, clean and print the subtitle file
|
||||||
url = get_url_from_dialog()
|
with open(subtitle_file, 'r', encoding='utf-8') as f:
|
||||||
if not url:
|
raw_content = f.read()
|
||||||
|
cleaned_content = clean_subtitles(raw_content)
|
||||||
|
print(cleaned_content)
|
||||||
|
|
||||||
|
# Clean up the subtitle file
|
||||||
|
os.remove(subtitle_file)
|
||||||
|
print(f"Cleaned up: {subtitle_file}", file=sys.stderr)
|
||||||
|
else:
|
||||||
|
print("Error: No Swedish subtitles found for this video", file=sys.stderr)
|
||||||
|
print("Available subtitle languages might not include Swedish auto-generated", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
subtitles = download_subtitles(url)
|
except subprocess.CalledProcessError as e:
|
||||||
set_clipboard(subtitles)
|
print(f"Error running yt-dlp: {e}", file=sys.stderr)
|
||||||
|
if e.stderr:
|
||||||
|
print(e.stderr, file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("Error: yt-dlp not found. Please install it first:", file=sys.stderr)
|
||||||
|
print(" pip install yt-dlp", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Unexpected error: {e}", file=sys.stderr)
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
url = None
|
||||||
|
|
||||||
|
# Get URL from command line argument or dialog
|
||||||
|
if len(sys.argv) == 2:
|
||||||
|
url = sys.argv[1]
|
||||||
|
elif len(sys.argv) == 1:
|
||||||
|
# No argument provided - show dialog (macOS only)
|
||||||
|
if platform.system() == 'Darwin':
|
||||||
|
url = get_url_from_dialog()
|
||||||
|
if not url:
|
||||||
|
print("No URL provided. Exiting.", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("Usage: python download-subs.py <youtube_url>", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("Usage: python download-subs.py [youtube_url]", file=sys.stderr)
|
||||||
|
print(" If no URL is provided on macOS, a dialog will appear.", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
download_subtitles(url)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user