This commit is contained in:
RockinChaos 2024-07-26 16:53:52 -07:00
commit aecfbb7083
10 changed files with 191 additions and 19 deletions

View file

@ -269,7 +269,7 @@ export default class TorrentClient extends WebTorrent {
}
this.current = found
if (data.data.external && this.player) {
this.playerProcess = spawn(this.player, [encodeURI('' + new URL('http://localhost:' + this.server.address().port + found.streamURL))])
this.playerProcess = spawn(this.player, ['' + new URL('http://localhost:' + this.server.address().port + found.streamURL)])
this.playerProcess.stdout.on('data', () => {})
const startTime = Date.now()
this.playerProcess.once('close', () => {

View file

@ -1109,9 +1109,11 @@
<!-- eslint-disable-next-line svelte/valid-compile -->
<div class='w-full h-full position-absolute toggle-immerse d-none' on:dblclick={toggleFullscreen} on:click|self={toggleImmerse} />
<div class='w-full h-full position-absolute mobile-focus-target d-none' use:click={() => { page = 'player' }} />
<span class='material-symbols-outlined ctrl h-full align-items-center justify-content-end w-150 mw-full mr-auto' use:click={rewind}> fast_rewind </span>
<!-- eslint-disable-next-line svelte/valid-compile -->
<span class='material-symbols-outlined ctrl h-full align-items-center justify-content-end w-150 mw-full mr-auto' on:click={rewind}> fast_rewind </span>
<span class='material-symbols-outlined ctrl' data-name='playPause' use:click={playPause}> {ended ? 'replay' : paused ? 'play_arrow' : 'pause'} </span>
<span class='material-symbols-outlined ctrl h-full align-items-center w-150 mw-full ml-auto' use:click={forward}> fast_forward </span>
<!-- eslint-disable-next-line svelte/valid-compile -->
<span class='material-symbols-outlined ctrl h-full align-items-center w-150 mw-full ml-auto' on:click={forward}> fast_forward </span>
<div class='position-absolute bufferingDisplay' />
{#if currentSkippable}
<button class='skip btn text-dark position-absolute bottom-0 right-0 mr-20 mb-5 font-weight-bold z-30' use:click={skip}>

View file

@ -1,6 +1,6 @@
{
"name": "Miru",
"version": "5.2.3",
"version": "5.2.6",
"private": true,
"author": "ThaUnknown_ <ThaUnknown@users.noreply.github.com>",
"description": "Stream anime torrents, real-time with no waiting for downloads.",

View file

@ -28,6 +28,7 @@ export default class Updater {
install () {
if (this.hasUpdate) {
autoUpdater.quitAndInstall()
this.hasUpdate = false
return true
}
}

32
extensions/example.js Normal file
View file

@ -0,0 +1,32 @@
export default class AbstractSource {
name = 'Missing name'
description = 'No description provided'
/** @type {import('./type-definitions').Accuracy} */
accuracy = 'Low'
/** @type {import('./type-definitions').Config} */
config = {}
/**
* Gets results for single episode
* @type {import('./type-definitions').SearchFunction}
*/
single (options) {
throw new Error('Source doesn\'t implement single')
}
/**
* Gets results for batch of episodes
* @type {import('./type-definitions').SearchFunction}
*/
batch (options) {
throw new Error('Source doesn\'t implement batch')
}
/**
* Gets results for a movie
* @type {import('./type-definitions').SearchFunction}
*/
movie (options) {
throw new Error('Source doesn\'t implement movie')
}
}

42
extensions/type-definitions.d.ts vendored Normal file
View file

@ -0,0 +1,42 @@
export interface Result {
title: string // torrent title
link: string // link to .torrent file, or magnet link
id?: number
seeders: number
leechers: number
downloads: number
hash: string // info hash
size: number // size in bytes
verified: boolean // if it's a verified release, e.g. it's 100% certain it's the correct episode, manually verified by the provider e.g. anidb
date: Date // date the torrent was uploaded
type?: 'batch' | 'best' | 'alt'
}
export interface Options {
anilistId: number // anilist anime id
anidbAid?: number // anidb anime id
anidbEid?: number // anidb episode id
titles: string[] // list of titles and alternative titles
episode?: number
episodeCount?: number // total episode count for the series
resolution: '2160' | '1080' | '720' | '540' | '480' | ''
exclusions: string[] // list of keywords to exclude from searches
}
export type SearchFunction = (options: Options) => Promise<Result[]>
export type Config = {
seed?: 'perma' | number // seed ratio to hit
}
export type Accuracy = 'High' | 'Medium' | 'Low'
export class Source {
name: string
description: string
accuracy: Accuracy
config: Config
single: SearchFunction
batch: SearchFunction
movie: SearchFunction
}

View file

@ -789,8 +789,8 @@ packages:
engines: {node: '>=16.0.0'}
dependencies:
'@ionic/utils-terminal': 2.3.5
debug: 4.3.4
tslib: 2.6.2
debug: 4.3.5
tslib: 2.6.3
transitivePeerDependencies:
- supports-color
@ -855,8 +855,8 @@ packages:
'@ionic/utils-stream': 3.1.6
'@ionic/utils-terminal': 2.3.4
cross-spawn: 7.0.3
debug: 4.3.4
tslib: 2.6.2
debug: 4.3.5
tslib: 2.6.3
transitivePeerDependencies:
- supports-color
@ -881,12 +881,12 @@ packages:
engines: {node: '>=16.0.0'}
dependencies:
'@types/slice-ansi': 4.0.0
debug: 4.3.4
debug: 4.3.5
signal-exit: 3.0.7
slice-ansi: 4.0.0
string-width: 4.2.3
strip-ansi: 6.0.1
tslib: 2.6.2
tslib: 2.6.3
untildify: 4.0.0
wrap-ansi: 7.0.0
transitivePeerDependencies:
@ -6496,13 +6496,13 @@ packages:
'@ionic/utils-fs': 3.1.7
'@ionic/utils-terminal': 2.3.5
bplist-parser: 0.3.2
debug: 4.3.4
debug: 4.3.5
elementtree: 0.1.7
ini: 3.0.1
plist: 3.1.0
split2: 4.2.0
through2: 4.0.2
tslib: 2.6.2
tslib: 2.6.3
yauzl: 2.10.0
transitivePeerDependencies:
- supports-color

View file

@ -48,7 +48,7 @@
}
</script>
<div class='position-absolute w-350 h-400 absolute-container top-0 bottom-0 m-auto bg-dark-light rounded overflow-hidden pointer'>
<div class='position-absolute w-350 h-400 absolute-container z-10 top-0 bottom-0 m-auto bg-dark-light rounded overflow-hidden pointer'>
<div class='banner position-relative bg-black'>
<img src={media.bannerImage || ' '} alt='banner' class='img-cover w-full h-full' loading='lazy' />
{#if media.trailer?.id}

View file

@ -0,0 +1,66 @@
<div class='container font-size-18 pb-20'>
<div class='content'>
<div class='h-vh-half px-20 px-sm-0 d-flex justify-content-center flex-column'>
<h1 class='font-weight-bold text-white title'>About Extensions</h1>
<div class='font-size-18 text-muted'>Frequently Asked Questions about Extensions.</div>
</div>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>What are some recommended extensions and sources?</h3>
<p>Miru is bring-your-own-content and does not offer anything, however <kbd>anisearch</kbd> is recommended.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Is there a curated list of extensions and sources?</h3>
<p>No. Miru is not directly associated with any extensions or sources. It's merely a client for streaming one's own media.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>How to install/uninstall extensions?</h3>
<p>Inside <kbd>Settings &gt; Torrent &gt; Extensions</kbd> you can add extensions by either inputting a full URL such as <kbd>https://example.website/file.js</kbd> or if an extension is published on npm <kbd>packagename</kbd> and pressing add. This will automatically import all sources the extension provides. You can then uninstall an extension by pressing the remove button next to it.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Can you disable sources?</h3>
<p>You can disable sources in the sources list by clicking on it's toggle.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>How to develop new extensions?</h3>
<p>Extensions for Miru need to be written in JavaScript which are run in an isolated <a href='https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API' target='_blank'>Web Worker</a>. Make sure the data you're fetching is CORS enabled. Extension type definitions and example structures are available on <a href='https://github.com/ThaUnknown/miru/tree/master/extensions' target='_blank'>GitHub</a>.</p>
<p>Options object, which is passed to the class's single, batch and movie functions as the first parameters has the following fields:</p>
<ul>
<li>anilistId: number - Anilist anime id, can be used to query data from Anilist, such as MalID, episode metadata etc</li>
<li>anidbAid?: number - AniDB anime id, not always present, useful to query mapping API's</li>
<li>anidbEid?: number - AniDB episode id, not always present, useful to query specific data, as AnidbEIDs map to manually maintained files</li>
<li>titles: string[] - list of titles and alternative titles for the given anime</li>
<li>episode?: number - episode to look for, not always present</li>
<li>episodeCount?: number - total episode count for the series, not always present</li>
<li>resolution: '2160' | '1080' | '720' | '540' | '480' | '' - resolution height. empty string means any</li>
<li>exclusions: string[] - list of keywords to exclude from searches such as codecs unsuppored by the platform, etc</li>
</ul>
<p>Results object, array of which is returned by the functions of the class has the following fields:</p>
<ul>
<li>title: string - torrent title, this isn't always the file title as a torrent might include multiple files</li>
<li>link: string - http:// link to .torrent file, or magnet:// link</li>
<li>id?: number - unused for now</li>
<li>seeders: number</li>
<li>leechers: number</li>
<li>downloads: number</li>
<li>hash: string - info hash REQUIRED</li>
<li>size: number - size in bytes</li>
<li>verified: boolean - if it's a verified release, e.g. it's 100% certain it's the correct episode, manually verified by the provider e.g. anidb</li>
<li>date: Date - date the torrent was uploaded</li>
<li>type?: 'batch' | 'best' | 'alt' - type of the result best/alt means it's the best known release</li>
</ul>
</div>
</div>
<style>
a {
--dm-link-text-color: #1890ff !important;
--dm-link-text-color-hover: #45a3fb !important;
}
h3 {
margin-top: 0;
padding-top: 0.75em;
}
p {
margin-bottom: 0;
padding-bottom: 1em;
}
.title {
font-size: 5rem
}
</style>

View file

@ -1,22 +1,34 @@
<div class='container font-size-18 pb-20'>
<div class='content'>
<h1 class='text-white font-weight-bold'>Frequently Asked Questions</h1>
<h3 class='text-white font-weight-bold'>Won't this kill swarm health?</h3>
<p>Depends. On average no. The app is always seeding 1 torrent as long as it's open. Additionally the upload speed is forced to be x1.5 that of the download speed. Those 2 things combined will already make this app seed more than the average leecher which removes the torrent the moment it's downloaded.</p>
<div class='h-vh-half row px-20 px-sm-0 d-flex justify-content-center flex-column'>
<h1 class='font-weight-bold text-white title'>Frequently Asked Questions</h1>
<div class='font-size-18 text-muted'>Most commonly asked questions about Miru and its usage.</div>
</div>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>What extensions are there? How to make extensions?</h3>
<p>You can find all information regarding extensions on the <a href='../extensions/' target='_blank'>extensions</a> page.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Can I close the miniplayer?</h3>
<p>No. See above. The miniplayer provides feedback that something is happening in the background. Closing it would make the user feel like the app is lagging [because it's maxing out your internet in the background by torrenting] when nothing is happening.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Can I reduce the upload speed?</h3>
<p>No. See above. This app is also meant to seed the torrents the user downloads, if you want freeleech go to some private tracker.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Does Miru stream the video or does it store it?</h3>
<p>Miru only stores 1 torrent on your drive, unless <kbd>Persist Files</kbd> is enabled in settings. It doesn't stream the content as it also needs to seed the data it downloads to keep the swarm alive. It's important to note that it stores 1 torrent, not 1 video. A single torrent can sometimes consist of many video files, and as such take up a lot of space.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>I have an existing media library, can Miru import it?</h3>
<p>No. Miru does not scan libraries like Plex or Jellyfin. You can however specify Miru's <kbd>Torrent Download Location</kbd> in settings, and if you pick torrents which are already in the selected folder, Miru will use them without re-download them. Make sure that <kbd>Persis Files</kbd> is enabled, or Miru will delete content that was already watched.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Is this safe?</h3>
<p>It's recommended that you read the <a href='https://thewiki.moe/getting-started/torrenting/' target='_blank'>guide about basics of torrenting</a>.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Will this replace streaming sites?</h3>
<p>Not really. The underlying source of video are still torrents, which aren't always seeded, so anime that's a few years old might not play back smoothly.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Can I log in with MAL?</h3>
<p>No. You can however migrate MAL to AL, <a href='https://anilist.co/forum/thread/3393' target='_blank'>see this guide</a>.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Why is anime X not playing?</h3>
<p>One of four reasons:</p>
<ul>
@ -25,29 +37,46 @@
<li>your ISP blocks Torrenting, see <a href='https://thewiki.moe/tutorials/unblock/' target='_blank'>this tutorial</a> for a potential fix, or simply use a VPN</li>
<li>the app couldn't find a matching torrent for the anime</li>
</ul>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>I selected an episode to play, but Miru plays something else!</h3>
<p>Finding desired episodes can sometimes be difficult, if Miru auto-selects an episode incorrectly you can either disable auto-play torrents in settings to select torrents yourself during episode choosing, or manually find and paste in a .torrent file URL or a magnet URL into Miru to play a desired episode manually.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Can I play my own torrents?</h3>
<p>Yes. For the home menu you can specify a different RSS feed to check when the app looks for new releases. Additionally you can just paste/drag-drop a torrent file/magnet link anywhere when using the app, and it will try it's best to auto-detect what anime is playing.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Can I change what tracker torrents are found from?</h3>
<p>Yes. If you find other community made extensions, you can import them in the app settings, however there is no curated list of community made extensions.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>How is this different from sequential qBit?</h3>
<p>Unlike qBit's sequential, this will prioritise downloading torrent pieces directly needed for playback, which with the user seeking isn't always just sequential.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Won't this kill swarm health?</h3>
<p>Depends. On average no. The app is always seeding 1 torrent as long as it's open. Additionally the upload speed is forced to be x1.5 that of the download speed. Those 2 things combined will already make this app seed more than the average leecher which removes the torrent the moment it's downloaded.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Why is it a native app, not a website?</h3>
<p>The BitTorrent protocol requires TCP/UDP to function, that is the only reason. Browsers can't access TCP/UDP which means they can't access the global BitTorrent swarm.</p>
<h5 class='text-white font-weight-bold'>&gt; Can't you make this just use WebRTC?</h5>
<p>Yes. A BitTorrent implementation which uses WebRTC exists, but it's not yet adopted by any clients, and libtorrent [the library which qBit and others use] is still working on/just added support for WebRTC, which means there's no global swarm. This will hopefully change in the future.</p>
<hr class='my-20' />
<h3 class='text-white font-weight-bold'>Miru crashed too many times.</h3>
<p>This is likely because Miru updated from a very old version to a very new one. Uninstall Miru, go to <kbd>%appdata%/miru</kbd> remove all files and re-install it. If this issue persists visit the Discord for help.</p>
</div>
</div>
<style>
.container {
padding-top: 10rem;
}
a {
--dm-link-text-color: #1890ff !important;
--dm-link-text-color-hover: #45a3fb !important;
}
h3 {
margin-top: 0;
padding-top: 0.75em;
}
p {
margin-bottom: 0;
padding-bottom: 1em;
}
.title {
font-size: 5rem
}
</style>