-
-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ea27157
Showing
7 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.wgt | ||
www | ||
.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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="[email protected]">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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta http-equiv="refresh" content="0; url=www/index.html" /> | ||
</head> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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'); | ||
}); | ||
}); |