diff --git a/Pipfile b/Pipfile index bf281e5..b7a81df 100644 --- a/Pipfile +++ b/Pipfile @@ -7,6 +7,7 @@ name = "pypi" fugashi = "*" unidic = "*" pykakasi = "*" +django = "*" [dev-packages] diff --git a/ktsite/__init__.py b/ktsite/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ktsite/asgi.py b/ktsite/asgi.py new file mode 100644 index 0000000..7993b0d --- /dev/null +++ b/ktsite/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for ktsite project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ktsite.settings') + +application = get_asgi_application() diff --git a/ktsite/settings.py b/ktsite/settings.py new file mode 100644 index 0000000..2e0c3cf --- /dev/null +++ b/ktsite/settings.py @@ -0,0 +1,124 @@ +""" +Django settings for ktsite project. + +Generated by 'django-admin startproject' using Django 5.1.4. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-p2(%ui_u8&s%#3wozb4n9hfao+ont5#az#g-5ze*i4-629bw2&' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['topcez-lhw', '127.0.0.1'] + + +# Application definition + +INSTALLED_APPS = [ + 'lyrics', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'ktsite.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'ktsite.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/5.1/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.1/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/ktsite/urls.py b/ktsite/urls.py new file mode 100644 index 0000000..217f34a --- /dev/null +++ b/ktsite/urls.py @@ -0,0 +1,23 @@ +""" +URL configuration for ktsite project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import include, path + +urlpatterns = [ + path('lyrics/', include('lyrics.urls')), + path('admin/', admin.site.urls), +] diff --git a/ktsite/wsgi.py b/ktsite/wsgi.py new file mode 100644 index 0000000..4f5c2d6 --- /dev/null +++ b/ktsite/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for ktsite project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ktsite.settings') + +application = get_wsgi_application() diff --git a/lyrics/__init__.py b/lyrics/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lyrics/admin.py b/lyrics/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/lyrics/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/lyrics/apps.py b/lyrics/apps.py new file mode 100644 index 0000000..4245d05 --- /dev/null +++ b/lyrics/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class LyricsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'lyrics' diff --git a/lyrics/migrations/__init__.py b/lyrics/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lyrics/models.py b/lyrics/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/lyrics/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/lyrics/static/jass/COPYRIGHT b/lyrics/static/jass/COPYRIGHT new file mode 100644 index 0000000..3e35c60 --- /dev/null +++ b/lyrics/static/jass/COPYRIGHT @@ -0,0 +1,951 @@ +# The following lists all copyright notices and licenses for the +# work contained in JASSUB per project. + +# Project: jassub +# Project: brotli +License: Expat +Copyright: 2014 Google Inc. + 2015 The Chromium Authors. + 2016 Google Inc. + 2017 Google Inc. + 2018 Google Inc. + 2015 Google Inc. + group">assemblmaking pressedwidget.ps:" ? rebuiltby someFormer editorsdelayedCanonichad thepushingclass="but arepartialBabylonbottom carrierCommandits useAs withcoursesa thirddenotesalso inHouston20px;">accuseddouble goal ofFamous ).bind(priests Onlinein Julyst + "gconsultdecimalhelpfulrevivedis veryr'+'iptlosing femalesis alsostringsdays ofarrivalfuture ntthere isencoded. The balloondone by/commonbgcolorlaw of Indianaavoidedbut the2px 3pxjquery.after apolicy.men andfooter-= true;for usescreen.Indian image =family,http:  driverseternalsame asnoticedviewers})();n is moreseasonsformer the newis justconsent Searchwas thewhy theshippedbr>
width: height=made ofcuisineis thata very Admiral fixed;normal MissionPress, ontariocharsettry to invaded="true"spacingis mosta more totallyfall of});rn immensetime inset outsatisfyto finddown tolot of Playersin Junequantumnot thetime todistantFinnishsrc = (single help ofGerman law andlabeledforestscookingspace">header-well asStanleybridges/globalCroatia About [0];n it, andgroupedbeing a){throwhe madelighterethicalFFFFFF"bottom"like a employslive inas seenprintermost ofub-linkrejectsand useimage">succeedfeedingNuclearinformato helpWomen'sNeitherMexicanproteinus.js"> Since universlarger open to!-- endlies in']);rn marketwho is ("DOMComanagedone fortypeof Kingdomprofitsproposeto showcenter;made itdressedwere inmixtureprecisearisingsrc = 'make a securedBaptistvoting nttvar March 2grew upClimate.removeskilledway theface ofacting right">to workreduceshas haderectedshow();action=book ofan area== "httconformfacing cookie.rely onhosted .customhe wentbut forspread Family a meansout theforums.footage">MobilClements" id="as highintense-->rnn +
+

Song Information

+ +
+ + + + + + + + + + + + +
+ + +

Save/Load

+ + + + +
+

Custom Word Overrides

+
The automatic furigana generation uses MeCab/Unidic to parse/tokenize the original japanese text. + This has some word priorities that are bad in general, e.g. わたくし and ぬし, which this program overrides to わたし and しゅ by default, but you may also want to define your own kana readings for other words that are used a lot in this song.
+ + For individual words, you can instead specify a reading within the lyrics by writing {漢字|かんじ} which will prevent the automatic parser from touching it, and produce 漢字かんじ in the output.
+ + + + + + + + + + + +
+
+ +
+

Lyrics Input

+ +
+ +
+

Lyrics Output

+
+
+
+ +
+

Arrangement Input

+ Comma-separated section tags, numbers are beats to insert between sections.
+ +
+ +
+

Video

+ You may select a local video file for subtitle timing and preview. It will not be uploaded anywhere. +
+ + +
+ + + diff --git a/lyrics/tests.py b/lyrics/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/lyrics/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/lyrics/urls.py b/lyrics/urls.py new file mode 100644 index 0000000..f8409d1 --- /dev/null +++ b/lyrics/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('', views.index, name='index'), + path('tokenize', views.tokenize, name='tokenize'), +] diff --git a/lyrics/views.py b/lyrics/views.py new file mode 100644 index 0000000..4ef7110 --- /dev/null +++ b/lyrics/views.py @@ -0,0 +1,21 @@ +from django.shortcuts import render +from django.http import HttpRequest, JsonResponse +from japanese_converters import parse_japanese_line +# Create your views here. + +def index(request: HttpRequest): + # return HttpResponse("Hello world. You're at the Lyrics app index.") + return render(request, 'lyrics/index.html', {}) + +def tokenize(request: HttpRequest): + if 'input' in request.GET: + overrides = request.GET.get('word_overrides', '') + lines = request.GET.get('input').splitlines() + parsed = [] + for line in lines: + if (line.strip() and not line.startswith('[')): + parsed.append(parse_japanese_line(line, overrides_str=overrides)) + else: + parsed.append(line) + return JsonResponse({'parsed_lines': parsed}) + return JsonResponse(request.GET) diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..8a19ac6 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ktsite.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main()