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 @@
+
+
+
+
+
+
+
+
+
+
+ home
+ Home
+
+
+ search
+ Search
+
+
+ settings
+ Settings
+
+
+ more_vert
+ More
+
+
+
+
+ home
+
+
+ search
+
+
+ settings
+
+
+ more_vert
+
+
+
+
\ 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 @@
+
+
+
+
+
+
+
+
![]()
+
+
+
+
{{ torrentInfo.name }}
+
+
+
+
+
+
+
+ {{ torrentInfo.description }}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 @@
+
+
+
+
+
+
+
+ done_all
+ Завантажити нові серії
+
+
+ restart_alt
+ Оновити список
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
{{ title.torrent_name }} ({{ title.codename }})
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 @@
+
+
+
+
settings Налаштування WIP
+
+
+
+
+
+
+ person Обліковий запис Tokoka.to
+
+ hub BitTorrent
+
+ comic_bubble Аніме
+
+ bug_report Дебагінг
+
+
+
+ title Toloka2Web v2 Vue Version
+
+ conversion_path v1.0.0
+
+
+
+
+
\ 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