├── .prettierrc ├── environments ├── capacitor │ └── android │ │ ├── app │ │ ├── .gitignore │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── drawable │ │ │ │ │ │ ├── splash.png │ │ │ │ │ │ └── ic_launcher_background.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── drawable-land-hdpi │ │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-mdpi │ │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-xhdpi │ │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-hdpi │ │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-mdpi │ │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-xhdpi │ │ │ │ │ │ └── splash.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── drawable-hdpi │ │ │ │ │ │ └── ic_action_name.png │ │ │ │ │ ├── drawable-land-xxhdpi │ │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-xxxhdpi │ │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-mdpi │ │ │ │ │ │ └── ic_action_name.png │ │ │ │ │ ├── drawable-port-xxhdpi │ │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-xxxhdpi │ │ │ │ │ │ └── splash.png │ │ │ │ │ ├── values │ │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── drawable-xhdpi │ │ │ │ │ │ └── ic_action_name.png │ │ │ │ │ ├── drawable-xxhdpi │ │ │ │ │ │ └── ic_action_name.png │ │ │ │ │ ├── drawable-xxxhdpi │ │ │ │ │ │ └── ic_action_name.png │ │ │ │ │ ├── xml │ │ │ │ │ │ ├── config.xml │ │ │ │ │ │ └── file_paths.xml │ │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ │ │ ├── ic_launcher.xml │ │ │ │ │ │ └── ic_launcher_round.xml │ │ │ │ │ ├── layout │ │ │ │ │ │ └── activity_main.xml │ │ │ │ │ └── drawable-v24 │ │ │ │ │ │ └── ic_launcher_foreground.xml │ │ │ │ ├── java │ │ │ │ │ └── io │ │ │ │ │ │ └── github │ │ │ │ │ │ └── zyrouge │ │ │ │ │ │ └── yukino │ │ │ │ │ │ └── MainActivity.java │ │ │ │ ├── assets │ │ │ │ │ ├── capacitor.config.json │ │ │ │ │ └── capacitor.plugins.json │ │ │ │ └── AndroidManifest.xml │ │ │ ├── test │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── getcapacitor │ │ │ │ │ └── myapp │ │ │ │ │ └── ExampleUnitTest.java │ │ │ └── androidTest │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── getcapacitor │ │ │ │ └── myapp │ │ │ │ └── ExampleInstrumentedTest.java │ │ ├── capacitor.build.gradle │ │ ├── proguard-rules.pro │ │ └── build.gradle │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── .idea │ │ ├── compiler.xml │ │ ├── misc.xml │ │ ├── runConfigurations.xml │ │ └── jarRepositories.xml │ │ ├── settings.gradle │ │ ├── variables.gradle │ │ ├── build.gradle │ │ ├── capacitor.settings.gradle │ │ ├── gradle.properties │ │ ├── .gitignore │ │ ├── gradlew.bat │ │ └── gradlew └── electron │ ├── igniter │ ├── dev-mock-update.yml │ ├── preload.js │ ├── splash.html │ └── index.js │ ├── util.js │ ├── store.js │ ├── builder.config.js │ ├── logger.js │ ├── preload.js │ ├── ipc.js │ ├── rpc.js │ └── main.js ├── resources ├── icon.png ├── large.png ├── splash.png └── android │ ├── icon-background.png │ └── icon-foreground.png ├── screenshots ├── home.png ├── anime.png ├── manga.png ├── player.png ├── search.png ├── sources.png └── episodes.png ├── src ├── env.d.ts ├── plugins │ ├── api │ │ ├── index.ts │ │ ├── initiator │ │ │ ├── index.ts │ │ │ └── capacitor.ts │ │ ├── rpc.ts │ │ ├── requester │ │ │ ├── index.ts │ │ │ └── capacitor.ts │ │ ├── store │ │ │ ├── capacitor.ts │ │ │ └── index.ts │ │ ├── externalLink.ts │ │ └── extractors.ts │ ├── types.ts │ ├── logger.ts │ ├── router.ts │ ├── icons.ts │ └── util.ts ├── shims-vue.d.ts ├── components │ ├── PageTitle.vue │ ├── Loading.vue │ ├── ExternalLink.vue │ ├── Logger.vue │ ├── TitleBar.vue │ ├── MangaSourceViewer.vue │ ├── AnimeSourceViewer.vue │ ├── SideBar.vue │ ├── LastLeft.vue │ └── AnimePlayer.vue ├── main.ts ├── assets │ └── main.css ├── App.vue └── pages │ ├── MangaSourceInfo.vue │ ├── Home.vue │ ├── AnimeSourceInfo.vue │ └── Settings.vue ├── postcss.config.js ├── .gitignore ├── scripts ├── capacitor-android-debug.js ├── capacitor-android-release.js ├── electron-dev.js └── utils │ └── capacitor-android-build.js ├── .vscode └── settings.json ├── tsconfig.json ├── tailwind.config.js ├── capacitor.config.ts ├── .github ├── FUNDING.yml └── workflows │ ├── Publish (Electron).yml │ ├── Publish (Capacitor - Android).yml │ └── codeql-analysis.yml ├── index.html ├── LICENSE ├── vite.config.ts ├── README.md └── package.json /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "useTabs": false 4 | } 5 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build/* 2 | !/build/.npmkeep 3 | -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/resources/icon.png -------------------------------------------------------------------------------- /resources/large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/resources/large.png -------------------------------------------------------------------------------- /resources/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/resources/splash.png -------------------------------------------------------------------------------- /screenshots/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/screenshots/home.png -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | interface ImportMetaEnv { 2 | VITE_PLATFORM: string | undefined; 3 | } 4 | -------------------------------------------------------------------------------- /screenshots/anime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/screenshots/anime.png -------------------------------------------------------------------------------- /screenshots/manga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/screenshots/manga.png -------------------------------------------------------------------------------- /screenshots/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/screenshots/player.png -------------------------------------------------------------------------------- /screenshots/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/screenshots/search.png -------------------------------------------------------------------------------- /screenshots/sources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/screenshots/sources.png -------------------------------------------------------------------------------- /screenshots/episodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/screenshots/episodes.png -------------------------------------------------------------------------------- /environments/electron/igniter/dev-mock-update.yml: -------------------------------------------------------------------------------- 1 | provider: github 2 | owner: zyrouge 3 | repo: yukino-app 4 | -------------------------------------------------------------------------------- /resources/android/icon-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/resources/android/icon-background.png -------------------------------------------------------------------------------- /resources/android/icon-foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/resources/android/icon-foreground.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | "@tailwindcss/jit": {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | resources/icons 7 | resources/android/icon 8 | resources/android/splash 9 | environments/electron/logs -------------------------------------------------------------------------------- /environments/capacitor/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/plugins/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./extractors"; 2 | export * from "./requester"; 3 | export * from "./store"; 4 | export * from "./rpc"; 5 | export * from "./externalLink"; 6 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue' 3 | const component: DefineComponent<{}, {}, any> 4 | export default component 5 | } 6 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-land-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-land-hdpi/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-land-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-land-mdpi/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-land-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-land-xhdpi/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-port-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-port-hdpi/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-port-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-port-mdpi/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-port-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-port-xhdpi/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-hdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-hdpi/ic_action_name.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-land-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-land-xxhdpi/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-land-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-land-xxxhdpi/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-mdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-mdpi/ic_action_name.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-port-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-port-xxhdpi/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-port-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-port-xxxhdpi/splash.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-xhdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-xhdpi/ic_action_name.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-xxhdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-xxhdpi/ic_action_name.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-xxxhdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/drawable-xxxhdpi/ic_action_name.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhygg/yukino-app/HEAD/environments/capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /environments/capacitor/android/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/java/io/github/zyrouge/yukino/MainActivity.java: -------------------------------------------------------------------------------- 1 | package io.github.zyrouge.yukino; 2 | 3 | import com.getcapacitor.BridgeActivity; 4 | 5 | public class MainActivity extends BridgeActivity {} 6 | -------------------------------------------------------------------------------- /scripts/capacitor-android-debug.js: -------------------------------------------------------------------------------- 1 | const builder = require("./utils/capacitor-android-build"); 2 | 3 | const start = async () => { 4 | const out = await builder("debug"); 5 | console.log(`Output apk can be found at: ${out}`); 6 | }; 7 | 8 | start(); 9 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/xml/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /scripts/capacitor-android-release.js: -------------------------------------------------------------------------------- 1 | const builder = require("./utils/capacitor-android-build"); 2 | 3 | const start = async () => { 4 | const out = await builder("release"); 5 | console.log(`Output apk can be found at: ${out}`); 6 | }; 7 | 8 | start(); 9 | -------------------------------------------------------------------------------- /environments/capacitor/android/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /environments/capacitor/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | include ':capacitor-cordova-android-plugins' 3 | project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') 4 | 5 | apply from: 'capacitor.settings.gradle' -------------------------------------------------------------------------------- /environments/capacitor/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/components/PageTitle.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "files.watcherExclude": { 4 | "**/.git/objects/**": true, 5 | "**/.git/subtree-cache/**": true, 6 | "**/node_modules/*/**": true, 7 | "**/.hg/store/**": true, 8 | "**/environments/capacitor/android/**": true 9 | } 10 | } -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Yukino 4 | Yukino 5 | io.github.zyrouge.yukino 6 | io.github.zyrouge.yukino 7 | 8 | -------------------------------------------------------------------------------- /environments/capacitor/android/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /src/plugins/api/initiator/index.ts: -------------------------------------------------------------------------------- 1 | export type InitiatorFn = () => Promise; 2 | 3 | const noop: InitiatorFn = async () => {}; 4 | 5 | export const Initiator = { 6 | async getClient() { 7 | switch (app_platform) { 8 | case "capacitor": 9 | return (await import("./capacitor")).initiator; 10 | 11 | default: 12 | return noop; 13 | } 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "jsx": "preserve", 8 | "sourceMap": true, 9 | "resolveJsonModule": true, 10 | "esModuleInterop": true, 11 | "lib": ["esnext", "dom"], 12 | "types": ["vite/client"] 13 | }, 14 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] 15 | } 16 | -------------------------------------------------------------------------------- /src/plugins/types.ts: -------------------------------------------------------------------------------- 1 | export interface LastLeftEntity { 2 | title: string; 3 | episode?: { 4 | episode: string; 5 | watched: number; 6 | total: number; 7 | }; 8 | reading?: { 9 | volume: string; 10 | chapter: string; 11 | read: string; 12 | total: string; 13 | }; 14 | updatedAt: number; 15 | route: { 16 | route: string; 17 | queries: Record; 18 | }; 19 | showPopup: boolean; 20 | } 21 | -------------------------------------------------------------------------------- /environments/capacitor/android/variables.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | minSdkVersion = 21 3 | compileSdkVersion = 30 4 | targetSdkVersion = 30 5 | androidxActivityVersion = '1.2.0' 6 | androidxAppCompatVersion = '1.2.0' 7 | androidxCoordinatorLayoutVersion = '1.1.0' 8 | androidxCoreVersion = '1.3.2' 9 | androidxFragmentVersion = '1.3.0' 10 | junitVersion = '4.13.1' 11 | androidxJunitVersion = '1.1.2' 12 | androidxEspressoCoreVersion = '3.3.0' 13 | cordovaAndroidVersion = '7.0.0' 14 | } -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/assets/capacitor.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId": "io.github.zyrouge.yukino", 3 | "appName": "Yukino", 4 | "webDir": "dist/vite", 5 | "android": { 6 | "path": "environments/capacitor/android" 7 | }, 8 | "plugins": { 9 | "SplashScreen": { 10 | "androidScaleType": "CENTER_CROP", 11 | "launchAutoHide": false, 12 | "splashImmersive": false, 13 | "splashFullScreen": false, 14 | "backgroundColor": "#18181b", 15 | "showSpinner": false 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/plugins/api/rpc.ts: -------------------------------------------------------------------------------- 1 | export type RpcEntity = (act: any) => void; 2 | 3 | export const Rpc = { 4 | __rpc: null, 5 | async getClient() { 6 | if (!this.__rpc) { 7 | switch (app_platform) { 8 | case "electron": 9 | this.__rpc = window.PlatformBridge.rpc; 10 | break; 11 | 12 | default: 13 | break; 14 | } 15 | } 16 | 17 | return this.__rpc; 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const colors = require("tailwindcss/colors"); 2 | 3 | module.exports = { 4 | purge: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx,css}"], 5 | darkMode: "class", 6 | theme: { 7 | fontFamily: { 8 | sans: ["Poppins", "sans-serif"], 9 | }, 10 | extend: { 11 | colors: { 12 | gray: colors.gray, 13 | indigo: colors.indigo, 14 | }, 15 | }, 16 | }, 17 | variants: { 18 | extend: {}, 19 | }, 20 | plugins: [], 21 | }; 22 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.myapp; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | 14 | @Test 15 | public void addition_isCorrect() throws Exception { 16 | assertEquals(4, 2 + 2); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /src/plugins/logger.ts: -------------------------------------------------------------------------------- 1 | export type LoggerTypes = "info" | "error" | "warn"; 2 | 3 | export type EventListener = (type: LoggerTypes, msg: string) => any; 4 | 5 | class Logger { 6 | listeners: EventListener[]; 7 | 8 | constructor() { 9 | this.listeners = []; 10 | } 11 | 12 | on(handler: EventListener) { 13 | this.listeners.push(handler); 14 | } 15 | 16 | emit(type: LoggerTypes, msg: string) { 17 | this.listeners.forEach((handler) => { 18 | try { 19 | handler(type, msg); 20 | } catch (err) {} 21 | }); 22 | } 23 | } 24 | 25 | export default Logger; 26 | -------------------------------------------------------------------------------- /environments/electron/util.js: -------------------------------------------------------------------------------- 1 | module.exports.merge2Obj = (one, two) => { 2 | for (const key in two) { 3 | if (Object.prototype.hasOwnProperty.call(two, key)) { 4 | const ele = two[key]; 5 | if (Array.isArray(ele)) 6 | Array.isArray(ele) ? one[key].push(...ele) : one[key].push(ele); 7 | else if (typeof ele === "object") 8 | one[key] = module.exports.merge2Obj(one[key], ele); 9 | else one[key] = ele; 10 | } 11 | } 12 | return one; 13 | }; 14 | 15 | module.exports.mergeObj = (res, ...objs) => { 16 | objs.forEach((obj) => module.exports.merge2Obj(res, obj)); 17 | return res; 18 | }; 19 | -------------------------------------------------------------------------------- /src/plugins/api/requester/index.ts: -------------------------------------------------------------------------------- 1 | import { Requester } from "anime-ext/dist/types"; 2 | 3 | export const http = { 4 | __http: null, 5 | async getClient() { 6 | if (!this.__http) { 7 | switch (app_platform) { 8 | case "electron": 9 | this.__http = window.PlatformBridge.http; 10 | break; 11 | 12 | case "capacitor": 13 | this.__http = (await import("./capacitor")).requester; 14 | break; 15 | 16 | default: 17 | break; 18 | } 19 | } 20 | 21 | return this.__http; 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/plugins/api/store/capacitor.ts: -------------------------------------------------------------------------------- 1 | import { SecureStoragePlugin } from "capacitor-secure-storage-plugin"; 2 | import { StoreEntity } from "./"; 3 | 4 | export const Store: StoreEntity = { 5 | async get(key) { 6 | try { 7 | const { value } = await SecureStoragePlugin.get({ 8 | key, 9 | }); 10 | return JSON.parse(value); 11 | } catch (err) { 12 | return null; 13 | } 14 | }, 15 | async set(key, value) { 16 | try { 17 | await SecureStoragePlugin.set({ 18 | key, 19 | value: JSON.stringify(value), 20 | }); 21 | } catch (err) {} 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /capacitor.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { CapacitorConfig } from "@capacitor/cli"; 4 | import { productName } from "./package.json"; 5 | 6 | const config: CapacitorConfig = { 7 | appId: "io.github.zyrouge.yukino", 8 | appName: productName, 9 | webDir: "dist/vite", 10 | android: { 11 | path: "environments/capacitor/android", 12 | }, 13 | plugins: { 14 | SplashScreen: { 15 | androidScaleType: "CENTER_CROP", 16 | launchAutoHide: false, 17 | splashImmersive: false, 18 | splashFullScreen: false, 19 | backgroundColor: "#18181b", 20 | showSpinner: false, 21 | }, 22 | }, 23 | }; 24 | 25 | export default config; 26 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: zyrouge # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /environments/capacitor/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:4.2.1' 11 | classpath 'com.google.gms:google-services:4.3.5' 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | apply from: "variables.gradle" 19 | 20 | allprojects { 21 | repositories { 22 | google() 23 | jcenter() 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /src/plugins/api/store/index.ts: -------------------------------------------------------------------------------- 1 | export interface StoreEntity { 2 | set(key: string, value: any): Promise; 3 | get(key: string): Promise; 4 | } 5 | 6 | export const Store = { 7 | __store: null, 8 | async getClient() { 9 | if (!this.__store) { 10 | switch (app_platform) { 11 | case "electron": 12 | this.__store = window.PlatformBridge.store; 13 | break; 14 | 15 | case "capacitor": 16 | this.__store = (await import("./capacitor")).Store; 17 | break; 18 | 19 | default: 20 | break; 21 | } 22 | } 23 | 24 | return this.__store; 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/assets/capacitor.plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pkg": "@capacitor-community/http", 4 | "classpath": "com.getcapacitor.plugin.http.Http" 5 | }, 6 | { 7 | "pkg": "@capacitor/app", 8 | "classpath": "com.capacitorjs.plugins.app.AppPlugin" 9 | }, 10 | { 11 | "pkg": "@capacitor/browser", 12 | "classpath": "com.capacitorjs.plugins.browser.BrowserPlugin" 13 | }, 14 | { 15 | "pkg": "@capacitor/dialog", 16 | "classpath": "com.capacitorjs.plugins.dialog.DialogPlugin" 17 | }, 18 | { 19 | "pkg": "@capacitor/splash-screen", 20 | "classpath": "com.capacitorjs.plugins.splashscreen.SplashScreenPlugin" 21 | }, 22 | { 23 | "pkg": "capacitor-secure-storage-plugin", 24 | "classpath": "com.whitestein.securestorage.SecureStoragePlugin" 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /src/plugins/api/externalLink.ts: -------------------------------------------------------------------------------- 1 | export type ExternalLinkEntity = (url: string) => Promise; 2 | 3 | export const ExternalLink = { 4 | __opener: null, 5 | async getClient() { 6 | if (!this.__opener) { 7 | switch (app_platform) { 8 | case "electron": 9 | this.__opener = window.PlatformBridge.openExternalLink; 10 | break; 11 | 12 | case "capacitor": { 13 | const { Browser } = await import("@capacitor/browser"); 14 | this.__opener = (url: string) => Browser.open({ url }); 15 | } 16 | 17 | default: 18 | break; 19 | } 20 | } 21 | 22 | return this.__opener; 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/capacitor.build.gradle: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN 2 | 3 | android { 4 | compileOptions { 5 | sourceCompatibility JavaVersion.VERSION_1_8 6 | targetCompatibility JavaVersion.VERSION_1_8 7 | } 8 | } 9 | 10 | apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" 11 | dependencies { 12 | implementation project(':capacitor-community-http') 13 | implementation project(':capacitor-app') 14 | implementation project(':capacitor-browser') 15 | implementation project(':capacitor-dialog') 16 | implementation project(':capacitor-splash-screen') 17 | implementation project(':capacitor-secure-storage-plugin') 18 | 19 | } 20 | 21 | 22 | if (hasProperty('postBuildExtras')) { 23 | postBuildExtras() 24 | } 25 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | {{ head }} 19 | 20 | 21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /src/plugins/router.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router"; 2 | 3 | const routes: RouteRecordRaw[] = [ 4 | { path: "/", component: () => import("../pages/Home.vue") }, 5 | { path: "/search", component: () => import("../pages/Search.vue") }, 6 | { 7 | path: "/anime", 8 | component: () => import("../pages/Anime.vue"), 9 | }, 10 | { 11 | path: "/anime/source", 12 | component: () => import("../pages/AnimeSourceInfo.vue"), 13 | }, 14 | { 15 | path: "/manga/source", 16 | component: () => import("../pages/MangaSourceInfo.vue"), 17 | }, 18 | { 19 | path: "/settings", 20 | component: () => import("../pages/Settings.vue"), 21 | }, 22 | ]; 23 | 24 | const router = createRouter({ 25 | history: createWebHashHistory(), 26 | routes, 27 | }); 28 | 29 | export default router; 30 | -------------------------------------------------------------------------------- /environments/electron/store.js: -------------------------------------------------------------------------------- 1 | const Store = require("electron-store"); 2 | 3 | class DataStore { 4 | constructor() { 5 | this.store = new Store(); 6 | } 7 | 8 | /** 9 | * @returns {ReturnType & { isMaximized: boolean; }} 10 | */ 11 | getWindowSize() { 12 | const data = this.store.get("window_size"); 13 | 14 | return ( 15 | data || { 16 | x: undefined, 17 | y: undefined, 18 | width: 800, 19 | height: 600, 20 | isMaximized: false, 21 | } 22 | ); 23 | } 24 | 25 | /** 26 | * @param {ReturnType & { isMaximized: boolean; }} size 27 | */ 28 | setWindowSize(size) { 29 | this.store.set("window_size", size); 30 | } 31 | } 32 | 33 | module.exports = new DataStore(); 34 | -------------------------------------------------------------------------------- /src/components/Loading.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | 26 | 45 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.myapp; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import android.content.Context; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | import androidx.test.platform.app.InstrumentationRegistry; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * @see Testing documentation 15 | */ 16 | @RunWith(AndroidJUnit4.class) 17 | public class ExampleInstrumentedTest { 18 | 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 23 | 24 | assertEquals("com.getcapacitor.app", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/components/ExternalLink.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 38 | -------------------------------------------------------------------------------- /environments/electron/builder.config.js: -------------------------------------------------------------------------------- 1 | const { productName } = require("../../package.json"); 2 | 3 | module.exports = { 4 | productName, 5 | appId: "io.github.zyrouge.yukino", 6 | copyright: "Copyright © 2021 Zyrouge", 7 | files: [ 8 | "dist/vite/**/*", 9 | "resources/**/*", 10 | "environments/electron/**/*", 11 | "node_modules/**/*", 12 | "package.json", 13 | ], 14 | directories: { 15 | buildResources: "resources", 16 | output: "dist/electron", 17 | }, 18 | extraMetadata: { 19 | main: "environments/electron/main.js", 20 | }, 21 | publish: ["github"], 22 | win: { 23 | target: "nsis", 24 | }, 25 | nsis: { 26 | oneClick: false, 27 | allowToChangeInstallationDirectory: true, 28 | }, 29 | linux: { 30 | target: "AppImage", 31 | }, 32 | mac: { 33 | target: "dmg", 34 | category: "public.app-category.entertainment", 35 | }, 36 | generateUpdatesFilesForAllChannels: true, 37 | }; 38 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | import "./assets/main.css"; 4 | 5 | import Icon from "./plugins/icons"; 6 | import Router from "./plugins/router"; 7 | import Logger from "./plugins/logger"; 8 | import { Initiator } from "./plugins/api/initiator"; 9 | 10 | const app = createApp(App); 11 | 12 | const start = async () => { 13 | document.title = app_name; 14 | 15 | app.component("Icon", Icon); 16 | app.use(Router); 17 | app.config.globalProperties.$logger = new Logger(); 18 | app.mount("#app"); 19 | 20 | const initiator = await Initiator.getClient(); 21 | await initiator(); 22 | }; 23 | 24 | start(); 25 | 26 | declare global { 27 | const app_name: string; 28 | const app_platform: string; 29 | const app_version: string; 30 | const app_builtAt: number; 31 | 32 | interface Window { 33 | PlatformBridge?: any; 34 | } 35 | } 36 | 37 | declare module "@vue/runtime-core" { 38 | export interface ComponentCustomProperties { 39 | $logger: Logger; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 17 | 18 | 19 | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ZYROUGE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /environments/electron/logger.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const fs = require("fs"); 3 | const { app } = require("electron"); 4 | 5 | const logDir = path.join(app.getPath("appData"), app.getName()); 6 | 7 | const isDev = process.env.NODE_ENV === "development"; 8 | 9 | class Logger { 10 | constructor() { 11 | fs.mkdirSync(logDir, { 12 | recursive: true, 13 | }); 14 | 15 | this.file = fs.createWriteStream(path.join(logDir, "logger.log")); 16 | } 17 | 18 | debug(txt) { 19 | this.write(`[${Logger.time} DBUG] ${txt}`); 20 | } 21 | 22 | info(txt) { 23 | this.write(`[${Logger.time} INFO] ${txt}`); 24 | } 25 | 26 | error(txt) { 27 | this.write(`[${Logger.time} ERR!] ${txt}`); 28 | } 29 | 30 | warn(txt) { 31 | this.write(`[${Logger.time} WARN] ${txt}`); 32 | } 33 | 34 | write(txt) { 35 | if (this.file && this.file.writable) this.file.write(`${txt}\n`); 36 | if (isDev) console.log(txt); 37 | } 38 | 39 | static get time() { 40 | return new Date().toLocaleString(); 41 | } 42 | } 43 | 44 | module.exports = new Logger(); 45 | -------------------------------------------------------------------------------- /environments/capacitor/android/capacitor.settings.gradle: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN 2 | include ':capacitor-android' 3 | project(':capacitor-android').projectDir = new File('../../../node_modules/@capacitor/android/capacitor') 4 | 5 | include ':capacitor-community-http' 6 | project(':capacitor-community-http').projectDir = new File('../../../node_modules/@capacitor-community/http/android') 7 | 8 | include ':capacitor-app' 9 | project(':capacitor-app').projectDir = new File('../../../node_modules/@capacitor/app/android') 10 | 11 | include ':capacitor-browser' 12 | project(':capacitor-browser').projectDir = new File('../../../node_modules/@capacitor/browser/android') 13 | 14 | include ':capacitor-dialog' 15 | project(':capacitor-dialog').projectDir = new File('../../../node_modules/@capacitor/dialog/android') 16 | 17 | include ':capacitor-splash-screen' 18 | project(':capacitor-splash-screen').projectDir = new File('../../../node_modules/@capacitor/splash-screen/android') 19 | 20 | include ':capacitor-secure-storage-plugin' 21 | project(':capacitor-secure-storage-plugin').projectDir = new File('../../../node_modules/capacitor-secure-storage-plugin/android') 22 | -------------------------------------------------------------------------------- /environments/capacitor/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | # AndroidX package structure to make it clearer which packages are bundled with the 20 | # Android operating system, and which are packaged with your app's APK 21 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 22 | android.useAndroidX=true 23 | # Automatically convert third-party libraries to use AndroidX 24 | android.enableJetifier=true 25 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import vue from "@vitejs/plugin-vue"; 3 | import { productName, version } from "./package.json"; 4 | 5 | const platform = process.env.YUKINO_PLATFORM || "unknown"; 6 | 7 | export default defineConfig({ 8 | base: getBase(platform), 9 | plugins: [ 10 | vue(), 11 | { 12 | name: "transform-html", 13 | enforce: "pre", 14 | transformIndexHtml(html) { 15 | html = html.replace("{{ head }}", getHead(platform)); 16 | return html; 17 | }, 18 | }, 19 | ], 20 | build: { 21 | outDir: "dist/vite", 22 | }, 23 | define: { 24 | app_name: `"${productName}"`, 25 | app_platform: `"${platform}"`, 26 | app_version: `"${version}"`, 27 | app_builtAt: Date.now(), 28 | }, 29 | }); 30 | 31 | function getBase(platform: string) { 32 | switch (platform) { 33 | case "electron": 34 | return "./"; 35 | 36 | default: 37 | return "/"; 38 | } 39 | } 40 | 41 | function getHead(platform: string) { 42 | const head: string[] = []; 43 | 44 | return head.join("\n"); 45 | } 46 | -------------------------------------------------------------------------------- /scripts/electron-dev.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const spawn = require("cross-spawn"); 3 | const { createServer } = require("vite"); 4 | const pkgJson = require("../package.json"); 5 | 6 | const PORT = process.env.PORT ? +process.env.PORT : 3000; 7 | 8 | const start = async () => { 9 | process.env.NODE_ENV = "development"; 10 | process.env.VITE_SERVE_URL = `http://localhost:${PORT}`; 11 | 12 | const server = await createServer({ 13 | root: path.resolve(__dirname, ".."), 14 | server: { 15 | port: PORT, 16 | }, 17 | }); 18 | 19 | await server.listen(); 20 | 21 | const electronStart = "electron:start"; 22 | if (!electronStart in pkgJson.scripts) 23 | throw new Error("Missing 'scripts.electron:start' in package.json"); 24 | 25 | const electronProcess = spawn(`yarn ${electronStart}`, { 26 | stdio: "inherit", 27 | }); 28 | 29 | electronProcess.on("error", (err) => { 30 | console.error(err); 31 | }); 32 | 33 | electronProcess.on("exit", (code) => { 34 | console.warn(`Electron process exited with code ${code}! Exiting...`); 35 | process.exit(code); 36 | }); 37 | }; 38 | 39 | start(); 40 | -------------------------------------------------------------------------------- /scripts/utils/capacitor-android-build.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const spawn = require("cross-spawn"); 3 | 4 | const androidRoot = path.resolve( 5 | __dirname, 6 | "..", 7 | "..", 8 | "environments", 9 | "capacitor", 10 | "android" 11 | ); 12 | 13 | /** 14 | * @param {"debug" | "release"} mode 15 | * @returns {Promise} 16 | */ 17 | module.exports = (mode) => 18 | new Promise((resolve, reject) => { 19 | const allowed = ["debug", "release"]; 20 | if (!allowed.includes(mode)) 21 | return reject(`Invalid build mode: ${mode}`); 22 | 23 | const buildProcess = spawn( 24 | "gradlew", 25 | [ 26 | `assemble${mode.charAt(0).toUpperCase()}${mode.slice(1)}`, 27 | "--rerun-tasks", 28 | ], 29 | { 30 | stdio: "inherit", 31 | cwd: androidRoot, 32 | } 33 | ); 34 | 35 | buildProcess.on("close", () => { 36 | return resolve( 37 | path.join(androidRoot, "app", "build", "outputs", "apk", mode) 38 | ); 39 | }); 40 | 41 | buildProcess.on("error", (err) => { 42 | return reject(err); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /environments/capacitor/android/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /src/plugins/icons.ts: -------------------------------------------------------------------------------- 1 | import { library, config } from "@fortawesome/fontawesome-svg-core"; 2 | import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; 3 | import { 4 | faHome, 5 | faSearch, 6 | faExternalLinkAlt, 7 | faArrowUp, 8 | faCaretLeft, 9 | faCaretRight, 10 | faCaretDown, 11 | faInfoCircle, 12 | faExclamationCircle, 13 | faQuestionCircle, 14 | faPlay, 15 | faExpandAlt, 16 | faTimes, 17 | faRedo, 18 | faArrowLeft, 19 | faArrowRight, 20 | faCog, 21 | faHeart, 22 | faSortAmountUp, 23 | faSyncAlt, 24 | faEye, 25 | faEyeSlash, 26 | faTrash, 27 | } from "@fortawesome/free-solid-svg-icons"; 28 | import { 29 | faSnowflake, 30 | faWindowMinimize, 31 | faWindowMaximize, 32 | } from "@fortawesome/free-regular-svg-icons"; 33 | 34 | config.searchPseudoElements = true; 35 | 36 | library.add( 37 | faHome, 38 | faSearch, 39 | faSnowflake, 40 | faExternalLinkAlt, 41 | faArrowUp, 42 | faCaretLeft, 43 | faCaretRight, 44 | faCaretDown, 45 | faInfoCircle, 46 | faExclamationCircle, 47 | faQuestionCircle, 48 | faPlay, 49 | faWindowMinimize, 50 | faExpandAlt, 51 | faWindowMaximize, 52 | faTimes, 53 | faRedo, 54 | faArrowLeft, 55 | faArrowRight, 56 | faCog, 57 | faHeart, 58 | faSortAmountUp, 59 | faSyncAlt, 60 | faEye, 61 | faEyeSlash, 62 | faTrash 63 | ); 64 | 65 | export default FontAwesomeIcon; 66 | -------------------------------------------------------------------------------- /environments/electron/igniter/preload.js: -------------------------------------------------------------------------------- 1 | const { ipcRenderer } = require("electron"); 2 | 3 | document.addEventListener("DOMContentLoaded", () => { 4 | const queries = new URLSearchParams(location.search); 5 | 6 | document.title = document.getElementById("hero-title").innerText = 7 | queries.get("title"); 8 | 9 | document.getElementById("currentVersion").innerText = 10 | queries.get("version"); 11 | 12 | const state = document.getElementById("status"); 13 | const progressParent = document.getElementById("progress"); 14 | const progressBar = document.getElementById("progress-bar"); 15 | 16 | ipcRenderer.on("checking-for-update", (e) => { 17 | state.innerHTML = `Checking for update...`; 18 | }); 19 | 20 | ipcRenderer.on("new-update", (e, version) => { 21 | progressParent.style.display = "block"; 22 | state.innerHTML = `New version found ${version}!`; 23 | }); 24 | 25 | ipcRenderer.on("download-progress", (e, progress) => { 26 | state.innerHTML = `Downloaded ${progress.transferred}Mb of ${progress.total}Mb`; 27 | progressBar.style.width = `${progress.percent}%`; 28 | }); 29 | 30 | ipcRenderer.on("update-downloaded", (e) => { 31 | state.innerHTML = "Updated has been downloaded!"; 32 | progressParent.style.display = "none"; 33 | }); 34 | 35 | ipcRenderer.on("error", (e, err) => { 36 | state.innerHTML = `Error: ${err}!`; 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/plugins/api/initiator/capacitor.ts: -------------------------------------------------------------------------------- 1 | import { App } from "@capacitor/app"; 2 | import { SplashScreen } from "@capacitor/splash-screen"; 3 | import { Dialog } from "@capacitor/dialog"; 4 | import { InitiatorFn } from "./"; 5 | import Router from "../../router"; 6 | import { http } from "../requester"; 7 | import { ExternalLink } from "../externalLink"; 8 | 9 | export const initiator: InitiatorFn = async () => { 10 | await SplashScreen.hide(); 11 | 12 | App.addListener("backButton", () => { 13 | try { 14 | Router.go(-1); 15 | } catch (err) {} 16 | }); 17 | 18 | notifyUpdate(); 19 | }; 20 | 21 | async function notifyUpdate() { 22 | try { 23 | const client = await http.getClient(); 24 | const latest: any = JSON.parse( 25 | await client.get( 26 | "https://api.github.com/repos/zyrouge/yukino-app/releases/latest", 27 | { 28 | headers: {}, 29 | } 30 | ) 31 | ); 32 | 33 | if (latest && !latest.draft && app_version !== latest.name) { 34 | const { value } = await Dialog.confirm({ 35 | title: "Update", 36 | message: `Newer version of the app is available! (v${app_version} -> v${latest.name})\nWould you like to download it?`, 37 | }); 38 | 39 | if (value) { 40 | const opener = await ExternalLink.getClient(); 41 | opener?.(latest.html_url); 42 | } 43 | } 44 | } catch (err) {} 45 | } 46 | -------------------------------------------------------------------------------- /src/plugins/util.ts: -------------------------------------------------------------------------------- 1 | export type Await = T extends Promise ? U : T; 2 | 3 | export type StateStates = "waiting" | "resolving" | "resolved" | "failed"; 4 | 5 | export interface StateController { 6 | state: StateStates; 7 | data: T | null; 8 | } 9 | 10 | export interface StateControllerNoNull { 11 | state: StateStates; 12 | data: T; 13 | } 14 | 15 | export const util = { 16 | getHighResMALImage(url: string) { 17 | return url.replace( 18 | /(https:\/\/cdn\.myanimelist\.net\/).*(images.*)\?.*/g, 19 | "$1$2" 20 | ); 21 | }, 22 | getValidImageUrl(url: string) { 23 | if (url.startsWith("//")) url = `https:${url}`; 24 | if (url.startsWith("http:")) url = url.replace("http:", "https:"); 25 | return url; 26 | }, 27 | createStateController() { 28 | return >{ 29 | state: "waiting", 30 | data: null, 31 | }; 32 | }, 33 | createStateControllerNoNull(data: T) { 34 | return >{ 35 | state: "waiting", 36 | data, 37 | }; 38 | }, 39 | parseMs: (ms: number) => { 40 | let secs = ms / 1000; 41 | const days = secs / (24 * 60 * 60); 42 | secs %= 24 * 60 * 60; 43 | const hours = secs / (60 * 60); 44 | secs %= 60 * 60; 45 | const mins = secs / 60; 46 | secs %= 60; 47 | return { 48 | days: Math.trunc(days), 49 | hours: Math.trunc(hours), 50 | mins: Math.trunc(mins), 51 | secs: Math.trunc(secs), 52 | }; 53 | }, 54 | }; 55 | -------------------------------------------------------------------------------- /.github/workflows/Publish (Electron).yml: -------------------------------------------------------------------------------- 1 | name: Publish (Electron) 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | windows: 11 | runs-on: windows-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - uses: actions/setup-node@v2 17 | with: 18 | node-version: "14.16.0" 19 | 20 | - name: Install dependencies 21 | run: yarn --dev 22 | 23 | - name: Publish 24 | run: yarn electron:publish -w 25 | env: 26 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | 28 | linux: 29 | runs-on: ubuntu-latest 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - uses: actions/setup-node@v2 35 | with: 36 | node-version: "14.16.0" 37 | 38 | - name: Install dependencies 39 | run: yarn --dev 40 | 41 | - name: Publish 42 | run: yarn electron:publish -l 43 | env: 44 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | 46 | mac: 47 | runs-on: macos-latest 48 | 49 | steps: 50 | - uses: actions/checkout@v2 51 | 52 | - uses: actions/setup-node@v2 53 | with: 54 | node-version: "14.16.0" 55 | 56 | - name: Install dependencies 57 | run: yarn --dev 58 | 59 | - name: Publish 60 | run: yarn electron:publish -m 61 | env: 62 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 63 | -------------------------------------------------------------------------------- /environments/electron/preload.js: -------------------------------------------------------------------------------- 1 | const { contextBridge, ipcRenderer } = require("electron"); 2 | 3 | const PlatformBridge = { 4 | rpc: (act) => ipcRenderer.invoke("Rpc-Set", act), 5 | store: { 6 | get: (key) => ipcRenderer.invoke("Store-Get", key), 7 | set: (key, data) => ipcRenderer.invoke("Store-Set", key, data), 8 | }, 9 | http: { 10 | get: (url, options) => ipcRenderer.invoke("Request-get", url, options), 11 | post: (url, body, options) => 12 | ipcRenderer.invoke("Request-post", url, body, options), 13 | }, 14 | openExternalLink: (url) => ipcRenderer.invoke("Open-Externally", url), 15 | }; 16 | 17 | contextBridge.exposeInMainWorld("PlatformBridge", PlatformBridge); 18 | 19 | document.addEventListener("DOMContentLoaded", () => { 20 | const minimizeBtn = document.getElementById("titlebar-minimize"); 21 | const maximizeBtn = document.getElementById("titlebar-maximize"); 22 | const closeBtn = document.getElementById("titlebar-close"); 23 | const reloadBtn = document.getElementById("titlebar-reload"); 24 | 25 | if (minimizeBtn) 26 | minimizeBtn.addEventListener("click", () => { 27 | ipcRenderer.invoke("minimize-window"); 28 | }); 29 | 30 | if (maximizeBtn) 31 | maximizeBtn.addEventListener("click", () => { 32 | ipcRenderer.invoke("toggle-maximize-window"); 33 | }); 34 | 35 | if (closeBtn) 36 | closeBtn.addEventListener("click", () => { 37 | ipcRenderer.invoke("close-window"); 38 | }); 39 | 40 | if (reloadBtn) 41 | reloadBtn.addEventListener("click", () => { 42 | ipcRenderer.invoke("reload-window"); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /src/assets/main.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | margin: 0; 8 | padding: 0; 9 | } 10 | 11 | body { 12 | @apply bg-white dark:bg-gray-900 text-gray-800 dark:text-white font-sans overflow-x-hidden; 13 | } 14 | 15 | hr { 16 | @apply border-gray-600; 17 | } 18 | 19 | .panel { 20 | @apply dark:bg-gray-800 px-8 py-6 shadow rounded; 21 | } 22 | 23 | .text-box { 24 | @apply focus:outline-none ring-2 ring-gray-100 dark:ring-gray-800 bg-gray-100 dark:bg-gray-800 focus:ring-indigo-500 dark:focus:ring-indigo-500 rounded-sm px-3 py-1.5 transition duration-300; 25 | } 26 | 27 | .btn { 28 | @apply text-white bg-indigo-500 hover:bg-indigo-600 px-3 py-2 focus:outline-none rounded transition duration-300; 29 | } 30 | 31 | .hover-pop { 32 | transition: 0.2s; 33 | } 34 | 35 | .hover-pop:hover { 36 | transform: scale(1.015); 37 | } 38 | 39 | .select { 40 | @apply appearance-none relative flex flex-row justify-center items-center bg-gray-100 dark:bg-gray-800 rounded; 41 | } 42 | 43 | .select select { 44 | background: inherit; 45 | color: inherit; 46 | 47 | @apply appearance-none w-full bg-gray-100 dark:bg-gray-800 focus:outline-none pr-7 pl-3 py-2 rounded cursor-pointer; 48 | } 49 | 50 | .select::after { 51 | content: ""; 52 | clip-path: polygon(100% 0, 0 0, 50% 70%); 53 | 54 | @apply absolute pointer-events-none mt-0.5 right-3 bg-black dark:bg-white w-2.5 h-2.5; 55 | } 56 | 57 | ::-webkit-scrollbar { 58 | width: 8px; 59 | } 60 | 61 | ::-webkit-scrollbar-track { 62 | @apply bg-gray-100 dark:bg-gray-800; 63 | } 64 | 65 | ::-webkit-scrollbar-thumb { 66 | @apply bg-gray-300 dark:bg-gray-700 hover:bg-gray-400 dark:hover:bg-gray-600 rounded-full; 67 | } 68 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /environments/electron/ipc.js: -------------------------------------------------------------------------------- 1 | const { shell, dialog } = require("electron"); 2 | const got = require("got").default; 3 | const Store = require("./store"); 4 | const Logger = require("./logger"); 5 | const RPC = require("./rpc"); 6 | 7 | const http = { 8 | async get(url, options) { 9 | const res = await got.get(url, { 10 | headers: options.headers, 11 | timeout: options.timeout, 12 | responseType: "text", 13 | }); 14 | 15 | return res.body; 16 | }, 17 | async post(url, body, options) { 18 | const res = await got.post(url, { 19 | body, 20 | headers: options.headers, 21 | timeout: options.timeout, 22 | responseType: "text", 23 | }); 24 | 25 | return res.body; 26 | }, 27 | }; 28 | 29 | /** 30 | * @param {import("electron").ipcMain} ipc 31 | */ 32 | module.exports = (ipc) => { 33 | ipc.handle("Store-Get", (e, key) => { 34 | return Store.store.get(key); 35 | }); 36 | 37 | ipc.handle("Store-Set", (e, key, data) => { 38 | Store.store.set(key, data); 39 | }); 40 | 41 | ipc.handle("Rpc-Set", (e, act) => { 42 | RPC.setActivity(act); 43 | }); 44 | 45 | Object.entries(http).forEach(([method, fn]) => { 46 | ipc.handle(`Request-${method}`, (e, ...args) => { 47 | return fn(...args); 48 | }); 49 | }); 50 | 51 | ipc.handle("Open-Externally", async (e, url) => { 52 | Logger.info(`Open external url: ${url}`); 53 | 54 | const resp = await dialog.showMessageBox(null, { 55 | title: "External Link", 56 | message: `Do you want to visit ${url} in your browser?`, 57 | type: "warning", 58 | buttons: ["Yes", "No"], 59 | defaultId: 1, 60 | }); 61 | 62 | if (resp.response === 0) { 63 | Logger.info(`Opening external url: ${url}`); 64 | shell.openExternal(url); 65 | } else { 66 | Logger.info(`User aborted opening external url: ${url}`); 67 | } 68 | }); 69 | }; 70 | -------------------------------------------------------------------------------- /src/plugins/api/requester/capacitor.ts: -------------------------------------------------------------------------------- 1 | import qs from "qs"; 2 | import { Http } from "@capacitor-community/http"; 3 | import { Requester } from "anime-ext/dist/types"; 4 | 5 | const getUrl = (url: URL) => url.origin + url.pathname; 6 | // @ts-ignore 7 | const getParams = (url: URL) => Object.fromEntries(url.searchParams); 8 | 9 | const getContentType = (headers: Record) => { 10 | const contentTypeKey = Object.keys(headers).find( 11 | (x) => x.toLowerCase() === "content-type" 12 | ); 13 | return (contentTypeKey ? headers[contentTypeKey] : null); 14 | }; 15 | 16 | const getBody = (body: any, contentType: ReturnType) => { 17 | if (contentType?.includes("application/x-www-form-urlencoded")) { 18 | try { 19 | body = qs.parse(body); 20 | } catch (err) {} 21 | } 22 | 23 | return body; 24 | }; 25 | 26 | const getData = (data: any) => { 27 | if (typeof data === "object") { 28 | try { 29 | data = JSON.stringify(data); 30 | } catch (err) {} 31 | } 32 | 33 | return data; 34 | }; 35 | 36 | export const requester: Requester = { 37 | async get(url, options) { 38 | const parsed = new URL(url); 39 | const res = await Http.request({ 40 | method: "GET", 41 | url: getUrl(parsed), 42 | params: getParams(parsed), 43 | headers: options.headers, 44 | responseType: "text", 45 | connectTimeout: options.timeout, 46 | }); 47 | return getData(res.data); 48 | }, 49 | async post(url, body, options) { 50 | const parsed = new URL(url); 51 | const res = await Http.request({ 52 | method: "POST", 53 | url: getUrl(parsed), 54 | params: getParams(parsed), 55 | data: getBody(body, getContentType(options.headers)), 56 | headers: options.headers, 57 | responseType: "text", 58 | connectTimeout: options.timeout, 59 | }); 60 | return getData(res.data); 61 | }, 62 | }; 63 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 38 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /environments/capacitor/android/.gitignore: -------------------------------------------------------------------------------- 1 | # Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore 2 | 3 | # Built application files 4 | *.apk 5 | *.aar 6 | *.ap_ 7 | *.aab 8 | 9 | # Files for the ART/Dalvik VM 10 | *.dex 11 | 12 | # Java class files 13 | *.class 14 | 15 | # Generated files 16 | bin/ 17 | gen/ 18 | out/ 19 | # Uncomment the following line in case you need and you don't have the release build type files in your app 20 | # release/ 21 | 22 | # Gradle files 23 | .gradle/ 24 | build/ 25 | release/ 26 | 27 | # Local configuration file (sdk path, etc) 28 | local.properties 29 | 30 | # Proguard folder generated by Eclipse 31 | proguard/ 32 | 33 | # Log Files 34 | *.log 35 | 36 | # Android Studio Navigation editor temp files 37 | .navigation/ 38 | 39 | # Android Studio captures folder 40 | captures/ 41 | 42 | # IntelliJ 43 | *.iml 44 | .idea/workspace.xml 45 | .idea/tasks.xml 46 | .idea/gradle.xml 47 | .idea/assetWizardSettings.xml 48 | .idea/dictionaries 49 | .idea/libraries 50 | # Android Studio 3 in .gitignore file. 51 | .idea/caches 52 | .idea/modules.xml 53 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 54 | .idea/navEditor.xml 55 | 56 | # Keystore files 57 | # Uncomment the following lines if you do not want to check your keystore files in. 58 | #*.jks 59 | #*.keystore 60 | 61 | # External native build folder generated in Android Studio 2.2 and later 62 | .externalNativeBuild 63 | .cxx/ 64 | 65 | # Google Services (e.g. APIs or Firebase) 66 | # google-services.json 67 | 68 | # Freeline 69 | freeline.py 70 | freeline/ 71 | freeline_project_description.json 72 | 73 | # fastlane 74 | fastlane/report.xml 75 | fastlane/Preview.html 76 | fastlane/screenshots 77 | fastlane/test_output 78 | fastlane/readme.md 79 | 80 | # Version control 81 | vcs.xml 82 | 83 | # lint 84 | lint/intermediates/ 85 | lint/generated/ 86 | lint/outputs/ 87 | lint/tmp/ 88 | # lint/reports/ 89 | 90 | # Android Profiling 91 | *.hprof 92 | 93 | # Cordova plugins for Capacitor 94 | capacitor-cordova-android-plugins 95 | 96 | # Copied web assets 97 | app/src/main/assets/public 98 | -------------------------------------------------------------------------------- /.github/workflows/Publish (Capacitor - Android).yml: -------------------------------------------------------------------------------- 1 | name: Publish (Capacitor - Android) 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | android: 11 | runs-on: windows-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - uses: actions/setup-node@v2 17 | with: 18 | node-version: 14.16.0 19 | 20 | - name: Install dependencies 21 | run: yarn --dev 22 | 23 | - name: Set up our JDK environment 24 | uses: actions/setup-java@v2 25 | with: 26 | java-version: 11 27 | distribution: 'adopt' 28 | 29 | - name: Build APK 30 | run: yarn capacitor:android:release 31 | 32 | - name: Sign APK 33 | uses: r0adkll/sign-android-release@v1 34 | id: sign_app 35 | with: 36 | releaseDirectory: ${{ github.workspace }}/environments/capacitor/android/app/build/outputs/apk/release 37 | signingKeyBase64: ${{ secrets.ANDROID_SIGN_KEY }} 38 | alias: ${{ secrets.ANDROID_SIGN_ALIAS }} 39 | keyStorePassword: ${{ secrets.ANDROID_SIGN_STORE_PASSWORD }} 40 | keyPassword: ${{ secrets.ANDROID_SIGN_KEY_PASSWORD }} 41 | 42 | - name: Upload artifacts 43 | uses: actions/upload-artifact@v2 44 | with: 45 | name: Signed APK 46 | path: ${{ steps.sign_app.outputs.signedReleaseFile }} 47 | 48 | - name: Create tag and upload 49 | uses: actions/github-script@v4 50 | with: 51 | github-token: ${{secrets.GITHUB_TOKEN}} 52 | script: | 53 | github.issues.createComment({ 54 | issue_number: context.issue.number, 55 | owner: context.repo.owner, 56 | repo: context.repo.repo, 57 | body: '👋 Thanks for reporting!' 58 | }) 59 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | defaultConfig { 6 | applicationId "io.github.zyrouge.yukino" 7 | minSdkVersion rootProject.ext.minSdkVersion 8 | targetSdkVersion rootProject.ext.targetSdkVersion 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 12 | aaptOptions { 13 | // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. 14 | // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61 15 | ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~' 16 | } 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | repositories { 27 | flatDir{ 28 | dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' 29 | } 30 | } 31 | 32 | dependencies { 33 | implementation fileTree(include: ['*.jar'], dir: 'libs') 34 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" 35 | implementation project(':capacitor-android') 36 | testImplementation "junit:junit:$junitVersion" 37 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" 38 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" 39 | implementation project(':capacitor-cordova-android-plugins') 40 | } 41 | 42 | apply from: 'capacitor.build.gradle' 43 | 44 | try { 45 | def servicesJSON = file('google-services.json') 46 | if (servicesJSON.text) { 47 | apply plugin: 'com.google.gms.google-services' 48 | } 49 | } catch(Exception e) { 50 | logger.warn("google-services.json not found, google-services plugin not applied. Push Notifications won't work") 51 | } 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Yukino (fork) 6 | 7 | This repository is a fork of the [Yukino app](https://github.com/yukino-org/yukino-app). 8 | 9 | ## Download 10 | 11 | You can download the latest version of app from the [releases](https://github.com/zyrouge/yukino-app/releases) tab. 12 | 13 | ## Preview 14 | 15 | ![Home](./screenshots/home.png) 16 | ![Search](./screenshots/search.png) 17 | ![Anime](./screenshots/anime.png) 18 | ![Episodes](./screenshots/episodes.png) 19 | ![Sources](./screenshots/sources.png) 20 | ![Player](./screenshots/player.png) 21 | ![Manga](./screenshots/manga.png) 22 | 23 | ## Branding 24 | 25 | ### Colors 26 | 27 | [![Primary](https://img.shields.io/badge/Primary-%236366F1-white.svg?style=flat&color=6366F1)](https://img.shields.io/badge/Indigo-%236366F1-white.svg?color=6366F1) [![Secondary](https://img.shields.io/badge/Secondary-%2318181b-white.svg?style=flat&color=18181b)](https://img.shields.io/badge/Indigo-%236366F1-white.svg?color=6366F1) 28 | 29 | ## Technology 30 | 31 | - [Node.js](https://nodejs.org) (JavaScript Runtime) 32 | - [Typescript](https://www.typescriptlang.org/) (Runtime) 33 | - [Yarn](https://yarnpkg.com/) (Package manager) 34 | - [Vite](https://vitejs.dev) (Base site) 35 | - [Electron](https://electronjs.org) (Desktop app) 36 | - [Capacitor](https://capacitorjs.com) (Mobile app) 37 | - [Tailwind CSS](https://tailwindcss.com/) (Styling) 38 | 39 | ## Code structure 40 | 41 | - [./src](./src) - Core vue app (SPA) 42 | - [./environments](./environments) 43 | - [./electron](./environments/electron) - Electron-related files (Windows, Linux, MacOS) 44 | - [./capacitor](./environments/capacitor) 45 | - [./android](./environments/capacitor/android) - Capacitor-related files (Android) 46 | - [./scripts](./scripts) - Required scripts 47 | - [./resources](./resources) - Required assets 48 | - [./screenshots](./resources) - App previews 49 | 50 | ## Under the hood 51 | 52 | - [anime-ext](https://zyrouge.github.io/anime-ext) - Fetches all the required data 53 | 54 | ## Contributing 55 | 56 | Ways to contribute to this project: 57 | 58 | - Submitting bugs and feature requests in [issues](https://github.com/zyrouge/yukino-app/issues) 59 | - Opening [pull requests](https://github.com/zyrouge/yukino-app/pulls) containing bug fixes, new features, etc. 60 | 61 | ## Developer guide 62 | 63 | ### Cloning & Installing 64 | 65 | ```bash 66 | git clone https://github.com/zyrouge/yukino-app.git 67 | cd yukino-app 68 | yarn 69 | ``` 70 | 71 | ### Running the app in development 72 | 73 | ```bash 74 | yarn vite:dev # Vite 75 | yarn electron:dev # Electron 76 | # No hot reload for Capacitor 77 | ``` 78 | 79 | ### Building the app in development 80 | 81 | ```bash 82 | yarn vite:build # Vite 83 | yarn electron:build # Electron 84 | yarn capacitor:android:build # Capacitor (android) 85 | ``` 86 | 87 | ## License 88 | 89 | [MIT](./LICENSE) 90 | -------------------------------------------------------------------------------- /environments/electron/igniter/splash.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 19 |
20 |

21 | 22 |
Version:
23 | 24 |

29 | Starting... 30 |

31 | 32 | 35 |
36 | 37 | 38 | 101 | 102 | -------------------------------------------------------------------------------- /environments/capacitor/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | workflow_dispatch: 16 | push: 17 | branches: [next] 18 | pull_request: 19 | # The branches below must be a subset of the branches above 20 | branches: [next] 21 | schedule: 22 | - cron: "38 22 * * 6" 23 | 24 | jobs: 25 | analyze: 26 | name: Analyze 27 | runs-on: ubuntu-latest 28 | permissions: 29 | actions: read 30 | contents: read 31 | security-events: write 32 | 33 | strategy: 34 | fail-fast: false 35 | matrix: 36 | language: ["javascript"] 37 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 38 | # Learn more: 39 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v2 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v1 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 54 | 55 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 56 | # If this step fails, then you should remove it and run the build manually (see below) 57 | - name: Autobuild 58 | uses: github/codeql-action/autobuild@v1 59 | 60 | # ℹ️ Command-line programs to run using the OS shell. 61 | # 📚 https://git.io/JvXDl 62 | 63 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 64 | # and modify them (or add more) to build your code if your project 65 | # uses a compiled language 66 | 67 | #- run: | 68 | # make bootstrap 69 | # make release 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v1 73 | -------------------------------------------------------------------------------- /src/components/Logger.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 94 | 95 | 110 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yukino-app", 3 | "productName": "Yukino", 4 | "version": "0.0.9-beta.0", 5 | "description": "Yukino lets you read manga or stream anime ad-free from multiple sources.", 6 | "author": { 7 | "name": "ZYROUGE", 8 | "email": "zyrouge@hotmail.com" 9 | }, 10 | "license": "MIT", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/zyrouge/yukino-app" 14 | }, 15 | "homepage": "https://zyrouge.github.io/yukino-app", 16 | "scripts": { 17 | "vite:dev": "vite", 18 | "vite:serve": "vite preview", 19 | "vite:build": "rimraf ./dist/vite && vue-tsc --noEmit && vite build", 20 | "electron:icons": "electron-icon-builder --flatten --input=./resources/icon.png --output=./resources", 21 | "electron:start": "cross-env YUKINO_PLATFORM=\"electron\" electron environments/electron/main.js", 22 | "electron:dev": "cross-env YUKINO_PLATFORM=\"electron\" node scripts/electron-dev", 23 | "electron:pack": "cross-env DEBUG=\"electron-builder\" yarn electron:build --dir", 24 | "electron:build": "rimraf ./dist/electron && yarn electron:icons && cross-env YUKINO_PLATFORM=\"electron\" yarn vite:build && electron-builder --config=environments/electron/builder.config.js", 25 | "electron:publish": "yarn electron:build --publish=always", 26 | "capacitor:sync": "cap sync", 27 | "capacitor:android:icons": "cordova-res android --skip-config --copy --android-project environments/capacitor/android", 28 | "capacitor:android:build": "cross-env YUKINO_PLATFORM=\"capacitor\" yarn vite:build && yarn capacitor:android:icons && yarn capacitor:sync", 29 | "capacitor:android:open": "cap open android", 30 | "capacitor:android:pack": "yarn capacitor:android:build && node scripts/capacitor-android-debug", 31 | "capacitor:android:release": "yarn capacitor:android:build && node scripts/capacitor-android-release" 32 | }, 33 | "dependencies": { 34 | "@capacitor-community/http": "^1.0.0", 35 | "@capacitor/android": "^3.0.0", 36 | "@capacitor/app": "^1.0.0", 37 | "@capacitor/browser": "^1.0.0", 38 | "@capacitor/core": "^3.0.0", 39 | "@capacitor/dialog": "^1.0.0", 40 | "@capacitor/splash-screen": "^1.0.0", 41 | "@fortawesome/fontawesome-svg-core": "^1.2.35", 42 | "@fortawesome/free-regular-svg-icons": "^5.15.3", 43 | "@fortawesome/free-solid-svg-icons": "^5.15.3", 44 | "@fortawesome/vue-fontawesome": "^3.0.0-3", 45 | "anime-ext": "^1.0.14", 46 | "capacitor-secure-storage-plugin": "^0.6.2", 47 | "discord-rpc": "^3.2.0", 48 | "electron-store": "^8.0.0", 49 | "electron-updater": "^4.3.9", 50 | "got": "^11.8.2", 51 | "qs": "^6.10.1", 52 | "vue": "^3.0.5", 53 | "vue-router": "4" 54 | }, 55 | "devDependencies": { 56 | "@capacitor/cli": "^3.0.0", 57 | "@tailwindcss/jit": "^0.1.18", 58 | "@types/qs": "^6.9.6", 59 | "@vitejs/plugin-vue": "^1.2.2", 60 | "@vue/compiler-sfc": "^3.0.5", 61 | "autoprefixer": "^10.2.5", 62 | "cordova-res": "^0.15.3", 63 | "cross-env": "^7.0.3", 64 | "cross-spawn": "^7.0.3", 65 | "electron": "^12.0.7", 66 | "electron-builder": "^22.10.5", 67 | "electron-icon-builder": "^2.0.1", 68 | "postcss": "^8.2.15", 69 | "rimraf": "^3.0.2", 70 | "tailwindcss": "^2.1.2", 71 | "typescript": "^4.1.3", 72 | "vite": "^2.3.0", 73 | "vue-tsc": "^0.0.24" 74 | } 75 | } -------------------------------------------------------------------------------- /environments/electron/rpc.js: -------------------------------------------------------------------------------- 1 | const { 2 | productName, 3 | description, 4 | version, 5 | homepage, 6 | } = require("../../package.json"); 7 | const { Client: DiscordRPC } = require("discord-rpc"); 8 | const Logger = require("./logger"); 9 | const Store = require("./store"); 10 | const Util = require("./util"); 11 | 12 | class RPC { 13 | constructor() { 14 | this.id = "845615853479133194"; 15 | this.rpc = new DiscordRPC({ 16 | transport: "ipc", 17 | }); 18 | this.started = Date.now(); 19 | this.disabled = Store.store.get("settings.discordRpc") === "disabled"; 20 | this.ready = false; 21 | this.alreadySetInPrivacyMode = false; 22 | } 23 | 24 | /** 25 | * @typedef Activity 26 | * @property {number} startTimestamp 27 | * @property {string} details 28 | * @property {string} state 29 | * @property {{ label: string; url: string; }[]} buttons 30 | */ 31 | 32 | /** 33 | * @param {Partial} activity 34 | */ 35 | setActivity(activity) { 36 | try { 37 | if (this.ready) { 38 | if ( 39 | Store.store.get("settings.discordRpcPrivacy") === "enabled" 40 | ) { 41 | if (!this.alreadySetInPrivacyMode) { 42 | this.rpc.setActivity(this.defaultActivity); 43 | this.alreadySetInPrivacyMode = true; 44 | return; 45 | } 46 | } 47 | 48 | this.rpc.setActivity( 49 | Util.mergeObj(this.defaultActivity, activity) 50 | ); 51 | 52 | if (activity.startTimestamp) 53 | this.started = activity.startTimestamp; 54 | } 55 | } catch (err) { 56 | Logger.error(`Failed to set Rpc activity: ${err}`); 57 | } 58 | } 59 | 60 | /** 61 | * @returns {Promise { 70 | this.rpc.on("ready", () => { 71 | this.ready = true; 72 | if (this.rpc.user) { 73 | Logger.info( 74 | `RPC set for ${this.rpc.user.username}#${this.rpc.user.discriminator} (${this.rpc.user.id})` 75 | ); 76 | } 77 | 78 | resolve(true); 79 | }); 80 | 81 | this.rpc 82 | .login({ 83 | clientId: this.id, 84 | }) 85 | .catch((err) => { 86 | Logger.error(`Failed to connect to Rpc: ${err}`); 87 | resolve(false); 88 | }); 89 | }); 90 | } 91 | 92 | get defaultActivity() { 93 | return { 94 | startTimestamp: this.started, 95 | largeImageKey: "large", 96 | largeImageText: `${productName} v${version}`, 97 | smallImageKey: "snowflake_inverted", 98 | smallImageText: description, 99 | buttons: [ 100 | { 101 | label: "Download App", 102 | url: homepage, 103 | }, 104 | ], 105 | }; 106 | } 107 | } 108 | 109 | module.exports = new RPC(); 110 | -------------------------------------------------------------------------------- /src/components/TitleBar.vue: -------------------------------------------------------------------------------- 1 | 83 | 84 | 101 | 102 | 115 | -------------------------------------------------------------------------------- /src/plugins/api/extractors.ts: -------------------------------------------------------------------------------- 1 | import { http } from "./requester"; 2 | import { Requester } from "anime-ext/dist/types"; 3 | 4 | import MALSearchAnime, { 5 | SearchResult as MALSearchAnimeSearchResult, 6 | } from "anime-ext/dist/integrations/myanimelist/search-anime"; 7 | import MALAnimeInfo, { 8 | InfoResult as MALAnimeInfoInfoResult, 9 | } from "anime-ext/dist/integrations/myanimelist/anime-info"; 10 | import * as MALTopAnimes from "anime-ext/dist/integrations/myanimelist/top"; 11 | 12 | import { AnimeExtractorModel } from "anime-ext/dist/extractors/anime/model"; 13 | import FourAnime from "anime-ext/dist/extractors/anime/4anime"; 14 | import GogoAnime from "anime-ext/dist/extractors/anime/gogoanime"; 15 | import GogoStreamAnime from "anime-ext/dist/extractors/anime/gogostream"; 16 | import SimplyMoeAnime from "anime-ext/dist/extractors/anime/simplydotmoe"; 17 | import TwistDotMoeAnime from "anime-ext/dist/extractors/anime/twistdotmoe"; 18 | import KawaiifuAnime from "anime-ext/dist/extractors/anime/kawaiifu"; 19 | import TenshiDotMoeAnime from "anime-ext/dist/extractors/anime/tenshidotmoe"; 20 | 21 | import { MangaExtractorModel } from "anime-ext/dist/extractors/manga/model"; 22 | import FanFoxManga from "anime-ext/dist/extractors/manga/fanfox"; 23 | import MangaDexManga from "anime-ext/dist/extractors/manga/mangadex"; 24 | import MangaInnManga from "anime-ext/dist/extractors/manga/mangainn"; 25 | import ManhwatopManga from "anime-ext/dist/extractors/manga/manhwatop"; 26 | 27 | export interface ExtractorsEntity { 28 | integrations: { 29 | MyAnimeList: { 30 | search(term: string): Promise; 31 | getAnimeInfo(url: string): Promise; 32 | getTopAnime(type: string): Promise; 33 | getTopAnimeTypes(): Promise; 34 | }; 35 | }; 36 | anime: Record; 37 | manga: Record; 38 | } 39 | 40 | export interface OptionsEntity { 41 | http: Requester; 42 | } 43 | 44 | export const Extractors = { 45 | __extractor: null, 46 | __options: null, 47 | async getOptions() { 48 | if (!this.__options) { 49 | this.__options = { 50 | http: await http.getClient(), 51 | }; 52 | } 53 | 54 | return this.__options; 55 | }, 56 | async getClient() { 57 | if (!this.__extractor) { 58 | const options = await this.getOptions(); 59 | 60 | this.__extractor = { 61 | integrations: { 62 | MyAnimeList: { 63 | async search(terms: string) { 64 | return MALSearchAnime(terms, options); 65 | }, 66 | async getAnimeInfo(url: string) { 67 | return MALAnimeInfo(url, options); 68 | }, 69 | async getTopAnime(type: string) { 70 | return MALTopAnimes.default(type, options); 71 | }, 72 | async getTopAnimeTypes() { 73 | return ["all", ...MALTopAnimes.TopAnimeTypes]; 74 | }, 75 | }, 76 | }, 77 | anime: { 78 | "4Anime": new FourAnime(options), 79 | GogoAnime: new GogoAnime(options), 80 | GogoStream: new GogoStreamAnime(options), 81 | SimplyMoe: new SimplyMoeAnime(options), 82 | TwistMoe: new TwistDotMoeAnime(options), 83 | Kawaiifu: new KawaiifuAnime(options), 84 | TenshiMoe: new TenshiDotMoeAnime(options), 85 | }, 86 | manga: { 87 | FanFox: new FanFoxManga(options), 88 | MangaDex: new MangaDexManga(options), 89 | MangaInn: new MangaInnManga(options), 90 | Manhwatop: new ManhwatopManga(options), 91 | }, 92 | }; 93 | } 94 | 95 | return this.__extractor; 96 | }, 97 | }; 98 | -------------------------------------------------------------------------------- /environments/electron/main.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { app, BrowserWindow, ipcMain, dialog } = require("electron"); 3 | const Store = require("./store"); 4 | const Rpc = require("./rpc"); 5 | const Igniter = require("./igniter"); 6 | const Logger = require("./logger"); 7 | const { productName } = require("../../package.json"); 8 | 9 | const isDev = process.env.NODE_ENV === "development"; 10 | Logger.info("Starting app"); 11 | 12 | const createWindow = async () => { 13 | Logger.info(`Environment: ${process.env.NODE_ENV}`); 14 | 15 | const ignition = new Igniter(); 16 | Logger.info("Created igniter"); 17 | 18 | ignition.start(); 19 | Logger.info("Started igniter"); 20 | 21 | const continueProc = await ignition.update(); 22 | Logger.warn(`Continue process: ${continueProc}`); 23 | if (!continueProc) return ignition.close(); 24 | 25 | await Rpc.connect(); 26 | 27 | const dimensions = Store.getWindowSize(); 28 | const win = new BrowserWindow({ 29 | title: productName, 30 | x: dimensions.x, 31 | y: dimensions.y, 32 | width: dimensions.width, 33 | height: dimensions.height, 34 | minWidth: 400, 35 | minHeight: 300, 36 | webPreferences: { 37 | contextIsolation: true, 38 | nodeIntegration: false, 39 | preload: path.join(__dirname, "preload.js"), 40 | }, 41 | show: false, 42 | frame: false, 43 | icon: path.join(__dirname, "..", "..", "resources", "icon.png"), 44 | }); 45 | if (dimensions.isMaximized) win.maximize(); 46 | Logger.info("Created main window"); 47 | 48 | if (isDev) { 49 | if (!process.env.VITE_SERVE_URL) { 50 | Logger.error("Missing env variable: process.env.VITE_SERVE_URL"); 51 | throw new Error("Missing 'process.env.VITE_SERVE_URL'!"); 52 | } 53 | 54 | win.loadURL(process.env.VITE_SERVE_URL); 55 | win.webContents.openDevTools(); 56 | Logger.info(`Opened URL: ${process.env.VITE_SERVE_URL}`); 57 | } else { 58 | const file = path.join( 59 | __dirname, 60 | "..", 61 | "..", 62 | "dist", 63 | "vite", 64 | "index.html" 65 | ); 66 | win.loadFile(file); 67 | Logger.info(`Opened file: ${file}`); 68 | } 69 | 70 | win.on("ready-to-show", () => { 71 | Logger.warn("Closing igniter and opening main window"); 72 | ignition.close(); 73 | win.show(); 74 | }); 75 | 76 | win.on("close", () => { 77 | Store.setWindowSize({ 78 | ...win.getBounds(), 79 | isMaximized: win.isMaximized(), 80 | }); 81 | 82 | if (!win.isDestroyed()) { 83 | Logger.warn("Main window has been closed!"); 84 | win.destroy(); 85 | } 86 | }); 87 | 88 | ipcMain.handle("minimize-window", () => { 89 | Logger.warn("Main window has been minimized!"); 90 | win.minimize(); 91 | }); 92 | 93 | ipcMain.handle("toggle-maximize-window", () => { 94 | if (win.isMaximized()) { 95 | win.unmaximize(); 96 | Logger.warn("Main window has been unmaximized!"); 97 | } else { 98 | win.maximize(); 99 | Logger.warn("Main window has been maximized!"); 100 | } 101 | }); 102 | 103 | ipcMain.handle("close-window", async () => { 104 | const resp = await dialog.showMessageBox(null, { 105 | title: "Exit", 106 | message: "Do you want to close the app?", 107 | type: "warning", 108 | buttons: ["Yes", "No"], 109 | defaultId: 1, 110 | }); 111 | 112 | if (resp.response === 0) { 113 | Logger.warn("Closing window"); 114 | win.close(); 115 | } else { 116 | Logger.info("User aborted app close!"); 117 | } 118 | }); 119 | 120 | ipcMain.handle("reload-window", () => { 121 | Logger.warn("Reloading window"); 122 | win.reload(); 123 | }); 124 | }; 125 | 126 | require("./ipc")(ipcMain); 127 | 128 | app.on("ready", async () => { 129 | Logger.warn("Creating window (app ready)"); 130 | await createWindow(); 131 | }); 132 | 133 | app.on("activate", async () => { 134 | if (BrowserWindow.getAllWindows().length === 0) { 135 | Logger.warn("No windows were open so opening new one (app activate)"); 136 | await createWindow(); 137 | } 138 | }); 139 | 140 | app.on("window-all-closed", () => { 141 | if (process.platform !== "darwin") { 142 | Logger.warn("Qutting app"); 143 | app.quit(); 144 | } 145 | }); 146 | -------------------------------------------------------------------------------- /environments/electron/igniter/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { app, BrowserWindow } = require("electron"); 3 | const Store = require("../store"); 4 | const Logger = require("../logger"); 5 | const { productName, version } = require("../../../package.json"); 6 | 7 | const isDev = process.env.NODE_ENV === "development"; 8 | 9 | if (isDev) { 10 | app.getVersion = () => version; 11 | Logger.warn(`Changed app version to ${app.getVersion()}`); 12 | } 13 | 14 | class Igniter { 15 | /** 16 | * @param {import("electron-updater").AppUpdater} updater 17 | */ 18 | constructor() { 19 | this.win = null; 20 | this.autoUpdater = require("electron-updater").autoUpdater; 21 | this.autoUpdater.autoDownload = false; 22 | this.autoUpdater.logger = null; 23 | this.autoUpdater.channel = 24 | Store.store.get("settings.updateChannel") || "latest"; 25 | this.autoUpdater.allowDowngrade = false; 26 | 27 | if (isDev) { 28 | this.autoUpdater.updateConfigPath = path.join( 29 | __dirname, 30 | "dev-mock-update.yml" 31 | ); 32 | Logger.warn( 33 | `Changed updater config path to ${this.autoUpdater.updateConfigPath}` 34 | ); 35 | } 36 | } 37 | 38 | start() { 39 | this.win = new BrowserWindow({ 40 | title: productName, 41 | width: 300, 42 | height: 330, 43 | resizable: false, 44 | webPreferences: { 45 | contextIsolation: true, 46 | nodeIntegration: false, 47 | preload: path.join(__dirname, "preload.js"), 48 | }, 49 | frame: false, 50 | transparent: true, 51 | icon: path.join( 52 | __dirname, 53 | "..", 54 | "..", 55 | "..", 56 | "resources", 57 | "icon.png" 58 | ), 59 | }); 60 | Logger.info("Created ignition window"); 61 | 62 | const url = `file://${path.join( 63 | __dirname, 64 | "splash.html" 65 | )}?title=${encodeURIComponent( 66 | productName 67 | )}&version=${encodeURIComponent(app.getVersion())}`; 68 | this.win.loadURL(url); 69 | Logger.info(`Opened url in ignition window: ${url}`); 70 | } 71 | 72 | /** 73 | * @returns {Promise { 77 | this.autoUpdater.checkForUpdates(); 78 | 79 | this.autoUpdater.on("update-not-available", () => { 80 | Logger.info("No updates were found"); 81 | resolve(true); 82 | }); 83 | 84 | this.autoUpdater.on("update-downloaded", () => { 85 | Logger.info("Downloaded update"); 86 | this.win.webContents.send("update-downloaded"); 87 | this.autoUpdater.quitAndInstall(); 88 | resolve(false); 89 | }); 90 | 91 | this.autoUpdater.on("checking-for-update", () => { 92 | Logger.info("Checking for update"); 93 | this.win.webContents.send("checking-for-update"); 94 | }); 95 | 96 | this.autoUpdater.on("update-available", (info) => { 97 | Logger.info(`New update is available: ${info.version}`); 98 | this.win.webContents.send("new-update", info.version); 99 | this.autoUpdater.downloadUpdate(); 100 | }); 101 | 102 | this.autoUpdater.on("download-progress", (progress) => { 103 | Logger.info( 104 | `Update progress: ${progress.percent.toFixed(2)}%/100%` 105 | ); 106 | const toMb = (n) => (n / 1000000).toFixed(2); 107 | this.win.webContents.send("download-progress", { 108 | percent: progress.percent, 109 | transferred: toMb(progress.transferred), 110 | total: toMb(progress.total), 111 | }); 112 | }); 113 | 114 | this.autoUpdater.on("error", (err) => { 115 | Logger.error(`Updated error: ${err}`); 116 | this.win.webContents.send( 117 | "error", 118 | err && err.message ? err.message : err 119 | ); 120 | resolve(true); 121 | }); 122 | 123 | this.autoUpdater.checkForUpdates(); 124 | Logger.info("Checking for update"); 125 | }); 126 | } 127 | 128 | close() { 129 | try { 130 | this.win.destroy(); 131 | } catch (err) {} 132 | } 133 | } 134 | 135 | module.exports = Igniter; 136 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 79 | 80 | 145 | 146 | 178 | -------------------------------------------------------------------------------- /src/components/MangaSourceViewer.vue: -------------------------------------------------------------------------------- 1 | 95 | 96 | 156 | -------------------------------------------------------------------------------- /src/components/AnimeSourceViewer.vue: -------------------------------------------------------------------------------- 1 | 100 | 101 | 161 | -------------------------------------------------------------------------------- /environments/capacitor/android/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /environments/capacitor/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src/components/SideBar.vue: -------------------------------------------------------------------------------- 1 | 111 | 112 | 206 | -------------------------------------------------------------------------------- /src/components/LastLeft.vue: -------------------------------------------------------------------------------- 1 | 112 | 113 | 198 | 199 | 217 | -------------------------------------------------------------------------------- /src/pages/MangaSourceInfo.vue: -------------------------------------------------------------------------------- 1 | 96 | 97 | 234 | -------------------------------------------------------------------------------- /src/pages/Home.vue: -------------------------------------------------------------------------------- 1 | 149 | 150 | -------------------------------------------------------------------------------- /src/pages/AnimeSourceInfo.vue: -------------------------------------------------------------------------------- 1 | 136 | 137 | 298 | -------------------------------------------------------------------------------- /src/pages/Settings.vue: -------------------------------------------------------------------------------- 1 | 169 | 170 | 287 | -------------------------------------------------------------------------------- /src/components/AnimePlayer.vue: -------------------------------------------------------------------------------- 1 | 160 | 161 | 358 | --------------------------------------------------------------------------------