mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2024-11-28 06:46:13 +03:00
feat(pages): Deploy mocked demo version (#1690)
Some checks are pending
Build project and release / Run Release Please action (push) Waiting to run
Build project and release / Build VueTorrent (vuetorrent-build, ./vuetorrent, build) (push) Waiting to run
Build project and release / Build VueTorrent (vuetorrent-demo, ./vuetorrent-demo, build-demo) (push) Waiting to run
Build project and release / Push to nightly branch (push) Blocked by required conditions
Build project and release / Push to demo repo (push) Blocked by required conditions
Build project and release / Upload release to GitHub (push) Blocked by required conditions
Build project and release / Push to latest branch (push) Blocked by required conditions
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Some checks are pending
Build project and release / Run Release Please action (push) Waiting to run
Build project and release / Build VueTorrent (vuetorrent-build, ./vuetorrent, build) (push) Waiting to run
Build project and release / Build VueTorrent (vuetorrent-demo, ./vuetorrent-demo, build-demo) (push) Waiting to run
Build project and release / Push to nightly branch (push) Blocked by required conditions
Build project and release / Push to demo repo (push) Blocked by required conditions
Build project and release / Upload release to GitHub (push) Blocked by required conditions
Build project and release / Push to latest branch (push) Blocked by required conditions
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
This commit is contained in:
parent
e121cebf53
commit
f8695bf9a6
24 changed files with 98 additions and 70 deletions
57
.github/workflows/build-release.yml
vendored
57
.github/workflows/build-release.yml
vendored
|
@ -14,24 +14,28 @@ jobs:
|
|||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
actions: write
|
||||
|
||||
steps:
|
||||
- name: Run release please
|
||||
uses: google-github-actions/release-please-action@v4
|
||||
uses: googleapis/release-please-action@v4
|
||||
id: release
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
config-file: release-please-config.json
|
||||
manifest-file: .release-please-manifest.json
|
||||
|
||||
build-release:
|
||||
name: Build VueTorrent
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
actions: write
|
||||
strategy:
|
||||
matrix:
|
||||
npm-step: [ 'build', 'build-demo' ]
|
||||
include:
|
||||
- npm-step: build
|
||||
artifact-name: vuetorrent-build
|
||||
artifact-path: ./vuetorrent
|
||||
- npm-step: build-demo
|
||||
artifact-name: vuetorrent-demo
|
||||
artifact-path: ./vuetorrent-demo
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
@ -45,7 +49,7 @@ jobs:
|
|||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
key: "${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}"
|
||||
restore-keys: ${{ runner.os }}-node-
|
||||
|
||||
- name: Install dependencies
|
||||
|
@ -63,13 +67,13 @@ jobs:
|
|||
tolgee_secret: ${{ secrets.TOLGEE_TOKEN }}
|
||||
|
||||
- name: Build VueTorrent
|
||||
run: npm run build
|
||||
run: npm run ${{ matrix.npm-step }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: vuetorrent-build
|
||||
path: ./vuetorrent
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: ${{ matrix.artifact-path }}
|
||||
retention-days: 1
|
||||
|
||||
push-nightly:
|
||||
|
@ -94,9 +98,29 @@ jobs:
|
|||
branch: nightly-release
|
||||
folder: ./vuetorrent
|
||||
|
||||
push-demo:
|
||||
name: Push to demo repo
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-release
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: vuetorrent-demo
|
||||
path: ./vuetorrent-demo
|
||||
|
||||
- name: Push to demo repo
|
||||
uses: JamesIves/github-pages-deploy-action@v4.6.0
|
||||
with:
|
||||
folder: './vuetorrent-demo'
|
||||
repository-name: 'VueTorrent/demo'
|
||||
token: ${{ secrets.GH_PAT }}
|
||||
|
||||
upload-release:
|
||||
name: Upload release to GitHub
|
||||
needs: [setup-release, build-release]
|
||||
needs: [ setup-release, build-release ]
|
||||
if: needs.setup-release.outputs.release_created
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
@ -120,7 +144,7 @@ jobs:
|
|||
|
||||
push-release:
|
||||
name: Push to latest branch
|
||||
needs: [setup-release, build-release]
|
||||
needs: [ setup-release, build-release ]
|
||||
if: needs.setup-release.outputs.release_created
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
@ -135,6 +159,5 @@ jobs:
|
|||
- name: Push to latest-release
|
||||
uses: JamesIves/github-pages-deploy-action@v4.6.0
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: latest-release
|
||||
FOLDER: ./vuetorrent
|
||||
branch: latest-release
|
||||
folder: ./vuetorrent
|
||||
|
|
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
|
@ -25,8 +25,8 @@ jobs:
|
|||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: ${{ runner.os }}-node-
|
||||
key: "${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}"
|
||||
restore-keys: "${{ runner.os }}-node-"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
|
4
.github/workflows/translations.yml
vendored
4
.github/workflows/translations.yml
vendored
|
@ -26,8 +26,8 @@ jobs:
|
|||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: ${{ runner.os }}-node
|
||||
key: "${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}"
|
||||
restore-keys: "${{ runner.os }}-node"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -27,6 +27,7 @@ coverage
|
|||
|
||||
# Custom
|
||||
vuetorrent/**
|
||||
vuetorrent-demo/**
|
||||
docker/**
|
||||
coverage/
|
||||
config/
|
||||
|
|
30
README.md
30
README.md
|
@ -37,6 +37,15 @@ The sleekest looking WebUI for qBittorrent made with Vue.js!
|
|||
<img src="readme_assets/screenshot-mobile-navbar-dark-mode.png" width="400" alt="Screenshot Mobile Dashboard (Light Mode)" />
|
||||
</p>
|
||||
|
||||
## Demo
|
||||
|
||||
A live demo **with mocked data** is available here: https://vuetorrent.github.io/demo
|
||||
|
||||
> [!NOTE]
|
||||
> This version isn't connected to a qBittorrent instance.
|
||||
>
|
||||
> Don't try to download torrents or change preferences, it won't work 😉
|
||||
|
||||
## Installation
|
||||
|
||||
Checkout the [wiki](https://github.com/VueTorrent/VueTorrent/wiki/Installation)!
|
||||
|
@ -50,9 +59,9 @@ Checkout the [wiki](https://github.com/VueTorrent/VueTorrent/wiki/Installation)!
|
|||
- `docker-compose up -d` (starts a qbittorrent docker, optional)
|
||||
- Open the WebUI on localhost with the default credentials
|
||||
- Default username is always `admin`
|
||||
- Default password is `adminadmin` **on 4.6.0 and below**, and is generated on 4.6.1 and above
|
||||
- Make sure "CSRF protection" and "Host header verification" is disabled on the target server!
|
||||
- Edit `env.development` to tweak your dev environment (e.g. fake torrents)
|
||||
- Default password is `adminadmin` **on 4.6.0 and below**, and is generated in logs on 4.6.1 and above
|
||||
- Make sure "CSRF protection" and "Host header verification" is disabled in the qBittorrent preferences
|
||||
- Edit `env.development` to tweak your dev environment (e.g. mocked data)
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -89,7 +98,7 @@ Checkout the [wiki](https://github.com/VueTorrent/VueTorrent/wiki/Installation)!
|
|||
|
||||
VueTorrent is a **WebUI** (think of it as a "visual skin") that uses qBittorrent's API, enabling compatibility with automation solutions like the Servarr stack.
|
||||
|
||||
Everything that is compatible with qBittorrent will work regardless of the WebUI you chose to use.
|
||||
Everything that is compatible with the classic qBittorrent WebUI will work regardless of the WebUI you chose to use, whether its VueTorrent or another one.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -101,16 +110,13 @@ See the [Contributing Guidelines](https://github.com/VueTorrent/VueTorrent/blob/
|
|||
|
||||
## Support
|
||||
|
||||
[![Discord](https://img.shields.io/discord/1170618192956243998?logo=discord)](https://discord.gg/KDQP7fR467)
|
||||
[![Wiki](https://img.shields.io/badge/Wiki-blue)](https://github.com/VueTorrent/VueTorrent/wiki)
|
||||
[![FAQ](https://img.shields.io/badge/FAQ-orange)](https://github.com/VueTorrent/VueTorrent/wiki/FAQ)
|
||||
- [![Discord](https://img.shields.io/discord/1170618192956243998?logo=discord)](https://discord.gg/KDQP7fR467)
|
||||
- [![Wiki](https://img.shields.io/badge/Wiki-blue)](https://github.com/VueTorrent/VueTorrent/wiki)
|
||||
- [![FAQ](https://img.shields.io/badge/FAQ-orange)](https://github.com/VueTorrent/VueTorrent/wiki/FAQ)
|
||||
|
||||
Open up an issue 😛
|
||||
If any of the above didn't help, feel free to open an issue!
|
||||
|
||||
but before you do that:
|
||||
|
||||
- confirm you're on the latest version of VueTorrent
|
||||
- confirm there is no other issue mentioning the same problem
|
||||
See the [Contributing Guidelines](https://github.com/VueTorrent/VueTorrent/blob/master/.github/CONTRIBUTING.md) for more information.
|
||||
|
||||
## Funding
|
||||
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
"dev": "vite",
|
||||
"build": "vue-tsc && vite build",
|
||||
"postbuild": "node write-version.cjs",
|
||||
"build-demo": "vue-tsc && vite build -m demo",
|
||||
"check-build": "vue-tsc",
|
||||
"preview": "vite preview",
|
||||
"preview-demo": "vite preview -m demo",
|
||||
"lint": "eslint --fix && prettier . -w -u",
|
||||
"test": "vitest run",
|
||||
"coverage": "vitest run --coverage"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { DiskIOMode, DiskIOType, ResumeDataStorageType, UploadChokingAlgorithm, UploadSlotsBehavior, UtpTcpMixedMode } from '@/constants/qbit/AppPreferences'
|
||||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
import { usePreferenceStore } from '@/stores'
|
||||
import { computed, onBeforeMount, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
import IProvider from './IProvider'
|
||||
import QBitProvider from './QbitProvider'
|
||||
|
||||
async function getProvider(): Promise<IProvider> {
|
||||
if (import.meta.env.DEV && import.meta.env.VITE_USE_MOCK_PROVIDER === 'true') {
|
||||
try {
|
||||
const { default: MockProvider } = await import('./MockProvider')
|
||||
return MockProvider.getInstance()
|
||||
} catch (error) {
|
||||
console.error('Failed to load MockProvider:', error)
|
||||
return new QBitProvider()
|
||||
}
|
||||
} else {
|
||||
return new Promise(resolve => resolve(new QBitProvider()))
|
||||
}
|
||||
}
|
||||
|
||||
const qbit = await getProvider()
|
||||
|
||||
export { qbit }
|
|
@ -24,7 +24,7 @@ import IProvider from './IProvider'
|
|||
|
||||
export default class MockProvider implements IProvider {
|
||||
private static instance: MockProvider
|
||||
private static hashes: string[] = Array(parseInt(import.meta.env.VITE_FAKE_TORRENTS_COUNT))
|
||||
private static hashes: string[] = Array(parseInt(import.meta.env.VITE_FAKE_TORRENTS_COUNT || 15))
|
||||
.fill('')
|
||||
.map((_, i) => (i + 1).toString(16).padStart(40, '0'))
|
||||
|
||||
|
@ -666,7 +666,7 @@ export default class MockProvider implements IProvider {
|
|||
|
||||
async getTorrents(_?: GetTorrentPayload): Promise<Torrent[]> {
|
||||
const result = MockProvider.hashes.map(hash => {
|
||||
const added_on = faker.date.past().getTime()
|
||||
const added_on = faker.date.past().getTime() / 1000
|
||||
const name = faker.system.fileName()
|
||||
const num_complete = faker.number.int({ min: 0, max: 250 })
|
||||
const num_incomplete = faker.number.int({ min: 0, max: 250 })
|
||||
|
@ -682,7 +682,7 @@ export default class MockProvider implements IProvider {
|
|||
availability: faker.number.float({ min: 0, max: 100, multipleOf: 0.01 }),
|
||||
category: faker.helpers.arrayElement(['ISO', 'Other', 'Movie', 'Music', 'TV']),
|
||||
completed,
|
||||
completion_on: faker.date.between({ from: added_on, to: Date.now() }).getTime(),
|
||||
completion_on: faker.date.between({ from: added_on, to: Date.now() }).getTime() / 1000,
|
||||
content_path: faker.system.filePath(),
|
||||
dl_limit: faker.number.float({ min: 0, max: 1, multipleOf: 0.01 }),
|
||||
dlspeed: faker.number.int({ min: 0, max: 5_000_000 }), // [0; 5 Mo/s]
|
|
@ -25,9 +25,10 @@ import type IProvider from './IProvider'
|
|||
type Parameters = Record<string, any>
|
||||
|
||||
export default class QBitProvider implements IProvider {
|
||||
private static _instance: QBitProvider
|
||||
private axios: AxiosInstance
|
||||
|
||||
constructor() {
|
||||
private constructor() {
|
||||
this.axios = axios.create({
|
||||
baseURL: 'api/v2'
|
||||
})
|
||||
|
@ -35,6 +36,13 @@ export default class QBitProvider implements IProvider {
|
|||
this.axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
|
||||
}
|
||||
|
||||
public static getInstance() {
|
||||
if (!this._instance) {
|
||||
this._instance = new QBitProvider()
|
||||
}
|
||||
return this._instance
|
||||
}
|
||||
|
||||
/// Misc ///
|
||||
|
||||
/**
|
8
src/services/qbit/index.ts
Normal file
8
src/services/qbit/index.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import IProvider from './IProvider'
|
||||
import MockProvider from './MockProvider'
|
||||
import QBitProvider from './QbitProvider'
|
||||
|
||||
const qbit: IProvider =
|
||||
import.meta.env.MODE === 'demo' || (import.meta.env.DEV && import.meta.env.VITE_USE_MOCK_PROVIDER === 'true') ? MockProvider.getInstance() : QBitProvider.getInstance()
|
||||
|
||||
export default qbit
|
|
@ -1,4 +1,4 @@
|
|||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
|
||||
export const useAuthStore = defineStore('auth', () => {
|
||||
const isAuthenticated = ref(false)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useSearchQuery, useTreeBuilder } from '@/composables'
|
||||
import { FilePriority } from '@/constants/qbit'
|
||||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
import { useDialogStore } from '@/stores/dialog'
|
||||
import { useMaindataStore } from '@/stores/maindata'
|
||||
import { useVueTorrentStore } from '@/stores/vuetorrent'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
import { Log } from '@/types/qbit/models'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, watch } from 'vue'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useTorrentBuilder } from '@/composables'
|
||||
import { SortOptions } from '@/constants/qbit'
|
||||
import { extractHostname } from '@/helpers'
|
||||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
import { Category, ServerState } from '@/types/qbit/models'
|
||||
import { defineStore, storeToRefs } from 'pinia'
|
||||
import { MaybeRefOrGetter, ref, toValue } from 'vue'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import AppPreferences from '@/types/qbit/models/AppPreferences'
|
||||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
|
||||
export const usePreferenceStore = defineStore(
|
||||
'preferences',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
import { Feed, FeedRule } from '@/types/qbit/models'
|
||||
import { RssArticle } from '@/types/vuetorrent'
|
||||
import { AxiosError } from 'axios'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
import { SearchPlugin } from '@/types/qbit/models'
|
||||
import { SearchData } from '@/types/vuetorrent'
|
||||
import { defineStore } from 'pinia'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
import { TorrentProperties } from '@/types/qbit/models'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useSearchQuery } from '@/composables'
|
||||
import { SortOptions, TorrentState } from '@/constants/qbit'
|
||||
import { extractHostname } from '@/helpers'
|
||||
import { qbit } from '@/services'
|
||||
import qbit from '@/services/qbit'
|
||||
import { AddTorrentPayload, GetTorrentPayload } from '@/types/qbit/payloads'
|
||||
import { Torrent } from '@/types/vuetorrent'
|
||||
import { defineStore } from 'pinia'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ContentLayout } from '@/constants/qbit/AppPreferences.ts'
|
||||
import { ContentLayout } from '@/constants/qbit/AppPreferences'
|
||||
import { AddTorrentParams } from '@/types/qbit/models'
|
||||
|
||||
export interface LegacyFeedRule {
|
||||
|
|
|
@ -16,7 +16,7 @@ export default defineConfig(({ mode }) => {
|
|||
base: './',
|
||||
build: {
|
||||
target: 'esnext',
|
||||
outDir: './vuetorrent/public',
|
||||
outDir: mode === 'demo' ? './vuetorrent-demo' : './vuetorrent/public',
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
|
|
Loading…
Reference in a new issue