diff --git a/.gitignore b/.gitignore index f241265..bd06b23 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,29 @@ dist/ build/ *.egg-info/ -cookie.txt \ No newline at end of file +cookie.txt + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +package-lock.json \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..4722bdc --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,44 @@ +import os +from flask import Flask, render_template, request, jsonify, redirect, url_for, current_app, send_file +from flask_caching import Cache + +from toloka2MediaServer.main_logic import ( + add_release_by_url, + update_release_by_name, + update_releases, + search_torrents, + get_torrent as get_torrent_external, + add_torrent as add_torrent_external, +) +from app.services.torrents import initiate_config, serialize_operation_result + +#from .api import api_bp +from .client import client_bp +from .api import * +from .db import db + +# App +app = Flask(__name__, static_folder='../frontend/dist/assets') +app.register_blueprint(client_bp) +app.register_blueprint(api_bp) + +# Cache +cache = Cache(config={"CACHE_TYPE": "SimpleCache"}) +cache.init_app(app) + +# Database +app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///t2w.db" +db.init_app(app) + +with app.app_context(): + db.create_all() + +# Production route +from .config import Config +app.logger.info('>>> {}'.format(Config.FLASK_ENV)) + +@app.route('/') +def index_client(): + dist_dir = current_app.config['DIST_DIR'] + entry = os.path.join(dist_dir, 'index.html') + return send_file(entry) diff --git a/app/api/__init__.py b/app/api/__init__.py new file mode 100644 index 0000000..bc6c705 --- /dev/null +++ b/app/api/__init__.py @@ -0,0 +1,7 @@ +from flask import Blueprint + +api_bp = Blueprint('api', __name__) + +from .titles import * +from .toloka import * +from .config_api import * \ No newline at end of file diff --git a/app/api/config_api.py b/app/api/config_api.py new file mode 100644 index 0000000..e54ba3f --- /dev/null +++ b/app/api/config_api.py @@ -0,0 +1,13 @@ +from flask import jsonify +from app.services.torrents import initiate_config +from . import api_bp + +@api_bp.route("/api/config/") +def config_route(): + config = initiate_config() + + config = dict(config.app_config) + for section in config.keys(): + config[section] = dict(config[section]) + + return jsonify(config) diff --git a/app/api/titles.py b/app/api/titles.py new file mode 100644 index 0000000..76867db --- /dev/null +++ b/app/api/titles.py @@ -0,0 +1,104 @@ +import os +from flask import Blueprint, jsonify, request, current_app +from app.services.torrents import initiate_config, serialize_operation_result +from flask_sqlalchemy import SQLAlchemy +from app.db import db, ImagesCache +from app.models.request_data import RequestData +from . import api_bp +from toloka2MediaServer.main_logic import ( + add_release_by_url, + update_release_by_name, + update_releases, + search_torrents, + get_torrent as get_torrent_external, + add_torrent as add_torrent_external, +) + + +@api_bp.route("/api/titles") +def titles_route(): + sections = [] + config = initiate_config() + titles = config.titles_config + + for title in titles.sections(): + if request.args.get("query", "") in title: + image_cache = db.session.execute( + db.select(ImagesCache).filter_by(codename=title) + ).scalar_one_or_none() + if image_cache: + titles[title]["image"] = image_cache.image + else: + toloka_torrent = config.toloka.get_torrent( + f"https://toloka.to/{titles[title]['guid']}" + ) + toloka_img = ( + f"https:{toloka_torrent.img}" + if toloka_torrent.img.startswith("//") + else toloka_torrent.img + ) + db.session.add(ImagesCache(title, toloka_img)) + db.session.commit() + + titles[title]["image"] = toloka_img + + titles[title]["codename"] = title + titles[title]["torrent_name"] = titles[title]["torrent_name"].replace( + '"', "" + ) + sections.append(dict(titles[title])) + + return jsonify(sections) + +@api_bp.route("/api/add", methods=['POST']) +def add_route(): + config = initiate_config() + + requestData = RequestData( + url=request.json["tolokaUrl"], + season=request.json["seasonIndex"], + index=int(request.json["episodeIndex"].split('.')[0]), + correction=int(request.json["adjustedEpisodeNumber"]), + title=request.json["dirname"], + ) + + config.args = requestData + operation_result = add_release_by_url(config) + output = serialize_operation_result(operation_result) + + return jsonify({"result": True}) + + +@api_bp.route("/api/delete/") +def delete_route(codename): + config = initiate_config() + titles = config.titles_config + titles.remove_section(codename) + with open("data/titles.ini", "w") as f: + titles.write(f) + + return f"{codename} успішно видалений." + + +@api_bp.route("/api/update/", defaults={"codename": None}) +@api_bp.route("/api/update/") +def update_route(codename): + # Process the name to update release + try: + config = initiate_config() + requestData = RequestData(codename=codename) + if codename: + config.args = requestData + operation_result = update_release_by_name(config) + else: + config.args = RequestData() + operation_result = update_releases(config) + + output = serialize_operation_result(operation_result) + return output + except Exception as e: + message = f"Error: {str(e)}" + return {"error": message} + + + diff --git a/app/api/toloka.py b/app/api/toloka.py new file mode 100644 index 0000000..02e32ff --- /dev/null +++ b/app/api/toloka.py @@ -0,0 +1,8 @@ +from flask import jsonify +from app.services.torrents import initiate_config +from . import api_bp + +@api_bp.route("/api/toloka/") +def toloka_torrent_route(id): + config = initiate_config() + return jsonify(config.toloka.get_torrent('https://toloka.to/' + id)) diff --git a/app/app.py b/app/app.py deleted file mode 100644 index 966564a..0000000 --- a/app/app.py +++ /dev/null @@ -1,152 +0,0 @@ -from flask import Flask, render_template, request, jsonify, redirect, url_for -import time -from services.torrents import initiate_config, serialize_operation_result - -from models.request_data import RequestData -from flask_caching import Cache -from flask_sqlalchemy import SQLAlchemy - - -from toloka2MediaServer.main_logic import ( - add_release_by_url, - update_release_by_name, - update_releases, - search_torrents, - get_torrent as get_torrent_external, - add_torrent as add_torrent_external, -) - -cache = Cache(config={"CACHE_TYPE": "SimpleCache"}) -app = Flask(__name__) -app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///t2w.db" -cache.init_app(app) - -from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass - - -class Base(DeclarativeBase, MappedAsDataclass): - pass - - -db = SQLAlchemy(app, model_class=Base) - -from models.db import ImagesCache - -with app.app_context(): - db.create_all() - - -@app.route("/") -@cache.cached(timeout=1) -def root_route(): - sections = [] - config = initiate_config() - titles = config.titles_config - new_torrent = 0 - for title in titles.sections(): - if request.args.get("query", "") in title: - image_cache = db.session.execute( - db.select(ImagesCache).filter_by(codename=title) - ).scalar_one_or_none() - if image_cache: - titles[title]["image"] = image_cache.image - else: - toloka_torrent = config.toloka.get_torrent( - f"https://toloka.to/{titles[title]['guid']}" - ) - toloka_img = ( - f"https:{toloka_torrent.img}" - if toloka_torrent.img.startswith("//") - else toloka_torrent.img - ) - db.session.add(ImagesCache(title, toloka_img)) - db.session.commit() - - titles[title]["image"] = toloka_img - - # Config data - titles[title]["codename"] = title - titles[title]["torrent_name"] = titles[title]["torrent_name"].replace( - '"', "" - ) - sections.append(titles[title]) - - return render_template("index.html", titles=sections, new_torrent=new_torrent) - - -# First stage -@app.route("/add") -def add_route(): - config = initiate_config() - if request.args.get("query"): - torrent = config.toloka.get_torrent(request.args.get("query")) - return render_template( - "add.html", - torrent=torrent, - episode_integers=[ - i - for i in "".join( - (ch if ch.isdigit() else " ") - for ch in f"{torrent.files[0].folder_name}/{torrent.files[0].file_name}" - ).split() - ], - default_dir=config.app_config.get("Toloka", "default_download_dir"), - ) - - if len(request.args) == 6: - requestData = RequestData( - url=request.args["toloka_url"], - season=request.args["season-index"], - index=int(request.args["episode-index"]), - correction=int(request.args["adjusted-episode-number"]), - title=request.args["dirname"], - ) - - config.args = requestData - operation_result = add_release_by_url(config) - output = serialize_operation_result(operation_result) - return redirect(url_for("root_route")) - - return render_template("add.html") - - -@app.route("/about") -def about_route(): - return render_template("about.html") - - -@app.route("/settings") -def settings_route(): - return render_template("settings.html") - - -@app.route("/delete/") -def delete_route(codename): - config = initiate_config() - titles = config.titles_config - titles.remove_section(codename) - with open("data/titles.ini", "w") as f: - titles.write(f) - - return f"{codename} успішно видалений." - - -@app.route("/update/", defaults={"codename": None}) -@app.route("/update/") -def update_route(codename): - # Process the name to update release - try: - config = initiate_config() - requestData = RequestData(codename=codename) - if codename: - config.args = requestData - operation_result = update_release_by_name(config) - else: - config.args = RequestData() - operation_result = update_releases(config) - - output = serialize_operation_result(operation_result) - return output - except Exception as e: - message = f"Error: {str(e)}" - return {"error": message} diff --git a/app/client.py b/app/client.py new file mode 100644 index 0000000..cc3092f --- /dev/null +++ b/app/client.py @@ -0,0 +1,9 @@ +""" Client App """ + +import os +from flask import Blueprint, render_template + +client_bp = Blueprint('client_app', __name__, + static_folder='../frontend/dist/assets/', + template_folder='../frontend/dist/', + ) diff --git a/app/config.py b/app/config.py new file mode 100644 index 0000000..2d9206d --- /dev/null +++ b/app/config.py @@ -0,0 +1,24 @@ +""" +Global Flask Application Setting + +See `.flaskenv` for default settings. +""" + +import os +from app import app + +class Config(object): + # If not set fall back to production for safety + FLASK_ENV = os.getenv('FLASK_ENV', 'production') + # Set FLASK_SECRET on your production Environment + SECRET_KEY = os.getenv('FLASK_SECRET', 'Secret') + + APP_DIR = os.path.dirname(__file__) + ROOT_DIR = os.path.dirname(APP_DIR) + DIST_DIR = os.path.join(ROOT_DIR, 'frontend/dist') + + if not os.path.exists(DIST_DIR): + raise Exception( + 'DIST_DIR not found: {}'.format(DIST_DIR)) + +app.config.from_object('app.config.Config') \ No newline at end of file diff --git a/app/data/titles.ini b/app/data/titles.ini deleted file mode 100644 index e664665..0000000 --- a/app/data/titles.ini +++ /dev/null @@ -1,52 +0,0 @@ -[TenseishitaraSlimeDattaKen] -episode_index = 2 -season_number = 03 -ext_name = .mkv -torrent_name = "Tensei shitara Slime Datta Ken" -download_dir = /media/HDD/Jellyfin/Anime -publish_date = 24-08-16 21:57 -release_group = FanVoxUA -meta = -hash = 18a83050fa77ae155d0df927c6142824c35094bb -adjusted_episode_number = 0 -guid = t678039 - -[DEADDEADDEMONSDEDEDEDEDESTRUCTION] -episode_index = 0 -season_number = 01 -ext_name = .mkv -torrent_name = "DEAD DEAD DEMONS DEDEDEDE DESTRUCTION" -download_dir = /media/HDD/Jellyfin/Anime -publish_date = 24-08-18 12:01 -release_group = FanVoxUA -meta = -hash = 40c5fbeed2f1c4c11fb7247eb81e72b70255f871 -adjusted_episode_number = 0 -guid = t679732 - -[ScottPilgrimTakesOff] -episode_index = 4 -season_number = 01 -ext_name = .mkv -torrent_name = "Scott Pilgrim Takes Off" -download_dir = /media/HDD/Jellyfin/Anime -publish_date = 24-06-29 19:41 -release_group = Altron320 -meta = -hash = 25946318d080809e65f32249bd3184d265af2146 -adjusted_episode_number = 0 -guid = t679822 - -[VinlandSaga] -episode_index = 2 -season_number = 01 -ext_name = .mkv -torrent_name = "Vinland Saga" -download_dir = /media/HDD/Jellyfin/Anime -publish_date = 20-06-29 20:08 -release_group = 11FrYkT -meta = -hash = 2d1c961f8899156ff4ef995b1ad9b03bc75442d6 -adjusted_episode_number = 0 -guid = t111251 - diff --git a/app/db.py b/app/db.py new file mode 100644 index 0000000..0fa5a5c --- /dev/null +++ b/app/db.py @@ -0,0 +1,14 @@ +from flask_sqlalchemy import SQLAlchemy +from sqlalchemy.orm import Mapped, mapped_column +from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass + +db = SQLAlchemy() + +class Base(DeclarativeBase, MappedAsDataclass): + pass + +class ImagesCache(Base): + __tablename__ = "image_cache" + + codename: Mapped[str] = mapped_column(primary_key=True) + image: Mapped[str] = mapped_column() diff --git a/app/models/db.py b/app/models/db.py deleted file mode 100644 index 87eafa7..0000000 --- a/app/models/db.py +++ /dev/null @@ -1,9 +0,0 @@ -from app import db -from sqlalchemy.orm import Mapped, mapped_column - - -class ImagesCache(db.Model): - __tablename__ = "image_cache" - - codename: Mapped[str] = mapped_column(primary_key=True) - image: Mapped[str] = mapped_column() diff --git a/app/data/app.ini b/data/app.ini similarity index 66% rename from app/data/app.ini rename to data/app.ini index 19b48f1..2d7419c 100644 --- a/app/data/app.ini +++ b/data/app.ini @@ -8,10 +8,10 @@ logging = DEBUG [transmission] -username = -password = +username = +password = port = 9091 -host = +host = 192.168.1.2 protocol = http rpc = /transmission/rpc category = sonarr @@ -19,8 +19,8 @@ tag = tolokaAnime [Toloka] username = -password = -client = -default_download_dir = +password = +client = transmission +default_download_dir = /media/HDD/Jellyfin/Anime wait_time = 10 client_wait_time = 2 diff --git a/data/titles.ini b/data/titles.ini new file mode 100644 index 0000000..bb264da --- /dev/null +++ b/data/titles.ini @@ -0,0 +1,104 @@ +[HazurewakunoJoutaiIjouSkill] +episode_index = 1 +season_number = 01 +ext_name = .mkv +torrent_name = "Failure Frame: I Became the Strongest and Annihilated Everything with Low-Level Spells" +download_dir = /media/HDD/Jellyfin/Anime +publish_date = 24-09-16 14:40 +release_group = GlassMoon +meta = +hash = 79419315387ad5121829276e41c148f86bc27b56 +adjusted_episode_number = 0 +guid = t679885 + +[Metalocalypse] +episode_index = 3 +season_number = 02 +ext_name = .mkv +torrent_name = "Metalocalypse" +download_dir = /media/HDD/Jellyfin/Cartoon +publish_date = 24-09-01 23:17 +release_group = fanat22012 +meta = +hash = b1d41c3d7671ca874a904896da3298b80fd4c648 +adjusted_episode_number = 0 +guid = t679197 + +[Noragami] +episode_index = 1 +season_number = 01 +ext_name = .mkv +torrent_name = "Noragami" +download_dir = /media/HDD/Jellyfin/Anime +publish_date = 24-08-04 13:26 +release_group = Amanogawa +meta = +hash = a5b5c50cc287839af87785d49a90deaccd26672d +adjusted_episode_number = 0 +guid = t680502 + +[MakeHeroinegaOosugiru] +episode_index = 1 +season_number = 01 +ext_name = .mkv +torrent_name = "Make Heroine ga Oosugiru" +download_dir = /media/HDD/Jellyfin/Anime +publish_date = 24-09-15 21:29 +release_group = GlassMoon +meta = +hash = e40b7ed0662832ce1ac5201272ba4697c877d8f9 +adjusted_episode_number = 0 +guid = t680215 + +[GimaiSeikatsu] +episode_index = 1 +season_number = 01 +ext_name = .mkv +torrent_name = "Gimai Seikatsu" +download_dir = /media/HDD/Jellyfin/Anime +publish_date = 24-09-20 22:03 +release_group = GlassMoon +meta = +hash = 833ce986aae5ead89ee65f90867bb3d87fc96ea2 +adjusted_episode_number = 0 +guid = t679864 + +[OokamitoKoushinryouMerchantMeetstheWiseWolf] +episode_index = 2 +season_number = 01 +ext_name = .mkv +torrent_name = "Ookami to Koushinryou: Merchant Meets the Wise Wolf" +download_dir = /media/HDD/Jellyfin/Anime +publish_date = 24-09-17 21:48 +release_group = GlassMoon +meta = +hash = 2dc1117d464bc5a4363711b81a8027afbc456bca +adjusted_episode_number = 0 +guid = t677900 + +[demon_academy] +episode_index = 2 +season_number = 02 +ext_name = .mkv +torrent_name = "The Misfit of Demon King Academy" +download_dir = /media/HDD/Jellyfin/Anime +publish_date = 24-09-01 17:06 +release_group = FanVoxUA +meta = +hash = 4810c24d846237d638d7bfb33d6d3fba68d031d8 +adjusted_episode_number = 0 +guid = t664369 + +[AngelBeats] +episode_index = 0 +season_number = 01 +ext_name = .mkv +torrent_name = "Angel.Beats" +download_dir = /media/HDD/Jellyfin/Anime +publish_date = 24-09-19 23:53 +release_group = stark62 +meta = +hash = abb7518024aa0a875b8d0a7841121e84936e2120 +adjusted_episode_number = 0 +guid = t49611 + diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend/.vscode/extensions.json b/frontend/.vscode/extensions.json new file mode 100644 index 0000000..a7cea0b --- /dev/null +++ b/frontend/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar"] +} diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..f28eb34 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1 @@ +# Toloka2Web v2 Vue Edition diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..dde16aa --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + Vue + TS + + +
+ + + diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..1cb01ca --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,26 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "axios": "^1.7.5", + "beercss": "^3.6.13", + "material-dynamic-colors": "^1.1.2", + "vue": "^3.4.37", + "vue-router": "^4.4.3" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.1.2", + "typescript": "^5.5.3", + "vite": "^5.4.1", + "vite-plugin-pages": "^0.32.3", + "vue-tsc": "^2.0.29" + } + +} diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/frontend/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/App.vue b/frontend/src/App.vue new file mode 100644 index 0000000..7ed950c --- /dev/null +++ b/frontend/src/App.vue @@ -0,0 +1,23 @@ + + + diff --git a/frontend/src/assets/vue.svg b/frontend/src/assets/vue.svg new file mode 100644 index 0000000..770e9d3 --- /dev/null +++ b/frontend/src/assets/vue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/components/Navbar.vue b/frontend/src/components/Navbar.vue new file mode 100644 index 0000000..169be3b --- /dev/null +++ b/frontend/src/components/Navbar.vue @@ -0,0 +1,69 @@ + + + + \ No newline at end of file diff --git a/frontend/src/main.ts b/frontend/src/main.ts new file mode 100644 index 0000000..f68b06c --- /dev/null +++ b/frontend/src/main.ts @@ -0,0 +1,16 @@ +import { createApp } from 'vue' +import './style.css' +import App from './App.vue' + +import { createRouter, createWebHistory } from 'vue-router' +import routes from '~pages' + +const router = createRouter({ + history: createWebHistory(), + routes +}) + +createApp(App) + .use(router) + .mount('#app') + diff --git a/frontend/src/pages/about.vue b/frontend/src/pages/about.vue new file mode 100644 index 0000000..5c52d8a --- /dev/null +++ b/frontend/src/pages/about.vue @@ -0,0 +1,35 @@ + + + \ No newline at end of file diff --git a/frontend/src/pages/add.vue b/frontend/src/pages/add.vue new file mode 100644 index 0000000..6cd0d87 --- /dev/null +++ b/frontend/src/pages/add.vue @@ -0,0 +1,140 @@ + + + \ No newline at end of file diff --git a/frontend/src/pages/index.vue b/frontend/src/pages/index.vue new file mode 100644 index 0000000..71892ba --- /dev/null +++ b/frontend/src/pages/index.vue @@ -0,0 +1,149 @@ + + + \ No newline at end of file diff --git a/frontend/src/pages/settings.vue b/frontend/src/pages/settings.vue new file mode 100644 index 0000000..40760aa --- /dev/null +++ b/frontend/src/pages/settings.vue @@ -0,0 +1,43 @@ + + + \ No newline at end of file diff --git a/frontend/src/style.css b/frontend/src/style.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..d2bf7af --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// \ No newline at end of file diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 0000000..c54e602 --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/frontend/tsconfig.app.tsbuildinfo b/frontend/tsconfig.app.tsbuildinfo new file mode 100644 index 0000000..f0a3b1b --- /dev/null +++ b/frontend/tsconfig.app.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/main.ts","./src/vite-env.d.ts","./src/App.vue","./src/components/Navbar.vue","./src/pages/index.vue"],"version":"5.6.2"} \ No newline at end of file diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json new file mode 100644 index 0000000..0d3d714 --- /dev/null +++ b/frontend/tsconfig.node.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/frontend/tsconfig.node.tsbuildinfo b/frontend/tsconfig.node.tsbuildinfo new file mode 100644 index 0000000..98ef2f9 --- /dev/null +++ b/frontend/tsconfig.node.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./vite.config.ts"],"version":"5.6.2"} \ No newline at end of file diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..9fd224f --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import Pages from 'vite-plugin-pages' + +// https://vitejs.dev/config/ +export default ({ }) => { + return defineConfig({ + plugins: [vue(), Pages()], + server: { + proxy: { + '/api': { + // Forward frontend dev server request for /api to flask dev server + target: 'http://localhost:5000/', + } + } + }, + }) +} diff --git a/run.py b/run.py new file mode 100644 index 0000000..5d1d0fb --- /dev/null +++ b/run.py @@ -0,0 +1,3 @@ +from app import app + +app.run(port=5000) \ No newline at end of file