Skip to content

Commit

Permalink
fix: torrent client sometimes loading without settings on android
Browse files Browse the repository at this point in the history
feat: persist files on android
feat: custom download directory on android
  • Loading branch information
ThaUnknown committed Aug 22, 2024
1 parent c595dd7 commit 94f8faf
Show file tree
Hide file tree
Showing 9 changed files with 442 additions and 535 deletions.
2 changes: 2 additions & 0 deletions capacitor/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
</manifest>
23 changes: 12 additions & 11 deletions capacitor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,25 @@
},
"devDependencies": {
"@capacitor/assets": "github:thaunknown/capacitor-assets",
"@capacitor/cli": "^6.1.1",
"@capacitor/cli": "^6.1.2",
"cordova-res": "^0.15.4",
"nodejs-mobile-gyp": "^0.3.1",
"nodejs-mobile-gyp": "^0.4.0",
"npm-run-all": "^4.1.5",
"webpack-cli": "^5.1.4",
"webpack-merge": "^5.10.0"
"webpack-merge": "^6.0.1"
},
"dependencies": {
"@capacitor/android": "^6.1.1",
"@capacitor/app": "^6.0.0",
"@capacitor/browser": "^6.0.1",
"@capacitor/core": "^6.1.1",
"@capacitor/android": "^6.1.2",
"@capacitor/app": "^6.0.1",
"@capacitor/browser": "^6.0.2",
"@capacitor/core": "^6.1.2",
"@capacitor/device": "^6.0.1",
"@capacitor/ios": "^6.1.1",
"@capacitor/local-notifications": "^6.0.0",
"@capacitor/status-bar": "^6.0.0",
"@capacitor/ios": "^6.1.2",
"@capacitor/local-notifications": "^6.1.0",
"@capacitor/status-bar": "^6.0.1",
"capacitor-folder-picker": "^0.0.2",
"capacitor-nodejs": "https://github.com/funniray/Capacitor-NodeJS/releases/download/nodejs-18/capacitor-nodejs-1.0.0-beta.6.tgz",
"capacitor-plugin-safe-area": "^2.0.6",
"capacitor-plugin-safe-area": "^3.0.3",
"common": "workspace:*",
"cordova-plugin-navigationbar": "^1.0.31",
"cordova-plugin-pip": "^0.0.2",
Expand Down
26 changes: 26 additions & 0 deletions capacitor/src/capacitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { App } from '@capacitor/app'
import { Browser } from '@capacitor/browser'
import { LocalNotifications } from '@capacitor/local-notifications'
import { Device } from '@capacitor/device'
import { FolderPicker } from 'capacitor-folder-picker'
import { toast } from 'svelte-sonner'
import IPC from './ipc.js'

IPC.on('open', url => Browser.open({ url }))
Expand Down Expand Up @@ -51,6 +53,30 @@ IPC.on('get-device-info', async () => {
IPC.emit('device-info', JSON.stringify(deviceInfo))
})

const STORAGE_TYPE_MAP = {
primary: '/sdcard/',
secondary: '/sdcard/'
}

IPC.on('dialog', async () => {
const result = await FolderPicker.chooseFolder()
const normalizedPath = decodeURIComponent(result.path)

const [, uri, ...path] = normalizedPath.split(':')
const [,, app, subpath, type, ...rest] = uri.split('/')

if (app !== 'com.android.externalstorage.documents') return toast.error('Unverified app', { description: 'Expected com.android.externalstorage.documents, got: ' + app })
if (rest.length) return toast.error('Unsupported uri', { description: 'Unxpected access type, got: tree/' + rest.join('/') })
if (subpath !== 'tree') return toast.error('Unsupported subpath type', { description: 'Expected tree subpath, got: ' + subpath })

let base = STORAGE_TYPE_MAP[type]
if (!base) {
if (!/[a-z0-9]{4}-[a-z0-9]{4}/i.test(type)) return toast.error('Unsupported storage type')
base = `/storage/${type}/`
}
IPC.emit('path', base + path.join(''))
})

// schema: miru://key/value
const protocolMap = {
auth: token => sendToken(token),
Expand Down
9 changes: 7 additions & 2 deletions capacitor/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@ channel.on('port-init', data => {
channel.send('ipc', { data })
}
}
let storedSettings = {}

try {
storedSettings = JSON.parse(localStorage.getItem('settings')) || {}
} catch (error) {}

if (!globalThis.client) globalThis.client = new TorrentClient(channel, storageQuota, 'node', storedSettings.torrentPathNew || env.TMPDIR)

channel.on('ipc', a => port.onmessage(a))
channel.emit('port', {
ports: [port]
})
})

globalThis.client = new TorrentClient(channel, storageQuota, 'node', env.TMPDIR)
4 changes: 0 additions & 4 deletions capacitor/src/support.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ export const SUPPORTS = {
update: false,
angle: false,
doh: false,
dht: true,
discord: false,
torrentPort: true,
torrentPath: false,
torrentPersist: false,
keybinds: false,
isAndroid: true,
externalPlayer: false,
Expand Down
4 changes: 0 additions & 4 deletions common/modules/support.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ export const SUPPORTS = {
update: true,
angle: true,
doh: true,
dht: true,
discord: true,
torrentPort: true,
torrentPath: true,
torrentPersist: true,
keybinds: true,
extensions: true,
isAndroid: false,
Expand Down
12 changes: 6 additions & 6 deletions common/modules/webtorrent.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@ const ANNOUNCE = [
atob('aHR0cDovL3RyYWNrZXIuYW5pcmVuYS5jb206ODAvYW5ub3VuY2U=')
]

let storedSettings = {}

try {
storedSettings = JSON.parse(localStorage.getItem('settings')) || {}
} catch (error) {}

export default class TorrentClient extends WebTorrent {
static excludedErrorMessages = ['WebSocket', 'User-Initiated Abort, reason=', 'Connection failed.']

Expand All @@ -54,6 +48,12 @@ export default class TorrentClient extends WebTorrent {
ipc

constructor (ipc, storageQuota, serverMode, torrentPath, controller) {
let storedSettings = {}

try {
storedSettings = JSON.parse(localStorage.getItem('settings')) || {}
} catch (error) {}

const settings = { ...defaults, ...storedSettings }
debug('Initializing TorrentClient with settings: ' + JSON.stringify(settings))
super({
Expand Down
64 changes: 30 additions & 34 deletions common/views/Settings/TorrentSettings.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -140,25 +140,25 @@
{/if}
<h4 class='mb-10 font-weight-bold'>Client Settings</h4>
{#if SUPPORTS.torrentPath}
<SettingCard title='Torrent Download Location' description='Path to the folder used to store torrents. By default this is the TMP folder, which might lose data when your OS tries to reclaim storage.'>
<div
class='input-group w-300 mw-full'>
<div class='input-group-prepend'>
<button type='button' use:click={handleFolder} class='btn btn-primary input-group-append'>Select Folder</button>
</div>
<input type='url' class='form-control bg-dark' readonly value={settings.torrentPathNew} placeholder='/tmp' />
</div>
</SettingCard>
{/if}
{#if SUPPORTS.torrentPersist}
<SettingCard title='Persist Files' description="Keeps torrents files instead of deleting them after a new torrent is played. This doesn't seed the files, only keeps them on your drive. This will quickly fill up your storage.">
<div class='custom-switch'>
<input type='checkbox' id='torrent-persist' bind:checked={settings.torrentPersist} />
<label for='torrent-persist'>{settings.torrentPersist ? 'On' : 'Off'}</label>
<SettingCard title='Torrent Download Location' description='Path to the folder used to store torrents. By default this is the TMP folder, which might lose data when your OS tries to reclaim storage. {SUPPORTS.isAndroid ? 'RESTART IS REQUIRED. /sdcard/ is internal storage, not external SD Cards. /storage/AB12-34CD/ is external storage, not internal. Thank you Android!' : ''}'>
<div
class='input-group w-300 mw-full'>
<div class='input-group-prepend'>
<button type='button' use:click={handleFolder} class='btn btn-primary input-group-append'>Select Folder</button>
</div>
</SettingCard>
{/if}
{#if !SUPPORTS.isAndroid}
<input type='url' class='form-control bg-dark' readonly bind:value={settings.torrentPathNew} placeholder='/tmp' />
{:else}
<input type='text' class='form-control bg-dark' bind:value={settings.torrentPathNew} placeholder='/tmp' />
{/if}
</div>
</SettingCard>
<SettingCard title='Persist Files' description="Keeps torrents files instead of deleting them after a new torrent is played. This doesn't seed the files, only keeps them on your drive. This will quickly fill up your storage.">
<div class='custom-switch'>
<input type='checkbox' id='torrent-persist' bind:checked={settings.torrentPersist} />
<label for='torrent-persist'>{settings.torrentPersist ? 'On' : 'Off'}</label>
</div>
</SettingCard>
<SettingCard title='Streamed Download' description="Only downloads the single file that's currently being watched, instead of downloading an entire batch of episodes. Saves bandwidth and reduces strain on the peer swarm.">
<div class='custom-switch'>
<input type='checkbox' id='torrent-streamed-download' bind:checked={settings.torrentStreamedDownload} />
Expand All @@ -176,22 +176,18 @@
<SettingCard title='Max Number of Connections' description='Number of peers per torrent. Higher values will increase download speeds but might quickly fill up available ports if your ISP limits the maximum allowed number of open connections.'>
<input type='number' inputmode='numeric' pattern='[0-9]*' bind:value={settings.maxConns} min='1' max='512' class='form-control text-right bg-dark w-100 mw-full' />
</SettingCard>
{#if SUPPORTS.torrentPort}
<SettingCard title='Torrent Port' description='Port used for Torrent connections. 0 is automatic.'>
<input type='number' inputmode='numeric' pattern='[0-9]*' bind:value={settings.torrentPort} min='0' max='65536' class='form-control text-right bg-dark w-150 mw-full' />
</SettingCard>
{/if}
{#if SUPPORTS.dht}
<SettingCard title='DHT Port' description='Port used for DHT connections. 0 is automatic.'>
<input type='number' inputmode='numeric' pattern='[0-9]*' bind:value={settings.dhtPort} min='0' max='65536' class='form-control text-right bg-dark w-150 mw-full' />
</SettingCard>
<SettingCard title='Disable DHT' description='Disables Distributed Hash Tables for use in private trackers to improve privacy. Might greatly reduce the amount of discovered peers.'>
<div class='custom-switch'>
<input type='checkbox' id='torrent-dht' bind:checked={settings.torrentDHT} />
<label for='torrent-dht'>{settings.torrentDHT ? 'On' : 'Off'}</label>
</div>
</SettingCard>
{/if}
<SettingCard title='Torrent Port' description='Port used for Torrent connections. 0 is automatic.'>
<input type='number' inputmode='numeric' pattern='[0-9]*' bind:value={settings.torrentPort} min='0' max='65536' class='form-control text-right bg-dark w-150 mw-full' />
</SettingCard>
<SettingCard title='DHT Port' description='Port used for DHT connections. 0 is automatic.'>
<input type='number' inputmode='numeric' pattern='[0-9]*' bind:value={settings.dhtPort} min='0' max='65536' class='form-control text-right bg-dark w-150 mw-full' />
</SettingCard>
<SettingCard title='Disable DHT' description='Disables Distributed Hash Tables for use in private trackers to improve privacy. Might greatly reduce the amount of discovered peers.'>
<div class='custom-switch'>
<input type='checkbox' id='torrent-dht' bind:checked={settings.torrentDHT} />
<label for='torrent-dht'>{settings.torrentDHT ? 'On' : 'Off'}</label>
</div>
</SettingCard>
<SettingCard title='Disable PeX' description='Disables Peer Exchange for use in private trackers to improve privacy. Might greatly reduce the amount of discovered peers.'>
<div class='custom-switch'>
<input type='checkbox' id='torrent-pex' bind:checked={settings.torrentPeX} />
Expand Down
Loading

0 comments on commit 94f8faf

Please sign in to comment.