mirror of
https://github.com/jellyfin/jellyfin-tizen.git
synced 2024-11-22 21:39:41 +00:00
first commit
This commit is contained in:
commit
ea271573c1
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.wgt
|
||||
www
|
||||
.*
|
63
README.md
Normal file
63
README.md
Normal file
@ -0,0 +1,63 @@
|
||||
<h1 align="center">Jellyfin Tizen</h1>
|
||||
<h3 align="center">Part of the <a href="https://jellyfin.media">Jellyfin Project</a></h3>
|
||||
|
||||
## Build Process
|
||||
|
||||
### Getting Started
|
||||
|
||||
1. Download and install Tizen Studio (<a href="https://developer.tizen.org/development/tizen-studio/download">https://developer.tizen.org/development/tizen-studio/download</a>).
|
||||
2. Setup Samsung certificate (need Samsung account).
|
||||
3. Clone or download this repository.
|
||||
```sh
|
||||
git clone https://github.com/jellyfin/jellyfin-tizen.git
|
||||
```
|
||||
4. Clone or download Jellyfin Web repository.
|
||||
```sh
|
||||
git clone https://github.com/jellyfin/jellyfin-web.git
|
||||
```
|
||||
5. Go to Jellyfin Tizen directory.
|
||||
```sh
|
||||
cd jellyfin-tizen
|
||||
```
|
||||
|
||||
### Prepare Interface
|
||||
|
||||
If any changes are made to `jellyfin-web/`, the `www/` directory will need to be rebuilt using the following command.
|
||||
|
||||
```sh
|
||||
JELLYFIN_WEB_DIR=../jellyfin-web/src npx gulp
|
||||
```
|
||||
|
||||
> If `NODE_ENV=development` is set in the environment, then the source files will be copied without being minified.
|
||||
|
||||
> The `JELLYFIN_WEB_DIR` environment variable can be used to override the location of `jellyfin-web`.
|
||||
|
||||
### Build WGT
|
||||
|
||||
```sh
|
||||
tizen build-web -e ".*" -e gulpfile.js
|
||||
tizen package -t wgt -o . -- .buildResult
|
||||
```
|
||||
|
||||
### Deploy to Emulator
|
||||
|
||||
1. Run emulator.
|
||||
2. Install package.
|
||||
```sh
|
||||
tizen install -n *.wgt -t T-samsung-5.0-x86
|
||||
```
|
||||
> Specify target with `-t` option.
|
||||
|
||||
### Deploy to TV
|
||||
|
||||
1. Run TV.
|
||||
2. Activate Developer Mode on TV (<a href="https://developer.samsung.com/tv/develop/getting-started/using-sdk/tv-device">https://developer.samsung.com/tv/develop/getting-started/using-sdk/tv-device</a>).
|
||||
3. Connect to TV with Device Manager from Tizen Studio. Or with sdb.
|
||||
```sh
|
||||
sdb connect YOUR_TV_IP
|
||||
```
|
||||
4. Install package.
|
||||
```sh
|
||||
tizen install -n *.wgt -t UE65NU7400
|
||||
```
|
||||
> Specify target with `-t` option.
|
14
config.xml
Normal file
14
config.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<widget xmlns:tizen="http://tizen.org/ns/widgets" xmlns="http://www.w3.org/ns/widgets" id="http://jellyfin.org/Jellyfin" version="0.1.0" viewmodes="fullscreen">
|
||||
<access origin="*" subdomains="true"></access>
|
||||
<tizen:application id="AprZAARz4r.Jellyfin" package="AprZAARz4r" required_version="3.0"/>
|
||||
<author href="http://jellyfin.org" email="apps@jellyfin.org">Jellyfin</author>
|
||||
<content src="index.html"/>
|
||||
<description>Jellyfin for Samsung Smart TV (Tizen).</description>
|
||||
<feature name="http://tizen.org/feature/screen.size.all"/>
|
||||
<icon src="icon.png"/>
|
||||
<name>Jellyfin</name>
|
||||
<tizen:privilege name="http://tizen.org/privilege/tv.inputdevice"/>
|
||||
<tizen:profile name="tv"/>
|
||||
<tizen:setting screen-orientation="auto-rotation" context-menu="enable" background-support="disable" encryption="disable" install-location="auto" hwkey-event="enable"/>
|
||||
</widget>
|
100
gulpfile.js
Normal file
100
gulpfile.js
Normal file
@ -0,0 +1,100 @@
|
||||
var gulp = require('gulp');
|
||||
var gulpif = require('gulp-if');
|
||||
var del = require('del');
|
||||
var dom = require('gulp-dom');
|
||||
var uglifyes = require('uglify-es');
|
||||
var composer = require('gulp-uglify/composer');
|
||||
var uglify = composer(uglifyes, console);
|
||||
|
||||
// Check the NODE_ENV environment variable
|
||||
var isDev = process.env.NODE_ENV === 'development';
|
||||
// Allow overriding of jellyfin-web directory
|
||||
var WEB_DIR = process.env.JELLYFIN_WEB_DIR || 'node_modules/jellyfin-web/dist';
|
||||
console.info('Using jellyfin-web from', WEB_DIR);
|
||||
|
||||
// Skip minification for development builds or minified files
|
||||
var compress = !isDev && [
|
||||
'**/*',
|
||||
'!**/*min.*',
|
||||
'!**/*hls.js',
|
||||
// Temporarily exclude apiclient until updated
|
||||
'!bower_components/emby-apiclient/**/*.js'
|
||||
];
|
||||
|
||||
var uglifyOptions = {
|
||||
compress: {
|
||||
drop_console: true
|
||||
}
|
||||
};
|
||||
|
||||
var paths = {
|
||||
assets: {
|
||||
src: [
|
||||
WEB_DIR + '/**/*',
|
||||
'!' + WEB_DIR + '/index.html'
|
||||
],
|
||||
dest: 'www/'
|
||||
},
|
||||
index: {
|
||||
src: WEB_DIR + '/index.html',
|
||||
dest: 'www/'
|
||||
}
|
||||
};
|
||||
|
||||
// Clean the www directory
|
||||
function clean() {
|
||||
return del([
|
||||
'www'
|
||||
]);
|
||||
}
|
||||
|
||||
// Copy unmodified assets
|
||||
function copy() {
|
||||
return gulp.src(paths.assets.src)
|
||||
.pipe(gulp.dest(paths.assets.dest));
|
||||
}
|
||||
|
||||
// Add required tags to index.html
|
||||
function modifyIndex() {
|
||||
return gulp.src(paths.index.src)
|
||||
.pipe(dom(function() {
|
||||
// inject CSP meta tag
|
||||
var meta = this.createElement('meta');
|
||||
meta.setAttribute('http-equiv', 'Content-Security-Policy');
|
||||
meta.setAttribute('content', 'default-src * \'self\' \'unsafe-inline\' \'unsafe-eval\' data: gap: file: filesystem: ws: wss:;');
|
||||
this.head.appendChild(meta);
|
||||
|
||||
// inject appMode script
|
||||
var appMode = this.createElement('script');
|
||||
appMode.text = 'window.appMode=\'cordova\';';
|
||||
this.body.appendChild(appMode);
|
||||
|
||||
// inject tizen.js
|
||||
var tizen = this.createElement('script');
|
||||
tizen.setAttribute('src', '../tizen.js');
|
||||
tizen.setAttribute('defer', '');
|
||||
this.body.appendChild(tizen);
|
||||
|
||||
// inject apploader.js
|
||||
var apploader = this.createElement('script');
|
||||
apploader.setAttribute('src', 'scripts/apploader.js');
|
||||
apploader.setAttribute('defer', '');
|
||||
this.body.appendChild(apploader);
|
||||
|
||||
return this;
|
||||
}))
|
||||
.pipe(gulp.dest(paths.index.dest))
|
||||
}
|
||||
|
||||
// Default build task
|
||||
var build = gulp.series(
|
||||
clean,
|
||||
gulp.parallel(copy, modifyIndex)
|
||||
);
|
||||
|
||||
// Export tasks so they can be run individually
|
||||
exports.clean = clean;
|
||||
exports.copy = copy;
|
||||
exports.modifyIndex = modifyIndex;
|
||||
// Export default task
|
||||
exports.default = build;
|
6
index.html
Normal file
6
index.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; url=www/index.html" />
|
||||
</head>
|
||||
</html>
|
179
tizen.js
Normal file
179
tizen.js
Normal file
@ -0,0 +1,179 @@
|
||||
'use strict';
|
||||
|
||||
console.log('Tizen adapter');
|
||||
|
||||
window.addEventListener('load', function() {
|
||||
|
||||
//console.log(JSON.stringify(tizen.tvinputdevice.getSupportedKeys()));
|
||||
|
||||
tizen.tvinputdevice.registerKey('MediaPlay');
|
||||
tizen.tvinputdevice.registerKey('MediaTrackPrevious');
|
||||
tizen.tvinputdevice.registerKey('MediaTrackNext');
|
||||
tizen.tvinputdevice.registerKey('MediaRewind');
|
||||
tizen.tvinputdevice.registerKey('MediaFastForward');
|
||||
|
||||
require(['inputManager', 'focusManager', 'viewManager', 'appRouter', 'actionsheet'], function(inputManager, focusManager, viewManager, appRouter, actionsheet) {
|
||||
|
||||
const commands = {
|
||||
'10009': 'back',
|
||||
'415': 'playpause',
|
||||
'10232': 'previoustrack',
|
||||
'10233': 'nexttrack',
|
||||
'412': 'rewind',
|
||||
'417': 'fastforward'
|
||||
};
|
||||
|
||||
var isRestored;
|
||||
var lastActiveElement;
|
||||
var historyStartup;
|
||||
var historyDepth = 0;
|
||||
var exitPromise;
|
||||
|
||||
//document.addEventListener('keypress', function(e) {
|
||||
// console.log('keypress');
|
||||
//});
|
||||
|
||||
//document.addEventListener('keyup', function(e) {
|
||||
// console.log('keyup');
|
||||
//});
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
//console.log('keydown: keyCode: ' + e.keyCode + ' key: ' + e.key + ' location: ' + e.location);
|
||||
|
||||
var command = commands[e.keyCode];
|
||||
|
||||
if (command) {
|
||||
//console.log('command: ' + command);
|
||||
|
||||
if (command === 'back' && historyDepth < 2 && !exitPromise) {
|
||||
exitPromise = actionsheet.show({
|
||||
title: Globalize.translate('Exit?'),
|
||||
items: [
|
||||
{id: 'yes', name: Globalize.translate('Yes')},
|
||||
{id: 'no', name: Globalize.translate('No')}
|
||||
]
|
||||
}).then(function (value) {
|
||||
exitPromise = null;
|
||||
|
||||
if (value === 'yes') {
|
||||
try {
|
||||
tizen.application.getCurrentApplication().exit();
|
||||
} catch (ignore) {}
|
||||
}
|
||||
},
|
||||
function () {
|
||||
exitPromise = null;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
inputManager.trigger(command);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('click', function() {
|
||||
lastActiveElement = document.activeElement;
|
||||
});
|
||||
|
||||
document.addEventListener('viewhide', function() {
|
||||
lastActiveElement = document.activeElement;
|
||||
});
|
||||
|
||||
function onPageLoad() {
|
||||
console.debug('onPageLoad ' + window.location.href + ' isRestored=' + isRestored);
|
||||
|
||||
if (isRestored) {
|
||||
return;
|
||||
}
|
||||
|
||||
var view = viewManager.currentView() || document.body;
|
||||
|
||||
var element = lastActiveElement;
|
||||
lastActiveElement = null;
|
||||
|
||||
// These elements are recreated
|
||||
if (element) {
|
||||
if (element.classList.contains('btnPreviousPage')) {
|
||||
element = view.querySelector('.btnPreviousPage');
|
||||
} else if (element.classList.contains('btnNextPage')) {
|
||||
element = view.querySelector('.btnNextPage');
|
||||
}
|
||||
}
|
||||
|
||||
if (element && focusManager.isCurrentlyFocusable(element)) {
|
||||
focusManager.focus(element);
|
||||
} else {
|
||||
element = focusManager.autoFocus(view);
|
||||
}
|
||||
}
|
||||
|
||||
// Starts listening for changes in the '.loading-spinner' HTML element
|
||||
function installMutationObserver() {
|
||||
var mutationObserver = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
console.debug(mutation.type);
|
||||
if (mutation.target.classList.contains('hide')) {
|
||||
onPageLoad();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var spinner = document.querySelector('.loading-spinner');
|
||||
|
||||
if (spinner) {
|
||||
mutationObserver.observe(spinner, { attributes : true });
|
||||
document.removeEventListener('viewshow', installMutationObserver);
|
||||
}
|
||||
}
|
||||
document.addEventListener('viewshow', installMutationObserver);
|
||||
|
||||
window.addEventListener('pushState', function(e) {
|
||||
|
||||
// Reset history on some pages
|
||||
|
||||
var path = e.arguments && e.arguments[2] ? e.arguments[2] : '';
|
||||
var pos = path.indexOf('?');
|
||||
path = path.substring(0, pos !== -1 ? pos : path.length);
|
||||
|
||||
switch (path) {
|
||||
case '#!/home.html':
|
||||
if (!historyStartup || historyStartup !== path) {
|
||||
historyStartup = path;
|
||||
historyDepth = 0;
|
||||
}
|
||||
break;
|
||||
case '#!/selectserver.html':
|
||||
case '#!/login.html':
|
||||
historyStartup = path;
|
||||
historyDepth = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
historyDepth++;
|
||||
|
||||
isRestored = false;
|
||||
|
||||
//console.log('history: ' + historyDepth + ', ' + historyStartup);
|
||||
});
|
||||
|
||||
window.addEventListener('popstate', function() {
|
||||
historyDepth--;
|
||||
isRestored = true;
|
||||
//console.log('history: ' + historyDepth + ', ' + historyStartup);
|
||||
});
|
||||
|
||||
// Add 'pushState' and 'replaceState' events
|
||||
var _wr = function(type) {
|
||||
var orig = history[type];
|
||||
return function() {
|
||||
var rv = orig.apply(this, arguments);
|
||||
var e = new Event(type);
|
||||
e.arguments = arguments;
|
||||
window.dispatchEvent(e);
|
||||
return rv;
|
||||
};
|
||||
};
|
||||
history.pushState = _wr('pushState');
|
||||
history.replaceState = _wr('replaceState');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user