forked from jellyfin-archive/jellyfin.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.xml
1249 lines (1198 loc) · 157 KB
/
index.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Jellyfin: The Free Software Media System</title>
<link>https://jellyfin.org/</link>
<description> Jellyfin: The Free Software Media System</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<atom:link href="https://jellyfin.org/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Jellyfin Android v2.4.0 - More audio codecs, stability improvements and various tweaks</title>
<link>https://jellyfin.org/posts/android-v2.4.0/</link>
<pubDate>Thu, 04 Nov 2021 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/android-v2.4.0/</guid>
<description><p>Compared to the last major release, Jellyfin Android 2.4.0 isn't as feature packed, but it still includes some useful changes and various fixes. Read on to learn more!</p>
<p>The biggest improvement right of the start is support for additional audio codecs in the integrated video player, allowing even more media to direct play on your device. Specifically, that includes Dolby Digital, Digital Plus and TrueHD, as well as DTS and Linear PCM audio, all commonly found on DVDs and Blu-rays, but also a more universal AAC support.</p>
<p>Additionally, The integrated player now follows the rewind/fast forward preferences selected in the Jellyfin settings.</p>
<p>Apart from that, connection reliability was again improved, handling timeouts properly now and showing a progress indicator while the app connects (thus it won't be stuck on black screen anymore).</p>
<h2 id="download-now">Download Now</h2>
<a class="NoLinkLook" href="https://play.google.com/store/apps/details?id=org.jellyfin.mobile">
<img width="153" alt="Jellyfin on Google Play" src="https://jellyfin.org/images/store-icons/google-play.png" />
</a>
<a class="NoLinkLook" href="https://www.amazon.com/gp/product/B081RFTTQ9">
<img width="153" alt="Jellyfin on Amazon App Store" src="https://jellyfin.org/images/store-icons/amazon.png" />
</a>
<a class="NoLinkLook" href="https://f-droid.org/en/packages/org.jellyfin.mobile/">
<img width="153" alt="Jellyfin on F-Droid" src="https://jellyfin.org/images/store-icons/fdroid.png" />
</a>
<p>Direct downloads are always available from <a href="https://repo.jellyfin.org/releases/client/android/">our repository</a>.</p>
<h2 id="full-release-notes">Full Release Notes</h2>
<p>The full (technical) release notes are available on <a href="https://github.com/jellyfin/jellyfin-android/releases/tag/v2.4.0">GitHub</a>.</p>
<h2 id="contributors">Contributors</h2>
<p>As always, lots of great people contributed in this release:</p>
<h3 id="jellyfin-team">Jellyfin Team</h3>
<ul>
<li><a href="https://github.com/nielsvanvelzen">@nielsvanvelzen</a> - <a href="https://github.com/sponsors/nielsvanvelzen">Sponsor</a></li>
<li><a href="https://github.com/Maxr1998">@Maxr1998</a> - <a href="https://github.com/sponsors/Maxr1998">Sponsor</a></li>
</ul>
<h3 id="others">Others</h3>
<ul>
<li><a href="https://github.com/CarlosOlivo">@CarlosOlivo</a></li>
</ul>
<h3 id="contribute">Contribute</h3>
<p>If you have some experience with Android development and are interested in contributing yourself, feel free to dive into the source code <a href="https://github.com/jellyfin/jellyfin-android">on GitHub</a> and open pull requests!</p>
<p>Alternatively, you can help translating the app into your language on our <a href="https://translate.jellyfin.org/projects/jellyfin-android/jellyfin-android/">Weblate</a>.</p></description>
</item>
<item>
<title>Android TV v0.12</title>
<link>https://jellyfin.org/posts/android-tv-12/</link>
<pubDate>Thu, 30 Sep 2021 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/android-tv-12/</guid>
<description><!-- markdownlint-disable MD033 MD036 -->
<p>Today we're bringing the Android TV app to 2021 with a modern design and tons of other changes.</p>
<p>Over 400 <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> pull requests containing 2400+ commits, 750+ changed files with 54000+ changed lines of code by roughly 50 contributors<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. This is the biggest update to the app we ever worked on. I'll talk a bit about why it is this big and why it took so long later in the post. But let's start with the part you probably came for: <strong>new features!</strong></p>
<h2 id="new-authentication-flow">New authentication flow</h2>
<p>We got a lot of complaints about our authentication flow. It wasn't obvious how to enable the auto-login option and managing multiple servers or users was not an easy task. We also didn't like this part of the app, and decided to completely revamp it! The rewritten sign-in screen looks more modern and is much easier to use. There is a new help section that links to our documentation to help new users get started with Jellyfin. The auto-discovery feature of the app now shows all servers instead of the first one, you can select one of those or manually enter your server address to connect. You can then proceed to add a user and start using the app. Users are automatically saved now with auto-login enabled by default.</p>
<div class="juxtapose">
<img data-label="0.11" src="https://jellyfin.org/images/posts/androidtv-0-12-0/11-user-select.png" />
<img data-label="0.12" src="https://jellyfin.org/images/posts/androidtv-0-12-0/12-user-select.png" />
</div>
<h2 id="updated-user-interface-design">Updated user interface design</h2>
<p>After logging in you will be presented with a modern look and feel in our refreshed user interface. A new toolbar is added to the top-right corner of the screen to open the search page, settings or to switch to a different user. No need to scroll down to the bottom of the home screen anymore.
Beneath this new toolbar is your media, like it always was, but the cards got a new look with the debatable colored backgrounds removed.</p>
<div class="juxtapose">
<img data-label="0.11" src="https://jellyfin.org/images/posts/androidtv-0-12-0/11-home.png" />
<img data-label="0.12" src="https://jellyfin.org/images/posts/androidtv-0-12-0/12-home.png" />
</div>
<p>The settings screen got a refresh too. It allows you to more easily change settings. Some new settings got added to customize the app to your own taste.</p>
<div class="juxtapose">
<img data-label="0.11" src="https://jellyfin.org/images/posts/androidtv-0-12-0/11-settings.png" />
<img data-label="0.12" src="https://jellyfin.org/images/posts/androidtv-0-12-0/12-settings.png" />
</div>
<p>The user interface when browsing inside libraries got some slight changes too. We're hoping to completely revamp this part of the app at some point, but that didn't stop us from making it slightly better now.</p>
<div class="juxtapose">
<img data-label="0.11" src="https://jellyfin.org/images/posts/androidtv-0-12-0/11-browse.png" />
<img data-label="0.12" src="https://jellyfin.org/images/posts/androidtv-0-12-0/12-browse.png" />
</div>
<div class="juxtapose">
<img data-label="0.11" src="https://jellyfin.org/images/posts/androidtv-0-12-0/11-details.png" />
<img data-label="0.12" src="https://jellyfin.org/images/posts/androidtv-0-12-0/12-details.png" />
</div>
<h3 id="themes">Themes</h3>
<p>The web client supported theming since forever but the Android TV app did not. That changes today with the introduction of three themes: Muted Purple together with Dark (Default) and Classic Emerald are now available in the app to supports basic theming. We're planning to expand this feature in the future with more themes and more variety between them. <em>Maybe we should add a light theme?</em></p>
<h3 id="new-video-player-design">New video player design</h3>
<p>The video player was completely redesigned to remove a lot of clutter and make it easier to use. The new design is bigger so you can more easily see the information on a television.</p>
<div class="juxtapose">
<img data-label="0.11" src="https://jellyfin.org/images/posts/androidtv-0-12-0/11-player.png" />
<img data-label="0.12" src="https://jellyfin.org/images/posts/androidtv-0-12-0/12-player.png" />
</div>
<p>The new video player design is just the beginning. A project to rewrite the playback code behind it is already in the works. This rewrite should help with the crashes and unnecessary transcoding that happens sometimes. It will also give us the opportunity to add new features like SyncPlay. But this doesn't mean the current code isn't being worked on anymore! We did fix some issues with the current video player code. Notable are changes for Fire TV to direct play more often and a lot of crashes got fixed.</p>
<h2 id="fixed-that-bug">Fixed that bug</h2>
<p>Together with all the visible changes we've made tons of fixes to the code. We're now using <a href="https://kotlinlang.org">Kotlin</a> as our primary language to help us writing type-safe code, migrated completely to <a href="https://developer.android.com/jetpack/androidx/">AndroidX</a> for better device compatibility and made a brand new <a href="https://github.com/jellyfin/jellyfin-sdk-kotlin">SDK</a> that is slowly being integrated for a more secure and stable connetion with your server. All of these modernizations in the code allow us to more frequently release updates.</p>
<p>A complete list of all the fixed bugs can be found in our changelog linked below. It's a big list!</p>
<h2 id="going-forward">Going forward</h2>
<p>It took some time to get this release out. We didn't feel like the state of the app was good enough for a release for a while.
Fortunately we've worked hard to make sure we did feel confident and here we are! Starting from this release we're changing some things
to make sure the next release won't take this long. Our brand new SDK that is already used in our Android app and third party apps is one of the tools helping us with faster releases. By having a more type-safe base we can prevent tons of crashes, allowing us to focus on actual features and bugs.</p>
<p>We're already working on some new stuff like the earlier mentioned rewrite of the playback code. We're using feature flags for this so we can work on this code while still being able to publish new versions. Other changes that we're looking into are more improvements to the user interface, better Live TV, better music support and more bugfixes!</p>
<h2 id="contributors">Contributors</h2>
<p>Like all releases, we couldn't do it without our contributors and your donations! Jellyfin is made entirely by volunteers that don't get paid for their work. A big shout-out to the following contributors that made this release possible:</p>
<p><strong>Jellyfin Team</strong></p>
<ul>
<li><a href="https://github.com/nielsvanvelzen">@nielsvanvelzen</a> - Donate via <a href="https://github.com/sponsors/nielsvanvelzen">GitHub sponsors</a></li>
<li><a href="https://github.com/thornbill">@thornbill</a> - Donate via <a href="https://github.com/sponsors/thornbill">GitHub sponsors</a></li>
<li><a href="https://github.com/MrChip53">@MrChip53</a></li>
<li><a href="https://github.com/AndreasGB">@AndreasGB</a></li>
</ul>
<p><strong>Other contributors</strong></p>
<ul>
<li><a href="https://github.com/linetrimmer">@linetrimmer</a></li>
<li><a href="https://github.com/Froghut">@Froghut</a></li>
<li><a href="https://github.com/koying">@koying</a></li>
<li><a href="https://github.com/Florianisme">@Florianisme</a></li>
<li><a href="https://github.com/jassycliq">@jassycliq</a></li>
<li><a href="https://github.com/tukilo">@tukilo</a></li>
<li><a href="https://github.com/vnidens">@vnidens</a></li>
<li><a href="https://github.com/Vardex">@Vardex</a></li>
<li><a href="https://github.com/MrLemur">@MrLemur</a></li>
<li><a href="https://github.com/willtrking">@willtrking</a></li>
<li><a href="https://github.com/sachk">@sachk</a></li>
<li><a href="https://github.com/PalAditya">@PalAditya</a></li>
<li><a href="https://github.com/okan35">@okan35</a></li>
<li><a href="https://github.com/jemlule">@jemlule</a></li>
<li><a href="https://github.com/jsquyres">@jsquyres</a></li>
<li><a href="https://github.com/ferferga">@ferferga</a></li>
<li><a href="https://github.com/Aerion">@Aerion</a></li>
<li><a href="https://github.com/dhiaayachi">@dhiaayachi</a></li>
<li><a href="https://github.com/jakeapp">@jakeapp</a></li>
<li><a href="https://github.com/GodTamIt">@GodTamIt</a></li>
<li><a href="https://github.com/JannikHoelling">@JannikHoelling</a></li>
</ul>
<h2 id="changelog">Changelog</h2>
<p>Full changelog with all pull requests available on <a href="https://github.com/jellyfin/jellyfin-androidtv/releases/tag/v0.12.0">GitHub</a>.</p>
<h2 id="download-now">Download Now</h2>
<a class="NoLinkLook" href="https://play.google.com/store/apps/details?id=org.jellyfin.androidtv">
<img width="153" alt='Jellyfin for Android TV on Google Play' src="https://jellyfin.org/images/store-icons/google-play.png" />
</a>
<a class="NoLinkLook" href="https://www.amazon.com/gp/product/B07TX7Z725">
<img width="153" alt="Jellyfin for Fire TV at Amazon App Store" src="https://jellyfin.org/images/store-icons/amazon.png" />
</a>
<p>Direct downloads are always available from <a href="https://repo.jellyfin.org/releases/client/androidtv/">our repository</a>.
You can also join our <a href="https://play.google.com/apps/testing/org.jellyfin.androidtv">beta program on Google Play</a> to test new versions.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p><a href="https://github.com/jellyfin/jellyfin-androidtv/projects/2?card_filter_query=is%3Apr+is%3Amerged">v0.12.0 project filtered by merged pull requests</a><a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#8617;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p><a href="https://github.com/jellyfin/jellyfin-androidtv/compare/v0.11.5...v0.12.0-beta.7">Git comparison between v0.11.5 and v0.12.0-beta.7</a><a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#8617;</a></p>
</li>
</ol>
</section></description>
</item>
<item>
<title>Jellyfin Android v2.3.0 - Improved Integrated Player</title>
<link>https://jellyfin.org/posts/android-v2.3.0/</link>
<pubDate>Sun, 01 Aug 2021 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/android-v2.3.0/</guid>
<description><p>After a prolonged beta testing period, we're excited to announce that version 2.3.0 of the Jellyfin Android app is now available!</p>
<p>A lot things have changed since the last stable release, mainly to improve stability and compatibility with the Jellyfin Server.</p>
<p>Communication between the Android app and the server was updated to use <a href="https://github.com/jellyfin/jellyfin-sdk-kotlin">a new library</a> that supports more modern technologies which improves the development process and allows us to support additional features in the future, eventually resulting in a fully native app that's specifically optimized for phones.</p>
<p>Due to the library changes, the new version of the app <strong>only supports servers of version 10.7.0 or later</strong>, so make sure your server is up-to-date before you install the update!</p>
<h3 id="integrated-video-player-improvements">Integrated Video Player Improvements</h3>
<p>The integrated/native video player was especially reworked and supports playlists now (so that you can binge-watch your shows more easily), allows setting the playback speed and introduced an option in the client settings to remember the screen brightness applied through gestures.</p>
<p><img alt="Playback speed controls" src="https://jellyfin.org/images/posts/android-v2.3.0/exoplayer-speed-controls.png" /></p>
<p>The Picture-in-Picture (PiP) mode now respects the aspect ratio of your media and will have smooth animations when entering it.
Soon, you'll also be able to select a bitrate limit to force transcoded streaming and reduce data usage, so please look forward to the next updates!</p>
<h2 id="polishing-and-bug-fixes">Polishing and Bug Fixes</h2>
<p>You can now set the location to download content to in the client settings.
There were also a lot of bug fixes which will improve the experience with the app, not only in the native player but also for Android Auto support and when casting media to Chromecast.</p>
<h2 id="download-now">Download Now</h2>
<a class="NoLinkLook" href="https://play.google.com/store/apps/details?id=org.jellyfin.mobile">
<img width="153" alt="Jellyfin on Google Play" src="https://jellyfin.org/images/store-icons/google-play.png" />
</a>
<a class="NoLinkLook" href="https://www.amazon.com/gp/product/B081RFTTQ9">
<img width="153" alt="Jellyfin on Amazon App Store" src="https://jellyfin.org/images/store-icons/amazon.png" />
</a>
<a class="NoLinkLook" href="https://f-droid.org/en/packages/org.jellyfin.mobile/">
<img width="153" alt="Jellyfin on F-Droid" src="https://jellyfin.org/images/store-icons/fdroid.png" />
</a>
<p>Direct downloads are always available from <a href="https://repo.jellyfin.org/releases/client/android/">our repository</a>.</p>
<h2 id="full-release-notes">Full Release Notes</h2>
<p>The full (technical) release notes are available on <a href="https://github.com/jellyfin/jellyfin-android/releases/tag/v2.3.0">GitHub</a>.</p>
<h2 id="contributors">Contributors</h2>
<p>As always, lots of great people contributed in this release:</p>
<h3 id="jellyfin-team">Jellyfin Team</h3>
<ul>
<li><a href="https://github.com/nielsvanvelzen">@nielsvanvelzen</a> - <a href="https://github.com/sponsors/nielsvanvelzen">Sponsor</a></li>
<li><a href="https://github.com/Maxr1998">@Maxr1998</a> - <a href="https://github.com/sponsors/Maxr1998">Sponsor</a></li>
<li><a href="https://github.com/h1dden-da3m0n">@h1dden-da3m0n</a> - <em>Special shout-out for helping with the migration to GitHub Actions!</em></li>
<li><a href="https://github.com/ferferga">@ferferga</a> - <a href="https://github.com/sponsors/ferferga">Sponsor</a></li>
</ul>
<h3 id="others">Others</h3>
<ul>
<li><a href="https://github.com/CarlosOlivo">@CarlosOlivo</a></li>
<li><a href="https://github.com/fedesenmartin">@fedesenmartin</a></li>
<li><a href="https://github.com/ThreeFive-O">@ThreeFive-O</a></li>
<li><a href="https://github.com/Codex-">@Codex-</a></li>
<li><a href="https://github.com/diederikdehaas">@diederikdehaas</a></li>
</ul>
<h3 id="contribute">Contribute</h3>
<p>If you have some experience with Android development and are interested in contributing yourself, feel free to dive into the source code <a href="https://github.com/jellyfin/jellyfin-android">on GitHub</a> and open pull requests!</p>
<p>Alternatively, you can help translating the app into your language on our <a href="https://translate.jellyfin.org/projects/jellyfin-android/jellyfin-android/">Weblate</a>.</p></description>
</item>
<item>
<title>Regarding the Android betas</title>
<link>https://jellyfin.org/posts/android-betas/</link>
<pubDate>Sat, 24 Jul 2021 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/android-betas/</guid>
<description><!-- markdownlint-disable MD033 -->
<p>With the release of the first Android TV 0.12 release beta, this is a good time to explain how our Android beta programs work and how to start using them. The mobile app has used a public beta channel for around a year now and with the Android TV app coming close to a new release we're adding a similar program for that as well.</p>
<h2 id="what-is-the-difference-between-release-and-beta">What is the difference between release and beta?</h2>
<p>A beta version is an early build of an upcoming release. This means that most of the new features are available but there might still be some issues. In the case of the Jellyfin Android apps, we might release a beta version because we expect issues or want to test something with a larger audience. Generally the beta cycle should only last a short period.</p>
<h2 id="should-i-use-a-beta-version">Should I use a beta version?</h2>
<p>Beta versions may contain issues. Those issues could vary from a small annoyance to a major issue that prevents you from signing in to your server. Do not use a beta version if you are unable to provide bug reports with app-logs and reproducible steps.</p>
<h2 id="how-do-i-report-problems">How do I report problems?</h2>
<p>If you encounter a problem, we would appreciate a detailed issue with app-logs and reproducible steps so we can fix the problem before release. To do this, you will need an account on GitHub and open an issue on the repository for the app.</p>
<ul>
<li><a href="https://github.com/jellyfin/jellyfin-androidtv/issues/new/choose">GitHub issues Android TV</a></li>
<li><a href="https://github.com/jellyfin/jellyfin-android/issues/new/choose">GitHub issues Android (mobile)</a></li>
</ul>
<h2 id="where-do-i-get-the-beta">Where do I get the beta?</h2>
<p>The beta releases are only available on the Google Play store or in our own repository. Users of F-Droid or the Amazon Appstore can sideload the apk files available in our repository or wait for the release.</p>
<h3 id="what-about-the-amazon-appstore">What about the Amazon Appstore?</h3>
<p>The Amazon Appstore has no options for beta apps. Therefore, we unfortunately cannot provide beta versions of the app to users who do not have a Play Store on their device.</p>
<h3 id="android-tv">Android TV</h3>
<a class="NoLinkLook" href="https://play.google.com/apps/testing/org.jellyfin.androidtv">
<img width="153" alt="Jellyfin for Android TV on Google Play" src="https://jellyfin.org/images/store-icons/google-play.png" />
</a>
<p>Direct downloads available in <a href="https://repo.jellyfin.org/releases/client/androidtv/">our repository</a>.</p>
<h3 id="android-mobile">Android (mobile)</h3>
<a class="NoLinkLook" href="https://play.google.com/apps/testing/org.jellyfin.mobile">
<img width="153" alt="Jellyfin on Google Play" src="https://jellyfin.org/images/store-icons/google-play.png" />
</a>
<p>Direct downloads available in <a href="https://repo.jellyfin.org/releases/client/android/">our repository</a>.</p></description>
</item>
<item>
<title>Introducing Jellyfin Media Player</title>
<link>https://jellyfin.org/posts/client-jmp/</link>
<pubDate>Sun, 18 Apr 2021 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/client-jmp/</guid>
<description><p>Jellyfin Media Player is a new Jellyfin client option intended to offer a more user-friendly experience. It takes the user interface from jellyfin-web, including the playback interface, and combines it with the extensive codec support from MPV.</p>
<p><img src="https://jellyfin.org/images/jmp/player.png" name="Player" /></p>
<p>You can <a href="https://github.com/jellyfin/jellyfin-media-player/releases">download the client on GitHub</a>. It is also available on <a href="https://flathub.org/apps/details/com.github.iwalton3.jellyfin-media-player">FlatHub</a> and the <a href="https://aur.archlinux.org/packages/jellyfin-media-player/">AUR</a>.</p>
<h2 id="extensive-feature-set">Extensive Feature Set</h2>
<p><img src="https://jellyfin.org/images/jmp/config.png" name="Configuration Dialog" /></p>
<p>Building on the open source foundation of Plex Media Player, this client has support for selecting audio devices and configuring audio passthrough. It also supports changing the refresh rate of your display to match the video content. You can control the client with some remote controls, game controllers, and media keys through jellyfin-web’s TV display mode, in addition to remote control through the Jellyfin mobile apps. While testing the client it was known to be controllable with a PS3 controller in TV mode.</p>
<p>Since the media player is built on MPV, the mpv.conf file may be used to install scripts and shaders, as well as for tweaking the playback characteristics to the user’s liking. The software is also known to work with SVP with some tweaking of configuration files.</p>
<h2 id="music-support">Music Support</h2>
<p><img src="https://jellyfin.org/images/jmp/music.png" name="Music Playback" /></p>
<p>Jellyfin Media Player can also natively play music in addition to videos. Being built on jellyfin-web and implementing player support as plugins, all features of the web client are available as usual, including server management. The client can connect to and switch between multiple separate servers.</p>
<h2 id="extensive-crossplatform-support">Extensive Cross-Platform Support</h2>
<p>Through the help from several community contributions, Jellyfin Media Player now builds for Windows, macOS, and Linux. All release builds are automated through GitHub Actions. Linux users will be happy to know that Debian, Ubuntu, Flatpak, and AUR packages are available. Contributors are already improving the software’s foundation and have gotten it working on Wayland as well.</p></description>
</item>
<item>
<title>A Note About Privacy and Expo for iOS</title>
<link>https://jellyfin.org/posts/a-note-about-privacy-and-expo/</link>
<pubDate>Sat, 17 Apr 2021 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/a-note-about-privacy-and-expo/</guid>
<description><p>When it comes to Jellyfin, we guarantee that there is no involuntary tracking, from the server to the mobile apps. This still remains true, even with today's update to the Apple App Store.</p>
<p>In developing the Jellyfin Mobile app for iOS, we use a Javascript framework known as <a href="https://expo.io">Expo</a>. This framework is an integrated way of using <a href="https://reactnative.dev">React Native</a> to create mobile apps. For a variety of technical reasons, this has been the best way for us to deliver an iOS app, even with its current restrictions.</p>
<p>Starting with an update in December 2020, Apple has required all developers to submit Privacy Information with any new app, or any update to an app. There is an article covering these &ldquo;privacy badges&rdquo; available on Apple's website: &ldquo;<a href="https://support.apple.com/en-ca/HT211970">HT211970 - About privacy information on the App Store&hellip;</a>&quot;. As of our last Jellyfin Mobile update, we believed we were in the clear here - the Jellyfin app does not contain any code to track you or report any data. We declared this in our update information, and received the &ldquo;Data Not Collected&rdquo; badge.</p>
<p>However, we learned that Expo has an issue that prevents this from being true. In February, we were contacted by Apple, and received a notice that our badge was incorrect, and needs to be updated. We inquired into this further with Expo, in their forums: &ldquo;<a href="https://forums.expo.io/t/mail-from-app-store-connect-about-facebook-app-events/48927">Mail from App Store Connect about Facebook App Events</a>&quot;. When we use Expo to build the app (their &ldquo;managed&rdquo; workflow), their compiler automatically includes base code for a variety of different items, which includes code that can be used to provide analytics and tracking information. Even though we don't use any of these functions, this code is included in the final app binary, so we are now forced to declare that app can access the Device Identifier.</p>
<h2 id="i-want-to-stress-again-we-do-not-track-any-user-activity-or-collect-any-data">I want to stress again: <strong>We do not track any user activity or collect any data.</strong></h2>
<p>You can verify this by reviewing the code base here on GitHub: &ldquo;<a href="https://github.com/jellyfin/jellyfin-expo">jellyfin/jellyfin-expo</a>&quot;. Expo's current build process includes code that <em>could</em> be used for tracking, but it is never activated by our code, and we do not use it at all. Because this code is ultimately in the app, we have to update the badge on the App Store listing. As Expo explains on their <a href="https://docs.expo.io/distribution/app-stores/#ios-specific-guidelines">publishing details page</a>:</p>
<blockquote>
<p>Note: No data is sent to Branch, Facebook, Segment, or Amplitude from your app unless you explicitly do so using the APIs.</p>
</blockquote>
<p>In the <a href="https://forums.expo.io/t/mail-from-app-store-connect-about-facebook-app-events/48927">forum thread</a>, Expo has committed to a future update allowing their automated build service to only include the code modules that you actively use, which would allow us to return to the &ldquo;Data Not Collected&rdquo; badge. In an effort to help improve the app and add more features, we are looking to &ldquo;eject&rdquo; from Expo in the future, which means we can completely control the build process by ourselves.</p>
<hr>
<p>Thank you for using Jellyfin and supporting us this far. Our iOS app is largely developed only by one contributor, <a href="https://github.com/thornbill">@thornbill</a>, who gives generously of his spare time to develop the app and make it better all the time. He, along with a few of our <a href="https://github.com/orgs/jellyfin/people">contributors</a> have donation pages setup either through GitHub Sponsors, or other sites like LiberaPay, Patreon and more. If you'd like to support any of them, please see their profiles for more information. If you'd like to support Jellyfin as a whole (infrastructure and equipment costs only), you can visit our public ledger on <a href="https://opencollective.com/jellyfin">OpenCollective</a>. We're pretty well covered for now, so consider donating to contributors first.</p>
<p>Stay tuned for future posts talking about app updates, how we are committed to protecting privacy with Jellyfin, and on our contributor community, including how you can support them and development.</p>
<p>Best,
Anthony</p></description>
</item>
<item>
<title>The Jellyfin CDN: Mirrorbits for the masses</title>
<link>https://jellyfin.org/posts/mirrorbits-cdn/</link>
<pubDate>Mon, 12 Apr 2021 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/mirrorbits-cdn/</guid>
<description><p>For many projects, distributing binary assets is easy: put the files on GitHub and you're done. It's not something many think about. But at Jellyfin, we needed something more robust, something able to handle our needs more elegantly than GitHub or a basic web server could. And both for those interested, and for those supporting other similar projects, I'd like to share how we do it.</p>
<h2 id="prelude--pre1060">Prelude - Pre-10.6.0</h2>
<p>Before our 10.6.0 release, we had a fairly simple repository setup: everything would build on a VPS, running Debian, called <code>build1</code>, in response to a GitHub web-hook. This server, located on Digital Ocean in the Toronto zone, housed both the build process as well as our main repository, served directly via NGiNX.</p>
<p>But this release was the first where we noticed a problem. Jellyfin is a global project, and while I'm personally located in Ontario, Canada, the very vast majority of our users are not. And users, especially users in Europe and Asia, were having trouble downloading our releases. The main complaint was abysmally slow download speeds, and occasionally even full-on timeouts. We had to come up with a better solution.</p>
<p>As a DIYer at heart, and leading a project built by and for DIYers, I wasn't content to simply throw CloudFlare in front of the repo - my concerns with that provider notwithstanding. I wanted something we could control, and I went looking for a solution - how to effectively create a CDN for file downloads.</p>
<h2 id="enter-mirrorbits">Enter Mirrorbits</h2>
<p>Luckily, I wasn't alone. Many years before, another FLOSS project had encountered the same problem. VideoLAN, creators of the fantastic VLC Media Player, had the same issue of distributing files. So one of their talented developers created a solution: Mirrorbits.</p>
<p><a href="https://github.com/etix/mirrorbits">Mirrorbits</a> is a Go program with a single goal: provide a way to distribute requests from a single central repository to multiple geo-diverse repositories, based on the client's GeoIP information, handling availability and freshness seamlessly. It seemed to fit the bill exactly.</p>
<p>But there was a problem: documentation on how to actually run Mirrorbits was sparse, so it took quite a bit of trial-and-error to determine how to use it. I hope the following will help avoid this trouble for anyone else.</p>
<h2 id="file-layout">File Layout</h2>
<p>The first thing to consider is the layout of the files. In Jellyfin's case, our repository is large and sprawling, constituting many different components including the server, clients, plugins, and various secondary files. Mirrorbits requires everything to be housed under one directory, and we needed a way to synchronize this whole directory easily. We also had a problem of our &ldquo;archives&rdquo;, old stable releases that we did not need or want synchronized to all of our mirror servers wasting space.</p>
<p>The solution I came up with was the following directory structure:</p>
<pre><code>/srv/repository
/mirror
/releases
/client
/server
/plugin
etc.
/debian
/dists
/pool
/ubuntu
/dists
/pool
/archive
etc.
/releases --symlink--&gt; /mirror/releases
/debian --symlink--&gt; /mirror/debian
etc.
</code></pre><p>In effect, everything is under a <code>/mirror</code> directory, with external symlinks to provide the root links we wanted.</p>
<h2 id="additional-vpses-and-synchronization">Additional VPSes and Synchronization</h2>
<p>The next step after crafting a usable file layout was to create some additional VPSes and determine how to synchronize the files.</p>
<p>Since our origin server is in Toronto, I wanted to ensure we had wide geographic coverage. as well as a dedicated CDN for the same region as the origin server, just in case it got overloaded. Thus, I created 4 additional VPSes:</p>
<ul>
<li><code>tor1.mirror.jellyfin.org</code>: Toronto, Ontario, Canada for North/South America East</li>
<li><code>sfo1.mirror.jellyfin.org</code>: San Francisco, California, USA for North/South America West</li>
<li><code>fra1.mirror.jellyfin.org</code>: Frankfurt, Germany (not France as commonly assumed!) for Europe and Africa</li>
<li><code>sgp1.mirror.jellyfin.org</code>: Singapore for Asia and Pacific</li>
</ul>
<p>One worry when first setting up these 4 VPSes was that they would not be enough, but so far, through another major release and several minor releases, we've had the complaints about download speed completely stop, so they must be working. In future, as Digital Ocean expands, we'd also be able to add other locations as well, for instance Bangalore, India, Africa, and perhaps additional Europe and South America instances.</p>
<p>With the VPSes created, I then looked into file synchronization, and there was only one program on my mind: <code>rsync</code>. But while most users know <code>rsync</code> for it's <code>scp</code>-replacement functionality over SSH, I wanted something more robust without the need for handling SSH keys, and able to be extended further in the future, perhaps to untrusted (and untrusting) 3rd-party mirrors.</p>
<p>I thus opted to use the <code>rsync</code> daemon mode. Listening on port 873, it's able to do everything <code>rsync</code>-over-SSH can do, only without encryption overhead or requiring SSH/shell authentication.</p>
<p>I first prepared the the local <code>/etc/rsyncd.conf</code> on the origin server (<code>build1</code>). By default, the Debian <code>rsync</code> package does not install the daemon service unless this file exists, but after adding it the daemon can be started.</p>
<p>To handle the aforementioned &ldquo;archives&rdquo;, I split the repository into two &ldquo;components&rdquo;: one with the archives, and one without. This would allow a given mirror to pull either the entire archive, or just the current stable repositories. And once we started offering the &ldquo;unstable&rdquo; builds that can be generated many dozens of times per day, I opted to include them in the &ldquo;archive&rdquo; component as well.</p>
<p>Here is our configuration:</p>
<pre><code># /etc/rsyncd.conf
[mirror]
path = /srv/repository/mirror
comment = Jellyfin mirror (stable only)
exclude = *unstable* *archive*
[mirror-full]
path = /srv/repository/mirror
comment = Jellyfin mirror (all)
</code></pre><p>In many cases, it would be prudent to secure this, but since we wanted to open this up to anyone, I left the <code>rsync</code> endpoint completely exposed. Thus, if you want to host a local Jellyfin mirror - you can. Simply clone this rsync target and you'll have a full copy of the Jellyfin mirror!</p>
<p>On the mirror servers, we still needed to get the content however. Ultimately, I decided that every &ldquo;official&rdquo; mirror copying the <em>full</em> content (including archives and unstable builds) was more prudent, so all of them synchronize the <code>mirror-full</code> source.</p>
<p>Each node thus has a simple cron job, set to run every 15 minutes, that downloads an updated copy of the repository from the origin:</p>
<pre><code># /etc/cron.d/mirror-sync
12,27,42,57 * * * * root rsync -au --delete rsync://build1.jellyfin.org/mirror-full/ /srv/repository/mirror/
</code></pre><p>The slightly odd times were chosen specifically - the goal for 3rd parties, if and when we officially support them, would be to synchronize every X minutes on even intervals, e.g. at <code>00</code>, <code>30</code>, etc., from these &ldquo;official&rdquo; mirrors, instead of from build1 directly. This therefore ensures they would always be up-to-date before that time comes around, ensuring no additional delays for 3rd party mirrors. We don't officially support this <em>yet</em>, but if our traffic continues to grow, we will probably expand to 3rd parties as well as additional Digital Ocean locations.</p>
<p>The <code>rsync</code> command should create the destination directory automatically, but to be prudent, I ensured it was created manually first. Thus, we now have 5 servers with exactly the same content, with the mirrors synchronizing from the origin every 15 minutes.</p>
<h2 id="web-server-configuration">Web server Configuration</h2>
<p>From the very beginning we have used NGiNX as the web server. The reasons are simple: maximum configuration flexibility, and performance. Apache has its place, but we didn't need its additional features, and early on budget was tight. I've been so satisfied with it, I haven't even considered a change.</p>
<p>On the mirrors, the configuration is dead-simple. Only a single &ldquo;site&rdquo; is configured, providing full access to the repository directory. SSL is provided by Let's Encrypt.</p>
<pre><code># /etc/nginx/sites-enabled/jellyfin-mirror (from fra1.mirror.jellyfin.org)
server {
listen [::]:80 default_server ipv6only=on;
listen 80 default_server;
listen [::]:443 ssl ipv6only=on;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/fra1.mirror.jellyfin.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/fra1.mirror.jellyfin.org/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
server_name fra1.mirror.jellyfin.org _;
root /srv/repository;
index index.php index.html index.htm;
access_log /var/log/nginx/access.log;
aio threads;
directio 1M;
output_buffers 3 1M;
sendfile on;
sendfile_max_chunk 0;
autoindex on;
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param HTTP_PROXY &quot;&quot;;
fastcgi_pass unix:/run/php/php7.3-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
</code></pre><p>During testing, we did notice one thing that might be of use to other admins. We were finding that performance, when many requests for large files came in at once, would drop significantly. I ended up tracing the problem to the I/O stack within NGiNX, which appeared to be a bottleneck. I was able to find some documentation about this problem, and thus have set the <code>aio threads</code>, <code>directio</code>, <code>output_buffers</code>, and <code>sendfile</code> options above. These ensure NGiNX will use direct I/O for any file larger than 1M, and provide 3 output buffers with a maximum chunk size of 0, increasing performance under load.</p>
<p>On the origin, the NGiNX configuration is much more complicated. Because Mirrorbits will only distribute the actual large files themselves, I need to handle any pre-file redirection first on the origin. Thus clients are directed to the right file location, and the Mirrorbits directs <em>that</em> request to the mirrors.</p>
<pre><code># /etc/nginx/sites-enabled/jellyfin-origin (on build1.jellyfin.org)
server {
listen 80 default_server proxy_protocol;
listen [::]:80 default_server proxy_protocol;
server_name repo.jellyfin.org build.jellyfin.org repo1.jellyfin.org build1.jellyfin.org _;
access_log /var/log/nginx/access.log proxy;
aio threads;
directio 1M;
output_buffers 3 1M;
sendfile on;
sendfile_max_chunk 0;
autoindex on;
root /srv/repository/mirror;
index index.php index.html index.htm index.nginx-debian.html;
location / {
autoindex off;
}
#
# Kodi Repository redirection
#
location ^~ /releases/client/kodi/py2 {
index index.html index.php;
autoindex on;
}
location ^~ /releases/client/kodi/py3 {
index index.html index.php;
autoindex on;
}
location ^~ /releases/client/kodi {
# Kodi 20
if ($http_user_agent ~* &quot;(Kodi.*/20.*)&quot;) {
rewrite ^/releases/client/kodi/(.*)$ /releases/client/kodi/py3/$1 last;
}
# Kodi 19
if ($http_user_agent ~* &quot;(Kodi.*/19.*)&quot;) {
rewrite ^/releases/client/kodi/(.*)$ /releases/client/kodi/py3/$1 last;
}
# Kodi 18 and older
if ($http_user_agent ~* &quot;(Kodi.*)&quot;) {
rewrite ^/releases/client/kodi/(.*)$ /releases/client/kodi/py2/$1 last;
}
index index.html index.php;
autoindex on;
}
#
# Main repository
#
# Main release directories
location /releases {
autoindex on;
}
# Main archive directories (not forwarded to Mirrorbits)
location ^~ /archive {
try_files $uri $uri/ =404;
autoindex on;
}
# Mirrorbits fallback
location ^~ /master {
try_files $uri $uri/ =404;
autoindex on;
}
# Mirrorbits forwards for large file types
location ~ ^/(?&lt;fwd_path&gt;.*)(?&lt;fwd_file&gt;\.apk|\.buildinfo|\.bz|\.changes|\.db|\.deb|\.dmg|\.dsc|\.exe|\.gz|\.md5|\.lzma|\.rpm|\.sha256sum|\.xml|\.xz|\.zip|\.css|\.ttf|\.woff2|\.json)$ {
proxy_pass http://127.0.0.1:8080;
proxy_buffering off;
}
location ~ ^/(?&lt;fwd_path&gt;.*)(/mirrorlist)$ {
proxy_pass http://127.0.0.1:8080/$fwd_path?mirrorlist;
proxy_buffering off;
}
location ~ ^/(?&lt;fwd_path&gt;.*)(/mirrorstats)$ {
proxy_pass http://127.0.0.1:8080/$fwd_path?mirrorstats;
proxy_buffering off;
}
location /mirrorstats {
proxy_pass http://127.0.0.1:8080/?mirrorstats;
proxy_buffering off;
}
#
# PHP handling
#
location ~ \.php$ {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param HTTP_PROXY &quot;&quot;;
fastcgi_pass unix:/run/php/php7.3-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
</code></pre><p>Some of the configuration here is worthy of describing in detail.</p>
<p>The Kodi selector is used due to the Kodi backend transition from Python 2 to Python 3. Thus, some versions require assets for Python 2, and newer versions for Python 3. This selector operates based on the sent user agent of the client, deciding which version of Kodi they are using, and thus directing them to the right location.</p>
<p>The main locations are <code>/archive</code>, <code>/releases</code>, and <code>/master</code>. The first contains archives and is not forwarded on to the Mirrorbits process (despite the files being synced above) due to the <code>try_files</code> directive. The second is the main repository directory, and the third is a duplicate location that is used for fallback and also does not redirect to Mirrorbits.</p>
<p>Next is the main Mirrorbits handler. The forwarding is based off the file extension of the requested file. Thus, when loading, e.g. the PHP index pages, the requests are not forwarded; only requests for the listed file types are forwarded on to the Mirrorbits process to be distributed to mirrors.</p>
<p>The next 3 options are for Mirrorbits status pages, which provide information on the currently available mirrors. For any file (e.g. <a href="https://repo.jellyfin.org/releases/server/debian/stable/meta/jellyfin_10.7.2-1_all.deb">https://repo.jellyfin.org/releases/server/debian/stable/meta/jellyfin_10.7.2-1_all.deb</a>), one can append the <code>/mirrorlist</code> or <code>/mirrorinfo</code> locations to show information about the available mirrors. Try it yourself: <a href="https://repo.jellyfin.org/releases/server/debian/stable/meta/jellyfin_10.7.2-1_all.deb/mirrorlist">https://repo.jellyfin.org/releases/server/debian/stable/meta/jellyfin_10.7.2-1_all.deb/mirrorlist</a>. Finally the <code>/mirrorstats</code> page, whether on a file or at the root of the domain (<a href="https://repo.jellyfin.org/mirrorstats">https://repo.jellyfin.org/mirrorstats</a>) shows the current status of the mirrors in general, including if any are offline.</p>
<p>All together, these NGiNX configs provide the foundation for Mirrorbits to work, and this was the part that actually took the longest. Thanks to <a href="https://github.com/PalinuroSec">@PalinuroSec</a> on GitHub for his <a href="https://gist.github.com/PalinuroSec/f0bfb815240573ab1b0b58f3c76620d4">fantastic example gist</a>.</p>
<h2 id="mirrorbits-the-workhorse">Mirrorbits: The Workhorse</h2>
<p>Installing Mirrorbits is quite straightforward: I simply downloaded the latest binary release (<code>0.5.1</code>) from the Mirrorbits repository, installed the <code>mirrorbits</code> binary to <code>/usr/local/bin</code>, the sample configuration to <code>/etc/mirrorbits.conf</code>, and the templates to <code>/usr/local/share/mirrorbits</code>. Unfortunately, Mirrorbits development seems to have stalled since 2018, including documentation. <a href="https://github.com/etix/mirrorbits/issues/105">I opened an issue</a> during my troubleshooting that is still unanswered, which is unfortunate, and I hope this blog post will be able to resolve that issue.</p>
<p>The basic configuration of Mirrorbits is quite simple. Most of the configuration options are explained well in the sample configuration file, and it was simply a matter of tuning them to our needs. Here is our configuration stripped of comments/explanations:</p>
<pre><code># /etc/mirrorbits.conf (on build1.jellyfin.org)
Repository: /srv/repository/mirror
Templates: /usr/local/share/mirrorbits/
LogDir: /var/log/mirrorbits
GeoipDatabasePath: /usr/local/share/GeoIP/
OutputMode: redirect
Gzip: false
ListenAddress: localhost:8080
RPCListenAddress: localhost:3390
RedisAddress: 127.0.0.1:6379
RedisDB: 0
TraceFileLocation: /mirrorsync
RepositoryScanInterval: 5
Hashes:
SHA256: On
ConcurrentSync: 5
ScanInterval: 30
CheckInterval: 1
Fallbacks:
- URL: https://repo.jellyfin.org/master/
CountryCode: ca
ContinentCode: na
</code></pre><p>A few options are worth mentioning as they differ from the obvious defaults.</p>
<p><code>Repository</code> points towards the local repository path, the exact file(s) that are synchronized with <code>rsync</code> above.</p>
<p><code>GeoipDatabasePath</code> is a path to a local copy of the GeoIP database; this will be discussed later.</p>
<p><code>OutputMode</code> is set to <code>redirect</code> to give clients an HTTP 302 redirect to the file path. There are several options here, but the 302 seemed like the most robust, being well-supported by most HTTP-speaking programs and preventing caching of the response.</p>
<p><code>TraceFileLocation</code> points to a file which is used to judge the &ldquo;freshness&rdquo; of the mirrors. It should be a file which guarantees that the remote copies of the repository are in sync with the local instance, and must be under the <code>Repository</code> location.</p>
<p><code>Hashes</code> provides several options, but we use SHA256 hashing for simplicity and to match our own provided hashes.</p>
<p><code>RedisAddress</code> points to a local Redis instance that Mirrorbits uses to handle state.</p>
<p><code>ConcurrentSync</code>, <code>RepositoryScanInterval</code>, <code>ScanInterval</code>, and <code>CheckInterval</code> are times in minutes that Mirrorbits <em>should</em> be checking and synchronizing itself, but I've found these to be unreliable; I used a cron task to do these tasks manually instead.</p>
<p>Finally, <code>Fallbacks</code> provides a list of fallback mirrors. As mentioned above, the <code>/master</code> path provides the exact same content as <code>/releases</code>, only without being forwarded back to Mirrorbits and creating a loop. Without this fallback, if all mirrors are unavailable for any given file, either due to its newness or due to mirror failures, clients would not be able to download files at all. The fallback ensures there is still at least one source - the origin - that is not normally used, but can be just in case.</p>
<p>The next step was creating a SystemD service for Mirrorbits. The process requires some special options for reloads and stopping, so these are included here. Note also that I run Mirrorbits as <code>www-data</code>, the same user as NGiNX itself:</p>
<pre><code># /etc/systemd/system/mirorrbits.service
[Unit]
Description=Mirrorbits redirector
Documentation=https://github.com/etix/mirrorbits
After=network.target
[Service]
Type=notify
DynamicUser=yes
LogsDirectory=mirrorbits
RuntimeDirectory=mirrorbits
User=www-data
PIDFile=/run/mirrorbits/mirrorbits.pid
ExecStart=/usr/local/bin/mirrorbits daemon -p /run/mirrorbits/mirrorbits.pid -debug
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=-/bin/kill -QUIT $MAINPID
TimeoutStopSec=5
KillMode=mixed
Restart=on-failure
[Install]
WantedBy=multi-user.target
</code></pre><p>Finally, I added some cron jobs to ensure that the <code>TraceFileLocation</code> is updated regularly, and that the mirror is scanned and refreshed regularly - the things that Mirrorbits itself didn't seem to be handling properly. The trace file is always updated 1 minute before the sync happens, while the mirror scan happens 1 minute after, to give the sync time to complete. The local repository is refreshed every minute to catch any new files as quickly as possible.</p>
<pre><code># /etc/cron.d/mirror-sync
11,26,41,56 * * * * root /usr/bin/date +\%s | /usr/bin/tee /srv/repository/mirror/mirrorsync &amp;&gt;/dev/null
13,28,42,58 * * * * root /usr/local/bin/mirrorbits scan -all
* * * * * root /usr/local/bin/mirrorbits refresh
</code></pre><h2 id="adding-mirrors-to-mirrorbits">Adding Mirrors to Mirrorbits</h2>
<p>Once all the setup was completed and Mirrorbits running, I added the mirrors to the Mirrorbits system. This is a straightforward process using the Mirrorbits binary:</p>
<pre><code>mirrorbits add -http https://fra1.mirror.jellyfin.org -rsync rsync://fra1.mirror.jellyfin.org/mirror fra1
mirrorbits scan --enable fra1
mirrorbits refresh
</code></pre><p>Once scanned, enabled, and refreshed, the mirror became active and and visible in the <code>/mirrorstats</code> output or on the CLI, ready to serve requests.</p>
<pre><code>[email protected] ~ $ mirrorbits list
Identifier STATE SINCE
fra1 up (Mon, 12 Apr 2021 07:15:29 UTC)
sgp1 up (Mon, 12 Apr 2021 06:51:03 UTC)
tor1 up (Sun, 11 Apr 2021 21:48:48 UTC)
sfo1 up (Sun, 11 Apr 2021 17:43:27 UTC)
</code></pre><h2 id="geoip">GeoIP</h2>
<p>One complication of using Mirrorbits is requiring a GeoIP database. It specifically requires the <code>GeoLite2` </code>mmdb` format to operate correctly. Unfortunately, this is no longer something that is provided freely. You must obtain this yourself, or find an alternative; I would prefer to use a freely available database, but I have yet to be able to find one that works with Mirrorbits. If you know of one, please let me know!</p>
<p>This database is extracted to the <code>GeoipDatabasePath</code> location and is loaded by Mirrorbits at runtime, providing the GeoIP information it then uses to direct clients to the nearest mirror server.</p>
<h2 id="conclusion">Conclusion</h2>
<p>All together, we hope this setup allows us to continue to scale our downloads for our users across the world. And I hope this post will help another admin of a small project who needs to distribute their downloads across many geo-diverse servers. Good luck!</p>
</description>
</item>
<item>
<title>Android app now on F-Droid</title>
<link>https://jellyfin.org/posts/android-on-fdroid/</link>
<pubDate>Mon, 01 Mar 2021 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/android-on-fdroid/</guid>
<description><p>We're happy to announce the immediate availability of the Android mobile app on the F-Droid store. The F-Droid version does not contain any proprietary libraries and builds are fully reproducible.</p>
<h2 id="missing-features">Missing features</h2>
<p>Unfortunately, the library required for casting support is proprietary, meaning that it's not available under a free license and Google doesn't publish the source code. Because of that, we had to remove it in the F-Droid version. Fortunately, the remote control feature still works.</p>
<p>Additionally, the Android Auto integration does not work because Google does not allow apps to integrate with it when the app was not installed from the Google Play store.</p>
<h2 id="download-now">Download Now</h2>
<a class="NoLinkLook" href="https://play.google.com/store/apps/details?id=org.jellyfin.mobile">
<img width="153" alt="Jellyfin on Google Play" src="https://jellyfin.org/images/store-icons/google-play.png" />
</a>
<a class="NoLinkLook" href="https://www.amazon.com/gp/product/B081RFTTQ9">
<img width="153" alt="Jellyfin on Amazon App Store" src="https://jellyfin.org/images/store-icons/amazon.png" />
</a>
<a class="NoLinkLook" href="https://f-droid.org/en/packages/org.jellyfin.mobile/">
<img width="153" alt="Jellyfin on F-Droid" src="https://jellyfin.org/images/store-icons/fdroid.png" />
</a>
<p>Direct downloads are always available from <a href="https://repo.jellyfin.org/releases/client/android/">our repository</a>.</p></description>
</item>
<item>
<title>Please refresh your Jellyfin Apt key on Debian/Ubuntu</title>
<link>https://jellyfin.org/posts/jellyfin-apt-key/</link>
<pubDate>Tue, 24 Nov 2020 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/jellyfin-apt-key/</guid>
<description><p>Our GPG key for signing our Debian and Ubuntu repositories (<code>https://repo.jellyfin.org/debian</code> and <code>https://repo.jellyfin.org/ubuntu</code>) is set to expire next month.</p>
<p>Unfortunately this was an oversight when we first set up this repo, and we never provided any convenient way to update this. As a remedy, we've removed the expiry on the key and put a new version on the repo. This brings us into line with numerous other 3rd-party Debian repositories, such as the Microsoft .NET and Docker repositories which also use an expiry-less key, and should avoid any such issues again, barring a need to rotate it. This does however require manually refreshing the key on your system.</p>
<p>Doing this is as easy as re-running the command from the install docs; it will overwrite the old key with the new one:</p>
<pre><code>wget -O- https://repo.jellyfin.org/jellyfin_team.gpg.key | sudo apt-key add -
</code></pre><p>You can verify this worked by checking the <code>apt-key</code> output like so; this is a good practice anyways to verify that the key has not been altered, as its signatures and fingerprint should all match:</p>
<pre><code>$ apt-key list | grep -C2 jellyfin # Notice the expires: field
Warning: apt-key output should not be parsed (stdout is not a terminal)
pub rsa3072 2018-12-16 [SC] [expires: 2020-12-15]
4918 AABC 486C A052 358D 778D 4902 3CD0 1DE2 1A7B
uid [ unknown] Jellyfin Team &lt;[email protected]&gt;
sub rsa3072 2018-12-16 [E] [expires: 2020-12-15]
$ wget -O- https://repo.jellyfin.org/jellyfin_team.gpg.key | sudo apt-key add -
[...]
$ apt-key list | grep -C2 jellyfin # Notice the expires: is now gone
Warning: apt-key output should not be parsed (stdout is not a terminal)
pub rsa3072 2018-12-16 [SC]
4918 AABC 486C A052 358D 778D 4902 3CD0 1DE2 1A7B
uid [ unknown] Jellyfin Team &lt;[email protected]&gt;
sub rsa3072 2018-12-16 [E]
</code></pre><p>If you find this didn't work, try removing the key first with this command, then re-add it again:</p>
<pre><code>sudo apt-key remove 1DE21A7B
</code></pre><p>We've also published the key to the Ubuntu keyserver as a backup, just in case, or if you prefer this method. Our docs will retain the direct-file method however. You can use this command to obtain the key directly from the Ubuntu keyserver:</p>
<pre><code>sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 1DE21A7B
</code></pre><p><strong>Please ensure you refresh the key before December 15th, or you will find that <code>apt update</code> no longer works!</strong></p>
<p>GitHub Issue for reference: <a href="https://github.com/jellyfin/jellyfin/issues/4528">https://github.com/jellyfin/jellyfin/issues/4528</a></p>
<p>Reddit thread for reference: <a href="https://www.reddit.com/r/jellyfin/comments/jz6u9o/debian_ubuntu_repo_users_our_key_is_expiring/">https://www.reddit.com/r/jellyfin/comments/jz6u9o/debian_ubuntu_repo_users_our_key_is_expiring/</a></p>
<p>Thanks,
Joshua</p>
</description>
</item>
<item>
<title>Android v2.1.0 - Jellyfin in your car!</title>
<link>https://jellyfin.org/posts/android-v2.1.0/</link>
<pubDate>Sun, 25 Oct 2020 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/android-v2.1.0/</guid>
<description><p>Jellyfin for Android version 2.1 is here with support for Android Auto.</p>
<p>A new version of the Android app: version 2.1 has just been released! This update contains some quality of life improvements, some bugfixes and new features.
It's been only a few weeks since 2.0 but we couldn't wait to bring these new exiting changes to you. Let's start with the most awesome feature.</p>
<h2 id="android-auto">Android Auto</h2>
<p>Starting with this update we now support playing music in cars. This change was contributed by <a href="https://github.com/Spacetech">@Spacetech</a> and we are excited to release it. Right now it supports browsing your music library in multiple categories: latest, albums, artists, songs and genres. It allows shuffling your albums and shows thumbnails when available.</p>
<video controls loop autoplay muted playsinline class="inline justify" height="500">
<source src="https://jellyfin.org/images/posts/android-2-1-0/android-auto.webm" type="video/webm" />
</video>
<p><em><strong>Note:</strong> since we do not have offline-support at the moment all music playback needs an active network connection to work. Be aware this may cause additional charges in your mobile plan.</em></p>
<h2 id="connectivity-issues">Connectivity issues</h2>
<p>Some users reported issues when connecting to their server. We've made some improvements to fix those problems:</p>
<ul>
<li>When your server uses an outdated version a warning is shown.</li>
<li>If the webui fails to load we now show a proper error allowing you to change the server address.</li>
<li>Users with self-signed certificates should be able to use the app again.</li>
<li>And lastly, when your device name includes special characters they are now removed to fix the &ldquo;endless loading&rdquo; issue.</li>
</ul>
<h2 id="playback-improvements">Playback improvements</h2>
<p>The native video player (ExoPlayer) now supports zooming using gestures so you can remove the black bars from the video. We made some changes to which audio codecs are supported to prevent unnecessary transcoding. We also made some big changes to the structure of the app to fix an issue where you weren't able to return to the app after leaving Picture-in-Picture mode.</p>
<p>There is a new option in the settings to select which external player to use. The listed players should also report playback status back to Jellyfin to track what you watch and allow the app to resume playback. Issues with subtitles (especially external subtitles) should now be less common.</p>
<h2 id="fdroid">F-Droid</h2>
<p>We have added the required metadata for F-Droid to our repository. We are currently working with the F-Droid team to get the app in their repository - we will post an additional announcement when this is ready.</p>
<h2 id="release-notes">Release Notes</h2>
<p>Full release notes available on <a href="https://github.com/jellyfin/jellyfin-android/releases/tag/v2.1.0">GitHub</a>.</p>
<h2 id="download-now">Download Now</h2>
<a class="NoLinkLook" href="https://play.google.com/store/apps/details?id=org.jellyfin.mobile">
<img width="153" alt="Jellyfin on Google Play" src="https://jellyfin.org/images/store-icons/google-play.png" />
</a>
<a class="NoLinkLook" href="https://www.amazon.com/gp/product/B081RFTTQ9">
<img width="153" alt="Jellyfin on Amazon App Store" src="https://jellyfin.org/images/store-icons/amazon.png" />
</a>
<p>Direct downloads are always available from <a href="https://repo.jellyfin.org/releases/client/android/">our repository</a>.</p>
<h2 id="contributors">Contributors</h2>
<p>We are grateful to all contributors this release:</p>
<ul>
<li><a href="https://github.com/Maxr1998">@Maxr1998</a> - <a href="https://github.com/sponsors/Maxr1998">Sponsor</a></li>
<li><a href="https://github.com/nielsvanvelzen">@nielsvanvelzen</a> - <a href="https://github.com/sponsors/nielsvanvelzen">Sponsor</a></li>
<li><a href="https://github.com/vitorsemeano">@vitorsemeano</a></li>
<li><a href="https://github.com/ferferga">@ferferga</a> - <a href="https://github.com/sponsors/ferferga">Sponsor</a></li>
<li><a href="https://github.com/CarlosOlivo">@CarlosOlivo</a></li>
<li><a href="https://github.com/Spacetech">@Spacetech</a></li>
<li><a href="https://github.com/h1dden-da3m0n">@h1dden-da3m0n</a></li>
<li><a href="https://github.com/IzzySoft">@IzzySoft</a></li>
</ul></description>
</item>
<item>
<title>Android Developers Rejoice</title>
<link>https://jellyfin.org/posts/android-next/</link>
<pubDate>Mon, 05 Oct 2020 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/android-next/</guid>
<description><p>This will be a net benefit for users and developers alike!</p>
<p>Everyone will enjoy the native video player spearheaded by <a href="https://github.com/Stampede10343">Stampede10343</a> and <a href="https://github.com/vitorsemeano">vitorsemeano</a> over the course of several months.
<a href="https://github.com/Maxr1998">Maxr1998</a> valiantly ported the Cordova portions to Kotlin (and a bit of Java) which means Android developers will feel right at home with the new codebase!</p>
<h3 id="migration">Migration</h3>
<p>The new release will be a drop-in replacement for the deprecated Cordova client, meaning you can just update from GitHub, Google Play, or Amazon App Store as you would have previously.
One minor issue is that you'll have to add your server and credentials again since we couldn't pull the information from Cordova.
Local user settings such as the theme will also be reset after the update.
Azure has also been updated so the releases will be automatically built, and Weblate now points to the new codebase.
Older versions will remain on <a href="https://repo.jellyfin.org">our repository</a> for the time being but don't expect them to stay forever, so if you have some reason to stash the older APKs download them soon!</p>
<blockquote>
<p>Please note that this client has a new set of translations, so if you speak more than one language head on over to Weblate to help out the new client!</p>
</blockquote>
<h3 id="exoplayer">ExoPlayer</h3>
<p>The key feature for this release is ExoPlayer, so we've reserved a whole section for news regarding the player and its functionality.
It's currently disabled by default since there may be small issues, but it works quite well in our experience.
The main features missing at the moment are bitrate limiting and SyncPlay, but they should get added eventually.</p>
<p>There is a new section in the user settings for the native client from which you can enable ExoPlayer, among other options.
A toggle for the notification dismissal was also added for customization.
Of course, using ExoPlayer means support for more codecs during video playback as well!
H265 should be working without transcodes, and several other problematic codecs are now much less troublesome with the new update.</p>
<blockquote>
<p>Note that the included device profile still needs some tweaking to actually mark every codec that the phone supports as supported to the server. You can follow the progress on this at <a href="https://github.com/jellyfin/jellyfin-android/issues/28">jellyfin/jellyfin-android#28</a>.</p>
</blockquote>
<h3 id="future">Future</h3>
<p>The goal is to use a mobile-first interface for ExoPlayer so we can focus more on desktop for the normal web player.
Bigger, easier clickable buttons and double tap to seek are some of the changes setting the new interface apart from the HTML5 video player.
As usual, since this is a volunteer project we don't actually have set milestones, so if you want something done, the quickest method is to add it yourself!
Head over to <a href="https://matrix.to/#/+jellyfin:matrix.org">Matrix</a> or Freenode and get in touch with the Android developers if you'd like to talk about adding a new feature.
Our <a href="https://github.com/jellyfin/jellyfin-android">GitHub</a> is also an excellent place to discuss long term changes for the new client now that a more modern build process is in place.</p></description>
</item>
<item>
<title>Client Spotlight: Videotape</title>
<link>https://jellyfin.org/posts/client-videotape/</link>
<pubDate>Sat, 22 Aug 2020 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/client-videotape/</guid>
<description><p>Videotape is a free lightweight video player for both Windows 10 &amp; Xbox. Their new 3.0 version now supports Jellyfin!</p>
<p>Videotape is a native UWP application with a strong focus on design and usability.</p>
<ul>
<li>Direct play almost all files, both from Jellyfin and other local files</li>
<li>Overlay and always on top modes</li>
<li>Adjustable playback speed</li>
</ul>
<p>Download it now from the Microsoft store!</p>
<p><a class="NoLinkLook" href="//www.microsoft.com/store/apps/9NLVH2LL4P1Z?cid=storebadge&ocid=badge"><img src="https://jellyfin.org/images/store-icons/microsoft.svg" alt="View VideoTape in the Microsoft Store" style="width: 142px; height: 52px;"/></a></p>
<p>Here's what Jellyfin looks like on Windows, with Videotape 3.</p>
<p><img src="https://jellyfin.org/images/posts/videotape/detailview.png" name="Detail View on Windows 10" /></p>
<p>Here's what it looks like on the Xbox One.</p>
<p><img src="https://jellyfin.org/images/posts/videotape/detailxbox.png" name="Detail View on Xbox One" /></p>
<blockquote>
<p>Client Spotlight</p>
<p>This blog series aims to highlight some of the amazing projects created by our community.</p>
<p>Feel free to send a message if you can think of a project that could use more love!</p>
</blockquote></description>
</item>
<item>
<title>Jellyfin Release - v10.6.0</title>
<link>https://jellyfin.org/posts/jellyfin-10-6-0/</link>
<pubDate>Sun, 19 Jul 2020 11:42:00 +0100</pubDate>
<guid>https://jellyfin.org/posts/jellyfin-10-6-0/</guid>
<description><p>After months of work, here comes another behemoth of a release, this time with over 30 major improvements and tons of fixes.</p>
<p><a href="https://jellyfin.org/downloads/" class="button button__accent">Download Jellyfin 10.6.0</a> <a href="https://github.com/jellyfin/jellyfin/releases/tag/v10.6.0" class="button hero__button">Read the full release notes</a></p>
<p>At <strong>more than 500 pull requests</strong> merged between the server and the web client, Jellyfin 10.6.0 brings an incredible number of new features, improvements and bug fixes. It's a huge release and we have a lot to cover, so let's get to it!</p>
<h1 id="syncplay">SyncPlay</h1>
<p>Other services have recently launched various ways to view your content together with friends. With the current global situation, it makes a lot of sense, and Jellyfin isn't lagging behind.</p>
<p>We're proud to announce Jellyfin 10.6's headline feature: <strong>SyncPlay</strong>.</p>
<p>SyncPlay allows you to create rooms that other users or clients can join in order to share a common viewing experience. There is no limit on the number of users in a room and you are free to join the same room with the same user from multiple clients as well.</p>
<p>Thanks to first-time contributor <a href="https://github.com/OancaAndrei">OancaAndrei</a>, who submitted pull requests to both the server and the web client (<a href="https://github.com/jellyfin/jellyfin/pull/2733">jf#2733</a>, <a href="https://github.com/jellyfin/jellyfin-web/pull/1011">jf-web#1011</a>) in order to lay out the foundations for this, you can now watch movies together with friends and family, from the comfort of your respective homes.</p>
<p>The feature is expected to be improved in future versions of Jellyfin, but has already been used by multiple users during the development cycle, with a delay between clients of only a couple of milliseconds.</p>
<h1 id="migration-to-entity-framework-core">Migration to Entity Framework Core</h1>
<p>It's been on our plate for a while, but thanks to new team member <a href="https://github.com/barronpm">barronpm</a>, we can finally say that the rewrite of our database model is progressing at a steady pace!</p>
<p>Previously, Jellyfin used a combination of SQLite databases (yes, multiple ones), XML files and C# spaghetti to perform database operations. Information was split in multiple places, sometimes even duplicated and generally filtered in C# instead of using the database engine's faster processing.</p>
<p>Over the course of this cycle, <a href="https://github.com/barronpm">barronpm</a> has been deciphering and untangling this mess, and managed to successfully migrate the ActivityDB (<a href="https://github.com/jellyfin/jellyfin/pull/2970">jf#2970</a>) and the UserDB (<a href="https://github.com/jellyfin/jellyfin/pull/3148">jf3148</a>) to EF Core.</p>
<p>While there is still a ways to go, EF Core should bring faster database queries, support for multiple database engines, cleaner code, and significantly reduced memory usage. Currently, there is still a bridge to make the link between the new EF Core databases and the existing code, which will be cleaned up down the line.</p>
<p>Part of the improved memory usage is due to our current inherited custom ORM caching everything in memory to make up for its slowness. For large databases, this could result in hundreds of megabytes of memory lost to caching. With EF Core, however, we leave the heavy lifting to the database engine, leading to better response times and less memory usage overall.</p>
<p>Your databases will be automatically migrated when you first launch Jellyfin 10.6. While the migration process has been well tested over the past few months, issues may arise during the migration process. To prevent any data loss, please <strong>backup your existing data files</strong> before starting the migration process.</p>
<h1 id="a-more-modern-web-client">A more modern web client</h1>
<p>Our web client has long suffered of a massive amount of technical debt, due to the project we forked from only providing minified versions of the source and using antiquated web technologies. Some of these old technologies have, until recently, prevented us from being able to use modern JavaScript tooling, which would allow us to significantly clean the source.</p>
<p>Thankfully, this is now behind us, as <a href="https://github.com/MrTimscampi">MrTimscampi</a> worked on improving the way we build the web client by using Gulp to perform various tasks necessary for building our current code structure with modern tools. (<a href="https://github.com/jellyfin/jellyfin-web/pull/862">jf-web#862</a>). This allows us to use bleeding edge JavaScript thanks to Babel, but also simplifies greatly our support for legacy clients (Most notably early WebOS and Tizen versions).</p>
<p>Among the benefits of this move to Gulp for building the client, we have started moving away from <a href="https://requirejs.org/">RequireJS</a> and towards using standard <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules">EcmaScript Modules</a>, thanks to <a href="https://github.com/Camc314">Camc314</a>, <a href="https://github.com/cromefire/">cromefire</a>, <a href="https://github.com/delgan">Delgan</a>, <a href="https://github.com/dkanada/">dkanada</a>, <a href="https://github.com/grafixeyehero/">grafixeyehero</a>, <a href="https://github.com/MrTimscampi">MrTimscampi</a>, and <a href="https://github.com/sarab97/">sarab97</a>.</p>
<p>This massive change, once it is complete, will allow us to simplify the web client build process, which will in turn allow us to start our migration to <a href="https://vuejs.org/">Vue</a> and significantly clean up our code. This should also bring some noticeable performance improvements to the web client down the line, as we tackle technical debt and remove deprecated practices and libraries from the code.</p>
<h1 id="server-performance-bug-fixes-and-better-networking">Server performance, bug fixes and better networking</h1>
<p>Our resident C# performance wizard, <a href="https://github.com/Bond-009">Bond-009</a> continues his quest to rid the server source of warnings and generally improve server performance, fixing multiple bugs in the process.</p>
<p><a href="https://github.com/mark-monteiro">mark-monteiro</a> worked on multiple fixes for 10.6, including reworking the network settings accessible through the administration dashboard (<a href="https://github.com/jellyfin/jellyfin/pull/2774">jf#2774</a>, <a href="https://github.com/jellyfin/jellyfin-web/pull/1140">jf-web#1140</a>).</p>
<p>Team member <a href="https://github.com/nyanmisaka">nyanmisaka</a>, with some help from <a href="https://github.com/artiume/">artiume</a>, brings a number of improvements to transcoding (<a href="https://github.com/jellyfin/jellyfin/pull/2809">jf#2809</a>, <a href="https://github.com/jellyfin/jellyfin-web/pull/1046">jf-web#1046</a>, <a href="https://github.com/jellyfin/jellyfin/pull/2821">jf#2821</a>, <a href="https://github.com/jellyfin/jellyfin/pull/2715">jf#2715</a>), with format toggles, options for toggling transcoding for HEVC and 10-bit VP9 videos off for older GPUs, providing support for the VP8/VP9 QSV and NVDEC decoders in FFmpeg 4.3, better support for UTF-16 subtitles and a host of other improvements.</p>
<p>Further changes to the server include fixes for collection metadata issues (<a href="https://github.com/jellyfin/jellyfin/pull/3117">jf#3117</a>), improvements to the metadata providers (<a href="https://github.com/jellyfin/jellyfin/pull/3071">jf#3071</a>, <a href="https://github.com/jellyfin/jellyfin/pull/3056">jf#3056</a>, <a href="https://github.com/jellyfin/jellyfin/pull/3289">jf#3289</a>), and more core providers moved to plugins (<a href="https://github.com/jellyfin/jellyfin/pull/3208">jf#3208</a>).</p>
<h1 id="more-web-client-improvements">More web client improvements</h1>
<p><a href="https://github.com/itegulov">Itegulov</a> and <a href="https://github.com/dkanada/">dkanada</a> have improved support for ebooks by adding an EPUB reader based on <a href="https://github.com/futurepress/epub.js/">epub.js</a> (<a href="https://github.com/jellyfin/jellyfin-web/pull/1263">jf-web#1263</a>). Reader support for more formats is in progress for future versions, including CBZ/CBR and PDF.</p>
<p>As we used the new 10.5 details screen over the last few months, we noticed some improvements we could make to the experience. Team member <a href="https://github.com/MrTimscampi">MrTimscampi</a>, along with input from the rest of the web team and some of our users, did a second pass on that screen (<a href="https://github.com/jellyfin/jellyfin-web/pull/949">jf-web#949</a>, <a href="https://github.com/jellyfin/jellyfin-web/pull/1206">jf-web#1206</a>), tightening the design and cleaning some visual issues along the way. <a href="https://github.com/jellyfin/jellyfin-web/pull/1406">Delgan</a> put in the final touches to the page by avoiding a jump in the content when rendering the track selectors on the page (<a href="https://github.com/jellyfin/jellyfin-web/pull/1406">jf-web#1406</a>)</p>
<div class="juxtapose">
<img data-label="10.5.5" src="https://jellyfin.org/images/posts/jellyfin-10-6-0/details-10-5.png" name="" />
<img data-label="10.6.0" src="https://jellyfin.org/images/posts/jellyfin-10-6-0/details-10-6.png" name="" />
</div>
<p>Team member <a href="https://github.com/ferferga">ferferga</a> and contributor <a href="https://github.com/samuel9554">samuel9554</a> have been working on redesigning our music experience. For 10.6, they overhauled our mobile music player interface and made significant changes to the mini player and the remote player UI (<a href="https://github.com/jellyfin/jellyfin-web/pull/1056">jf-web#1056</a>, <a href="https://github.com/jellyfin/jellyfin-web/pull/1430">jf-web#1430</a>).</p>
<div class="juxtapose">
<img data-label="10.5.5" src="https://jellyfin.org/images/posts/jellyfin-10-6-0/player-10-5.png" name="" />
<img data-label="10.6.0" src="https://jellyfin.org/images/posts/jellyfin-10-6-0/player-10-6.png" name="" />
</div>
<p><a href="https://github.com/MrTimscampi">MrTimscampi</a> also reworked the image loading system (<a href="https://github.com/jellyfin/jellyfin-web/pull/1065">jf-web#1065</a>), fixing some visual issues and improving memory usage by unloading out of view images. Along with this improvement, <a href="https://github.com/ferferga">ferferga</a>, <a href="https://github.com/GranPC">GranPC</a>, <a href="https://github.com/JustAMan">JustAMan</a> and <a href="https://github.com/Bond-009">Bond-009</a> have implemented <a href="https://blurha.sh/">Blurhash</a> placeholder support on both the server and the web client, which brings further visual refinement to the user interface.</p>
<p><a href="https://github.com/JustAMan">JustAMan</a> went back over our new SSA/ASS subtitle rendering system and significantly improved performance for subtitles with heavy effects (<a href="https://github.com/jellyfin/jellyfin-web/pull/1144">jf-web#1144</a>, <a href="https://github.com/jellyfin/jellyfin-web/pull/1095">jf-web#1095</a>, <a href="https://github.com/jellyfin/jellyfin-web/pull/1048">jf-web#1048</a>, <a href="https://github.com/jellyfin/jellyfin-web/pull/1005">jf-web#1005</a>). While we still consider the feature experimental, it should now be able to render most subtitles accurately and with correct performance.</p>
<p>Other improvements to the web client include a rewritten image viewer (<a href="https://github.com/jellyfin/jellyfin-web/pull/967">jf-web#967</a>), a configuration option for the number of items per page in libraries (<a href="https://github.com/jellyfin/jellyfin-web/pull/983">jf-web#983</a>), a toggle for the nightly version of the Chromecast client (<a href="https://github.com/jellyfin/jellyfin-web/pull/1242">jf-web#1242</a>), and support for multiple plugin repositories (<a href="https://github.com/jellyfin/jellyfin-web/pull/1393">jf-web#1393</a>, <a href="https://github.com/jellyfin/jellyfin/pull/3244">jf#3244</a>).</p>
<h1 id="patreons-and-github-sponsors">Patreons and Github Sponsors</h1>
<p>With the increased amount of activity on the project, we would like to give a signal boost to some ways to support the people working daily on Jellyfin.</p>
<p>We want to stress that, while some of our contributors individually accept financial donations, Jellyfin and its features will <strong>never</strong> be hidden behind a paywall. Supporting the developers financially is entirely voluntary and won't give you any exclusive access to features or support, nor will it change the priority of your feature requests or issues.</p>
<p><a href="https://github.com/anthonylavado">anthonylavado</a>, our wonderful PR and developer relation person, accepts donations through <a href="https://github.com/sponsors/anthonylavado">Github Sponsors</a>.</p>
<p><a href="https://github.com/barronpm">barronpm</a>, whose main work is on the server portion of Jellyfin and who has been spearheading the migration to EF Core has recently opened <a href="https://www.patreon.com/barronpm">a Patreon page</a>.</p>
<p><a href="https://github.com/dkanada/">dkanada</a>, whose work spreads from server to web client, accepts donations through <a href="https://github.com/sponsors/dkanada">Github Sponsors</a></p>
<p><a href="https://github.com/ferferga">ferferga</a>, web client contributor, localization aficionado and all-around awesome person accepts donations through <a href="https://github.com/sponsors/ferferga">Github Sponsors</a>.</p>
<p><a href="https://github.com/nielsvanvelzen">nielsvanvelzen</a>, who has been working hard on the Android TV client, can be supported on <a href="https://github.com/sponsors/nielsvanvelzen">Github Sponsors</a>.</p>
<p><a href="https://github.com/MrTimscampi">MrTimscampi</a>, whose main work has been cleaning up and modernizing the web client, also recently opened <a href="https://www.patreon.com/mrtimscampi">a Patreon page</a>.</p>
<p><a href="https://github.com/oddstr13">oddstr13</a>, one of the developers of Jellyfin for Kodi also accepts donations on <a href="https://github.com/sponsors/oddstr13">Github Sponsors</a>.</p>
<p><a href="https://github.com/thornbill">thornbill</a> who handles the iOS and Android clients, and also contributes to the Android TV client, can be supported on <a href="https://github.com/sponsors/thornbill">Github Sponsors</a></p>
<h1 id="contributors">Contributors</h1>
<p>As an final note, we would like to thank all the contributors who worked on making Jellyfin 10.6 a reality:</p>
<ul>
<li><a href="https://github.com/adavier/">adavier</a></li>
<li><a href="https://github.com/aled/">aled</a></li>
<li><a href="https://github.com/alset333/">alset333</a></li>
<li><a href="https://github.com/anthonylavado/">anthonylavado</a></li>
<li><a href="https://github.com/Artiume/">Artiume</a></li>
<li><a href="https://github.com/balu92/">balu92</a></li>
<li><a href="https://github.com/BaronGreenback/">BaronGreenback</a></li>
<li><a href="https://github.com/barronpm/">barronpm</a></li>
<li><a href="https://github.com/bendardenne/">bendardenne</a></li>
<li><a href="https://github.com/Bond-009">Bond-009</a></li>
<li><a href="https://github.com/Brissot/">Brissot</a></li>
<li><a href="https://github.com/Camc314/">Camc314</a></li>
<li><a href="https://github.com/ConfusedPolarBear/">ConfusedPolarBear</a></li>
<li><a href="https://github.com/crobibero/">crobibero</a></li>
<li><a href="https://github.com/cromefire/">cromefire</a></li>
<li><a href="https://github.com/cvium/">cvium</a></li>
<li><a href="https://github.com/dafo90/">dafo90</a></li>
<li><a href="https://github.com/danieladov/">danieladov</a></li>
<li><a href="https://github.com/Delgan/">Delgan</a></li>
<li><a href="https://github.com/dkanada/">dkanada</a></li>
<li><a href="https://github.com/dmitrylyzo/">dmitrylyzo</a></li>
<li><a href="https://github.com/dtparr/">dtparr</a></li>
<li><a href="https://github.com/EraYaN/">EraYaN</a></li>
<li><a href="https://github.com/ferferga/">ferferga</a></li>
<li><a href="https://github.com/fhriley/">fhriley</a></li>
<li><a href="https://github.com/grafixeyehero/">grafixeyehero</a></li>
<li><a href="https://github.com/GranPC/">GranPC</a></li>
<li><a href="https://github.com/h1nk/">h1nk</a></li>
<li><a href="https://github.com/hauntingEcho/">hauntingEcho</a></li>
<li><a href="https://github.com/itegulov/">itegulov</a></li>
<li><a href="https://github.com/iwalton3/">iwalton3</a></li>
<li><a href="https://github.com/jairbubbles/">jairbubbles</a></li>
<li><a href="https://github.com/joshuaboniface/">joshuaboniface</a></li>
<li><a href="https://github.com/JustAMan/">JustAMan</a></li>
<li><a href="https://github.com/kesslern/">kesslern</a></li>
<li><a href="https://github.com/KGT1/">KGT1</a></li>
<li><a href="https://github.com/KristupasSavickas/">KristupasSavickas</a></li>
<li><a href="https://github.com/KucharczykL/">KucharczykL</a></li>
<li><a href="https://github.com/lfoust/">lfoust</a></li>
<li><a href="https://github.com/lyonzy/">lyonzy</a></li>
<li><a href="https://github.com/macr/">macr</a></li>
<li><a href="https://github.com/mark-monteiro">mark-monteiro</a></li>
<li><a href="https://github.com/masterkoppa/">masterkoppa</a></li>
<li><a href="https://github.com/mijofa/">mijofa</a></li>
<li><a href="https://github.com/MrTimscampi/">MrTimscampi</a></li>
<li><a href="https://github.com/Nazar78/">Nazar78</a></li>
<li><a href="https://github.com/neilsb/">neilsb</a></li>
<li><a href="https://github.com/Nickbert7/">Nickbert7</a></li>
<li><a href="https://github.com/nielsvanvelzen/">nielsvanvelzen</a></li>
<li><a href="https://github.com/nyanmisaka/">nyanmisaka</a></li>
<li><a href="https://github.com/OancaAndrei/">OancaAndrei</a></li>
<li><a href="https://github.com/oddstr13">oddstr13</a></li>
<li><a href="https://github.com/ox0spy/">ox0spy</a></li>
<li><a href="https://github.com/Polpetta/">Polpetta</a></li>
<li><a href="https://github.com/PrplHaz4/">PrplHaz4</a></li>
<li><a href="https://github.com/puschie286/">puschie286</a></li>
<li><a href="https://github.com/pusta/">pusta</a></li>
<li><a href="https://github.com/randrey/">randrey</a></li>
<li><a href="https://github.com/redSpoutnik/">redSpoutnik</a></li>
<li><a href="https://github.com/rexbron/">rexbron</a></li>
<li><a href="https://github.com/rigtorp/">rigtorp</a></li>
<li><a href="https://github.com/rotvel/">rotvel</a></li>
<li><a href="https://github.com/samuel9554/">samuel9554</a></li>
<li><a href="https://github.com/sarab97/">sarab97</a></li>
<li><a href="https://github.com/Shawmon/">Shawmon</a></li>
<li><a href="https://github.com/shayaantx/">shayaantx</a></li>
<li><a href="https://github.com/sparky8251/">sparky8251</a></li>
<li><a href="https://github.com/Stampede10343/">Stampede10343</a></li>
<li><a href="https://github.com/telans/">telans</a></li>
<li><a href="https://github.com/ThibaultNocchi/">ThibaultNocchi</a></li>
<li><a href="https://github.com/thornbill/">thornbill</a></li>
<li><a href="https://github.com/twinkybot/">twinkybot</a></li>
<li><a href="https://github.com/Ullmie02/">Ullmie02</a></li>
<li><a href="https://github.com/viaregio/">viaregio</a></li>
<li><a href="https://github.com/villagra/">villagra</a></li>
<li><a href="https://github.com/whooo/">whooo</a></li>
<li><a href="https://github.com/xumix/">xumix</a></li>
<li><a href="https://github.com/YouKnowBlom/">YouKnowBlom</a></li>
<li><a href="https://github.com/ZadenRB/">ZadenRB</a></li>
</ul></description>
</item>
<item>
<title>Plugin Repositories</title>
<link>https://jellyfin.org/posts/plugin-updates/</link>
<pubDate>Fri, 17 Jul 2020 00:00:00 +0000</pubDate>
<guid>https://jellyfin.org/posts/plugin-updates/</guid>
<description><p>There have been several changes to plugins for the new release.
Here's a quick post going over the biggest updates for developers and users alike.</p>
<p>The most noticable change for everyone is that third party plugin repositories are now available!
You can access the current list at Dashboard -&gt; Plugins -&gt; Repositories, and items can be added or removed as desired.
Even the official repository can be removed if you'd prefer to avoid external calls to our server.</p>
<h1 id="manifest">Manifest</h1>
<p>For developers, the only required change is a JSON manifest at <em>any</em> location with versions that point to binary releases at <em>any</em> location.
We don't require any specific method for hosting these files, as that would go against the ideals of the project.
The official repository uses nginx for the manifest and GitHub Releases for the binaries, but you could potentially host the manifest on GitHub as well.
Here's an example manifest with all the properties.
Please note that the GUID must be unique (both in the manifest and the plugin itself) if you want to avoid conflicts with other plugins.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-json" data-lang="json">[
{
<span style="color:#f92672">&#34;category&#34;</span>: <span style="color:#e6db74">&#34;Metadata&#34;</span>,
<span style="color:#f92672">&#34;guid&#34;</span>: <span style="color:#e6db74">&#34;a4df60c5-6ab4-412a-8f79-2cab93fb2bc5&#34;</span>,
<span style="color:#f92672">&#34;name&#34;</span>: <span style="color:#e6db74">&#34;Anime&#34;</span>,
<span style="color:#f92672">&#34;description&#34;</span>: <span style="color:#e6db74">&#34;This plugin supports several different metadata providers and options for organizing your collection.&#34;</span>,
<span style="color:#f92672">&#34;owner&#34;</span>: <span style="color:#e6db74">&#34;jellyfin&#34;</span>,
<span style="color:#f92672">&#34;overview&#34;</span>: <span style="color:#e6db74">&#34;Manage Your Anime in Jellyfin&#34;</span>,
<span style="color:#f92672">&#34;versions&#34;</span>: [
{
<span style="color:#f92672">&#34;checksum&#34;</span>: <span style="color:#e6db74">&#34;ad6db5175f4732308b5dd166f79a1c2d&#34;</span>,
<span style="color:#f92672">&#34;changelog&#34;</span>: <span style="color:#e6db74">&#34;bug fixes and improvements&#34;</span>,
<span style="color:#f92672">&#34;targetAbi&#34;</span>: <span style="color:#e6db74">&#34;10.6.0.0&#34;</span>,
<span style="color:#f92672">&#34;sourceUrl&#34;</span>: <span style="color:#e6db74">&#34;https://repo.jellyfin.org/releases/other/whats-this-plugin.zip.gif&#34;</span>,
<span style="color:#f92672">&#34;timestamp&#34;</span>: <span style="color:#e6db74">&#34;2020-03-27 06:02:58&#34;</span>,
<span style="color:#f92672">&#34;version&#34;</span>: <span style="color:#e6db74">&#34;1.0.3.0&#34;</span>
}
]
}
]
</code></pre></div><p>The official repository manifest for <a href="https://repo.jellyfin.org/releases/plugin/manifest-stable.json">stable plugins</a> can be used for more examples.
You can also find the <a href="https://repo.jellyfin.org/releases/plugin/manifest.json">deprecated manifest</a> on the same domain for the old format.
However, all new plugin updates (on the official repository) will go to the new manifest, so older verions of Jellyfin won't receive plugin updates.
Plugins do have <a href="https://jellyfin.org/docs/plugin-api/MediaBrowser.Model.Updates.html">official documentation</a> on our DocFX instance.
Please be aware that our documentation is still a work in progress, since a lot of the C# code still has very little information for tools like this.
Things are improving thanks to the diligent server team though, who have been slowly adding information throughout the codebase.</p>
<h1 id="tools">Tools</h1>
<p>One excellent tool that might help with repository management is <a href="https://github.com/oddstr13/jellyfin-plugin-repository-manager">jellyfin-plugin-repository-manager</a> by Oddstr13, a frequent contributor.
He did mention that his tool works much better with nginx than GitHub releases, but feel free to check it out!
Another useful tool might be the <a href="https://github.com/jellyfin/jellyfin-build">jellyfin-build</a> repository, which used to be the method used for updates on the official repository.
We'll probably be migrating to the repository manager linked above though, since most of the other build systems have moved to Azure.</p>
<h1 id="code">Code</h1>
<p>There are always a few changes to the ABI you might want to know about if you maintain a plugin.
I'll include the most important ones for 10.6.0 here to hopefully reduce any issues with the update.</p>
<p>The first batch comes from the HTML for settings on the web client, which has been going through an overhaul lately.
One of the long term goals we have is deprecating jQuery entirely, since it's not 2008 anymore and better tools have come along.
That does mean plugin pages will have to migrate off it at some point, but we haven't made the full transition yet, don't worry.
Although jQuery will stick around a bit longer, we did remove two custom scripts in the web source that&hellip;extended the functionality a bit.
There was one for <a href="https://github.com/jellyfin/jellyfin-web/blob/release-10.5.z/src/legacy/selectmenu.js">select menus</a> and yet another for <a href="https://github.com/jellyfin/jellyfin-web/blob/release-10.5.z/src/legacy/fnchecked.js">checkbox</a> elements.
I can only assume the goal was compatibility with older browsers or clients at the time, but we've been pushing extremely hard to modernize the web client.
That means avoiding abandoned libraries, ancient JavaScript practices, and definitely custom extensions for dependencies we don't even want in the code.
The easiest fix for this change is to migrate from jQuery to vanilla JavaScript for checkboxes and select menus in the HTML source.</p>
<p>There were also several changes to the C# ABI that might affect your plugin.
The most troublesome is probably the ILogger tweaks, which were made to improve the server logs by appending the class name to every line.
You'll also find quite a few changes caused by the new database migration (Jellyfin.Data is the new namespace for these objects) and a few unrelated items.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">IExternalID.Name -&gt; IExternalID.ProviderName
MediaBrowser.Controller.Entities.User -&gt; Jellyfin.Data.Entities.User
MetadataProviders -&gt; MetadataProvider
CompressionMethod -&gt; CompressionMethods
RequestContentBytes <span style="color:#f92672">=</span> request -&gt; RequestContent <span style="color:#f92672">=</span> Encoding.UTF8.GetString<span style="color:#f92672">(</span>request<span style="color:#f92672">)</span>
User.Name -&gt; User.Username
item.GetDisplayExtras<span style="color:#f92672">(</span><span style="color:#f92672">)</span> -&gt; item.GetExtras<span style="color:#f92672">(</span>BaseItem.DisplayExtraTypes<span style="color:#f92672">)</span>
user.RootFolder -&gt; libraryManager.GetUserRootFolder<span style="color:#f92672">(</span><span style="color:#f92672">)</span>
</code></pre></div><h1 id="future">Future</h1>
<p>Third party repositories are the first step in a larger plan to vastly increase plugin usage within the codebase.
They will allow anyone to maintain their own plugin and push updates as quickly as they want, without having to deal with a centralized system.
It also gives users the power to reduce their reliance on an internet connection by allowing all repositories to be removed at will.</p>
<p>We understand some of these changes might be annoying to update within your plugin, but hopefully that will also see an improvement very soon.
The next goal (now that more than one repository can be used at the same time) will be an unstable repository for plugins.
This will fix the long-standing request for better plugin support on the unstable version, which has been a blocker for many users.
It will also have the side effect of requiring an unstable NuGet repository for the C# ABI, thus helping third party plugin developers test their plugins against any changes to the ABI before a server update has landed.</p>
<p>If you develop a plugin (or client) and would like to be included in our mailing list for third party developers, please contact us through Matrix or send an email to get the details.
The main goal here is excellent support for plugins and unofficial clients, so if you have any suggestions definitely contact us on one of our public forums.
Hopefully, the C# ABI will stabilize over time and huge changes will become more infrequent so we can focus on making plugins as great as possible!</p></description>
</item>
<item>
<title>Packaging Updates for 10.6.0</title>
<link>https://jellyfin.org/posts/packaging-updates/</link>
<pubDate>Sun, 21 Jun 2020 04:16:09 -0400</pubDate>
<guid>https://jellyfin.org/posts/packaging-updates/</guid>
<description><p>Packaging and building binaries for releases and testing has long been an issue for us. From fighting with duct-tape-and-coat-hanger scripts, to testing breaking changes, to massaging official releases, how we were doing things for the last year-and-a-half needed some improvements.</p>
<p>Luckily, today they are all completed. In this post, I'll detail the changes as well as what the entail for our users.</p>
<p>For a brief TL;DR: for most users of our stable releases, not much will change, and you will upgrade to 10.6.0 as you always have. For anyone using nightlies for testing, advanced setups, or who are just curious - read on!</p>
<h3 id="split-builds">Split Builds</h3>
<p>The first main component of the packaging changes is split builds. Previously, we were relying on some serious hackery in order to build both the Web UI (<a href="https://github.com/jellyfin/jellyfin-web">https://github.com/jellyfin/jellyfin-web</a>) and Server (<a href="https://github.com/jellyfin/jellyfin">https://github.com/jellyfin/jellyfin</a>) and combine them into one package. Ultimately, with the sheer number of changes in both repositories and speed at which updates happen, along with our eventual goal to decouple the two from each other for releases, this sort of solution had reached its limits. This is perhaps best exemplified by the mostly-unseen work I had to do to get 10.5.4 and 10.5.5 to build at all.</p>
<p>With split packages, the two repositories are now built completely independently for all platforms. If you build the <code>jellyfin-web</code> repository, you get out a Docker image, <code>.deb</code> packages, <code>.rpm</code> packages, or a <code>.tar.gz</code> archive that just contains the Web UI. Similarly, if you build the <code>jellyfin</code> repository, you get out the various Docker, <code>.deb</code>, <code>.rpm</code>, <code>.tar.gz</code>, and <code>.zip</code> archives you know and love.</p>
<p>The main difference is the naming - the <code>jellyfin-web</code> repository binaries are named, well, <code>jellyfin-web</code>, and the <code>jellyfin</code> repository binaries are named <code>jellyfin-server</code>. So, to use Debian as an example, where there was once <code>jellyfin</code>, there is now <code>jellyfin-web</code> and <code>jellyfin-server</code>. But don't worry, <code>jellyfin</code> is not gone - we'll get to that shortly.</p>
<h3 id="azure-pipelines-builds">Azure Pipelines builds</h3>
<p>Our previous build infrastructure consisted of a veritable spaghetti factory of Bash, Python, and Docker scripts that were executed on our build server, a DigitalOcean droplet. For the most part, it worked, but the process was very fragile, opaque (I'm not even sure <em>I</em> understand how it all worked all the time, and I wrote it all!), and resource-intensive.</p>
<p>As we've moved more and more functions to Azure for testing, verification, linting, etc. in the various repositories, it became obvious that Azure Pipelines had a lot of flexibility, and would be able to perform nearly all of our build steps for us. This eliminated at least 2/3 of the build server, and gives us another cool option - unstable builds, which I'll touch on shortly.</p>
<p>The Azure Pipelines build handles the actual building of all the archives for both repositories mentioned in the previous section, uploads the binary artifacts to the build server, and then kicks off a single script to handle the last 1/3 of the process, making things much clearer, more obvious, and with results visible to everyone in our Azure project page.</p>
<h3 id="metapackages-and-metaimages">Metapackages and Metaimages</h3>
<p>I previously mentioned that the package which used to be called <code>jellyfin</code> is now called <code>jellyfin-server</code>, and does not contain the Web UI. So, how do you get it all? And how will upgrades be seamless? The answer is metapackages, metaarchives, and metaimages! These new components can be found in <a href="https://github.com/jellyfin/jellyfin-metapackages">this repository page</a>, specifically the Docker images which will now be the source of truth for those configurations. I'll outline how each platform behaves below.</p>
<p>For Docker, the Azure pipelines split builds create docker images called <code>jellyfin/jellyfin-server</code> and <code>jellyfin/jellyfin-web</code>. On their own they're not too useful, but exist to enable the next step. When an Azure build finishes and has uploaded these images, a script is kicked off on our build server which builds the <code>jellyfin/jellyfin</code> &ldquo;metaimage&rdquo;, which will take the two separate images, and combine them into a single Docker image along with all the components to run them, like <code>jellyfin-ffmpeg</code>, then push the resulting image. The end result is a single image, <code>jellyfin/jellyfin</code>, like there has always been, but the builds are done independently rather than relying on <code>git clone</code>/archive downloads inside the build steps and other shenanigans.</p>
<p>For Debian and Ubuntu, the Azure pipelines split builds create separate <code>.deb</code> packages for each component. Unlike Docker, these are fully usable on their own, and installing Jellyfin in 10.6.0+ can be done with <code>apt install jellyfin-server jellyfin-web</code> if one wishes. The metapackage is a separate <code>.deb</code>, called <code>jellyfin</code>, who's only function is to have dependencies on these two component packages. Thus, installing <code>jellyfin</code> will automatically install <code>jellyfin-server</code> and <code>jellyfin-web</code>, along with the other required dependencies from each. This is how upgrades will be seamless from previous versions: upgrading from the old <code>jellyfin</code> to the new <code>jellyfin</code> will automatically pull in the two new subpackages and remove the old one, with no interruptions.</p>