Compare commits

...

125 Commits

Author SHA1 Message Date
Joshua M. Boniface
be195b0e24 Bump version to 10.7.7 2021-09-05 22:33:01 -04:00
dkanada
32330e3126 Merge pull request #2759 from thornbill/fix-serviceworker-paths
Fix serviceworker paths
2021-09-05 19:49:19 +09:00
Bill Thornton
af706726ef Upgrade workbox-webpack-plugin backport 2021-06-30 13:51:20 -04:00
Bill Thornton
393bfd2559 Update lockfile 2021-06-30 13:43:00 -04:00
Bill Thornton
575766b8e8 Merge pull request #2678 from grafixeyehero/window.global
Access Loading globally 

(cherry picked from commit c8fcb9e664)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-06-13 19:31:47 -04:00
Bill Thornton
f2cbfbb549 Merge pull request #2672 from nyanmisaka/patch-1
Remove OPUS from supported HLS audio formats

(cherry picked from commit 95256a87b5)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-27 02:46:37 -04:00
Bill Thornton
b589363d31 Merge pull request #2665 from dmitrylyzo/fix-server-hash-change
Add connection response handling

(cherry picked from commit eb79a8e045)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-27 02:46:37 -04:00
Anthony Lavado
4c1a301bdb Merge pull request #2676 from thornbill/fix-displaymessage-xss
(cherry picked from commit 70b41ff005)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-21 13:50:36 -04:00
Anthony Lavado
dfcfaad39c Merge pull request #2675 from thornbill/fix-share-url
(cherry picked from commit 8e465fb1fd)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-21 13:50:36 -04:00
Joshua M. Boniface
f9109a8194 Bump version to 10.7.6 2021-05-20 22:07:12 -04:00
Bill Thornton
2192388b78 Merge pull request #2673 from jellyfin/fix-serviceworker
Fix ServiceWorker URL

(cherry picked from commit 21b88e5efa)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-20 22:05:29 -04:00
Bill Thornton
f6d50b0721 Merge pull request #2475 from dmitrylyzo/fix-multiserver-wizard
Fix wizard in multi-server app

(cherry picked from commit 62d5c81120)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-20 22:05:29 -04:00
Joshua M. Boniface
05816d5562 Bump version to 10.7.5 2021-05-04 22:08:32 -04:00
Joshua M. Boniface
65f4e29d36 Bump version to 10.7.4 2021-05-04 21:16:31 -04:00
Joshua M. Boniface
0f0593f260 Bump version to 10.7.3 2021-05-04 20:00:47 -04:00
Bill Thornton
7d920beff0 Merge pull request #2657 from thornbill/apiclient-1.8
Bump jellyfin-apiclient to 1.8.0

(cherry picked from commit 4bfb59a00a)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-04 19:34:27 -04:00
Joshua M. Boniface
2dc95beb8f Merge pull request #2648 from thornbill/fix-docker-build
Fix alpine python package

(cherry picked from commit 79b36cd6b9)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-04 19:34:10 -04:00
Anthony Lavado
8449b94d16 Merge pull request #2647 from thornbill/safari-mov
(cherry picked from commit 4f13c10e8c)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-04 19:34:10 -04:00
Bill Thornton
4a17964e67 Merge pull request #2519 from dmitrylyzo/fix-hevc-in-ts
Add HEVC in TS for Tizen and webOS

(cherry picked from commit 59053ab6ae)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-04 19:34:10 -04:00
Joshua M. Boniface
c2106ab86c Remove erroneous package-lock.json 2021-05-03 18:06:37 -04:00
Joshua M. Boniface
591ee288bf Merge pull request #2645 from joshuaboniface/remove-image-proxy
(cherry picked from commit 9e845fb917)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-02 17:02:34 -04:00
Bill Thornton
87cae4336c Merge pull request #2624 from dmitrylyzo/fix-webos-customelements
webOS: fix Favorites tab
(cherry picked from commit 0a7b829c2c)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-01 13:25:37 -04:00
Bill Thornton
7cf812df37 Merge pull request #2617 from iwalton3/tv-scroll-styling-chrome
Set scrollbar width in TV mode.

(cherry picked from commit c1b847a309)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-05-01 13:25:37 -04:00
Anthony Lavado
b5d9ff9279 Merge pull request #2620 from dmitrylyzo/hide-search-alphapicker-on-tv
(cherry picked from commit 9f1bfe1631)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-29 15:00:36 -04:00
Bill Thornton
b053cb9d79 Merge pull request #2619 from jellyfin/fix-filter-hiding
Fix video filters hiding

(cherry picked from commit a8831cea3e)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-29 14:57:55 -04:00
Bill Thornton
ba0815e1c3 Merge pull request #2616 from jellyfin/fix-es6-2
Fix view style selection dialog (ES6 migration)

(cherry picked from commit d7bf7ae58b)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-29 14:57:55 -04:00
Bill Thornton
94ac2b22a2 Merge pull request #2604 from Artiume/patch-5
Update Audiobook Resume Help

(cherry picked from commit cdf1bf72de)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-29 14:57:55 -04:00
Bill Thornton
7af38bb60c Merge pull request #2593 from oddstr13/pr-imagefix-master
Ensure that fillHeight gets set on image requests

(cherry picked from commit 5c09077a2f)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-21 21:27:31 -04:00
Joshua M. Boniface
21fd1a96fe Merge pull request #2585 from nielsvanvelzen/fix-lockfile-10.7.2
Fix 10.7.2 lockfile
2021-04-11 16:43:34 -04:00
Joshua M. Boniface
b50eb4fa2e Merge pull request #2586 from joshuaboniface/fix-fedora-docker
Fix 10.7.2 Fedora docker
2021-04-11 16:43:15 -04:00
Joshua M. Boniface
458fad3cb0 Add nodejs dependency to Fedora Dockerfile 2021-04-11 16:37:06 -04:00
Niels van Velzen
b467e581b0 Fix 10.7.2 lockfile 2021-04-11 22:32:23 +02:00
Joshua M. Boniface
2d381bbdc6 Bump version to 10.7.2 2021-04-11 14:20:17 -04:00
Bill Thornton
bdfc09739e Merge pull request #2576 from jellyfin/fix-es6-1
Fix ES6 migration

(cherry picked from commit 98814a5b66)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-11 13:38:51 -04:00
Bill Thornton
ff0a46a004 Merge pull request #2575 from jellyfin/revert-2536-fix-invalid-credentials
Revert "fix: redirect to login if stored credentials are invalid"

(cherry picked from commit 70ac9e0f2b)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-11 13:38:51 -04:00
Bill Thornton
32d152150b Merge pull request #2572 from Ullmie02/music_video_fix
Fix music videos on artist and album page

(cherry picked from commit e813fa7b64)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-11 13:38:51 -04:00
Bill Thornton
b9e0dd4938 Merge pull request #2552 from jellyfin/add-unknown-command
add 'unknown' as an input command

(cherry picked from commit a20322e7c2)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-11 13:38:51 -04:00
Bill Thornton
79d0ed3ee4 Merge pull request #2536 from cvium/fix-invalid-credentials
fix: redirect to login if stored credentials are invalid
(cherry picked from commit 070671f206)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-11 13:38:51 -04:00
Bill Thornton
d73d00a344 Merge pull request #2530 from ssenart/feature/2529-album_shuffle_broken
[2529] [RegressionFix] [Dlna] Album shuffle button does not shuffle any more since 10.6.4.

(cherry picked from commit 9ee48ee0ca)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-11 13:38:51 -04:00
Joshua M. Boniface
d91d3120e9 Merge pull request #2524 from crobibero/fedora-33
Build from fedora-33

(cherry picked from commit de2bebc089)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-11 13:38:51 -04:00
Bill Thornton
74de218ff6 Merge pull request #2514 from oddstr13/image-fill-resize
Add support for fillWidth and fillHeight

(cherry picked from commit 2c85b7806b)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-11 13:38:50 -04:00
Bill Thornton
eb3f1a3ba3 Merge pull request #2509 from jellyfin/disable-first-episode
Disable first episodes in Next Up home section

(cherry picked from commit a025771410)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-04-11 13:38:50 -04:00
Joshua M. Boniface
8e63b38a08 Add missing bump version 2021-03-21 19:27:16 -04:00
Joshua M. Boniface
def3532019 Bump version to 10.7.1 2021-03-21 19:24:02 -04:00
Bill Thornton
5ec953e344 Merge pull request #2503 from thornbill/fix-invalid-configs
Fix default values for invalid config.json files

(cherry picked from commit 7650c885d6)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-03-21 19:18:36 -04:00
Bill Thornton
85013363e8 Merge pull request #2498 from thornbill/add-cbz-close-button
Add close button to comics player

(cherry picked from commit 312136c531)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-03-21 19:18:36 -04:00
Bill Thornton
79c8495a1b Merge pull request #2496 from thornbill/logos-without-backdrops
Allow logos without backdrops enabled

(cherry picked from commit 6407128575)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-03-21 19:18:36 -04:00
dkanada
add2ec132f Merge pull request #2502 from brianjmurrell/patch-4
Add BR: nodejs for Fedora 33 and up
2021-03-20 01:06:43 +09:00
Brian J. Murrell
bcba45fc7d Bump the Release:
So that it successfully upgrades any broken ones.

Signed-off-by: Brian J. Murrell <brian@interlinx.bc.ca>
2021-03-11 08:46:53 -05:00
Brian J. Murrell
e404106f9c Make directory permissions 755
Files can/should be 644 but directories need to be 755.

Signed-off-by: Brian J. Murrell <brian@interlinx.bc.ca>
2021-03-11 08:33:38 -05:00
Brian J. Murrell
31b52f2c32 Reduce permissions
Giving everything a blanket execute permission is overzealous and dangerous.

Change permissions to 644.

Signed-off-by: Brian J. Murrell <brian@interlinx.bc.ca>
2021-03-10 10:25:29 -05:00
Brian J. Murrell
a6d9897d8f Escape macro in comment
Not really allowed to use macros in comments and rpmbuild on F33 is starting
to enforce this.

Signed-off-by: Brian J. Murrell <brian@interlinx.bc.ca>
2021-03-10 09:59:31 -05:00
Brian J. Murrell
925c2c926d Add BR: nodejs for Fedora 33 and up
nodejs doesn't seem to be implicitly installed as a BR: on Fedora 33, so set
an explicit BR: for it.

Signed-off-by: Brian J. Murrell <brian@interlinx.bc.ca>
2021-03-10 09:37:44 -05:00
Joshua M. Boniface
a1dddf4524 Bump version to 10.7.0 2021-03-08 17:03:07 -05:00
dkanada
bad273ee3f Merge pull request #2482 from cvium/fix-addlibrary
don't use Locations as an indicator for AddLibrary

(cherry picked from commit ce95dced1d)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-03-06 14:35:06 -05:00
Bill Thornton
e6f59a761b Merge pull request #2473 from thornbill/cache-busting
Add hash to bundle urls for cache busting

(cherry picked from commit 68bf09de16)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-03-06 14:34:57 -05:00
dkanada
afdaf29dc6 Merge pull request #2470 from pgeorgi/fix-cros
browser.js: Avoid misdetecting Chrome OS as OS X

(cherry picked from commit 8d01ed530e)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-03-06 14:32:44 -05:00
dkanada
48201581d6 Merge pull request #2442 from jellyfin/plugin-tweaks
minor improvements to plugin pages

(cherry picked from commit d149430f65)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-03-06 14:32:41 -05:00
Joshua M. Boniface
8bb34c4266 Fix bad spacer in changelog line 2021-02-28 22:29:59 -05:00
Joshua M. Boniface
3ad0bb9118 Merge pull request #2461 from thornbill/remove-ios-limit
Remove iOS bandwidth limit

(cherry picked from commit 8f2437ab97)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-28 22:21:27 -05:00
Bill Thornton
7724b5fedc Merge pull request #2443 from dmitrylyzo/fix-tizen-subtitles
Fix attachment delivery urls

(cherry picked from commit 0a342ce095)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-27 22:36:16 -05:00
Bill Thornton
2a7d708944 Merge pull request #2378 from jellyfin/session-style
update style for active sessions

(cherry picked from commit bc557b1970)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-27 22:36:16 -05:00
dkanada
97461dabf2 Merge pull request #2343 from jellyfin/plugin-icon
fix image alignment on plugin cards

(cherry picked from commit 536797a22f)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-27 22:36:10 -05:00
Joshua M. Boniface
0ccbae44d1 Bump version to 10.7.0~rc4 2021-02-21 13:42:10 -05:00
dkanada
d85c91ce2e Merge pull request #2417 from MrLemur/source-type-change
Change babel.config.js sourceType to unamiguous

(cherry picked from commit fee5731038)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-21 13:27:22 -05:00
dkanada
93042157f8 Merge pull request #2375 from jellyfin/fix-no-repository-message
fix: message appearing after adding repositories
(cherry picked from commit bd297efac9)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-21 13:27:22 -05:00
dkanada
5e8c92a7a7 Merge pull request #2374 from cvium/fix_playaccess_validation
reject play access validation promise

(cherry picked from commit f6d0380486)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-21 13:27:22 -05:00
dkanada
3a57471b69 Merge pull request #2358 from Alcatraz077/master
Allows Search On Tizen

(cherry picked from commit caca17adba)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-21 13:27:22 -05:00
dkanada
fb17afad60 Merge pull request #2357 from thornbill/fix-epub-height
Fix epub player height

(cherry picked from commit 37bb21e347)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-21 13:27:22 -05:00
dkanada
4e38caba0a Merge pull request #2356 from jellyfin/fix-notch
fix: notched devices area not covered
(cherry picked from commit 9ee06bfa7e)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-21 13:27:22 -05:00
Bill Thornton
1f97acc46e Merge pull request #2353 from thornbill/comics-player-height
Fix scaling in comics player

(cherry picked from commit 441d7a4236)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-21 13:27:22 -05:00
Joshua M. Boniface
998df179a8 Merge pull request #2350 from nyanmisaka/nvdec-vpp
(cherry picked from commit f7f0d688e8)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-21 13:27:19 -05:00
Bill Thornton
ff9fab5af1 Merge pull request #2344 from jellyfin/remove-unused-imports
refactor: remove unused imports
(cherry picked from commit 8df5febb3a)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-21 13:26:24 -05:00
Bill Thornton
84c5df8ea4 Merge pull request #2327 from MrChip53/library-menu-edit
Edit admin dashboard menu for plugins

(cherry picked from commit 0ff9615b47)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-02-21 13:26:24 -05:00
Joshua M. Boniface
d4c8cceb7f Bump version to 10.7.0-rc3 2021-01-23 16:02:48 -05:00
Bill Thornton
d588fc42c6 Merge pull request #2323 from jarnedemeulemeester/fix-play-icon-replace-resume-icon
Fix replay icon not getting replaced with play_arrow icon

(cherry picked from commit dade850ccf)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-01-23 15:20:16 -05:00
dkanada
0fa42cb7e6 Merge pull request #2318 from thornbill/buttondelete
Fix removed ButtonDelete key

(cherry picked from commit 7c9703e93a)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-01-23 15:20:16 -05:00
Bill Thornton
ef4f5d1f08 Merge pull request #2313 from dmitrylyzo/fix-safari-tizen
Fix browser detection: Safari vs Tizen

(cherry picked from commit 41cfd7f412)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-01-23 15:20:15 -05:00
Bill Thornton
d27f661b46 Merge pull request #2312 from jarnedemeulemeester/use-local-noto-sans
Use local version of Noto Sans if available

(cherry picked from commit 798df9b050)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-01-23 15:20:15 -05:00
Bill Thornton
0f247fd9f4 Merge pull request #2311 from jellyfin/nielsvanvelzen-disable-multi-download
Disable multi download option

(cherry picked from commit d08c4e4274)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-01-23 15:20:15 -05:00
Bill Thornton
ac34647e85 Merge pull request #2309 from jellyfin/white-flashing-images
fix(card): white flashing images

(cherry picked from commit 945946b96d)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-01-23 15:20:15 -05:00
Bill Thornton
e8028aa1a1 Merge pull request #2306 from thornbill/fix-tiny-icons
Fix tiny card icons

(cherry picked from commit e2c4418485)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-01-23 15:20:15 -05:00
Bill Thornton
42b0b01a4e Merge pull request #2293 from thornbill/wrong-latest-tab
Fix latest tab links for tv and music

(cherry picked from commit e5531c363b)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-01-23 15:20:15 -05:00
Bill Thornton
cde21b3ff2 Merge pull request #2290 from MrTimscampi/chromecast-messages
Add Chromecast error messages to the locales

(cherry picked from commit a548bef8c2)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2021-01-23 15:20:15 -05:00
Joshua M. Boniface
58dc73cf66 Bump version to 10.7.0-rc2 2020-12-31 19:24:43 -05:00
Joshua M. Boniface
136983e026 Merge pull request #2288 from joshuaboniface/bump-apiclient
(cherry picked from commit 0a60f165a8)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-31 19:07:19 -05:00
Joshua M. Boniface
f38fb6eb46 Merge pull request #2280 from Artiume/patch-5
(cherry picked from commit b7eeebdd11)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-31 19:07:03 -05:00
Joshua M. Boniface
aba1d8655b Merge pull request #2225 from BaronGreenback/NewPluginController
(cherry picked from commit 9f175ee483)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-31 19:07:02 -05:00
Joshua M. Boniface
7582206eb3 Merge pull request #2286 from Artiume/patch-6
(cherry picked from commit b744fe4d74)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:13:21 -05:00
Bill Thornton
68edd48a0d Merge pull request #2283 from thornbill/allow-decimal-bitrate
Allow decimal entry for bitrate on mobile

(cherry picked from commit 9008a42cc9)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:02 -05:00
dkanada
e8d044fbb7 Merge pull request #2269 from jellyfin/dkanada-patch-1
Fix issue with double click fullscreen

(cherry picked from commit b64f50307d)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:02 -05:00
Bill Thornton
7379822c72 Merge pull request #2265 from MrTimscampi/sort-by-premiere-date
Sort items by premiere date on the details page

(cherry picked from commit 58aa865af0)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:02 -05:00
Bill Thornton
2c230388be Merge pull request #2263 from MrTimscampi/osd-pointer-events
Fix OSD gradients not letting pointer events through

(cherry picked from commit 6a8173718d)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:02 -05:00
dkanada
32514307eb Merge pull request #2260 from thornbill/moar-centering-issues
Fix chevron centering on home section titles

(cherry picked from commit af11671485)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:02 -05:00
Joshua M. Boniface
0f12bd64aa Merge pull request #2258 from thornbill/return-of-the-dashboard-theme
(cherry picked from commit 699a3d2046)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:01 -05:00
Bill Thornton
6ff1bdcaca Merge pull request #2247 from thornbill/cant-stop-wont-stop
Always allow stopping via the action menu

(cherry picked from commit 60cce55204)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:01 -05:00
Bill Thornton
88dc049a2f Merge pull request #2246 from thornbill/fix-item-details-mobile
Fix layout issues on mobile item details

(cherry picked from commit e1672db560)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:01 -05:00
Bill Thornton
5d42ac19c7 Merge pull request #2244 from Artiume/patch-2
Fix Continue Listening

(cherry picked from commit e752116209)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:01 -05:00
Bill Thornton
efe4374153 Merge pull request #2242 from thornbill/fix-prepare-script-windows
Replace bash prepare script with node version

(cherry picked from commit 898704d9b0)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:01 -05:00
Bill Thornton
cd256f7989 Merge pull request #2240 from thornbill/fix-sonarqube-bug
Remove duplicate try/catch

(cherry picked from commit 9f0b5bf673)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:01 -05:00
Bill Thornton
49fa4e0b65 Merge pull request #2239 from thornbill/disable-browser-hack-sass
Disable browser hack rule for sass files

(cherry picked from commit 86b8b55b1a)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:08:01 -05:00
Bill Thornton
3a4023ca40 Merge pull request #2238 from thornbill/revert-restart
Fix restart button being shown when unsupported

(cherry picked from commit 0a50c4ddc1)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:07:53 -05:00
Bill Thornton
982bbee9ea Merge pull request #2237 from thornbill/fix-plugin-cards
Fix layout of plugin cards

(cherry picked from commit be57362f21)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:06:54 -05:00
Joshua M. Boniface
142c56bf6a Merge pull request #2236 from thornbill/fix-epub-touch
Fix touch support in epub reader

(cherry picked from commit b60407abcc)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:06:54 -05:00
Bill Thornton
1207ac98be Merge pull request #2234 from thornbill/no-no-noto
Use Noto Sans from Fontsource

(cherry picked from commit d66d26b4f6)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:06:54 -05:00
Bill Thornton
c757c53e5c Merge pull request #2224 from Delgan/patch-1
Fix possible HLSError (BufferFullError) on Firefox

(cherry picked from commit ebb4b05081)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:06:54 -05:00
Bill Thornton
cd2d30eefc Merge pull request #2222 from nyanmisaka/finetune-tonemap
Modify some tone mapping related strings

(cherry picked from commit bb47abc2a4)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:06:54 -05:00
Joshua M. Boniface
07a33779d8 Merge pull request #2218 from thornbill/style-fixes
(cherry picked from commit 68fb95bf7d)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-30 19:06:50 -05:00
dkanada
4dedb8ae45 Merge pull request #2220 from jellyfin/dependabot/npm_and_yarn/ini-1.3.7
Bump ini from 1.3.5 to 1.3.7

(cherry picked from commit c1a675053c)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:23 -05:00
Bill Thornton
87d459f827 Merge pull request #2219 from crobibero/create-playlist
Set Content-Type header when creating a playlist

(cherry picked from commit 1c03e4c830)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:23 -05:00
dkanada
eeded17cbd Merge pull request #2217 from nyanmisaka/landingScreen-cleanup
Landing screen options clean up

(cherry picked from commit f94cbfed7c)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:23 -05:00
Bill Thornton
95a995327d Merge pull request #2216 from dmitrylyzo/fix-livetv-canplay
Fix canPlay for Live TV

(cherry picked from commit fdcf74d498)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:23 -05:00
dkanada
27896bcc84 Merge pull request #2215 from dmitrylyzo/fix-livetv-pages
Fix multiplication of event listeners on Live TV pages

(cherry picked from commit 568968f654)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
dkanada
4aeecfa043 Merge pull request #2214 from dmitrylyzo/fix-livetv-route
Fix LiveTV group anchors

(cherry picked from commit 5da9d93423)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
Bill Thornton
88bb7adaba Merge pull request #2213 from thornbill/fix-sonar-bugs
Fix sonarqube bugs

(cherry picked from commit 52543f8a51)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
dkanada
d768cf7970 Merge pull request #2211 from thornbill/fix-dlna-profile-link
Fix invalid dlna profile path

(cherry picked from commit 3995143690)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
dkanada
22df1eb3a6 Merge pull request #2210 from nyanmisaka/offset-step
Set the step of subtitle offset slider to 0.1

(cherry picked from commit c7a1c19d9e)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
dkanada
ac6ba3228f Merge pull request #2202 from thornbill/fix-user-edit
Remove reference to sharing help element

(cherry picked from commit a8005f2ec3)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
Bill Thornton
7e5fcd8374 Merge pull request #2195 from OancaAndrei/syncplay-fix-next-item
Fix SyncPlay switching to next item in queue

(cherry picked from commit 60e8fc4d8e)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
dkanada
ccef18ee5d Merge pull request #2188 from dmitrylyzo/fix-back
Fix anchor click action and plugin configuration page URL

(cherry picked from commit 62a09b7a4e)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
Bill Thornton
5f63743ed0 Merge pull request #2186 from Maxr1998/fix-plugin-loader
Fix plugin loader for function definitions in window

(cherry picked from commit 3992265189)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
dkanada
972ecc4106 Merge pull request #2183 from dmitrylyzo/fix-multiserver-syncplay
SyncPlay, don't use bad ApiClient

(cherry picked from commit 9815c64cdc)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
Bill Thornton
c4fd94b147 Merge pull request #2181 from MrTimscampi/no-userdata-field
Remove non-existing UserData field from requests

(cherry picked from commit 7cbaa99784)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-13 20:59:22 -05:00
Anthony Lavado
a0ef8a405c Merge pull request #2177 from anthonylavado/update-apiclient
Update the API Client version

(cherry picked from commit 46716fc25a)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
2020-12-05 01:10:16 -05:00
Joshua M. Boniface
4b9ffb7b22 Bump version to 10.7.0~rc1 2020-12-04 21:00:31 -05:00
154 changed files with 9117 additions and 944 deletions

View File

@@ -92,6 +92,7 @@ module.exports = {
'LibraryMenu': 'writable',
'LinkParser': 'writable',
'LiveTvHelpers': 'writable',
'Loading': 'writable',
'MetadataEditor': 'writable',
'PlaylistViewer': 'writable',
'UserParentalControlPage': 'writable',

View File

@@ -3,6 +3,7 @@
"plugins": [ "stylelint-scss" ],
"rules": {
"at-rule-no-unknown": null,
"scss/at-rule-no-unknown": true
"scss/at-rule-no-unknown": true,
"plugin/no-browser-hacks": null
}
}

View File

@@ -34,6 +34,7 @@
- [Ryan Hartzell](https://github.com/ryan-hartzell)
- [Thibault Nocchi](https://github.com/ThibaultNocchi)
- [MrTimscampi](https://github.com/MrTimscampi)
- [artiume](https://github.com/Artiume)
- [ConfusedPolarBear](https://github.com/ConfusedPolarBear)
- [Sarab Singh](https://github.com/sarab97)
- [DesertCookie](https://github.com/desertcookie)
@@ -43,6 +44,7 @@
- [Orry Verducci](https://github.com/orryverducci)
- [Camc314](https://github.com/camc314)
- [danieladov](https://github.com/danieladov)
- [Stephane Senart](https://github.com/ssenart)
# Emby Contributors

View File

@@ -3,6 +3,7 @@ module.exports = {
// Keep the root as a root
'.'
],
sourceType: 'unambiguous',
presets: [
[
'@babel/preset-env',

View File

@@ -1,7 +1,7 @@
---
# We just wrap `build` so this is really it
name: "jellyfin-web"
version: "10.7.0"
version: "10.7.7"
packages:
- debian.all
- fedora.all

52
debian/changelog vendored
View File

@@ -1,11 +1,45 @@
jellyfin-web (10.7.7-1) unstable; urgency=medium
* New upstream version 10.7.7; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.7
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 05 Sep 2021 22:32:59 -0400
jellyfin-web (10.7.6-1) unstable; urgency=medium
* New upstream version 10.7.6; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.6
-- Jellyfin Packaging Team <packaging@jellyfin.org> Thu, 20 May 2021 22:06:52 -0400
jellyfin-web (10.7.5-1) unstable; urgency=medium
* New upstream version 10.7.5; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.5
-- Jellyfin Packaging Team <packaging@jellyfin.org> Tue, 04 May 2021 22:08:30 -0400
jellyfin-web (10.7.4-1) unstable; urgency=medium
* New upstream version 10.7.4; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.4
-- Jellyfin Packaging Team <packaging@jellyfin.org> Tue, 04 May 2021 21:16:07 -0400
jellyfin-web (10.7.3-1) unstable; urgency=medium
* New upstream version 10.7.3; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.3
-- Jellyfin Packaging Team <packaging@jellyfin.org> Tue, 04 May 2021 20:00:22 -0400
jellyfin-web (10.7.2-1) unstable; urgency=medium
* New upstream version 10.7.2; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.2
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 11 Apr 2021 14:19:38 -0400
jellyfin-web (10.7.1-1) unstable; urgency=medium
* New upstream version 10.7.1; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.1
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 21 Mar 2021 19:23:29 -0400
jellyfin-web (10.7.0-1) unstable; urgency=medium
* Forthcoming stable release
-- Jellyfin Packaging Team <packaging@jellyfin.org> Mon, 27 Jul 2020 19:13:31 -0400
jellyfin-web (10.6.0-1) unstable; urgency=medium
* New upstream version 10.6.0; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.0
-- Jellyfin Packaging Team <packaging@jellyfin.org> Mon, 16 Mar 2020 11:15:00 -0400
* New upstream version 10.7.0; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.0

View File

@@ -1,9 +1,9 @@
FROM node:alpine
FROM node:lts-alpine
ARG SOURCE_DIR=/src
ARG ARTIFACT_DIR=/jellyfin-web
RUN apk add autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python
RUN apk add autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python3
WORKDIR ${SOURCE_DIR}
COPY . .

View File

@@ -1,4 +1,4 @@
FROM fedora:31
FROM fedora:33
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
@@ -11,7 +11,7 @@ ENV IS_DOCKER=YES
# Prepare Fedora environment
RUN dnf update -y \
&& dnf install -y @buildsys-build rpmdevtools git dnf-plugins-core nodejs-yarn autoconf automake glibc-devel
&& dnf install -y @buildsys-build rpmdevtools git dnf-plugins-core nodejs nodejs-yarn autoconf automake glibc-devel
# Link to build script
RUN ln -sf ${SOURCE_DIR}/deployment/build.fedora /build.sh

View File

@@ -1,12 +1,12 @@
%global debug_package %{nil}
Name: jellyfin-web
Version: 10.7.0
Version: 10.7.7
Release: 1%{?dist}
Summary: The Free Software Media System web client
License: GPLv3
URL: https://jellyfin.org
# Jellyfin Server tarball created by `make -f .copr/Makefile srpm`, real URL ends with `v%{version}.tar.gz`
# Jellyfin Server tarball created by `make -f .copr/Makefile srpm`, real URL ends with `v%%{version}.tar.gz`
Source0: jellyfin-web-%{version}.tar.gz
%if 0%{?centos}
@@ -18,6 +18,9 @@ BuildRequires: nodejs-yarn
# ditto for Fedora's yarn RPM
BuildRequires: git
BuildArch: noarch
%if 0%{?fedora} >= 33
BuildRequires: nodejs
%endif
# Disable Automatic Dependency Processing
AutoReqProv: no
@@ -38,10 +41,27 @@ mv dist %{buildroot}%{_datadir}/jellyfin-web
%{__install} -D -m 0644 LICENSE %{buildroot}%{_datadir}/licenses/jellyfin/LICENSE
%files
%attr(755,root,root) %{_datadir}/jellyfin-web
%defattr(644,root,root,755)
%{_datadir}/jellyfin-web
%{_datadir}/licenses/jellyfin/LICENSE
%changelog
* Sun Sep 05 2021 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.7.7; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.7
* Thu May 20 2021 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.7.6; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.6
* Tue May 04 2021 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.7.5; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.5
* Tue May 04 2021 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.7.4; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.4
* Tue May 04 2021 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.7.3; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.3
* Sun Apr 11 2021 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.7.2; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.2
* Sun Mar 21 2021 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.7.1; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.1
* Mon Mar 08 2021 Jellyfin Packaging Team <packaging@jellyfin.org>
- New stable release 10.7.0; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.7.0
* Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
- Forthcoming stable release
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>

View File

@@ -45,7 +45,7 @@
"webpack-cli": "^4.0.0",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^4.2.2",
"workbox-webpack-plugin": "^5.1.4",
"workbox-webpack-plugin": "^6.1.5",
"worker-plugin": "^5.0.0"
},
"dependencies": {
@@ -56,11 +56,15 @@
"epubjs": "^0.3.85",
"fast-text-encoding": "^1.0.3",
"flv.js": "^1.5.0",
"fontsource-noto-sans": "^3.1.5",
"fontsource-noto-sans-hk": "^3.1.5",
"fontsource-noto-sans-jp": "^3.1.5",
"fontsource-noto-sans-kr": "^3.1.5",
"fontsource-noto-sans-sc": "^3.1.5",
"headroom.js": "^0.12.0",
"hls.js": "^0.14.16",
"intersection-observer": "^0.11.0",
"jellyfin-apiclient": "^1.4.2",
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
"hls.js": "^0.14.17",
"intersection-observer": "^0.12.0",
"jellyfin-apiclient": "^1.8.0",
"jquery": "^3.5.1",
"jstree": "^3.3.10",
"libarchive.js": "^1.3.0",
@@ -97,7 +101,7 @@
"scripts": {
"start": "yarn serve",
"serve": "webpack serve --config webpack.dev.js",
"prepare": "./scripts/prepare.sh",
"prepare": "node ./scripts/prepare.js",
"build:development": "webpack --config webpack.dev.js",
"build:production": "webpack --config webpack.prod.js",
"lint": "eslint \"src/\"",

12
scripts/prepare.js Executable file
View File

@@ -0,0 +1,12 @@
const { execSync } = require('child_process');
/**
* The npm `prepare` script needs to run a build to support installing
* a package from git repositories (this is dumb but a limitation of how
* npm behaves). We don't want to run these in CI though because
* building is slow so this script will skip the build when the
* `SKIP_PREPARE` environment variable has been set.
*/
if (!process.env.SKIP_PREPARE) {
execSync('webpack --config webpack.prod.js', { stdio: 'inherit' });
}

View File

@@ -1,5 +0,0 @@
#!/usr/bin/env bash
if [ -z "${SKIP_PREPARE}" ]; then
webpack --config webpack.prod.js
fi

View File

@@ -127,8 +127,8 @@ div[data-role=controlgroup] a.ui-btn-active {
}
.sessionAppInfo img {
max-width: 40px;
max-height: 40px;
max-width: 2.5em;
max-height: 2.5em;
margin-right: 8px;
}
@@ -204,6 +204,10 @@ div[data-role=controlgroup] a.ui-btn-active {
flex-grow: 1;
}
.dashboardActionsContainer {
margin: 1em -0.3em 0;
}
.sessionNowPlayingContent {
-webkit-background-size: cover;
background-size: cover;
@@ -231,6 +235,13 @@ div[data-role=controlgroup] a.ui-btn-active {
margin-bottom: 0.5em;
}
.dashboardSection .sectionTitleTextButton > .material-icons.material-icons {
font-size: 1.17em;
margin-top: 0.5em;
margin-bottom: 0.5em;
padding-top: 0;
}
.activeRecordingItems > .card {
width: 50%;
}
@@ -246,20 +257,12 @@ div[data-role=controlgroup] a.ui-btn-active {
@media all and (min-width: 70em) {
.dashboardSections {
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
flex-direction: row;
}
.dashboardColumn-2-60 {
width: 46%;
}
.dashboardColumn-2-40 {
width: 27%;
flex-grow: 2;
}
.dashboardSection {
@@ -291,6 +294,7 @@ div[data-role=controlgroup] a.ui-btn-active {
}
.activeSession {
min-width: 20rem;
width: 100% !important;
}
@@ -304,27 +308,24 @@ div[data-role=controlgroup] a.ui-btn-active {
background-position: center;
}
@media all and (min-width: 40em) {
.activeSession {
width: 100% !important;
}
}
@media all and (min-width: 50em) {
.activeSession {
width: 50% !important;
max-width: 25rem;
flex-grow: 0;
flex-shrink: 0;
flex-basis: 50%;
}
}
.sessionCardFooter {
padding-top: 0.5em !important;
padding-bottom: 1em !important;
border-top: 1px solid #eee;
text-align: center;
position: relative;
}
.sessionAppInfo {
flex-grow: 1;
padding: 0.5em;
overflow: hidden;
}
@@ -344,11 +345,9 @@ div[data-role=controlgroup] a.ui-btn-active {
right: 0;
bottom: 0;
font-weight: 400;
}
.sessionNowPlayingContent-withbackground + .sessionNowPlayingInnerContent {
color: #fff !important;
background: rgba(0, 0, 0, 0.7);
display: flex;
flex-direction: column;
}
.sessionAppName {
@@ -358,9 +357,6 @@ div[data-role=controlgroup] a.ui-btn-active {
.sessionNowPlayingDetails {
display: flex;
position: absolute;
bottom: 0;
width: 100%;
}
.sessionNowPlayingInfo {
@@ -376,10 +372,6 @@ div[data-role=controlgroup] a.ui-btn-active {
padding: 0.8em 0.5em;
}
.sessionNowPlayingStreamInfo {
white-space: nowrap;
}
.playbackProgress,
.transcodingProgress {
margin: 0;
@@ -387,6 +379,12 @@ div[data-role=controlgroup] a.ui-btn-active {
background: transparent !important;
}
.activeDevices.itemsContainer {
/* offset for cardBox margin */
margin: -0.6em;
}
.activeSession .backgroundProgress,
.activeSession .playbackProgress,
.activeSession .transcodingProgress {
position: absolute;
@@ -403,9 +401,14 @@ div[data-role=controlgroup] a.ui-btn-active {
}
.transcodingProgress > div {
z-index: 10;
background-color: #dd4919;
}
.backgroundProgress > div {
background-color: #303030;
}
@media all and (max-width: 34.375em) {
.sessionAppName {
max-width: 160px;

View File

@@ -1,5 +1,7 @@
@import "../../styles/noto-sans/index.scss";
@mixin font($weight: null, $size: null) {
font-family: "Noto Sans", sans-serif;
font-family: "Noto Sans", "Noto Sans HK", "Noto Sans JP", "Noto Sans KR", "Noto Sans SC", sans-serif;
font-weight: $weight;
font-size: $size;
}

View File

@@ -250,6 +250,26 @@
padding-bottom: 10vh;
}
.primaryImageWrapper {
display: none;
}
.primaryImageWrapper > img {
display: block;
margin: 0 auto;
max-width: 80vw;
max-height: 50vh;
}
.primaryImageWrapper > img.aspect-square {
max-height: 45vh;
}
.layout-mobile .primaryImageWrapper {
display: block;
flex: 1 0 auto;
}
@media all and (min-width: 40em) {
.dashboardDocument .adminDrawerLogo,
.dashboardDocument .mainDrawerButton {
@@ -453,8 +473,7 @@
}
.layout-mobile .itemBackdrop {
background-attachment: scroll;
height: 26.5vh;
display: none;
}
.layout-desktop .itemBackdrop::after {
@@ -614,7 +633,8 @@
}
.layout-mobile .mainDetailButtons {
margin-top: 1em;
flex: 2 0 70%;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
@@ -638,9 +658,9 @@
}
.layout-mobile .detailPagePrimaryContainer {
display: block;
flex-wrap: wrap;
position: relative;
padding: 0.5em 3.3% 0.5em;
padding: 4.5rem 3.3% 0.5rem;
}
.layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer,
@@ -669,6 +689,10 @@
flex: 1 0 0;
}
.layout-mobile .infoWrapper {
flex: 2 0 70%;
}
.infoText {
white-space: nowrap;
text-overflow: ellipsis;
@@ -729,7 +753,8 @@
background-size: contain;
}
.noBackdrop .detailLogo {
.noBackdrop .detailLogo,
.layout-mobile .detailLogo {
display: none;
}
@@ -754,6 +779,17 @@ div.itemDetailGalleryLink.defaultCardBackground {
height: 23vw;
}
.sectionTitleTextButton > .material-icons {
font-size: 1.5em;
margin-bottom: 0.35em;
margin-top: 0;
}
.layout-mobile .sectionTitleTextButton > .material-icons {
margin-bottom: 0;
padding-top: 0.5em;
}
.itemDetailGalleryLink.defaultCardBackground > .material-icons {
font-size: 15vw;
margin-top: 50%;

View File

@@ -22,6 +22,7 @@
color: #fff;
user-select: none;
-webkit-touch-callout: none;
pointer-events: none;
}
.skinHeader-withBackground.osdHeader {
@@ -32,6 +33,7 @@
backdrop-filter: none;
color: #eee;
height: 7.5em;
pointer-events: none;
}
.osdHeader-hidden {
@@ -39,6 +41,7 @@
}
.osdHeader .headerTop {
pointer-events: all;
max-height: 3.5em;
}
@@ -104,6 +107,7 @@
}
.osdControls {
pointer-events: all;
flex-grow: 1;
padding: 0 0.8em;
}
@@ -261,6 +265,7 @@
justify-content: center;
align-items: center;
position: absolute;
pointer-events: none;
top: 0;
bottom: 0;
right: 0;

View File

@@ -427,12 +427,12 @@ class AppRouter {
if (data.status === 403) {
if (data.errorCode === 'ParentalControl') {
const isCurrentAllowed = this.currentRouteInfo ? (this.currentRouteInfo.route.anonymous || this.currentRouteInfo.route.startup) : true;
const isCurrentAllowed = appRouter.currentRouteInfo ? (appRouter.currentRouteInfo.route.anonymous || appRouter.currentRouteInfo.route.startup) : true;
// Bounce to the login screen, but not if a password entry fails, obviously
if (!isCurrentAllowed) {
this.showForcedLogoutMessage(globalize.translate('AccessRestrictedTryAgainLater'));
this.showLocalLogin(apiClient.serverId());
appRouter.showForcedLogoutMessage(globalize.translate('AccessRestrictedTryAgainLater'));
appRouter.showLocalLogin(apiClient.serverId());
}
}
}
@@ -446,7 +446,7 @@ class AppRouter {
normalizeImageOptions(options) {
let setQuality;
if (options.maxWidth || options.width || options.maxHeight || options.height) {
if (options.maxWidth || options.width || options.maxHeight || options.height || options.fillWidth || options.fillHeight) {
setQuality = true;
}
@@ -471,18 +471,9 @@ class AppRouter {
return null;
}
getMaxBandwidthIOS() {
return 800000;
}
onApiClientCreated(e, newApiClient) {
newApiClient.normalizeImageOptions = this.normalizeImageOptions;
if (browser.iOS) {
newApiClient.getMaxBandwidth = this.getMaxBandwidthIOS;
} else {
newApiClient.getMaxBandwidth = this.getMaxBandwidth;
}
newApiClient.getMaxBandwidth = this.getMaxBandwidth;
Events.off(newApiClient, 'requestfail', this.onRequestFail);
Events.on(newApiClient, 'requestfail', this.onRequestFail);
@@ -512,22 +503,28 @@ class AppRouter {
const firstResult = this.firstConnectionResult;
this.firstConnectionResult = null;
if (firstResult && firstResult.State === 'ServerSignIn') {
const url = firstResult.ApiClient.serverAddress() + '/System/Info/Public';
fetch(url).then(response => {
if (!response.ok) return Promise.reject('fetch failed');
return response.json();
}).then(data => {
if (data !== null && data.StartupWizardCompleted === false) {
Dashboard.navigate('wizardstart.html');
} else {
this.handleConnectionResult(firstResult);
}
}).catch(error => {
console.error(error);
});
if (firstResult) {
if (firstResult.State === 'ServerSignIn') {
const url = firstResult.ApiClient.serverAddress() + '/System/Info/Public';
fetch(url).then(response => {
if (!response.ok) return Promise.reject('fetch failed');
return response.json();
}).then(data => {
if (data !== null && data.StartupWizardCompleted === false) {
ServerConnections.setLocalApiClient(firstResult.ApiClient);
Dashboard.navigate('wizardstart.html');
} else {
this.handleConnectionResult(firstResult);
}
}).catch(error => {
console.error(error);
});
return;
return;
} else if (firstResult.State !== 'SignedIn') {
this.handleConnectionResult(firstResult);
return;
}
}
const apiClient = ServerConnections.currentApiClient();
@@ -821,14 +818,20 @@ class AppRouter {
url = '#!/tv.html?topParentId=' + item.Id;
if (options && options.section === 'latest') {
url += '&tab=2';
url += '&tab=1';
}
return url;
}
if (item.CollectionType == 'music') {
return '#!/music.html?topParentId=' + item.Id;
url = '#!/music.html?topParentId=' + item.Id;
if (options?.section === 'latest') {
url += '&tab=1';
}
return url;
}
}

View File

@@ -8,7 +8,7 @@ import globalize from '../scripts/globalize';
import profileBuilder from '../scripts/browserDeviceProfile';
const appName = 'Jellyfin Web';
const appVersion = '10.7.0';
const appVersion = '10.7.6';
function getBaseProfileOptions(item) {
const disableHlsVideoAudioCodecs = [];

View File

@@ -160,7 +160,6 @@ button::-moz-focus-inner {
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
display: -webkit-flex;
display: flex;
align-items: center;
justify-content: center;
@@ -169,8 +168,13 @@ button::-moz-focus-inner {
color: inherit;
}
.cardContent.cardImageContainer {
display: flex;
}
.cardScalable .cardImageContainer {
height: 100%;
width: 100%;
contain: strict;
}
@@ -222,8 +226,8 @@ button::-moz-focus-inner {
}
.visualCardBox .cardContent {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-top-left-radius: 0.2em;
border-top-right-radius: 0.2em;
}
.cardContent-shadow,
@@ -360,16 +364,11 @@ button::-moz-focus-inner {
font-weight: bold;
}
.cardImageContainer .cardImageIcon {
.cardImageIcon {
font-size: 5em;
color: inherit;
}
.cardImageIcon-small {
font-size: 3em !important;
margin-bottom: 0.1em;
}
.cardIndicators {
right: 0.225em;
top: 0.225em;

View File

@@ -498,7 +498,7 @@ import ServerConnections from '../ServerConnections';
let imgUrl = null;
let imgTag = null;
let coverImage = false;
let uiAspect = null;
const uiAspect = getDesiredAspect(shape);
let imgType = null;
let itemId = null;
@@ -543,11 +543,8 @@ import ServerConnections from '../ServerConnections';
forceName = true;
}
if (primaryImageAspectRatio) {
uiAspect = getDesiredAspect(shape);
if (uiAspect) {
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
}
if (primaryImageAspectRatio && uiAspect) {
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
}
} else if (item.SeriesPrimaryImageTag) {
imgType = 'Primary';
@@ -563,11 +560,8 @@ import ServerConnections from '../ServerConnections';
forceName = true;
}
if (primaryImageAspectRatio) {
uiAspect = getDesiredAspect(shape);
if (uiAspect) {
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
}
if (primaryImageAspectRatio && uiAspect) {
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
}
} else if (item.ParentPrimaryImageTag) {
imgType = 'Primary';
@@ -579,11 +573,8 @@ import ServerConnections from '../ServerConnections';
itemId = item.AlbumId;
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
if (primaryImageAspectRatio) {
uiAspect = getDesiredAspect(shape);
if (uiAspect) {
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
}
if (primaryImageAspectRatio && uiAspect) {
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
}
} else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) {
imgType = 'Thumb';
@@ -613,10 +604,15 @@ import ServerConnections from '../ServerConnections';
}
if (imgTag && imgType) {
// TODO: This place is a mess. Could do with a good spring cleaning.
if (!height && width && uiAspect) {
height = width / uiAspect;
}
imgUrl = apiClient.getScaledImageUrl(itemId, {
type: imgType,
maxHeight: height,
maxWidth: width,
fillHeight: height,
fillWidth: width,
quality: 96,
tag: imgTag
});
}
@@ -1421,6 +1417,8 @@ import ServerConnections from '../ServerConnections';
const pathData = item.Path ? (' data-path="' + item.Path + '"') : '';
const contextData = options.context ? (' data-context="' + options.context + '"') : '';
const parentIdData = options.parentId ? (' data-parentid="' + options.parentId + '"') : '';
const startDate = item.StartDate ? (' data-startdate="' + item.StartDate.toString() + '"') : '';
const endDate = item.EndDate ? (' data-enddate="' + item.EndDate.toString() + '"') : '';
let additionalCardContent = '';
@@ -1428,7 +1426,7 @@ import ServerConnections from '../ServerConnections';
additionalCardContent += getHoverMenuHtml(item, action);
}
return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + pathData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + '</' + tagName + '>';
return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + pathData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + startDate + endDate + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + '</' + tagName + '>';
}
/**

View File

@@ -17,21 +17,17 @@ import template from './displaySettings.template.html';
/* eslint-disable indent */
function fillThemes(context, userSettings) {
const select = context.querySelector('#selectTheme');
function fillThemes(select, selectedTheme) {
skinManager.getThemes().then(themes => {
select.innerHTML = themes.map(t => {
return `<option value="${t.id}">${t.name}</option>`;
}).join('');
// get default theme
const defaultTheme = themes.find(theme => {
return theme.default;
});
const defaultTheme = themes.find(theme => theme.default);
// set the current theme
select.value = userSettings.theme() || defaultTheme.id;
select.value = selectedTheme || defaultTheme.id;
});
}
@@ -89,6 +85,8 @@ import template from './displaySettings.template.html';
context.querySelector('.learnHowToContributeContainer').classList.add('hide');
}
context.querySelector('.selectDashboardThemeContainer').classList.toggle('hide', !user.Policy.IsAdministrator);
if (appHost.supports('screensaver')) {
context.querySelector('.selectScreensaverContainer').classList.remove('hide');
} else {
@@ -111,7 +109,9 @@ import template from './displaySettings.template.html';
context.querySelector('.fldThemeVideo').classList.add('hide');
}
fillThemes(context, userSettings);
fillThemes(context.querySelector('#selectTheme'), userSettings.theme());
fillThemes(context.querySelector('#selectDashboardTheme'), userSettings.dashboardTheme());
loadScreensavers(context, userSettings);
context.querySelector('.chkDisplayMissingEpisodes').checked = user.Configuration.DisplayMissingEpisodes || false;
@@ -147,6 +147,7 @@ import template from './displaySettings.template.html';
userSettingsInstance.enableThemeSongs(context.querySelector('#chkThemeSong').checked);
userSettingsInstance.enableThemeVideos(context.querySelector('#chkThemeVideo').checked);
userSettingsInstance.theme(context.querySelector('#selectTheme').value);
userSettingsInstance.dashboardTheme(context.querySelector('#selectDashboardTheme').value);
userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value);
userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value);

View File

@@ -6,27 +6,35 @@
<div class="selectContainer languageSection hide">
<select id="selectLanguage" is="emby-select" label="${LabelDisplayLanguage}">
<option value="">${Auto}</option>
<option value="af">Afrikaans</option>
<option value="sq">Albanian</option>
<option value="ar">Arabic</option>
<option value="be-BY">Belarusian (Belarus)</option>
<option value="bg-BG">Bulgarian (Bulgaria)</option>
<option value="be-BY">Belarusian</option>
<option value="bn_BD">Bengali (Bangladesh)</option>
<option value="bg-BG">Bulgarian</option>
<option value="ca">Catalan</option>
<option value="zh-CN">Chinese Simplified</option>
<option value="zh-TW">Chinese Traditional</option>
<option value="zh-HK">Chinese Traditional (Hong Kong)</option>
<option value="zh-HK">Chinese (Hong Kong)</option>
<option value="zh-CN">Chinese (Simplified)</option>
<option value="zh-TW">Chinese (Traditional)</option>
<option value="hr">Croatian</option>
<option value="cs">Czech</option>
<option value="da">Danish</option>
<option value="nl">Dutch</option>
<option value="en-US">English</option>
<option value="en-GB">English (United Kingdom)</option>
<option value="en-US">English (United States)</option>
<option value="eo">Esperanto</option>
<option value="fil">Filipino</option>
<option value="fi">Finnish</option>
<option value="fr">French</option>
<option value="fr-CA">French (Canada)</option>
<option value="gl">Galician</option>
<option value="de">German</option>
<option value="gsw">German (Swiss)</option>
<option value="el">Greek</option>
<option value="he">Hebrew</option>
<option value="hi-IN">Hindi (India)</option>
<option value="hi-IN">Hindi</option>
<option value="hu">Hungarian</option>
<option value="is">Icelandic</option>
<option value="id">Indonesian</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
@@ -34,9 +42,12 @@
<option value="ko">Korean</option>
<option value="lt-LT">Lithuanian</option>
<option value="ms">Malay</option>
<option value="mr">Marathi</option>
<option value="nb">Norwegian Bokmål</option>
<option value="fa">Persian</option>
<option value="pr">Pirate</option>
<option value="pl">Polish</option>
<option value="pt">Portuguese</option>
<option value="pt-BR">Portuguese (Brazil)</option>
<option value="pt-PT">Portuguese (Portugal)</option>
<option value="ro">Romanian</option>
@@ -44,12 +55,16 @@
<option value="sk">Slovak</option>
<option value="sl-SI">Slovenian (Slovenia)</option>
<option value="es">Spanish</option>
<option value="es_AR">Spanish (Argentina)</option>
<option value="es_DO">Spanish (Dominican Republic)</option>
<option value="es-419">Spanish (Latin America)</option>
<option value="es-MX">Spanish (Mexico)</option>
<option value="sv">Swedish</option>
<option value="gsw">Swiss German</option>
<option value="ta">Tamil</option>
<option value="th">Thai</option>
<option value="tr">Turkish</option>
<option value="uk">Ukrainian</option>
<option value="ur_PK">Urdu (Pakistan)</option>
<option value="vi">Vietnamese</option>
</select>
<div class="fieldDescription">
@@ -63,27 +78,35 @@
<div class="selectContainer fldDateTimeLocale hide">
<select is="emby-select" class="selectDateTimeLocale" label="${LabelDateTimeLocale}">
<option value="">${Auto}</option>
<option value="af">Afrikaans</option>
<option value="sq">Albanian</option>
<option value="ar">Arabic</option>
<option value="be-BY">Belarusian (Belarus)</option>
<option value="bg-BG">Bulgarian (Bulgaria)</option>
<option value="be-BY">Belarusian</option>
<option value="bn_BD">Bengali (Bangladesh)</option>
<option value="bg-BG">Bulgarian</option>
<option value="ca">Catalan</option>
<option value="zh-CN">Chinese Simplified</option>
<option value="zh-TW">Chinese Traditional</option>
<option value="zh-HK">Chinese Traditional (Hong Kong)</option>
<option value="zh-HK">Chinese (Hong Kong)</option>
<option value="zh-CN">Chinese (Simplified)</option>
<option value="zh-TW">Chinese (Traditional)</option>
<option value="hr">Croatian</option>
<option value="cs">Czech</option>
<option value="da">Danish</option>
<option value="nl">Dutch</option>
<option value="en-US">English</option>
<option value="en-GB">English (United Kingdom)</option>
<option value="en-US">English (United States)</option>
<option value="eo">Esperanto</option>
<option value="fil">Filipino</option>
<option value="fi">Finnish</option>
<option value="fr">French</option>
<option value="fr-CA">French (Canada)</option>
<option value="gl">Galician</option>
<option value="de">German</option>
<option value="gsw">German (Swiss)</option>
<option value="el">Greek</option>
<option value="he">Hebrew</option>
<option value="hi-IN">Hindi (India)</option>
<option value="hi-IN">Hindi</option>
<option value="hu">Hungarian</option>
<option value="is">Icelandic</option>
<option value="id">Indonesian</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
@@ -91,9 +114,12 @@
<option value="ko">Korean</option>
<option value="lt-LT">Lithuanian</option>
<option value="ms">Malay</option>
<option value="mr">Marathi</option>
<option value="nb">Norwegian Bokmål</option>
<option value="fa">Persian</option>
<option value="pr">Pirate</option>
<option value="pl">Polish</option>
<option value="pt">Portuguese</option>
<option value="pt-BR">Portuguese (Brazil)</option>
<option value="pt-PT">Portuguese (Portugal)</option>
<option value="ro">Romanian</option>
@@ -101,12 +127,16 @@
<option value="sk">Slovak</option>
<option value="sl-SI">Slovenian (Slovenia)</option>
<option value="es">Spanish</option>
<option value="es_AR">Spanish (Argentina)</option>
<option value="es_DO">Spanish (Dominican Republic)</option>
<option value="es-419">Spanish (Latin America)</option>
<option value="es-MX">Spanish (Mexico)</option>
<option value="sv">Swedish</option>
<option value="gsw">Swiss German</option>
<option value="ta">Tamil</option>
<option value="th">Thai</option>
<option value="tr">Turkish</option>
<option value="uk">Ukrainian</option>
<option value="ur_PK">Urdu (Pakistan)</option>
<option value="vi">Vietnamese</option>
</select>
</div>
@@ -126,6 +156,10 @@
<select id="selectTheme" is="emby-select" label="${LabelTheme}"></select>
</div>
<div class="selectContainer selectDashboardThemeContainer hide">
<select id="selectDashboardTheme" is="emby-select" label="${LabelDashboardTheme}"></select>
</div>
<div class="selectContainer hide selectScreensaverContainer">
<select is="emby-select" class="selectScreensaver" label="${LabelScreensaver}"></select>
</div>

View File

@@ -3,18 +3,18 @@
<div is="emby-collapse" title="${Filters}">
<div class="collapseContent">
<div class="checkboxList">
<label>
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
<label class="videoStandard">
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter"
data-filter="IsPlayed" />
<span>${Played}</span>
</label>
<label>
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
<label class="videoStandard">
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter"
data-filter="IsUnPlayed" />
<span>${Unplayed}</span>
</label>
<label>
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
<label class="videoStandard">
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter"
data-filter="IsResumable" />
<span>${OptionResumable}</span>
</label>

View File

@@ -57,8 +57,8 @@ import template from './homeScreenSettings.template.html';
value: 'suggestions'
});
list.push({
name: globalize.translate('Genres'),
value: 'genres'
name: globalize.translate('Trailers'),
value: 'trailers'
});
list.push({
name: globalize.translate('Favorites'),
@@ -68,6 +68,10 @@ import template from './homeScreenSettings.template.html';
name: globalize.translate('Collections'),
value: 'collections'
});
list.push({
name: globalize.translate('Genres'),
value: 'genres'
});
} else if (type === 'tvshows') {
list.push({
name: globalize.translate('Shows'),
@@ -79,7 +83,7 @@ import template from './homeScreenSettings.template.html';
value: 'suggestions'
});
list.push({
name: globalize.translate('Upcoming'),
name: globalize.translate('TabUpcoming'),
value: 'upcoming'
});
list.push({
@@ -87,7 +91,7 @@ import template from './homeScreenSettings.template.html';
value: 'genres'
});
list.push({
name: globalize.translate('Networks'),
name: globalize.translate('TabNetworks'),
value: 'networks'
});
list.push({
@@ -116,20 +120,40 @@ import template from './homeScreenSettings.template.html';
name: globalize.translate('Playlists'),
value: 'playlists'
});
list.push({
name: globalize.translate('Songs'),
value: 'songs'
});
list.push({
name: globalize.translate('Genres'),
value: 'genres'
});
} else if (type === 'livetv') {
list.push({
name: globalize.translate('Suggestions'),
value: 'suggestions',
name: globalize.translate('Programs'),
value: 'programs',
isDefault: true
});
list.push({
name: globalize.translate('Guide'),
value: 'guide'
});
list.push({
name: globalize.translate('Channels'),
value: 'channels'
});
list.push({
name: globalize.translate('Recordings'),
value: 'recordings'
});
list.push({
name: globalize.translate('Schedule'),
value: 'schedule'
});
list.push({
name: globalize.translate('Series'),
value: 'series'
});
}
return list;

View File

@@ -491,7 +491,7 @@ import ServerConnections from '../ServerConnections';
function loadResumeAudio(elem, apiClient, userId) {
let html = '';
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderContinueWatching') + '</h2>';
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderContinueListening') + '</h2>';
if (enableScrollX()) {
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">';
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x" data-monitor="audioplayback,markplayed">';
@@ -665,7 +665,8 @@ import ServerConnections from '../ServerConnections';
UserId: apiClient.getCurrentUserId(),
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
EnableTotalRecordCount: false
EnableTotalRecordCount: false,
DisableFirstEpisode: true
});
};
}

View File

@@ -158,15 +158,11 @@ import { Events } from 'jellyfin-apiclient';
// (but rewinding cannot happen as the first event with media of non-empty duration)
console.debug(`seeking to ${seconds} on ${e.type} event`);
setCurrentTimeIfNeeded(element, seconds);
events.map(function(name) {
element.removeEventListener(name, onMediaChange);
});
events.forEach(name => element.removeEventListener(name, onMediaChange));
if (onMediaReady) onMediaReady();
}
};
events.map(function (name) {
return element.addEventListener(name, onMediaChange);
});
events.forEach(name => element.addEventListener(name, onMediaChange));
}
}
}

View File

@@ -79,7 +79,7 @@ import template from './imageDownloader.template.html';
let html = '';
for (let i = 0, length = imagesResult.Images.length; i < length; i++) {
html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient);
html += getRemoteImageHtml(imagesResult.Images[i], imageType);
}
const availableImagesList = page.querySelector('.availableImagesList');
@@ -150,11 +150,7 @@ import template from './imageDownloader.template.html';
});
}
function getDisplayUrl(url, apiClient) {
return apiClient.getUrl('Images/Remote', { imageUrl: url });
}
function getRemoteImageHtml(image, imageType, apiClient) {
function getRemoteImageHtml(image, imageType) {
const tagName = layoutManager.tv ? 'button' : 'div';
const enableFooterButtons = !layoutManager.tv;
@@ -209,9 +205,9 @@ import template from './imageDownloader.template.html';
html += '<div class="cardContent">';
if (layoutManager.tv || !appHost.supports('externallinks')) {
html += '<div class="cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center center;background-size:contain;"></div>';
html += '<div class="cardImageContainer lazy" data-src="' + image.Url + '" style="background-position:center center;background-size:contain;"></div>';
} else {
html += '<a is="emby-linkbutton" target="_blank" href="' + getDisplayUrl(image.Url, apiClient) + '" class="button-link cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center center;background-size:contain"></a>';
html += '<a is="emby-linkbutton" target="_blank" href="' + image.Url + '" class="button-link cardImageContainer lazy" data-src="' + image.Url + '" style="background-position:center center;background-size:contain"></a>';
}
html += '</div>';

View File

@@ -87,9 +87,6 @@ import './style.css';
requestAnimationFrame(() => {
if (elem.tagName !== 'IMG') {
elem.style.backgroundImage = "url('" + url + "')";
if (elem.classList.contains('blurhashed')) {
elem.style.backgroundColor = '#fff';
}
} else {
elem.setAttribute('src', url);
}
@@ -101,6 +98,12 @@ import './style.css';
} else {
elem.classList.add('lazy-image-fadein');
}
const canvas = elem.previousSibling;
if (elem.classList.contains('blurhashed') && canvas && canvas.tagName === 'CANVAS') {
canvas.classList.remove('lazy-image-fadein-fast', 'lazy-image-fadein');
canvas.classList.add('lazy-hidden');
}
});
});
}
@@ -111,7 +114,6 @@ import './style.css';
if (elem.tagName !== 'IMG') {
url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, '');
elem.style.backgroundImage = 'none';
elem.style.backgroundColor = null;
} else {
url = elem.getAttribute('src');
elem.setAttribute('src', '');
@@ -120,6 +122,16 @@ import './style.css';
elem.classList.remove('lazy-image-fadein-fast', 'lazy-image-fadein');
elem.classList.add('lazy-hidden');
const canvas = elem.previousSibling;
if (canvas && canvas.tagName === 'CANVAS') {
canvas.classList.remove('lazy-hidden');
if (userSettings.enableFastFadein()) {
canvas.classList.add('lazy-image-fadein-fast');
} else {
canvas.classList.add('lazy-image-fadein');
}
}
}
export function lazyChildren(elem) {

View File

@@ -471,7 +471,7 @@ import toast from './toast/toast';
navigator.share({
title: item.Name,
text: item.Overview,
url: `${apiClient.serverAddress()}/web/index.html#!/${appRouter.getRouteUrl(item)}`
url: `${apiClient.serverAddress()}/web/index.html${appRouter.getRouteUrl(item)}`
});
break;
case 'album':

View File

@@ -171,9 +171,7 @@ import template from './itemidentifier.template.html';
let resultHtml = lines.join('<br/>');
if (identifyResult.ImageUrl) {
const displayUrl = getSearchImageDisplayUrl(identifyResult.ImageUrl, identifyResult.SearchProviderName);
resultHtml = `<div style="display:flex;align-items:center;"><img src="${displayUrl}" style="max-height:240px;" /><div style="margin-left:1em;">${resultHtml}</div>`;
resultHtml = `<div style="display:flex;align-items:center;"><img src="${identifyResult.ImageUrl}" style="max-height:240px;" /><div style="margin-left:1em;">${resultHtml}</div>`;
}
page.querySelector('.selectedSearchResult').innerHTML = resultHtml;
@@ -218,9 +216,7 @@ import template from './itemidentifier.template.html';
html += '<div class="cardContent searchImage">';
if (result.ImageUrl) {
const displayUrl = getSearchImageDisplayUrl(result.ImageUrl, result.SearchProviderName);
html += `<div class="cardImageContainer coveredImage" style="background-image:url('${displayUrl}');"></div>`;
html += `<div class="cardImageContainer coveredImage" style="background-image:url('${result.ImageUrl}');"></div>`;
} else {
html += `<div class="cardImageContainer coveredImage defaultCardBackground defaultCardBackground1"><div class="cardText cardCenteredText">${result.Name}</div></div>`;
}
@@ -258,16 +254,6 @@ import template from './itemidentifier.template.html';
return html;
}
function getSearchImageDisplayUrl(url, provider) {
const apiClient = getApiClient();
return apiClient.getUrl('Items/RemoteSearch/Image', {
imageUrl: url,
ProviderName: provider,
api_key: apiClient.accessToken()
});
}
function submitIdentficationResult(page) {
loading.show();

View File

@@ -76,12 +76,13 @@ import ServerConnections from '../ServerConnections';
return '';
}
function getImageUrl(item, width) {
function getImageUrl(item, size) {
const apiClient = ServerConnections.getApiClient(item.ServerId);
let itemId;
const options = {
maxWidth: width,
fillWidth: size,
fillHeight: size,
type: 'Primary'
};
@@ -105,10 +106,11 @@ import ServerConnections from '../ServerConnections';
return null;
}
function getChannelImageUrl(item, width) {
function getChannelImageUrl(item, size) {
const apiClient = ServerConnections.getApiClient(item.ServerId);
const options = {
maxWidth: width,
fillWidth: size,
fillHeight: size,
type: 'Primary'
};

View File

@@ -68,7 +68,11 @@ export function hide() {
}
}
export default {
show: show,
hide: hide
const loading = {
show,
hide
};
window.Loading = loading;
export default loading;

View File

@@ -196,11 +196,14 @@ import confirm from '../confirm/confirm';
}
if (user.Policy.EnableContentDownloading && appHost.supports('filedownload')) {
// Disabled because there is no callback for this item
/*
menuItems.push({
name: globalize.translate('Download'),
id: 'download',
icon: 'file_download'
});
*/
}
if (user.Policy.IsAdministrator) {

View File

@@ -556,6 +556,7 @@ import { appRouter } from '../appRouter';
const options = {
play: false,
queue: false,
stopPlayback: true,
clearQueue: true,
positionTo: contextButton
};

View File

@@ -156,7 +156,7 @@ function backdropImageUrl(apiClient, item, options) {
options.type = options.type || 'Backdrop';
// If not resizing, get the original image
if (!options.maxWidth && !options.width && !options.maxHeight && !options.height) {
if (!options.maxWidth && !options.width && !options.maxHeight && !options.height && !options.fillWidth && !options.fillHeight) {
options.quality = 100;
}

View File

@@ -142,14 +142,13 @@ import ServerConnections from '../ServerConnections';
});
}
if (audioChannels) {
sessionStats.push({
label: globalize.translate('LabelAudioChannels'),
value: audioChannels
});
}
if (displayPlayMethod === 'Transcode') {
if (audioChannels) {
sessionStats.push({
label: globalize.translate('LabelAudioChannels'),
value: audioChannels
});
}
if (totalBitrate) {
sessionStats.push({
label: globalize.translate('LabelBitrate'),

View File

@@ -49,7 +49,8 @@ import ServerConnections from '../ServerConnections';
apiClient.ajax({
type: 'POST',
url: url,
dataType: 'json'
dataType: 'json',
contentType: 'application/json'
}).then(result => {
loading.hide();

View File

@@ -74,14 +74,19 @@ import { playbackManager } from './playback/playbackmanager';
if (typeof pluginSpec === 'string') {
if (pluginSpec in window) {
console.log(`Loading plugin (via window): ${pluginSpec}`);
let pluginInstance = await window[pluginSpec];
if (typeof pluginInstance === 'function') {
pluginInstance = await new pluginInstance();
const pluginDefinition = await window[pluginSpec];
if (typeof pluginDefinition !== 'function') {
throw new TypeError('Plugin definitions in window have to be an (async) function returning the plugin class');
}
const pluginClass = await pluginDefinition();
if (typeof pluginClass !== 'function') {
throw new TypeError(`Plugin definition doesn't return a class for '${pluginSpec}'`);
}
// init plugin and pass basic dependencies
plugin = new pluginInstance({
plugin = new pluginClass({
events: Events,
loading,
appSettings,
@@ -98,9 +103,7 @@ import { playbackManager } from './playback/playbackmanager';
const pluginResult = await pluginSpec;
plugin = new pluginResult.default;
} else {
const err = new TypeError('Plugins have to be a Promise that resolves to a plugin builder function');
console.error(err);
throw err;
throw new TypeError('Plugins have to be a Promise that resolves to a plugin builder function');
}
return this.#preparePlugin(pluginSpec, plugin);

View File

@@ -209,11 +209,10 @@ function updateNowPlayingInfo(context, state, serverId) {
if (autoFocusContextButton) {
contextButton.focus();
}
const stopPlayback = !!layoutManager.mobile;
const options = {
play: false,
queue: false,
stopPlayback: stopPlayback,
stopPlayback: true,
clearQueue: true,
openAlbum: false,
positionTo: contextButton

View File

@@ -62,19 +62,13 @@ import template from './searchfields.template.html';
}
function embed(elem, instance, options) {
let html = globalize.translateHtml(template, 'core');
if (browser.tizen || browser.orsay) {
html = html.replace('<input ', '<input readonly ');
}
elem.innerHTML = html;
elem.innerHTML = globalize.translateHtml(template, 'core');
elem.classList.add('searchFields');
const txtSearch = elem.querySelector('.searchfields-txtSearch');
if (layoutManager.tv) {
if (layoutManager.tv && !browser.tv) {
const alphaPickerElement = elem.querySelector('.alphaPicker');
elem.querySelector('.alphaPicker').classList.remove('hide');

View File

@@ -1,7 +1,7 @@
<div class="searchFieldsInner flex align-items-center justify-content-center">
<span class="searchfields-icon material-icons search"></span>
<div class="inputContainer flex-grow" style="margin-bottom: 0;">
<input is="emby-input" class="searchfields-txtSearch" type="text" data-keyboard="false" placeholder="${Search}" autocomplete="off" maxlength="40" autofocus />
<input is="emby-input" class="searchfields-txtSearch" type="text" data-keyboard="true" placeholder="${Search}" autocomplete="off" maxlength="40" autofocus />
</div>
</div>
<div class="alphaPicker align-items-center hide"></div>

View File

@@ -147,6 +147,8 @@ import toast from './toast/toast';
MediaType: card.getAttribute('data-mediatype'),
Path: card.getAttribute('data-path'),
IsFolder: card.getAttribute('data-isfolder') === 'true',
StartDate: card.getAttribute('data-startdate'),
EndDate: card.getAttribute('data-enddate'),
UserData: {
PlaybackPositionTicks: parseInt(card.getAttribute('data-positionticks') || '0')
}

View File

@@ -71,7 +71,7 @@ function getBackdropImageUrl(item, options, apiClient) {
options.type = options.type || 'Backdrop';
// If not resizing, get the original image
if (!options.maxWidth && !options.width && !options.maxHeight && !options.height) {
if (!options.maxWidth && !options.width && !options.maxHeight && !options.height && !options.fillWidth && !options.fillHeight) {
options.quality = 100;
}

View File

@@ -45,11 +45,11 @@ function init(instance) {
let inputOffset = /[-+]?\d+\.?\d*/g.exec(this.textContent);
if (inputOffset) {
inputOffset = inputOffset[0];
inputOffset = parseFloat(inputOffset);
inputOffset = Math.min(30, Math.max(-30, inputOffset));
// replace current text by considered offset
this.textContent = inputOffset + 's';
inputOffset = parseFloat(inputOffset);
// set new offset
playbackManager.setSubtitleOffset(inputOffset, player);
// synchronize with slider value
@@ -121,7 +121,7 @@ function getPercentageFromOffset(value) {
// convert fraction to percent
percentValue *= 50;
percentValue += 50;
return Math.min(100, Math.max(0, percentValue.toFixed()));
return Math.min(100, Math.max(0, percentValue.toFixed(1)));
}
class SubtitleSync {

View File

@@ -3,7 +3,7 @@
<button type="button" is="paper-icon-button-light" class="subtitleSync-closeButton"><span class="material-icons close"></span></button>
<div class="subtitleSyncTextField" contenteditable="true" spellcheck="false">0s</div>
<div class="sliderContainer subtitleSyncSliderContainer">
<input is="emby-slider" type="range" step="1" min="0" max="100" value="50" class="subtitleSyncSlider" data-slider-keep-progress="true" />
<input is="emby-slider" type="range" step=".1" min="0" max="100" value="50" class="subtitleSyncSlider" data-slider-keep-progress="true" />
</div>
</div>
</div>

View File

@@ -70,7 +70,6 @@ class PlaybackCore {
onPlaybackStop(stopInfo) {
this.lastCommand = null;
Events.trigger(this.manager, 'playbackstop', [stopInfo]);
this.manager.releaseCurrentPlayer();
}
/**

View File

@@ -22,7 +22,7 @@ export default function (options) {
const elem = document.createElement('div');
elem.classList.add('toast');
elem.innerHTML = options.text;
elem.textContent = options.text;
document.body.appendChild(elem);

View File

@@ -15,11 +15,11 @@
<p id="architecture"></p>
</div>
<div style="margin-top:1em;">
<div class="dashboardActionsContainer">
<button is="emby-button" type="button" class="raised btnRefresh">
<span>${ButtonScanAllLibraries}</span>
</button>
<button is="emby-button" type="button" id="btnRestartServer" class="raised" onclick="DashboardPage.restart(this);" style="margin-left:0;">
<button is="emby-button" type="button" id="btnRestartServer" class="raised hide" onclick="DashboardPage.restart(this);">
<span>${Restart}</span>
</button>
<button is="emby-button" type="button" id="btnShutdown" class="raised" onclick="DashboardPage.shutdown(this);">

View File

@@ -40,9 +40,13 @@ import confirm from '../../components/confirm/confirm';
text.push(globalize.translate('DirectStreamHelp1'));
text.push('<br/>');
text.push(globalize.translate('DirectStreamHelp2'));
} else if (displayPlayMethod === 'DirectPlay') {
title = globalize.translate('DirectPlaying');
text.push(globalize.translate('DirectPlayHelp'));
} else if (displayPlayMethod === 'Transcode') {
title = globalize.translate('Transcoding');
text.push(globalize.translate('MediaIsBeingConverted'));
text.push(DashboardPage.getSessionNowPlayingStreamInfo(session));
if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length) {
text.push('<br/>');
@@ -200,6 +204,12 @@ import confirm from '../../components/confirm/confirm';
view.querySelector('#operatingSystem').innerHTML = globalize.translate('DashboardOperatingSystem', systemInfo.OperatingSystem);
view.querySelector('#architecture').innerHTML = globalize.translate('DashboardArchitecture', systemInfo.SystemArchitecture);
if (systemInfo.CanSelfRestart) {
view.querySelector('#btnRestartServer').classList.remove('hide');
} else {
view.querySelector('#btnRestartServer').classList.add('hide');
}
view.querySelector('#cachePath').innerHTML = systemInfo.CachePath;
view.querySelector('#logPath').innerHTML = systemInfo.LogPath;
view.querySelector('#transcodePath').innerHTML = systemInfo.TranscodingTempPath;
@@ -245,12 +255,13 @@ import confirm from '../../components/confirm/confirm';
} else {
const nowPlayingItem = session.NowPlayingItem;
const className = 'scalableCard card activeSession backdropCard backdropCard-scalable';
const imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem);
html += '<div class="' + className + '" id="' + rowId + '">';
html += '<div class="cardBox visualCardBox">';
html += '<div class="cardScalable visualCardBox-cardScalable">';
html += '<div class="cardPadder cardPadder-backdrop"></div>';
html += '<div class="cardContent">';
const imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem);
html += `<div class="cardContent ${cardBuilder.getDefaultBackgroundClass()}">`;
if (imgUrl) {
html += '<div class="sessionNowPlayingContent sessionNowPlayingContent-withbackground"';
@@ -281,29 +292,19 @@ import confirm from '../../components/confirm/confirm';
html += '<div class="sessionNowPlayingTime">' + DashboardPage.getSessionNowPlayingTime(session) + '</div>';
html += '</div>';
if (nowPlayingItem && nowPlayingItem.RunTimeTicks) {
const percent = 100 * (session.PlayState.PositionTicks || 0) / nowPlayingItem.RunTimeTicks;
html += indicators.getProgressHtml(percent, {
containerClass: 'playbackProgress'
});
} else {
// need to leave the element in just in case the device starts playback
html += indicators.getProgressHtml(0, {
containerClass: 'playbackProgress hide'
});
}
let percent = 100 * session?.PlayState?.PositionTicks / nowPlayingItem?.RunTimeTicks;
html += indicators.getProgressHtml(percent || 0, {
containerClass: 'playbackProgress'
});
if (session.TranscodingInfo && session.TranscodingInfo.CompletionPercentage) {
const percent = session.TranscodingInfo.CompletionPercentage.toFixed(1);
html += indicators.getProgressHtml(percent, {
containerClass: 'transcodingProgress'
});
} else {
// same issue as playbackProgress element above
html += indicators.getProgressHtml(0, {
containerClass: 'transcodingProgress hide'
});
}
percent = session?.TranscodingInfo?.CompletionPercentage?.toFixed(1);
html += indicators.getProgressHtml(percent || 0, {
containerClass: 'transcodingProgress'
});
html += indicators.getProgressHtml(100, {
containerClass: 'backgroundProgress'
});
html += '</div>';
html += '</div>';
@@ -316,18 +317,12 @@ import confirm from '../../components/confirm/confirm';
html += '<button is="paper-icon-button-light" class="sessionCardButton btnSessionPlayPause paper-icon-button-light ' + btnCssClass + '"><span class="material-icons ' + playIcon + '"></span></button>';
html += '<button is="paper-icon-button-light" class="sessionCardButton btnSessionStop paper-icon-button-light ' + btnCssClass + '"><span class="material-icons stop"></span></button>';
btnCssClass = session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length ? '' : ' hide';
html += '<button is="paper-icon-button-light" class="sessionCardButton btnSessionInfo paper-icon-button-light ' + btnCssClass + '" title="' + globalize.translate('ViewPlaybackInfo') + '"><span class="material-icons info"></span></button>';
btnCssClass = session.ServerId && session.SupportedCommands.indexOf('DisplayMessage') !== -1 && session.DeviceId !== ServerConnections.deviceId() ? '' : ' hide';
html += '<button is="paper-icon-button-light" class="sessionCardButton btnSessionSendMessage paper-icon-button-light ' + btnCssClass + '" title="' + globalize.translate('SendMessage') + '"><span class="material-icons message"></span></button>';
html += '</div>';
html += '<div class="sessionNowPlayingStreamInfo" style="padding:.5em 0 1em;">';
html += DashboardPage.getSessionNowPlayingStreamInfo(session);
html += '</div>';
html += '<div class="flex align-items-center justify-content-center">';
const userImage = DashboardPage.getUserImage(session);
html += userImage ? '<div class="activitylogUserPhoto" style="background-image:url(\'' + userImage + "');\"></div>" : '<div style="height:1.71em;"></div>';
@@ -409,10 +404,8 @@ import confirm from '../../components/confirm/confirm';
} else if (displayPlayMethod === 'DirectStream') {
html += globalize.translate('DirectStreaming');
} else if (displayPlayMethod === 'Transcode') {
html += globalize.translate('Transcoding');
if (session.TranscodingInfo && session.TranscodingInfo.Framerate) {
html += ' (' + session.TranscodingInfo.Framerate + ' fps)';
html += `${globalize.translate('Framerate')}: ${session.TranscodingInfo.Framerate}fps`;
}
showTranscodingInfo = true;
@@ -556,8 +549,10 @@ import confirm from '../../components/confirm/confirm';
if (nowPlayingItem) {
row.classList.add('playingSession');
row.querySelector('.btnSessionInfo').classList.remove('hide');
} else {
row.classList.remove('playingSession');
row.querySelector('.btnSessionInfo').classList.add('hide');
}
if (session.ServerId && session.SupportedCommands.indexOf('DisplayMessage') !== -1) {
@@ -566,12 +561,6 @@ import confirm from '../../components/confirm/confirm';
row.querySelector('.btnSessionSendMessage').classList.add('hide');
}
if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo) {
row.querySelector('.btnSessionInfo').classList.remove('hide');
} else {
row.querySelector('.btnSessionInfo').classList.add('hide');
}
const btnSessionPlayPause = row.querySelector('.btnSessionPlayPause');
if (session.ServerId && nowPlayingItem && session.SupportsRemoteControl) {
@@ -586,7 +575,6 @@ import confirm from '../../components/confirm/confirm';
btnSessionPlayPauseIcon.classList.remove('play_arrow', 'pause');
btnSessionPlayPauseIcon.classList.add(session.PlayState && session.PlayState.IsPaused ? 'play_arrow' : 'pause');
row.querySelector('.sessionNowPlayingStreamInfo').innerHTML = DashboardPage.getSessionNowPlayingStreamInfo(session);
row.querySelector('.sessionNowPlayingTime').innerHTML = DashboardPage.getSessionNowPlayingTime(session);
row.querySelector('.sessionUserName').innerHTML = DashboardPage.getUsersHtml(session);
row.querySelector('.sessionAppSecondaryText').innerHTML = DashboardPage.getAppSecondaryText(session);
@@ -599,30 +587,17 @@ import confirm from '../../components/confirm/confirm';
}
const playbackProgressElem = row.querySelector('.playbackProgress');
if (nowPlayingItem && nowPlayingItem.RunTimeTicks) {
const percent = 100 * (session.PlayState.PositionTicks || 0) / nowPlayingItem.RunTimeTicks;
playbackProgressElem.outerHTML = indicators.getProgressHtml(percent, {
containerClass: 'playbackProgress'
});
} else {
playbackProgressElem.outerHTML = indicators.getProgressHtml(0, {
containerClass: 'playbackProgress hide'
});
}
const transcodingProgress = row.querySelector('.transcodingProgress');
if (session.TranscodingInfo && session.TranscodingInfo.CompletionPercentage) {
const percent = session.TranscodingInfo.CompletionPercentage.toFixed(1);
transcodingProgress.outerHTML = indicators.getProgressHtml(percent, {
containerClass: 'transcodingProgress'
});
} else {
transcodingProgress.outerHTML = indicators.getProgressHtml(0, {
containerClass: 'transcodingProgress hide'
});
}
let percent = 100 * session?.PlayState?.PositionTicks / nowPlayingItem?.RunTimeTicks;
playbackProgressElem.outerHTML = indicators.getProgressHtml(percent || 0, {
containerClass: 'playbackProgress'
});
percent = session?.TranscodingInfo?.CompletionPercentage?.toFixed(1);
transcodingProgress.outerHTML = indicators.getProgressHtml(percent || 0, {
containerClass: 'transcodingProgress'
});
const imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem) || '';
const imgElem = row.querySelector('.sessionNowPlayingContent');

View File

@@ -25,7 +25,7 @@ import confirm from '../../../components/confirm/confirm';
confirm({
text: msg,
title: globalize.translate('HeaderDeleteDevices'),
confirmText: globalize.translate('ButtonDelete'),
confirmText: globalize.translate('Delete'),
primary: 'delete'
}).then(async () => {
loading.show();
@@ -96,7 +96,7 @@ import confirm from '../../../components/confirm/confirm';
deviceHtml += '<div class="cardBox visualCardBox">';
deviceHtml += '<div class="cardScalable">';
deviceHtml += '<div class="cardPadder cardPadder-backdrop"></div>';
deviceHtml += '<a is="emby-linkbutton" href="' + (canEdit ? '#!/device.html?id=' + device.Id : '#') + '" class="cardContent cardImageContainer">';
deviceHtml += `<a is="emby-linkbutton" href="${canEdit ? '#!/device.html?id=' + device.Id : '#'}" class="cardContent cardImageContainer">`;
const iconUrl = imageHelper.getDeviceIcon(device);
if (iconUrl) {

View File

@@ -41,7 +41,7 @@ import confirm from '../../../components/confirm/confirm';
html += '<div class="listItem listItem-border">';
html += '<span class="listItemIcon material-icons live_tv"></span>';
html += '<div class="listItemBody two-line">';
html += "<a is='emby-linkbutton' style='padding:0;margin:0;' data-ripple='false' class='clearLink' href='dlnaprofile.html?id=" + profile.Id + "'>";
html += "<a is='emby-linkbutton' style='padding:0;margin:0;' data-ripple='false' class='clearLink' href='#!/dlnaprofile.html?id=" + profile.Id + "'>";
html += '<div>' + profile.Name + '</div>';
html += '</a>';
html += '</div>';

View File

@@ -84,6 +84,13 @@
</label>
</div>
<div class="checkboxListContainer hide fldEnhancedNvdec">
<label>
<input type="checkbox" is="emby-checkbox" id="chkEnhancedNvdecDecoder" />
<span>${EnableEnhancedNvdecDecoder}</span>
</label>
</div>
<div class="checkboxListContainer">
<div class="checkboxList">
<label>
@@ -103,6 +110,13 @@
</div>
</div>
<div class="checkboxListContainer checkboxContainer-withDescription fldVppTonemapping hide">
<label>
<input type="checkbox" is="emby-checkbox" id="chkVppTonemapping" />
<span>${EnableVppTonemapping}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${AllowVppTonemappingHelp}</div>
</div>
<div class="tonemappingOptions hide">
<div class="checkboxListContainer checkboxContainer-withDescription">
<label>

View File

@@ -14,6 +14,7 @@ import alert from '../../components/alert';
});
page.querySelector('#chkDecodingColorDepth10Hevc').checked = config.EnableDecodingColorDepth10Hevc;
page.querySelector('#chkDecodingColorDepth10Vp9').checked = config.EnableDecodingColorDepth10Vp9;
page.querySelector('#chkEnhancedNvdecDecoder').checked = config.EnableEnhancedNvdecDecoder;
page.querySelector('#chkHardwareEncoding').checked = config.EnableHardwareEncoding;
page.querySelector('#chkAllowHevcEncoding').checked = config.AllowHevcEncoding;
$('#selectVideoDecoder', page).val(config.HardwareAccelerationType);
@@ -26,6 +27,7 @@ import alert from '../../components/alert';
page.querySelector('#chkEnableFallbackFont').checked = config.EnableFallbackFont;
$('#txtVaapiDevice', page).val(config.VaapiDevice || '');
page.querySelector('#chkTonemapping').checked = config.EnableTonemapping;
page.querySelector('#chkVppTonemapping').checked = config.EnableVppTonemapping;
page.querySelector('#txtOpenclDevice').value = config.OpenclDevice || '';
page.querySelector('#selectTonemappingAlgorithm').value = config.TonemappingAlgorithm;
page.querySelector('#selectTonemappingRange').value = config.TonemappingRange;
@@ -81,6 +83,7 @@ import alert from '../../components/alert';
config.VaapiDevice = $('#txtVaapiDevice', form).val();
config.OpenclDevice = form.querySelector('#txtOpenclDevice').value;
config.EnableTonemapping = form.querySelector('#chkTonemapping').checked;
config.EnableVppTonemapping = form.querySelector('#chkVppTonemapping').checked;
config.TonemappingAlgorithm = form.querySelector('#selectTonemappingAlgorithm').value;
config.TonemappingRange = form.querySelector('#selectTonemappingRange').value;
config.TonemappingDesat = form.querySelector('#txtTonemappingDesat').value;
@@ -101,6 +104,7 @@ import alert from '../../components/alert';
});
config.EnableDecodingColorDepth10Hevc = form.querySelector('#chkDecodingColorDepth10Hevc').checked;
config.EnableDecodingColorDepth10Vp9 = form.querySelector('#chkDecodingColorDepth10Vp9').checked;
config.EnableEnhancedNvdecDecoder = form.querySelector('#chkEnhancedNvdecDecoder').checked;
config.EnableHardwareEncoding = form.querySelector('#chkHardwareEncoding').checked;
config.AllowHevcEncoding = form.querySelector('#chkAllowHevcEncoding').checked;
ApiClient.updateNamedConfiguration('encoding', config).then(function () {
@@ -156,8 +160,19 @@ import alert from '../../components/alert';
}];
}
let systemInfo;
function getSystemInfo() {
return systemInfo ? Promise.resolve(systemInfo) : ApiClient.getPublicSystemInfo().then(
info => {
systemInfo = info;
return info;
}
);
}
$(document).on('pageinit', '#encodingSettingsPage', function () {
const page = this;
getSystemInfo();
page.querySelector('#selectVideoDecoder').addEventListener('change', function () {
if (this.value == 'vaapi') {
page.querySelector('.fldVaapiDevice').classList.remove('hide');
@@ -181,6 +196,18 @@ import alert from '../../components/alert';
page.querySelector('.tonemappingOptions').classList.add('hide');
}
if (this.value == 'nvenc') {
page.querySelector('.fldEnhancedNvdec').classList.remove('hide');
} else {
page.querySelector('.fldEnhancedNvdec').classList.add('hide');
}
if (systemInfo.OperatingSystem.toLowerCase() === 'linux' && (this.value == 'vaapi' || this.value == 'qsv')) {
page.querySelector('.fldVppTonemapping').classList.remove('hide');
} else {
page.querySelector('.fldVppTonemapping').classList.add('hide');
}
if (this.value) {
page.querySelector('.hardwareAccelerationOptions').classList.remove('hide');
} else {

View File

@@ -9,6 +9,7 @@ import '../../components/cardbuilder/card.css';
import '../../elements/emby-itemrefreshindicator/emby-itemrefreshindicator';
import Dashboard, { pageClassOn, pageIdOn } from '../../scripts/clientUtils';
import confirm from '../../components/confirm/confirm';
import cardBuilder from '../../components/cardbuilder/cardBuilder';
/* eslint-disable indent */
@@ -168,7 +169,8 @@ import confirm from '../../components/confirm/confirm';
showType: false,
showLocations: false,
showMenu: false,
showNameWithIcon: false
showNameWithIcon: false,
elementId: 'addLibrary'
});
for (let i = 0; i < virtualFolders.length; i++) {
@@ -254,11 +256,8 @@ import confirm from '../../components/confirm/confirm';
style += 'min-width:33.3%;';
}
if (virtualFolder.Locations.length == 0) {
html += '<div id="addLibrary" class="card backdropCard scalableCard backdropCard-scalable" style="' + style + '" data-index="' + index + '" data-id="' + virtualFolder.ItemId + '">';
} else {
html += '<div class="card backdropCard scalableCard backdropCard-scalable" style="' + style + '" data-index="' + index + '" data-id="' + virtualFolder.ItemId + '">';
}
const elementId = virtualFolder.elementId ? `id="${virtualFolder.elementId}" ` : '';
html += '<div ' + elementId + 'class="card backdropCard scalableCard backdropCard-scalable" style="' + style + '" data-index="' + index + '" data-id="' + virtualFolder.ItemId + '">';
html += '<div class="cardBox visualCardBox">';
html += '<div class="cardScalable visualCardBox-cardScalable">';
@@ -276,11 +275,12 @@ import confirm from '../../components/confirm/confirm';
let hasCardImageContainer;
if (imgUrl) {
html += '<div class="cardImageContainer editLibrary" style="cursor:pointer;background-image:url(\'' + imgUrl + "');\">";
html += `<div class="cardImageContainer editLibrary ${imgUrl ? '' : cardBuilder.getDefaultBackgroundClass()}" style="cursor:pointer">`;
html += `<img src="${imgUrl}" style="width:100%" />`;
hasCardImageContainer = true;
} else if (!virtualFolder.showNameWithIcon) {
html += '<div class="cardImageContainer editLibrary" style="cursor:pointer;">';
html += '<span class="cardImageIcon-small material-icons ' + (virtualFolder.icon || imageHelper.getLibraryIcon(virtualFolder.CollectionType)) + '"></span>';
html += `<div class="cardImageContainer editLibrary ${cardBuilder.getDefaultBackgroundClass()}" style="cursor:pointer;">`;
html += '<span class="cardImageIcon material-icons ' + (virtualFolder.icon || imageHelper.getLibraryIcon(virtualFolder.CollectionType)) + '"></span>';
hasCardImageContainer = true;
}
@@ -293,7 +293,7 @@ import confirm from '../../components/confirm/confirm';
if (!imgUrl && virtualFolder.showNameWithIcon) {
html += '<h3 class="cardImageContainer addLibrary" style="position:absolute;top:0;left:0;right:0;bottom:0;cursor:pointer;flex-direction:column;">';
html += '<span class="cardImageIcon-small material-icons ' + (virtualFolder.icon || imageHelper.getLibraryIcon(virtualFolder.CollectionType)) + '"></span>';
html += '<span class="cardImageIcon material-icons ' + (virtualFolder.icon || imageHelper.getLibraryIcon(virtualFolder.CollectionType)) + '"></span>';
if (virtualFolder.showNameWithIcon) {
html += '<div style="margin:1em 0;position:width:100%;">';

View File

@@ -17,6 +17,18 @@
${LabelMaxResumePercentageHelp}
</div>
</div>
<div class="inputContainer">
<input is="emby-input" type="number" id="txtMinAudiobookResume" name="txtMinAudiobookResume" pattern="[0-9]*" required min="0" max="100" label="${LabelMinAudiobookResume}"></input>
<div class="fieldDescription">
${LabelMinAudiobookResumeHelp}
</div>
</div>
<div class="inputContainer">
<input is="emby-input" type="number" id="txtMaxAudiobookResume" name="txtMaxAudiobookResume" pattern="[0-9]*" required min="1" max="100" label="${LabelMaxAudiobookResume}"></input>
<div class="fieldDescription">
${LabelMaxAudiobookResumeHelp}
</div>
</div>
<div class="inputContainer">
<input is="emby-input" type="number" id="txtMinResumeDuration" name="txtMinResumeDuration" pattern="[0-9]*" required min="0" label="${LabelMinResumeDuration}"></input>
<div class="fieldDescription">

View File

@@ -9,6 +9,8 @@ import Dashboard from '../../scripts/clientUtils';
function loadPage(page, config) {
$('#txtMinResumePct', page).val(config.MinResumePct);
$('#txtMaxResumePct', page).val(config.MaxResumePct);
$('#txtMinAudiobookResume', page).val(config.MinAudiobookResume);
$('#txtMaxAudiobookResume', page).val(config.MaxAudiobookResume);
$('#txtMinResumeDuration', page).val(config.MinResumeDurationSeconds);
loading.hide();
}
@@ -19,6 +21,8 @@ import Dashboard from '../../scripts/clientUtils';
ApiClient.getServerConfiguration().then(function (config) {
config.MinResumePct = $('#txtMinResumePct', form).val();
config.MaxResumePct = $('#txtMaxResumePct', form).val();
config.MinAudiobookResume = $('#txtMinAudiobookResume', form).val();
config.MaxAudiobookResume = $('#txtMaxAudiobookResume', form).val();
config.MinResumeDurationSeconds = $('#txtMinResumeDuration', form).val();
ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult);

View File

@@ -22,6 +22,10 @@ function populateHistory(packageInfo, page) {
function populateVersions(packageInfo, page, installedPlugin) {
let html = '';
packageInfo.versions.sort((a, b) => {
return b.timestamp < a.timestamp ? -1 : 1;
});
for (let i = 0; i < packageInfo.versions.length; i++) {
const version = packageInfo.versions[i];
html += '<option value="' + version.version + '">' + globalize.translate('PluginFromRepo', version.version, version.repositoryName) + '</option>';

View File

@@ -1,6 +1,7 @@
import loading from '../../../../components/loading/loading';
import libraryMenu from '../../../../scripts/libraryMenu';
import globalize from '../../../../scripts/globalize';
import * as cardBuilder from '../../../../components/cardbuilder/cardBuilder.js';
import '../../../../components/cardbuilder/card.css';
import '../../../../elements/emby-button/emby-button';
import '../../../../elements/emby-checkbox/emby-checkbox';
@@ -102,10 +103,20 @@ function getPluginHtml(plugin, options, installedPlugins) {
html += '<div class="cardBox visualCardBox">';
html += '<div class="cardScalable visualCardBox-cardScalable">';
html += '<div class="cardPadder cardPadder-backdrop"></div>';
html += '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + href + '"' + target + '>';
html += '<span class="cardImageIcon material-icons folder"></span>';
html += '<div class="cardContent">';
html += `<a class="cardImageContainer" is="emby-linkbutton" style="margin:0;padding:0" href="${href}" ${target}>`;
if (plugin.imageUrl) {
html += `<img src="${plugin.imageUrl}" style="width:100%" />`;
} else {
html += `<div class="cardImage flex align-items-center justify-content-center ${cardBuilder.getDefaultBackgroundClass()}">`;
html += '<span class="cardImageIcon material-icons extension"></span>';
html += '</div>';
}
html += '</a>';
html += '</div>';
html += '</div>';
html += '<div class="cardFooter">';
html += "<div class='cardText'>";
html += plugin.name;

View File

@@ -2,12 +2,13 @@ import loading from '../../../../components/loading/loading';
import libraryMenu from '../../../../scripts/libraryMenu';
import dom from '../../../../scripts/dom';
import globalize from '../../../../scripts/globalize';
import * as cardBuilder from '../../../../components/cardbuilder/cardBuilder.js';
import '../../../../components/cardbuilder/card.css';
import '../../../../elements/emby-button/emby-button';
import Dashboard, { pageIdOn } from '../../../../scripts/clientUtils';
import confirm from '../../../../components/confirm/confirm';
function deletePlugin(page, uniqueid, name) {
function deletePlugin(page, uniqueid, version, name) {
const msg = globalize.translate('UninstallPluginConfirmation', name);
confirm({
@@ -17,12 +18,26 @@ function deletePlugin(page, uniqueid, name) {
confirmText: globalize.translate('HeaderUninstallPlugin')
}).then(function () {
loading.show();
ApiClient.uninstallPlugin(uniqueid).then(function () {
ApiClient.uninstallPluginByVersion(uniqueid, version).then(function () {
reloadList(page);
});
});
}
function enablePlugin(page, uniqueid, version) {
loading.show();
ApiClient.enablePlugin(uniqueid, version).then(function () {
reloadList(page);
});
}
function disablePlugin(page, uniqueid, version) {
loading.show();
ApiClient.disablePlugin(uniqueid, version).then(function () {
reloadList(page);
});
}
function showNoConfigurationMessage() {
Dashboard.alert({
message: globalize.translate('MessageNoPluginConfiguration')
@@ -39,16 +54,31 @@ function getPluginCardHtml(plugin, pluginConfigurationPages) {
const configPage = pluginConfigurationPages.filter(function (pluginConfigurationPage) {
return pluginConfigurationPage.PluginId == plugin.Id;
})[0];
const configPageUrl = configPage ? Dashboard.getPluginUrl(configPage.Name) : null;
let html = '';
html += "<div data-id='" + plugin.Id + "' data-name='" + plugin.Name + "' data-removable='" + plugin.CanUninstall + "' class='card backdropCard'>";
html += `<div data-id='${plugin.Id}' data-version='${plugin.Version}' data-name='${plugin.Name}' data-removable='${plugin.CanUninstall}' data-status='${plugin.Status}' class='card backdropCard'>`;
html += '<div class="cardBox visualCardBox">';
html += '<div class="cardScalable">';
html += '<div class="cardPadder cardPadder-backdrop"></div>';
html += configPageUrl ? '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + configPageUrl + '">' : '<div class="cardContent noConfigPluginCard noHoverEffect cardImageContainer emby-button">';
html += '<span class="cardImageIcon material-icons folder"></span>';
html += '<div class="cardContent">';
if (configPageUrl) {
html += `<a class="cardImageContainer" is="emby-linkbutton" style="margin:0;padding:0" href="${configPageUrl}">`;
} else {
html += '<div class="cardImageContainer noConfigPluginCard noHoverEffect emby-button" style="margin:0;padding:0">';
}
if (plugin.HasImage) {
html += `<img src="/Plugins/${plugin.Id}/${plugin.Version}/Image" style="width:100%" />`;
} else {
html += `<div class="cardImage flex align-items-center justify-content-center ${cardBuilder.getDefaultBackgroundClass()}">`;
html += '<span class="cardImageIcon material-icons extension"></span>';
html += '</div>';
}
html += configPageUrl ? '</a>' : '</div>';
html += '</div>';
html += '</div>';
html += '<div class="cardFooter">';
if (configPage || plugin.CanUninstall) {
@@ -57,12 +87,10 @@ function getPluginCardHtml(plugin, pluginConfigurationPages) {
html += '</div>';
}
html += "<div class='cardText'>";
html += configPage && configPage.DisplayName ? configPage.DisplayName : plugin.Name;
html += '</div>';
html += "<div class='cardText cardText-secondary'>";
html += plugin.Version;
html += '<div class="cardText">';
html += `${plugin.Name}<span class='cardText cardText-secondary'>${plugin.Version}</span>`;
html += '</div>';
html += `<div class="cardText">${globalize.translate('LabelStatus')} ${plugin.Status}</div>`;
html += '</div>';
html += '</div>';
html += '</div>';
@@ -113,7 +141,9 @@ function showPluginMenu(page, elem) {
const id = card.getAttribute('data-id');
const name = card.getAttribute('data-name');
const removable = card.getAttribute('data-removable');
const configHref = card.querySelector('.cardContent').getAttribute('href');
const configHref = card.querySelector('.cardImageContainer').getAttribute('href');
const status = card.getAttribute('data-status');
const version = card.getAttribute('data-version');
const menuItems = [];
if (configHref) {
@@ -125,6 +155,22 @@ function showPluginMenu(page, elem) {
}
if (removable === 'true') {
if (status === 'Disabled') {
menuItems.push({
name: globalize.translate('EnablePlugin'),
id: 'enable',
icon: 'check_circle_outline'
});
}
if (status === 'Active') {
menuItems.push({
name: globalize.translate('DisablePlugin'),
id: 'disable',
icon: 'do_not_disturb'
});
}
menuItems.push({
name: globalize.translate('ButtonUninstall'),
id: 'delete',
@@ -142,7 +188,13 @@ function showPluginMenu(page, elem) {
Dashboard.navigate(configHref);
break;
case 'delete':
deletePlugin(page, id, name);
deletePlugin(page, id, version, name);
break;
case 'enable':
enablePlugin(page, id, version);
break;
case 'disable':
disablePlugin(page, id, version);
break;
}
}

View File

@@ -52,6 +52,8 @@ function populateList(options) {
html += '</div>';
if (!options.repositories.length) {
options.noneElement.classList.remove('hide');
} else {
options.noneElement.classList.add('hide');
}
options.listElement.innerHTML = html;

View File

@@ -7,7 +7,7 @@
<h2 class="sectionTitle">${TabStreaming}</h2>
</div>
<div class="inputContainer">
<input is="emby-input" type="number" id="txtRemoteClientBitrateLimit" pattern="[0-9]*" min="0" step=".25" label="${LabelRemoteClientBitrateLimit}" />
<input is="emby-input" type="number" id="txtRemoteClientBitrateLimit" inputmode="decimal" pattern="[0-9]*(\.[0-9]+)?" min="0" step=".25" label="${LabelRemoteClientBitrateLimit}" />
<div class="fieldDescription">${LabelRemoteClientBitrateLimitHelp}</div>
</div>
</div>

View File

@@ -99,7 +99,7 @@
<br />
<div class="verticalSection">
<div class="inputContainer">
<input is="emby-input" type="number" id="txtRemoteClientBitrateLimit" pattern="[0-9]*" min="0" step=".25" label="${LabelRemoteClientBitrateLimit}" />
<input is="emby-input" type="number" id="txtRemoteClientBitrateLimit" inputmode="decimal" pattern="[0-9]*(\.[0-9]+)?" min="0" step=".25" label="${LabelRemoteClientBitrateLimit}" />
<div class="fieldDescription">${LabelRemoteClientBitrateLimitHelp}</div>
<div class="fieldDescription">${LabelUserRemoteClientBitrateLimitHelp}</div>
</div>

View File

@@ -174,7 +174,6 @@ import toast from '../../../components/toast/toast';
$(document).on('pageinit', '#editUserPage', function () {
$('.editUserProfileForm').off('submit', onSubmit).on('submit', onSubmit);
this.querySelector('.sharingHelp').innerHTML = globalize.translate('OptionAllowLinkSharingHelp', 30);
const page = this;
$('#chkEnableDeleteAllFolders', this).on('change', function () {
if (this.checked) {

View File

@@ -10,6 +10,7 @@ import '../../../components/indicators/indicators.css';
import '../../../assets/css/flexstyles.scss';
import Dashboard, { pageIdOn } from '../../../scripts/clientUtils';
import confirm from '../../../components/confirm/confirm';
import cardBuilder from '../../../components/cardbuilder/cardBuilder';
/* eslint-disable indent */
@@ -93,7 +94,7 @@ import confirm from '../../../components/confirm/confirm';
html += '<div class="cardBox visualCardBox">';
html += '<div class="cardScalable visualCardBox-cardScalable">';
html += '<div class="cardPadder cardPadder-square"></div>';
html += '<a is="emby-linkbutton" class="cardContent" href="#!/useredit.html?userId=' + user.Id + '">';
html += `<a is="emby-linkbutton" class="cardContent ${imgUrl ? '' : cardBuilder.getDefaultBackgroundClass()}" href="#!/useredit.html?userId=${user.Id}">`;
let imgUrl;
if (user.PrimaryImageTag) {
@@ -113,7 +114,7 @@ import confirm from '../../../components/confirm/confirm';
if (imgUrl) {
html += '<div class="' + imageClass + '" style="background-image:url(\'' + imgUrl + "');\">";
} else {
html += '<div class="' + imageClass + ' flex align-items-center justify-content-center">';
html += `<div class="${imageClass} ${imgUrl ? '' : cardBuilder.getDefaultBackgroundClass()} flex align-items-center justify-content-center">`;
html += '<span class="material-icons cardImageIcon person"></span>';
}

View File

@@ -256,6 +256,8 @@ import ServerConnections from '../components/ServerConnections';
}
elem.innerHTML = html;
window.CustomElements.upgradeSubtree(elem);
const elems = elem.querySelectorAll('.itemsContainer');
for (let i = 0, length = elems.length; i < length; i++) {

View File

@@ -5,6 +5,10 @@
<div class="detailLogo"></div>
<div class="detailPageWrapperContainer">
<div class="detailPagePrimaryContainer padded-left padded-right">
<div class="primaryImageWrapper hide">
<img id="primaryImage" />
</div>
<div class="infoWrapper infoText">
<div class="nameContainer"></div>
<div class="itemMiscInfo itemMiscInfo-primary" style="margin-bottom: 0.6em;"></div>

View File

@@ -351,9 +351,13 @@ function reloadPlayButtons(page, item) {
const isResumable = item.UserData && item.UserData.PlaybackPositionTicks > 0;
hideAll(page, 'btnResume', isResumable);
if (isResumable) {
for (const elem of page.querySelectorAll('.btnPlay')) {
elem.querySelector('.detailButton-icon').classList.replace('play_arrow', 'replay');
for (const elem of page.querySelectorAll('.btnPlay')) {
const btnPlay = elem.querySelector('.detailButton-icon');
if (isResumable) {
btnPlay.classList.replace('play_arrow', 'replay');
} else {
btnPlay.classList.replace('replay', 'play_arrow');
}
}
} else {
@@ -552,7 +556,7 @@ function renderDetailPageBackdrop(page, item, apiClient) {
let hasbackdrop = false;
const itemBackdropElement = page.querySelector('#itemBackdrop');
if (!layoutManager.mobile && !userSettings.detailsBanner()) {
if (layoutManager.mobile || !userSettings.detailsBanner()) {
return false;
}
@@ -589,6 +593,24 @@ function renderDetailPageBackdrop(page, item, apiClient) {
return hasbackdrop;
}
function renderPrimaryImage(page, item, apiClient) {
if (item?.ImageTags?.Primary) {
const imageUrl = apiClient.getScaledImageUrl(item.Id, {
type: 'Primary',
maxWidth: dom.getScreenWidth(),
tag: item.ImageTags.Primary
});
const imageElem = page.querySelector('#primaryImage');
imageElem.src = imageUrl;
imageElem.alt = item.Name;
if (item.PrimaryImageAspectRatio === 1) {
imageElem.classList.add('aspect-square');
}
page.querySelector('.primaryImageWrapper')?.classList.remove('hide');
}
}
function reloadFromItem(instance, page, params, item, user) {
const apiClient = ServerConnections.getApiClient(item.ServerId);
@@ -601,6 +623,9 @@ function reloadFromItem(instance, page, params, item, user) {
renderLogo(page, item, apiClient);
renderDetailPageBackdrop(page, item, apiClient);
}
if (layoutManager.mobile) {
renderPrimaryImage(page, item, apiClient);
}
renderBackdrop(item);
// Render the main information for the item
@@ -720,9 +745,7 @@ function renderLogo(page, item, apiClient) {
const url = logoImageUrl(item, apiClient, {});
if (!layoutManager.mobile && !userSettings.enableBackdrops()) {
detailLogo.classList.add('hide');
} else if (url) {
if (url) {
detailLogo.classList.remove('hide');
imageLoader.setLazyImage(detailLogo, url);
} else {
@@ -1188,7 +1211,7 @@ function renderMoreFromArtist(view, item, apiClient) {
IncludeItemTypes: 'MusicAlbum',
Recursive: true,
ExcludeItemIds: item.Id,
SortBy: 'ProductionYear,SortName',
SortBy: 'PremiereDate,ProductionYear,SortName',
SortOrder: 'Descending'
};
@@ -1244,7 +1267,7 @@ function renderSimilarItems(page, item, context) {
const options = {
userId: apiClient.getCurrentUserId(),
limit: 12,
fields: 'PrimaryImageAspectRatio,UserData,CanDelete'
fields: 'PrimaryImageAspectRatio,CanDelete'
};
if (item.Type == 'MusicAlbum' && item.AlbumArtists && item.AlbumArtists.length) {
@@ -1370,7 +1393,7 @@ function renderChildren(page, item) {
Fields: fields
});
} else if (item.Type == 'MusicArtist') {
query.SortBy = 'ProductionYear,SortName';
query.SortBy = 'PremiereDate,ProductionYear,SortName';
}
promise = promise || apiClient.getItems(apiClient.getCurrentUserId(), query);
@@ -1772,7 +1795,7 @@ function renderMusicVideos(page, item, user) {
}).then(function (result) {
if (result.Items.length) {
page.querySelector('#musicVideosCollapsible').classList.remove('hide');
const musicVideosContent = page.querySelector('.musicVideosContent');
const musicVideosContent = page.querySelector('#musicVideosContent');
musicVideosContent.innerHTML = getVideosHtml(result.Items);
imageLoader.lazyChildren(musicVideosContent);
} else {
@@ -2073,7 +2096,7 @@ export default function (view, params) {
view.addEventListener('viewshow', function (e) {
const page = this;
libraryMenu.setTransparentMenu(true);
libraryMenu.setTransparentMenu(!layoutManager.mobile);
if (e.detail.isRestored) {
if (currentItem) {

View File

@@ -338,7 +338,7 @@ export default function (view, params) {
let initialTabIndex = currentTabIndex;
let lastFullRender = 0;
[].forEach.call(view.querySelectorAll('.sectionTitleTextButton-programs'), function (link) {
const href = link.href;
const href = link.getAttribute('href');
if (href) {
link.href = href + '&serverId=' + ApiClient.serverId();

View File

@@ -56,75 +56,73 @@ function showSaveMessage(recordingPathChanged) {
}
}
export default function () {
$(document).on('pageinit', '#liveTvSettingsPage', function () {
const page = this;
$('.liveTvSettingsForm').off('submit', onSubmit).on('submit', onSubmit);
$('#btnSelectRecordingPath', page).on('click.selectDirectory', function () {
import('../components/directorybrowser/directorybrowser').then(({default: directoryBrowser}) => {
const picker = new directoryBrowser();
picker.show({
callback: function (path) {
if (path) {
$('#txtRecordingPath', page).val(path);
}
picker.close();
},
validateWriteable: true
});
});
});
$('#btnSelectMovieRecordingPath', page).on('click.selectDirectory', function () {
import('../components/directorybrowser/directorybrowser').then(({default: directoryBrowser}) => {
const picker = new directoryBrowser();
picker.show({
callback: function (path) {
if (path) {
$('#txtMovieRecordingPath', page).val(path);
}
picker.close();
},
validateWriteable: true
});
});
});
$('#btnSelectSeriesRecordingPath', page).on('click.selectDirectory', function () {
import('../components/directorybrowser/directorybrowser').then(({default: directoryBrowser}) => {
const picker = new directoryBrowser();
picker.show({
callback: function (path) {
if (path) {
$('#txtSeriesRecordingPath', page).val(path);
}
picker.close();
},
validateWriteable: true
});
});
});
$('#btnSelectPostProcessorPath', page).on('click.selectDirectory', function () {
import('../components/directorybrowser/directorybrowser').then(({default: directoryBrowser}) => {
const picker = new directoryBrowser();
picker.show({
includeFiles: true,
callback: function (path) {
if (path) {
$('#txtPostProcessor', page).val(path);
}
picker.close();
$(document).on('pageinit', '#liveTvSettingsPage', function () {
const page = this;
$('.liveTvSettingsForm').off('submit', onSubmit).on('submit', onSubmit);
$('#btnSelectRecordingPath', page).on('click.selectDirectory', function () {
import('../components/directorybrowser/directorybrowser').then(({default: directoryBrowser}) => {
const picker = new directoryBrowser();
picker.show({
callback: function (path) {
if (path) {
$('#txtRecordingPath', page).val(path);
}
});
picker.close();
},
validateWriteable: true
});
});
}).on('pageshow', '#liveTvSettingsPage', function () {
loading.show();
const page = this;
ApiClient.getNamedConfiguration('livetv').then(function (config) {
loadPage(page, config);
});
});
}
$('#btnSelectMovieRecordingPath', page).on('click.selectDirectory', function () {
import('../components/directorybrowser/directorybrowser').then(({default: directoryBrowser}) => {
const picker = new directoryBrowser();
picker.show({
callback: function (path) {
if (path) {
$('#txtMovieRecordingPath', page).val(path);
}
picker.close();
},
validateWriteable: true
});
});
});
$('#btnSelectSeriesRecordingPath', page).on('click.selectDirectory', function () {
import('../components/directorybrowser/directorybrowser').then(({default: directoryBrowser}) => {
const picker = new directoryBrowser();
picker.show({
callback: function (path) {
if (path) {
$('#txtSeriesRecordingPath', page).val(path);
}
picker.close();
},
validateWriteable: true
});
});
});
$('#btnSelectPostProcessorPath', page).on('click.selectDirectory', function () {
import('../components/directorybrowser/directorybrowser').then(({default: directoryBrowser}) => {
const picker = new directoryBrowser();
picker.show({
includeFiles: true,
callback: function (path) {
if (path) {
$('#txtPostProcessor', page).val(path);
}
picker.close();
}
});
});
});
}).on('pageshow', '#liveTvSettingsPage', function () {
loading.show();
const page = this;
ApiClient.getNamedConfiguration('livetv').then(function (config) {
loadPage(page, config);
});
});

View File

@@ -293,36 +293,34 @@ function onDevicesListClick(e) {
}
}
export default function () {
$(document).on('pageinit', '#liveTvStatusPage', function () {
const page = this;
$('.btnAddDevice', page).on('click', function () {
addDevice(this);
});
$('.formAddDevice', page).on('submit', function () {
submitAddDeviceForm(page);
return false;
});
$('.btnAddProvider', page).on('click', function () {
addProvider(this);
});
page.querySelector('.devicesList').addEventListener('click', onDevicesListClick);
}).on('pageshow', '#liveTvStatusPage', function () {
const page = this;
reload(page);
taskButton({
mode: 'on',
progressElem: page.querySelector('.refreshGuideProgress'),
taskKey: 'RefreshGuide',
button: page.querySelector('.btnRefresh')
});
}).on('pagehide', '#liveTvStatusPage', function () {
const page = this;
taskButton({
mode: 'off',
progressElem: page.querySelector('.refreshGuideProgress'),
taskKey: 'RefreshGuide',
button: page.querySelector('.btnRefresh')
});
$(document).on('pageinit', '#liveTvStatusPage', function () {
const page = this;
$('.btnAddDevice', page).on('click', function () {
addDevice(this);
});
}
$('.formAddDevice', page).on('submit', function () {
submitAddDeviceForm(page);
return false;
});
$('.btnAddProvider', page).on('click', function () {
addProvider(this);
});
page.querySelector('.devicesList').addEventListener('click', onDevicesListClick);
}).on('pageshow', '#liveTvStatusPage', function () {
const page = this;
reload(page);
taskButton({
mode: 'on',
progressElem: page.querySelector('.refreshGuideProgress'),
taskKey: 'RefreshGuide',
button: page.querySelector('.btnRefresh')
});
}).on('pagehide', '#liveTvStatusPage', function () {
const page = this;
taskButton({
mode: 'off',
progressElem: page.querySelector('.refreshGuideProgress'),
taskKey: 'RefreshGuide',
button: page.querySelector('.btnRefresh')
});
});

View File

@@ -234,7 +234,7 @@ import '../../elements/emby-itemscontainer/emby-itemscontainer';
});
});
const btnSelectView = tabContent.querySelector('.btnSelectView');
btnSelectView.addEventListener('click', function (e) {
btnSelectView.addEventListener('click', (e) => {
libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle(), 'List,Poster,PosterCard,Thumb,ThumbCard'.split(','));
});
btnSelectView.addEventListener('layoutchange', function (e) {

View File

@@ -238,8 +238,8 @@ import '../../elements/emby-itemscontainer/emby-itemscontainer';
});
}
const btnSelectView = tabContent.querySelector('.btnSelectView');
btnSelectView.addEventListener('click', function (e) {
libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle, 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(','));
btnSelectView.addEventListener('click', (e) => {
libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle(), 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(','));
});
btnSelectView.addEventListener('layoutchange', function (e) {
const viewStyle = e.detail.viewStyle;

View File

@@ -229,7 +229,7 @@ import '../../elements/emby-itemscontainer/emby-itemscontainer';
alphaPickerElement.classList.add('alphaPicker-fixed-right');
itemsContainer.classList.add('padded-right-withalphapicker');
tabContent.querySelector('.btnFilter').addEventListener('click', function () {
tabContent.querySelector('.btnFilter').addEventListener('click', () => {
this.showFilterMenu();
});
tabContent.querySelector('.btnSort').addEventListener('click', function (e) {

View File

@@ -24,7 +24,7 @@ import '../../elements/emby-itemscontainer/emby-itemscontainer';
function shuffle() {
ApiClient.getItem(ApiClient.getCurrentUserId(), params.topParentId).then(function (item) {
getQuery();
playbackManager.shuffle(item, null);
playbackManager.shuffle(item);
});
}

View File

@@ -218,7 +218,7 @@ import '../../elements/emby-itemscontainer/emby-itemscontainer';
this.showFilterMenu();
});
const btnSelectView = tabContent.querySelector('.btnSelectView');
btnSelectView.addEventListener('click', function (e) {
btnSelectView.addEventListener('click', (e) => {
libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle(), 'List,Poster,PosterCard'.split(','));
});
btnSelectView.addEventListener('layoutchange', function (e) {

View File

@@ -64,7 +64,7 @@ import ServerConnections from '../../../components/ServerConnections';
}
function goBack() {
import('../../../components/appRouter').then(({default: appRouter}) => {
import('../../../components/appRouter').then(({appRouter}) => {
appRouter.back();
});
}

View File

@@ -13,6 +13,7 @@ import ServerConnections from '../../../components/ServerConnections';
import toast from '../../../components/toast/toast';
import dialogHelper from '../../../components/dialogHelper/dialogHelper';
import baseAlert from '../../../components/alert';
import cardBuilder from '../../../components/cardbuilder/cardBuilder';
/* eslint-disable indent */
@@ -131,29 +132,6 @@ import baseAlert from '../../../components/alert';
}
}
const metroColors = ['#6FBD45', '#4BB3DD', '#4164A5', '#E12026', '#800080', '#E1B222', '#008040', '#0094FF', '#FF00C7', '#FF870F', '#7F0037'];
function getRandomMetroColor() {
const index = Math.floor(Math.random() * (metroColors.length - 1));
return metroColors[index];
}
function getMetroColor(str) {
if (str) {
const character = String(str.substr(0, 1).charCodeAt());
let sum = 0;
for (let i = 0; i < character.length; i++) {
sum += parseInt(character.charAt(i));
}
const index = String(sum).substr(-1);
return metroColors[index];
}
return getRandomMetroColor();
}
function loadUserList(context, apiClient, users) {
let html = '';
@@ -176,7 +154,7 @@ import baseAlert from '../../../components/alert';
html += '<div class="' + cardBoxCssClass + '">';
html += '<div class="cardScalable">';
html += '<div class="cardPadder cardPadder-square"></div>';
html += '<div class="cardContent" data-haspw="' + user.HasPassword + '" data-username="' + user.Name + '" data-userid="' + user.Id + '">';
html += `<div class="cardContent" style="border-radius:0.2em" data-haspw="${user.HasPassword}" data-username="${user.Name}" data-userid="${user.Id}">`;
let imgUrl;
if (user.PrimaryImageTag) {
@@ -185,11 +163,12 @@ import baseAlert from '../../../components/alert';
tag: user.PrimaryImageTag,
type: 'Primary'
});
html += '<div class="cardImageContainer coveredImage" style="background-image:url(\'' + imgUrl + "');\"></div>";
} else {
const background = getMetroColor(user.Id);
imgUrl = 'assets/img/avatar.png';
html += '<div class="cardImageContainer coveredImage" style="background-image:url(\'' + imgUrl + "');background-color:" + background + ';"></div>';
html += `<div class="cardImage flex align-items-center justify-content-center ${cardBuilder.getDefaultBackgroundClass()}">`;
html += '<span class="material-icons cardImageIcon person"></span>';
html += '</div>';
}
html += '</div>';

View File

@@ -17,6 +17,7 @@ import '../../../elements/emby-button/emby-button';
import Dashboard from '../../../scripts/clientUtils';
import ServerConnections from '../../../components/ServerConnections';
import alert from '../../../components/alert';
import cardBuilder from '../../../components/cardbuilder/cardBuilder';
/* eslint-disable indent */
@@ -64,7 +65,7 @@ import alert from '../../../components/alert';
cardContainer += '<div class="cardPadder cardPadder-square">';
cardContainer += '</div>';
cardContainer += '<div class="cardContent">';
cardContainer += '<div class="cardImageContainer coveredImage" style="background:#0288D1;border-radius:.15em;">';
cardContainer += `<div class="cardImageContainer coveredImage ${cardBuilder.getDefaultBackgroundClass()}" style="border-radius:0.2em">`;
cardContainer += cardImageContainer;
cardContainer += '</div>';
cardContainer += '</div>';

View File

@@ -23,7 +23,7 @@ import Dashboard from '../../scripts/clientUtils';
SortOrder: 'Ascending',
IncludeItemTypes: 'Episode',
Recursive: true,
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,UserData',
Fields: 'PrimaryImageAspectRatio,MediaSourceCount',
IsMissing: false,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb',

View File

@@ -13,7 +13,7 @@ import '../../elements/emby-itemscontainer/emby-itemscontainer';
loading.show();
const query = {
Limit: 48,
Fields: 'AirTime,UserData',
Fields: 'AirTime',
UserId: ApiClient.getCurrentUserId(),
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',

View File

@@ -3,7 +3,7 @@
display: inline-flex;
align-items: center;
box-sizing: border-box;
margin: 0 0.3em;
margin: 0.3em;
text-align: center;
font-size: inherit;
font-family: inherit;

View File

@@ -18,6 +18,7 @@ function onAnchorClick(e) {
shell.openUrl(href);
}
} else {
e.preventDefault();
appRouter.show(href);
}
} else {

View File

@@ -2,7 +2,7 @@
<html class="preload">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">
<link rel="manifest" href="manifest.json">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
@@ -11,6 +11,7 @@
<meta name="mobile-web-app-capable" content="yes">
<meta name="application-name" content="Jellyfin">
<meta name="robots" content="noindex, nofollow, noarchive">
<meta name="referrer" content="no-referrer">
<meta property="og:title" content="Jellyfin">
<meta property="og:site_name" content="Jellyfin">
<meta property="og:url" content="http://jellyfin.org">

View File

@@ -6,7 +6,7 @@ import keyboardnavigation from '../../scripts/keyboardNavigation';
import dialogHelper from '../../components/dialogHelper/dialogHelper';
import ServerConnections from '../../components/ServerConnections';
import TableOfContents from './tableOfContents';
import browser from '../../scripts/browser';
import dom from '../../scripts/dom';
import { translateHtml } from '../../scripts/globalize';
import '../../scripts/dom';
@@ -22,18 +22,12 @@ export class BookPlayer {
this.id = 'bookplayer';
this.priority = 1;
this.epubOptions = {
width: '100%',
height: '100%',
// TODO: Add option for scrolled-doc
flow: 'paginated'
};
this.onDialogClosed = this.onDialogClosed.bind(this);
this.openTableOfContents = this.openTableOfContents.bind(this);
this.prevChapter = this.prevChapter.bind(this);
this.nextChapter = this.nextChapter.bind(this);
this.previous = this.previous.bind(this);
this.next = this.next.bind(this);
this.onWindowKeyUp = this.onWindowKeyUp.bind(this);
this.onTouchStart = this.onTouchStart.bind(this);
}
play(options) {
@@ -109,20 +103,18 @@ export class BookPlayer {
onWindowKeyUp(e) {
const key = keyboardnavigation.getKeyName(e);
const rendition = this.rendition;
const book = rendition.book;
if (!this.loaded) return;
switch (key) {
case 'l':
case 'ArrowRight':
case 'Right':
book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next();
this.next();
break;
case 'j':
case 'ArrowLeft':
case 'Left':
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
this.previous();
break;
case 'Escape':
if (this.tocElement) {
@@ -136,6 +128,19 @@ export class BookPlayer {
}
}
onTouchStart(e) {
if (!this.loaded || !e.touches || e.touches.length === 0) return;
// epubjs stores pages off the screen or something for preloading
// get the modulus of the touch event to account for the increased width
const touchX = e.touches[0].clientX % dom.getWindowSize().innerWidth;
if (touchX < dom.getWindowSize().innerWidth / 2) {
this.previous();
} else {
this.next();
}
}
onDialogClosed() {
this.stop();
}
@@ -146,8 +151,8 @@ export class BookPlayer {
elem.addEventListener('close', this.onDialogClosed, {once: true});
elem.querySelector('#btnBookplayerExit').addEventListener('click', this.onDialogClosed, {once: true});
elem.querySelector('#btnBookplayerToc').addEventListener('click', this.openTableOfContents);
elem.querySelector('#btnBookplayerPrev')?.addEventListener('click', this.prevChapter);
elem.querySelector('#btnBookplayerNext')?.addEventListener('click', this.nextChapter);
elem.querySelector('#btnBookplayerPrev')?.addEventListener('click', this.previous);
elem.querySelector('#btnBookplayerNext')?.addEventListener('click', this.next);
}
bindEvents() {
@@ -155,7 +160,7 @@ export class BookPlayer {
document.addEventListener('keyup', this.onWindowKeyUp);
// FIXME: I don't really get why document keyup event is not triggered when epub is in focus
this.rendition.on('touchstart', this.onTouchStart);
this.rendition.on('keyup', this.onWindowKeyUp);
}
@@ -165,8 +170,8 @@ export class BookPlayer {
elem.removeEventListener('close', this.onDialogClosed);
elem.querySelector('#btnBookplayerExit').removeEventListener('click', this.onDialogClosed);
elem.querySelector('#btnBookplayerToc').removeEventListener('click', this.openTableOfContents);
elem.querySelector('#btnBookplayerPrev')?.removeEventListener('click', this.prevChapter);
elem.querySelector('#btnBookplayerNext')?.removeEventListener('click', this.nextChapter);
elem.querySelector('#btnBookplayerPrev')?.removeEventListener('click', this.previous);
elem.querySelector('#btnBookplayerNext')?.removeEventListener('click', this.next);
}
unbindEvents() {
@@ -176,9 +181,8 @@ export class BookPlayer {
document.removeEventListener('keyup', this.onWindowKeyUp);
if (this.rendition) {
this.rendition.off('keyup', this.onWindowKeyUp);
}
this.rendition?.off('touchstart', this.onTouchStart);
this.rendition?.off('keyup', this.onWindowKeyUp);
}
openTableOfContents() {
@@ -187,14 +191,18 @@ export class BookPlayer {
}
}
prevChapter(e) {
this.rendition.prev();
e.preventDefault();
previous(e) {
e?.preventDefault();
if (this.rendition) {
this.rendition.book.package.metadata.direction === 'rtl' ? this.rendition.next() : this.rendition.prev();
}
}
nextChapter(e) {
this.rendition.next();
e.preventDefault();
next(e) {
e?.preventDefault();
if (this.rendition) {
this.rendition.book.package.metadata.direction === 'rtl' ? this.rendition.prev() : this.rendition.next();
}
}
createMediaElement() {
@@ -242,7 +250,14 @@ export class BookPlayer {
import('epubjs').then(({default: epubjs}) => {
const downloadHref = apiClient.getItemDownloadUrl(item.Id);
const book = epubjs(downloadHref, {openAs: 'epub'});
const rendition = book.renderTo('bookPlayerContainer', this.epubOptions);
const rendition = book.renderTo('bookPlayerContainer', {
width: '100%',
// Calculate the height of the window because using 100% is not accurate when the dialog is opening
height: document.body.clientHeight,
// TODO: Add option for scrolled-doc
flow: 'paginated'
});
this.currentSrc = downloadHref;
this.rendition = rendition;

View File

@@ -9,6 +9,8 @@ import ServerConnections from '../../components/ServerConnections';
import { Swiper } from 'swiper/swiper-bundle.esm';
import 'swiper/swiper-bundle.css';
import './style.scss';
export class ComicsPlayer {
constructor() {
this.name = 'Comics Player';
@@ -55,11 +57,29 @@ export class ComicsPlayer {
}
}
bindMediaElementEvents() {
const elem = this.mediaElement;
elem?.addEventListener('close', this.onDialogClosed, {once: true});
elem?.querySelector('.btnExit').addEventListener('click', this.onDialogClosed, {once: true});
}
bindEvents() {
this.bindMediaElementEvents();
document.addEventListener('keyup', this.onWindowKeyUp);
}
unbindMediaElementEvents() {
const elem = this.mediaElement;
elem?.removeEventListener('close', this.onDialogClosed);
elem?.querySelector('.btnExit').removeEventListener('click', this.onDialogClosed);
}
unbindEvents() {
this.unbindMediaElementEvents();
document.removeEventListener('keyup', this.onWindowKeyUp);
}
@@ -83,13 +103,16 @@ export class ComicsPlayer {
elem.id = 'comicsPlayer';
elem.classList.add('slideshowDialog');
elem.innerHTML = '<div class="slideshowSwiperContainer"><div class="swiper-wrapper"></div></div>';
elem.innerHTML = `<div class="slideshowSwiperContainer"><div class="swiper-wrapper"></div></div>
<div class="actionButtons">
<button is="paper-icon-button-light" class="autoSize btnExit" tabindex="-1"><i class="material-icons actionButtonIcon close"></i></button>
</div>`;
this.bindEvents();
dialogHelper.open(elem);
}
this.mediaElement = elem;
this.bindEvents();
return elem;
}

View File

@@ -0,0 +1,16 @@
#comicsPlayer {
background: #fff;
.slideshowSwiperContainer {
height: 100%;
}
.slider-zoom-container {
text-align: center;
height: 100%;
}
.swiper-slide-img {
max-height: 100%;
}
}

View File

@@ -387,11 +387,11 @@ function tryRemoveElement(elem) {
let maxBufferLength = 30;
let maxMaxBufferLength = 600;
// chromium based browsers cannot handle huge fragments in high bitrate.
// Some browsers cannot handle huge fragments in high bitrate.
// This issue usually happens when using HWA encoders with a high bitrate setting.
// Limit the BufferLength to 6s, it works fine when playing 4k 120Mbps over HLS on chrome.
// https://github.com/video-dev/hls.js/issues/876
if ((browser.chrome || browser.edgeChromium) && playbackManager.getMaxStreamingBitrate(this) >= 25000000) {
if ((browser.chrome || browser.edgeChromium || browser.firefox) && playbackManager.getMaxStreamingBitrate(this) >= 25000000) {
maxBufferLength = 6;
maxMaxBufferLength = 6;
}
@@ -1049,11 +1049,11 @@ function tryRemoveElement(elem) {
renderSsaAss(videoElement, track, item) {
const avaliableFonts = [];
const attachments = this._currentPlayOptions.mediaSource.MediaAttachments || [];
const apiClient = ServerConnections.getApiClient(item);
attachments.map(function (i) {
// embedded font url
return avaliableFonts.push(i.DeliveryUrl);
return avaliableFonts.push(apiClient.getUrl(i.DeliveryUrl));
});
const apiClient = ServerConnections.getApiClient(item);
const fallbackFontList = apiClient.getUrl('/FallbackFont/Fonts', {
api_key: apiClient.accessToken()
});

View File

@@ -34,7 +34,7 @@ class PlayAccessValidation {
return Promise.reject();
}
return showErrorMessage();
return showErrorMessage().finally(Promise.reject);
});
}
}

View File

@@ -1,8 +1,8 @@
import * as userSettings from './settings/userSettings';
import * as webSettings from './settings/webSettings';
import skinManager from './themeManager';
import { Events } from 'jellyfin-apiclient';
import ServerConnections from '../components/ServerConnections';
import { pageClassOn } from '../scripts/clientUtils';
// Set the default theme when loading
skinManager.setTheme(userSettings.theme())
@@ -12,6 +12,14 @@ skinManager.setTheme(userSettings.theme())
.then(() => document.body.classList.add('force-scroll'));
// set the saved theme once a user authenticates
Events.on(ServerConnections, 'localusersignedin', function (e, user) {
Events.on(ServerConnections, 'localusersignedin', () => {
skinManager.setTheme(userSettings.theme());
});
pageClassOn('viewbeforeshow', 'page', function () {
if (this.classList.contains('type-interior')) {
skinManager.setTheme(userSettings.dashboardTheme());
} else {
skinManager.setTheme(userSettings.theme());
}
});

View File

@@ -210,7 +210,7 @@ if (!browser.chrome && !browser.edgeChromium && !browser.edge && !browser.opera
browser.safari = true;
}
browser.osx = userAgent.toLowerCase().indexOf('os x') !== -1;
browser.osx = userAgent.toLowerCase().indexOf('mac os x') !== -1;
// This is a workaround to detect iPads on iOS 13+ that report as desktop Safari
// This may break in the future if Apple releases a touchscreen Mac
@@ -240,6 +240,9 @@ browser.edgeUwp = browser.edge && (userAgent.toLowerCase().indexOf('msapphost')
if (!browser.tizen) {
browser.orsay = userAgent.toLowerCase().indexOf('smarthub') !== -1;
} else {
// UserAgent string contains 'Safari' and 'safari' is set by matched browser, but we only want 'tizen' to be true
delete browser.safari;
const v = (navigator.appVersion).match(/Tizen (\d+).(\d+)/);
browser.tizenVersion = parseInt(v[1]);
}

View File

@@ -228,7 +228,7 @@ import browser from './browser';
supported = browser.tizen;
break;
case 'mov':
supported = browser.tizen || browser.web0s || browser.chrome || browser.edgeChromium || browser.edgeUwp;
supported = browser.safari || browser.tizen || browser.web0s || browser.chrome || browser.edgeChromium || browser.edgeUwp;
videoCodecs.push('h264');
break;
case 'm2ts':
@@ -414,8 +414,10 @@ import browser from './browser';
if (canPlayAudioFormat('opus')) {
videoAudioCodecs.push('opus');
hlsInTsVideoAudioCodecs.push('opus');
webmAudioCodecs.push('opus');
if (browser.tizen) {
hlsInTsVideoAudioCodecs.push('opus');
}
}
if (canPlayAudioFormat('flac')) {
@@ -463,6 +465,10 @@ import browser from './browser';
if (!browser.safari) {
mp4VideoCodecs.push('hevc');
}
if (browser.tizen || browser.web0s) {
hlsInTsVideoCodecs.push('hevc');
}
}
if (supportsMpeg2Video()) {

View File

@@ -95,7 +95,7 @@ export function logout() {
}
export function getPluginUrl(name) {
return '#!/configurationpage?name=' + encodeURIComponent(name);
return 'configurationpage?name=' + encodeURIComponent(name);
}
export function navigate(url, preserveQueryString) {

View File

@@ -1,11 +1,13 @@
import { arDZ, be, bg, ca, cs, da, de, el, enGB, enUS, es, faIR, fi, fr, frCA, he, hi, hr, hu, id, it, ja, kk, ko, lt, ms, nb,
nl, pl, ptBR, pt, ro, ru, sk, sl, sv, tr, uk, vi, zhCN, zhTW } from 'date-fns/locale';
import { af, arDZ, be, bg, bn, ca, cs, da, de, el, enGB, enUS, eo, es, faIR, fi, fr, frCA, he, hi, hr, hu, gl, id, is, it, ja, kk, ko, lt, ms, nb,
nl, pl, ptBR, pt, ro, ru, sk, sl, sv, ta, th, tr, uk, vi, zhCN, zhTW } from 'date-fns/locale';
import globalize from './globalize';
const dateLocales = (locale) => ({
'af': af,
'ar': arDZ,
'be-by': be,
'bg-bg': bg,
'bn': bn,
'ca': ca,
'cs': cs,
'da': da,
@@ -13,19 +15,23 @@ const dateLocales = (locale) => ({
'el': el,
'en-gb': enGB,
'en-us': enUS,
'eo': eo,
'es': es,
'es-ar': es,
'es-do': es,
'es-mx': es,
'fa': faIR,
'fi': fi,
'fr': fr,
'fr-ca': frCA,
'gl': gl,
'gsw': de,
'he': he,
'hi-in': hi,
'hr': hr,
'hu': hu,
'id': id,
'is': is,
'it': it,
'ja': ja,
'kk': kk,
@@ -35,6 +41,7 @@ const dateLocales = (locale) => ({
'nb': nb,
'nl': nl,
'pl': pl,
'pt': pt,
'pt-br': ptBR,
'pt-pt': pt,
'ro': ro,
@@ -42,6 +49,8 @@ const dateLocales = (locale) => ({
'sk': sk,
'sl-si': sl,
'sv': sv,
'ta': ta,
'th': th,
'tr': tr,
'uk': uk,
'vi': vi,

View File

@@ -235,6 +235,9 @@ import { appHost } from '../components/apphost';
},
'repeatone': () => {
playbackManager.setRepeatMode('RepeatOne');
},
'unknown': () => {
// This is the command given by 'notify', it's a no-op
}
})[command];

View File

@@ -146,7 +146,7 @@ function renderSection(page, item, element, type) {
Limit: 10,
SortBy: 'SortName'
}, {
shape: 'overflowPortrait',
shape: 'overflowBackdrop',
showTitle: true,
centerText: true,
overlayPlayButton: true
@@ -195,7 +195,7 @@ function renderSection(page, item, element, type) {
ArtistIds: '',
AlbumArtistIds: '',
SortOrder: 'Descending',
SortBy: 'ProductionYear,Sortname'
SortBy: 'PremiereDate,ProductionYear,Sortname'
}, {
shape: 'overflowSquare',
playFromHere: true,
@@ -329,7 +329,7 @@ function addCurrentItemToQuery(query, item) {
} else if (item.Type === 'Studio') {
query.StudioIds = item.Id;
} else if (item.Type === 'MusicArtist') {
query.AlbumArtistIds = item.Id;
query.ArtistIds = item.Id;
}
}

View File

@@ -464,6 +464,7 @@ import Headroom from 'headroom.js';
pageIds: ['liveTvSettingsPage'],
icon: 'dvr'
});
addPluginPagesToMainMenu(links, pluginItems, 'livetv');
links.push({
divider: true,
name: globalize.translate('TabAdvanced')
@@ -504,14 +505,27 @@ import Headroom from 'headroom.js';
pageIds: ['scheduledTasksPage', 'scheduledTaskPage'],
icon: 'schedule'
});
addPluginPagesToMainMenu(links, pluginItems);
if (hasUnsortedPlugins(pluginItems)) {
links.push({
divider: true,
name: globalize.translate('TabPlugins')
});
addPluginPagesToMainMenu(links, pluginItems);
}
return links;
}
function addPluginPagesToMainMenu(links, pluginItems, section) {
for (let i = 0, length = pluginItems.length; i < length; i++) {
const pluginItem = pluginItems[i];
function hasUnsortedPlugins(pluginItems) {
for (const pluginItem of pluginItems) {
if (pluginItem.EnableInMainMenu && pluginItem.MenuSection === undefined) {
return true;
}
}
return false;
}
function addPluginPagesToMainMenu(links, pluginItems, section) {
for (const pluginItem of pluginItems) {
if (pluginItem.EnableInMainMenu && pluginItem.MenuSection === section) {
links.push({
name: pluginItem.DisplayName,

View File

@@ -3,7 +3,7 @@ import listView from '../components/listview/listview';
function getFetchPlaylistItemsFn(itemId) {
return function () {
const query = {
Fields: 'PrimaryImageAspectRatio,UserData',
Fields: 'PrimaryImageAspectRatio',
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
UserId: ApiClient.getCurrentUserId()
};

View File

@@ -1,5 +1,6 @@
let data;
import DefaultConfig from '../../config.json';
let data;
const urlResolver = document.createElement('a');
// `fetch` with `file:` support
@@ -55,30 +56,14 @@ async function getConfig() {
return data;
} catch (error) {
console.warn('failed to fetch the web config file:', error);
return getDefaultConfig();
}
}
async function getDefaultConfig() {
try {
const response = await fetchLocal('config.template.json', {
cache: 'no-cache'
});
if (!response.ok) {
throw new Error('network response was not ok');
}
data = await response.json();
data = DefaultConfig;
return data;
} catch (error) {
console.error('failed to fetch the default web config file:', error);
}
}
export function getIncludeCorsCredentials() {
return getConfig()
.then(config => config.includeCorsCredentials)
.then(config => !!config.includeCorsCredentials)
.catch(error => {
console.log('cannot get web config:', error);
return false;
@@ -87,7 +72,7 @@ export function getIncludeCorsCredentials() {
export function getMultiServer() {
return getConfig().then(config => {
return config.multiserver;
return !!config.multiserver;
}).catch(error => {
console.log('cannot get web config:', error);
return false;
@@ -126,13 +111,16 @@ const checkDefaultTheme = (themes) => {
export function getThemes() {
return getConfig().then(config => {
const themes = Array.isArray(config.themes) ? config.themes : [];
if (!Array.isArray(config.themes)) {
console.error('web config is invalid, missing themes:', config);
}
const themes = Array.isArray(config.themes) ? config.themes : DefaultConfig.themes;
checkDefaultTheme(themes);
return themes;
}).catch(error => {
console.log('cannot get web config:', error);
checkDefaultTheme();
return [];
return DefaultConfig.themes;
});
}
@@ -140,9 +128,12 @@ export const getDefaultTheme = () => internalDefaultTheme;
export function getPlugins() {
return getConfig().then(config => {
return config.plugins;
if (!config.plugins) {
console.error('web config is invalid, missing plugins:', config);
}
return config.plugins || DefaultConfig.plugins;
}).catch(error => {
console.log('cannot get web config:', error);
return [];
return DefaultConfig.plugins;
});
}

View File

@@ -6,7 +6,6 @@ import 'intersection-observer';
import 'classlist.js';
import 'whatwg-fetch';
import 'resize-observer-polyfill';
import 'jellyfin-noto/font-faces.css';
import '../assets/css/site.scss';
import { Events } from 'jellyfin-apiclient';
import ServerConnections from '../components/ServerConnections';
@@ -69,7 +68,7 @@ window.getParameterByName = function(name, url) {
};
function loadCoreDictionary() {
const languages = ['ar', 'be-by', 'bg-bg', 'ca', 'cs', 'da', 'de', 'el', 'en-gb', 'en-us', 'es', 'es-ar', 'es-mx', 'fa', 'fi', 'fr', 'fr-ca', 'gsw', 'he', 'hi-in', 'hr', 'hu', 'id', 'it', 'ja', 'kk', 'ko', 'lt-lt', 'ms', 'nb', 'nl', 'pl', 'pt-br', 'pt-pt', 'ro', 'ru', 'sk', 'sl-si', 'sv', 'tr', 'uk', 'vi', 'zh-cn', 'zh-hk', 'zh-tw'];
const languages = ['af', 'ar', 'be-by', 'bg-bg', 'bn_bd', 'ca', 'cs', 'da', 'de', 'el', 'en-gb', 'en-us', 'eo', 'es', 'es-419', 'es-ar', 'es_do', 'es-mx', 'fa', 'fi', 'fil', 'fr', 'fr-ca', 'gl', 'gsw', 'he', 'hi-in', 'hr', 'hu', 'id', 'it', 'ja', 'kk', 'ko', 'lt-lt', 'mr', 'ms', 'nb', 'nl', 'pl', 'pr', 'pt', 'pt-br', 'pt-pt', 'ro', 'ru', 'sk', 'sl-si', 'sq', 'sv', 'ta', 'th', 'tr', 'uk', 'ur_pk', 'vi', 'zh-cn', 'zh-hk', 'zh-tw'];
const translations = languages.map(function (language) {
return {
lang: language,
@@ -169,8 +168,11 @@ function initSyncPlay() {
// Start SyncPlay.
const apiClient = ServerConnections.currentApiClient();
SyncPlay.Manager.init(apiClient);
if (apiClient) SyncPlay.Manager.init(apiClient);
SyncPlayToasts.init();
// FIXME: Multiple apiClients?
Events.on(ServerConnections, 'apiclientcreated', (e, newApiClient) => SyncPlay.Manager.init(newApiClient));
}
function onAppReady() {
@@ -243,15 +245,11 @@ function onAppReady() {
function registerServiceWorker() {
/* eslint-disable compat/compat */
if (navigator.serviceWorker && window.appMode !== 'cordova' && window.appMode !== 'android') {
try {
navigator.serviceWorker.register('/serviceworker.js').then(() =>
console.log('serviceWorker registered')
).catch(error =>
console.log('error registering serviceWorker: ' + error)
);
} catch (err) {
console.error('error registering serviceWorker: ' + err);
}
navigator.serviceWorker.register('serviceworker.js').then(() =>
console.log('serviceWorker registered')
).catch(error =>
console.log('error registering serviceWorker: ' + error)
);
} else {
console.warn('serviceWorker unsupported');
}

View File

@@ -239,6 +239,7 @@
"LabelCustomCss": "CSS по избор:",
"LabelCustomCssHelp": "Добавете собствен стил към уеб-интерфейса.",
"LabelCustomRating": "Оценка по избор:",
"LabelDashboardTheme": "Облик на сървърното табло:",
"LabelDateAdded": "Дата на добавяне:",
"LabelDateTimeLocale": "Местоположение за дата и час:",
"LabelDay": "Ден:",

Some files were not shown because too many files have changed in this diff Show More