From 2db57d64501800be6298960ad305dad3dfc4666d Mon Sep 17 00:00:00 2001 From: pannal Date: Sun, 24 Dec 2023 04:02:22 +0100 Subject: [PATCH] [script.plexmod] 0.7.3-rev2 --- script.plexmod/.gitignore | 3 + script.plexmod/LICENSE.txt | 492 + script.plexmod/README.md | 33 + script.plexmod/TESTING_SQUAD.md | 2 + script.plexmod/addon.xml | 49 + script.plexmod/changelog.txt | 655 ++ script.plexmod/default.py | 5 + script.plexmod/fanart.jpg | Bin 0 -> 71213 bytes script.plexmod/icon.png | Bin 0 -> 25724 bytes script.plexmod/lib/__init__.py | 20 + .../lib/_included_packages/__init__.py | 8 + .../_included_packages/icmplib/__init__.py | 44 + .../_included_packages/icmplib/exceptions.py | 214 + .../lib/_included_packages/icmplib/models.py | 491 + .../_included_packages/icmplib/multiping.py | 277 + .../lib/_included_packages/icmplib/ping.py | 298 + .../lib/_included_packages/icmplib/sockets.py | 806 ++ .../_included_packages/icmplib/traceroute.py | 212 + .../lib/_included_packages/icmplib/utils.py | 199 + .../_included_packages/plexnet/__init__.py | 0 .../plexnet/asyncadapter.py | 338 + .../lib/_included_packages/plexnet/audio.py | 153 + .../_included_packages/plexnet/audioobject.py | 83 + .../_included_packages/plexnet/callback.py | 54 + .../_included_packages/plexnet/captions.py | 80 + .../lib/_included_packages/plexnet/compat.py | 26 + .../_included_packages/plexnet/exceptions.py | 22 + .../lib/_included_packages/plexnet/gdm.py | 347 + .../lib/_included_packages/plexnet/http.py | 329 + .../lib/_included_packages/plexnet/locks.py | 67 + .../lib/_included_packages/plexnet/media.py | 258 + .../_included_packages/plexnet/mediachoice.py | 55 + .../plexnet/mediadecisionengine.py | 510 + .../lib/_included_packages/plexnet/myplex.py | 92 + .../plexnet/myplexaccount.py | 323 + .../plexnet/myplexmanager.py | 79 + .../plexnet/myplexrequest.py | 13 + .../plexnet/myplexserver.py | 36 + .../plexnet/netif/__init__.py | 217 + .../plexnet/netif/getifaddrs.py | 192 + .../plexnet/netif/ipconfig.py | 58 + .../plexnet/netif/winpsif.py | 22 + .../plexnet/nowplayingmanager.py | 215 + .../lib/_included_packages/plexnet/photo.py | 63 + .../_included_packages/plexnet/playlist.py | 183 + .../_included_packages/plexnet/playqueue.py | 786 ++ .../lib/_included_packages/plexnet/plexapp.py | 403 + .../plexnet/plexconnection.py | 284 + .../_included_packages/plexnet/plexlibrary.py | 634 ++ .../_included_packages/plexnet/plexmedia.py | 154 + .../_included_packages/plexnet/plexobjects.py | 572 ++ .../_included_packages/plexnet/plexpart.py | 178 + .../_included_packages/plexnet/plexplayer.py | 934 ++ .../_included_packages/plexnet/plexrequest.py | 46 + .../plexnet/plexresource.py | 231 + .../_included_packages/plexnet/plexresult.py | 102 + .../_included_packages/plexnet/plexserver.py | 700 ++ .../plexnet/plexservermanager.py | 651 ++ .../_included_packages/plexnet/plexstream.py | 195 + .../plexnet/serverdecision.py | 102 + .../plexnet/signalslot/__init__.py | 11 + .../plexnet/signalslot/contrib/__init__.py | 0 .../signalslot/contrib/task/__init__.py | 1 + .../plexnet/signalslot/contrib/task/task.py | 76 + .../plexnet/signalslot/contrib/task/test.py | 185 + .../plexnet/signalslot/exceptions.py | 28 + .../plexnet/signalslot/signal.py | 176 + .../plexnet/signalslot/slot.py | 74 + .../plexnet/signalslot/tests.py | 206 + .../plexnet/signalsmixin.py | 41 + .../plexnet/simpleobjects.py | 21 + .../_included_packages/plexnet/threadutils.py | 94 + .../lib/_included_packages/plexnet/util.py | 311 + .../lib/_included_packages/plexnet/verlib.py | 329 + .../lib/_included_packages/plexnet/video.py | 782 ++ .../plexnet/videosession.py | 416 + script.plexmod/lib/backgroundthread.py | 255 + script.plexmod/lib/colors.py | 79 + script.plexmod/lib/compat.py | 21 + script.plexmod/lib/distro.py | 1399 +++ script.plexmod/lib/exceptions.py | 4 + script.plexmod/lib/image.py | 12 + script.plexmod/lib/kodijsonrpc.py | 106 + script.plexmod/lib/main.py | 178 + script.plexmod/lib/metadata.py | 34 + script.plexmod/lib/playback_utils.py | 201 + script.plexmod/lib/player.py | 1480 +++ script.plexmod/lib/plex.py | 454 + script.plexmod/lib/util.py | 1009 ++ script.plexmod/lib/windows/__init__.py | 5 + script.plexmod/lib/windows/background.py | 43 + script.plexmod/lib/windows/busy.py | 142 + script.plexmod/lib/windows/currentplaylist.py | 337 + script.plexmod/lib/windows/dropdown.py | 247 + script.plexmod/lib/windows/episodes.py | 1202 +++ script.plexmod/lib/windows/home.py | 1388 +++ script.plexmod/lib/windows/info.py | 149 + script.plexmod/lib/windows/kodigui.py | 1105 +++ script.plexmod/lib/windows/library.py | 1868 ++++ script.plexmod/lib/windows/mixins.py | 61 + script.plexmod/lib/windows/musicplayer.py | 169 + script.plexmod/lib/windows/opener.py | 169 + script.plexmod/lib/windows/optionsdialog.py | 55 + script.plexmod/lib/windows/pagination.py | 274 + script.plexmod/lib/windows/photos.py | 530 + .../lib/windows/playbacksettings.py | 64 + .../lib/windows/playerbackground.py | 54 + script.plexmod/lib/windows/playersettings.py | 340 + script.plexmod/lib/windows/playlist.py | 325 + script.plexmod/lib/windows/playlists.py | 138 + script.plexmod/lib/windows/preplay.py | 720 ++ script.plexmod/lib/windows/preplayutils.py | 35 + script.plexmod/lib/windows/search.py | 435 + script.plexmod/lib/windows/seekdialog.py | 2204 ++++ script.plexmod/lib/windows/settings.py | 836 ++ script.plexmod/lib/windows/signin.py | 146 + script.plexmod/lib/windows/slidehshow.py | 108 + script.plexmod/lib/windows/subitems.py | 647 ++ script.plexmod/lib/windows/tracks.py | 348 + script.plexmod/lib/windows/userselect.py | 234 + script.plexmod/lib/windows/videoplayer.py | 596 ++ script.plexmod/lib/windows/windowutils.py | 84 + script.plexmod/plugin.py | 75 + script.plexmod/pm4k_cache_template.xml | 5 + .../resource.language.cs_cz/strings.po | 927 ++ .../resource.language.de_de/strings.po | 1946 ++++ .../resource.language.en_gb/strings.po | 1647 +++ .../resource.language.es_es/strings.po | 951 ++ .../resource.language.fr_fr/strings.po | 953 ++ .../resource.language.hu_hu/strings.po | 928 ++ .../resource.language.it_it/strings.po | 951 ++ .../resource.language.pl_pl/strings.po | 984 ++ .../resource.language.pt_br/strings.po | 951 ++ .../resource.language.pt_pt/strings.po | 980 ++ .../resource.language.ru_ru/strings.po | 951 ++ .../resource.language.zh_cn/strings.po | 1075 ++ script.plexmod/resources/settings.xml | 335 + .../skins/Main/1080i/script-plex-album.xml | 628 ++ .../skins/Main/1080i/script-plex-artist.xml | 527 + .../Main/1080i/script-plex-background.xml | 65 + .../skins/Main/1080i/script-plex-blank.xml | 12 + .../skins/Main/1080i/script-plex-busy.xml | 28 + .../skins/Main/1080i/script-plex-busy_msg.xml | 35 + .../skins/Main/1080i/script-plex-dropdown.xml | 201 + .../1080i/script-plex-dropdown_header.xml | 247 + .../skins/Main/1080i/script-plex-episodes.xml | 1820 ++++ .../skins/Main/1080i/script-plex-home.xml | 8622 ++++++++++++++++ .../skins/Main/1080i/script-plex-info.xml | 281 + .../script-plex-listview-16x9-chunked.xml | 879 ++ .../Main/1080i/script-plex-listview-16x9.xml | 842 ++ .../script-plex-listview-square-chunked.xml | 943 ++ .../1080i/script-plex-listview-square.xml | 908 ++ .../script-plex-music_current_playlist.xml | 790 ++ .../Main/1080i/script-plex-music_player.xml | 578 ++ .../Main/1080i/script-plex-options_dialog.xml | 136 + .../skins/Main/1080i/script-plex-photo.xml | 717 ++ .../Main/1080i/script-plex-pin_login.xml | 82 + .../skins/Main/1080i/script-plex-playlist.xml | 883 ++ .../Main/1080i/script-plex-playlists.xml | 567 ++ .../Main/1080i/script-plex-plex_pass.xml | 39 + .../Main/1080i/script-plex-posters-small.xml | 877 ++ .../skins/Main/1080i/script-plex-posters.xml | 851 ++ .../skins/Main/1080i/script-plex-pre_play.xml | 1494 +++ .../Main/1080i/script-plex-pre_signin.xml | 39 + .../Main/1080i/script-plex-refresh_code.xml | 39 + .../skins/Main/1080i/script-plex-search.xml | 8839 +++++++++++++++++ .../skins/Main/1080i/script-plex-seasons.xml | 1361 +++ .../Main/1080i/script-plex-seek_dialog.xml | 1106 +++ .../skins/Main/1080i/script-plex-settings.xml | 684 ++ .../script-plex-settings_select_dialog.xml | 94 + .../1080i/script-plex-signin_background.xml | 21 + .../Main/1080i/script-plex-signin_blank.xml | 49 + .../Main/1080i/script-plex-slideshow.xml | 63 + .../skins/Main/1080i/script-plex-squares.xml | 769 ++ .../Main/1080i/script-plex-track_context.xml | 67 + .../Main/1080i/script-plex-user_select.xml | 901 ++ .../script-plex-video_current_playlist.xml | 480 + .../Main/1080i/script-plex-video_player.xml | 1343 +++ .../script-plex-video_settings_dialog.xml | 159 + .../Main/media/script.plex/busy-back.png | Bin 0 -> 1280 bytes .../Main/media/script.plex/busy-diffuse.png | Bin 0 -> 356 bytes .../skins/Main/media/script.plex/busy.gif | Bin 0 -> 739 bytes .../media/script.plex/buttons/blank-focus.png | Bin 0 -> 2808 bytes .../Main/media/script.plex/buttons/blank.png | Bin 0 -> 436 bytes .../script.plex/buttons/chapters-focus.png | Bin 0 -> 3360 bytes .../media/script.plex/buttons/chapters.png | Bin 0 -> 596 bytes .../media/script.plex/buttons/home-focus.png | Bin 0 -> 1303 bytes .../Main/media/script.plex/buttons/home.png | Bin 0 -> 845 bytes .../media/script.plex/buttons/info-focus.png | Bin 0 -> 4487 bytes .../Main/media/script.plex/buttons/info.png | Bin 0 -> 1263 bytes .../media/script.plex/buttons/media-focus.png | Bin 0 -> 3780 bytes .../Main/media/script.plex/buttons/media.png | Bin 0 -> 825 bytes .../media/script.plex/buttons/more-focus.png | Bin 0 -> 3286 bytes .../script.plex/buttons/more-vertical.png | Bin 0 -> 433 bytes .../Main/media/script.plex/buttons/more.png | Bin 0 -> 663 bytes .../media/script.plex/buttons/next-focus.png | Bin 0 -> 3894 bytes .../Main/media/script.plex/buttons/next.png | Bin 0 -> 923 bytes .../media/script.plex/buttons/pause-focus.png | Bin 0 -> 3269 bytes .../Main/media/script.plex/buttons/pause.png | Bin 0 -> 493 bytes .../media/script.plex/buttons/play-focus.png | Bin 0 -> 3790 bytes .../Main/media/script.plex/buttons/play.png | Bin 0 -> 910 bytes .../Main/media/script.plex/buttons/power.png | Bin 0 -> 868 bytes .../script.plex/buttons/pqueue-focus.png | Bin 0 -> 4124 bytes .../Main/media/script.plex/buttons/pqueue.png | Bin 0 -> 1052 bytes .../script.plex/buttons/repeat-focus.png | Bin 0 -> 3473 bytes .../script.plex/buttons/repeat-one-focus.png | Bin 0 -> 3645 bytes .../media/script.plex/buttons/repeat-one.png | Bin 0 -> 873 bytes .../Main/media/script.plex/buttons/repeat.png | Bin 0 -> 752 bytes .../script.plex/buttons/resume-focus.png | Bin 0 -> 3414 bytes .../Main/media/script.plex/buttons/resume.png | Bin 0 -> 756 bytes .../script.plex/buttons/role-selected.png | Bin 0 -> 13304 bytes .../media/script.plex/buttons/role-shadow.png | Bin 0 -> 13171 bytes .../script.plex/buttons/rotate-focus.png | Bin 0 -> 4439 bytes .../Main/media/script.plex/buttons/rotate.png | Bin 0 -> 1317 bytes .../script.plex/buttons/search-focus.png | Bin 0 -> 1526 bytes .../Main/media/script.plex/buttons/search.png | Bin 0 -> 861 bytes .../script.plex/buttons/settings-focus.png | Bin 0 -> 4159 bytes .../media/script.plex/buttons/settings.png | Bin 0 -> 1079 bytes .../script.plex/buttons/shuffle-focus.png | Bin 0 -> 4873 bytes .../media/script.plex/buttons/shuffle.png | Bin 0 -> 1407 bytes .../buttons/skip-forward-focus.png | Bin 0 -> 5065 bytes .../script.plex/buttons/skip-forward.png | Bin 0 -> 1223 bytes .../script.plex/buttons/square2x2-focus.png | Bin 0 -> 3445 bytes .../media/script.plex/buttons/square2x2.png | Bin 0 -> 539 bytes .../media/script.plex/buttons/stop-focus.png | Bin 0 -> 3402 bytes .../Main/media/script.plex/buttons/stop.png | Bin 0 -> 474 bytes .../script.plex/buttons/subtitle-focus.png | Bin 0 -> 4620 bytes .../media/script.plex/buttons/subtitle.png | Bin 0 -> 1072 bytes .../media/script.plex/buttons/tags-focus.png | Bin 0 -> 5419 bytes .../Main/media/script.plex/buttons/tags.png | Bin 0 -> 1601 bytes .../script.plex/buttons/trailer-focus.png | Bin 0 -> 5999 bytes .../media/script.plex/buttons/trailer.png | Bin 0 -> 1899 bytes .../media/script.plex/circle-progress/0.png | Bin 0 -> 420 bytes .../media/script.plex/circle-progress/1.png | Bin 0 -> 516 bytes .../media/script.plex/circle-progress/10.png | Bin 0 -> 1500 bytes .../media/script.plex/circle-progress/11.png | Bin 0 -> 1613 bytes .../media/script.plex/circle-progress/12.png | Bin 0 -> 1733 bytes .../media/script.plex/circle-progress/13.png | Bin 0 -> 1764 bytes .../media/script.plex/circle-progress/14.png | Bin 0 -> 1818 bytes .../media/script.plex/circle-progress/15.png | Bin 0 -> 1824 bytes .../media/script.plex/circle-progress/2.png | Bin 0 -> 641 bytes .../media/script.plex/circle-progress/3.png | Bin 0 -> 770 bytes .../media/script.plex/circle-progress/4.png | Bin 0 -> 914 bytes .../media/script.plex/circle-progress/5.png | Bin 0 -> 1006 bytes .../media/script.plex/circle-progress/6.png | Bin 0 -> 1063 bytes .../media/script.plex/circle-progress/7.png | Bin 0 -> 1142 bytes .../media/script.plex/circle-progress/8.png | Bin 0 -> 1269 bytes .../media/script.plex/circle-progress/9.png | Bin 0 -> 1391 bytes .../Main/media/script.plex/drop-shadow.png | Bin 0 -> 1819 bytes .../Main/media/script.plex/gray-square.png | Bin 0 -> 155 bytes .../media/script.plex/home/avatar-diffuse.png | Bin 0 -> 589 bytes .../script.plex/home/background-fallback.png | Bin 0 -> 188030 bytes .../Main/media/script.plex/home/busy.gif | Bin 0 -> 58766 bytes .../media/script.plex/home/device/check.png | Bin 0 -> 520 bytes .../media/script.plex/home/device/error.png | Bin 0 -> 1217 bytes .../home/device/focus-refreshing.gif | Bin 0 -> 6211 bytes .../script.plex/home/device/focus-secure.png | Bin 0 -> 561 bytes .../script.plex/home/device/focus-unknown.png | Bin 0 -> 561 bytes .../home/device/focus-unreachable.png | Bin 0 -> 506 bytes .../media/script.plex/home/device/home.png | Bin 0 -> 367 bytes .../script.plex/home/device/home_small.png | Bin 0 -> 300 bytes .../script.plex/home/device/lock-24px.png | Bin 0 -> 598 bytes .../media/script.plex/home/device/lock.png | Bin 0 -> 630 bytes .../media/script.plex/home/device/plex.png | Bin 0 -> 4939 bytes .../script.plex/home/device/refreshing.gif | Bin 0 -> 6238 bytes .../media/script.plex/home/device/secure.png | Bin 0 -> 674 bytes .../media/script.plex/home/device/unknown.png | Bin 0 -> 664 bytes .../script.plex/home/device/unreachable.png | Bin 0 -> 651 bytes .../Main/media/script.plex/home/plex.png | Bin 0 -> 1579 bytes .../script.plex/home/selected-section.png | Bin 0 -> 6642 bytes .../Main/media/script.plex/home/selected.png | Bin 0 -> 851 bytes .../media/script.plex/home/type/artist.png | Bin 0 -> 1331 bytes .../media/script.plex/home/type/channels.png | Bin 0 -> 298 bytes .../script.plex/home/type/home-selected.png | Bin 0 -> 7286 bytes .../Main/media/script.plex/home/type/home.png | Bin 0 -> 1846 bytes .../media/script.plex/home/type/movie.png | Bin 0 -> 1107 bytes .../media/script.plex/home/type/photo.png | Bin 0 -> 1252 bytes .../media/script.plex/home/type/playlists.png | Bin 0 -> 268 bytes .../Main/media/script.plex/home/type/show.png | Bin 0 -> 396 bytes .../script.plex/indicators/arrow-down.png | Bin 0 -> 409 bytes .../media/script.plex/indicators/arrow-up.png | Bin 0 -> 403 bytes .../script.plex/indicators/busy-photo.gif | Bin 0 -> 62280 bytes .../media/script.plex/indicators/camera.png | Bin 0 -> 634 bytes .../indicators/chevron-white-l.png | Bin 0 -> 1127 bytes .../script.plex/indicators/chevron-white.png | Bin 0 -> 564 bytes .../script.plex/indicators/circle-152.png | Bin 0 -> 4185 bytes .../script.plex/indicators/circle-19.png | Bin 0 -> 316 bytes .../script.plex/indicators/cornerbox.png | Bin 0 -> 317 bytes .../indicators/dropdown-triangle.png | Bin 0 -> 275 bytes .../media/script.plex/indicators/info-sep.png | Bin 0 -> 178 bytes .../media/script.plex/indicators/pause.png | Bin 0 -> 212 bytes .../indicators/player-selection-time.png | Bin 0 -> 446 bytes .../player-selection-time_arrow.png | Bin 0 -> 249 bytes .../indicators/player-selection-time_box.png | Bin 0 -> 335 bytes .../script.plex/indicators/playing-circle.png | Bin 0 -> 680 bytes .../media/script.plex/indicators/remove.png | Bin 0 -> 450 bytes .../media/script.plex/indicators/replay.png | Bin 0 -> 1168 bytes .../indicators/seek-selection-marker.png | Bin 0 -> 339 bytes .../media/script.plex/indicators/spinner.png | Bin 0 -> 824 bytes .../indicators/unwatched-rounded.png | Bin 0 -> 2180 bytes .../script.plex/indicators/unwatched.png | Bin 0 -> 2112 bytes .../masks/listview-16x9-backgroundmask.png | Bin 0 -> 1204 bytes .../Main/media/script.plex/masks/role.png | Bin 0 -> 4606 bytes .../Main/media/script.plex/player-fade.png | Bin 0 -> 332 bytes .../Main/media/script.plex/progress/0.png | Bin 0 -> 154 bytes .../Main/media/script.plex/progress/10.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/100.png | Bin 0 -> 156 bytes .../Main/media/script.plex/progress/12.png | Bin 0 -> 163 bytes .../Main/media/script.plex/progress/14.png | Bin 0 -> 163 bytes .../Main/media/script.plex/progress/16.png | Bin 0 -> 163 bytes .../Main/media/script.plex/progress/18.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/2.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/20.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/22.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/24.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/26.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/28.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/30.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/32.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/34.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/36.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/38.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/4.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/40.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/42.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/44.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/46.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/48.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/50.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/52.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/54.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/56.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/58.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/6.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/60.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/62.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/64.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/66.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/68.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/70.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/72.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/74.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/76.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/78.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/8.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/80.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/82.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/84.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/86.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/88.png | Bin 0 -> 164 bytes .../Main/media/script.plex/progress/90.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/92.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/94.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/96.png | Bin 0 -> 165 bytes .../Main/media/script.plex/progress/98.png | Bin 0 -> 165 bytes .../script.plex/ratings/imdb/image.rating.png | Bin 0 -> 2909 bytes .../ratings/other/image.rating.png | Bin 0 -> 662 bytes .../rottentomatoes/image.rating.certified.png | Bin 0 -> 2754 bytes .../rottentomatoes/image.rating.plus.png | Bin 0 -> 462 bytes .../rottentomatoes/image.rating.ripe.png | Bin 0 -> 1990 bytes .../rottentomatoes/image.rating.rotten.png | Bin 0 -> 2358 bytes .../rottentomatoes/image.rating.spilled.png | Bin 0 -> 2802 bytes .../rottentomatoes/image.rating.upright.png | Bin 0 -> 2108 bytes .../script.plex/ratings/tmdb/image.rating.png | Bin 0 -> 1243 bytes .../reviews/image.review.fresh.png | Bin 0 -> 1238 bytes .../reviews/image.review.rotten.png | Bin 0 -> 1306 bytes .../media/script.plex/section_type/movie.png | Bin 0 -> 16177 bytes .../media/script.plex/section_type/music.png | Bin 0 -> 16307 bytes .../media/script.plex/section_type/photo.png | Bin 0 -> 16385 bytes .../media/script.plex/section_type/show.png | Bin 0 -> 15762 bytes .../media/script.plex/settings/checkbox.png | Bin 0 -> 364 bytes .../media/script.plex/settings/checkmark.png | Bin 0 -> 512 bytes .../media/script.plex/settings/expanded.png | Bin 0 -> 338 bytes .../Main/media/script.plex/sign_in/back.jpg | Bin 0 -> 130557 bytes .../media/script.plex/sign_in/digits/0.png | Bin 0 -> 4573 bytes .../media/script.plex/sign_in/digits/1.png | Bin 0 -> 713 bytes .../media/script.plex/sign_in/digits/2.png | Bin 0 -> 3368 bytes .../media/script.plex/sign_in/digits/3.png | Bin 0 -> 4067 bytes .../media/script.plex/sign_in/digits/4.png | Bin 0 -> 2566 bytes .../media/script.plex/sign_in/digits/5.png | Bin 0 -> 2997 bytes .../media/script.plex/sign_in/digits/6.png | Bin 0 -> 5154 bytes .../media/script.plex/sign_in/digits/7.png | Bin 0 -> 2246 bytes .../media/script.plex/sign_in/digits/8.png | Bin 0 -> 5382 bytes .../media/script.plex/sign_in/digits/9.png | Bin 0 -> 5106 bytes .../media/script.plex/sign_in/digits/A.png | Bin 0 -> 4290 bytes .../media/script.plex/sign_in/digits/B.png | Bin 0 -> 3575 bytes .../media/script.plex/sign_in/digits/C.png | Bin 0 -> 4192 bytes .../media/script.plex/sign_in/digits/D.png | Bin 0 -> 3586 bytes .../media/script.plex/sign_in/digits/E.png | Bin 0 -> 552 bytes .../media/script.plex/sign_in/digits/F.png | Bin 0 -> 539 bytes .../media/script.plex/sign_in/digits/G.png | Bin 0 -> 4383 bytes .../media/script.plex/sign_in/digits/H.png | Bin 0 -> 537 bytes .../media/script.plex/sign_in/digits/I.png | Bin 0 -> 511 bytes .../media/script.plex/sign_in/digits/J.png | Bin 0 -> 1134 bytes .../media/script.plex/sign_in/digits/K.png | Bin 0 -> 3368 bytes .../media/script.plex/sign_in/digits/L.png | Bin 0 -> 525 bytes .../media/script.plex/sign_in/digits/M.png | Bin 0 -> 4291 bytes .../media/script.plex/sign_in/digits/N.png | Bin 0 -> 3641 bytes .../media/script.plex/sign_in/digits/O.png | Bin 0 -> 5231 bytes .../media/script.plex/sign_in/digits/P.png | Bin 0 -> 2346 bytes .../media/script.plex/sign_in/digits/Q.png | Bin 0 -> 5435 bytes .../media/script.plex/sign_in/digits/R.png | Bin 0 -> 3523 bytes .../media/script.plex/sign_in/digits/S.png | Bin 0 -> 4454 bytes .../media/script.plex/sign_in/digits/T.png | Bin 0 -> 520 bytes .../media/script.plex/sign_in/digits/U.png | Bin 0 -> 2371 bytes .../media/script.plex/sign_in/digits/V.png | Bin 0 -> 4241 bytes .../media/script.plex/sign_in/digits/W.png | Bin 0 -> 5489 bytes .../media/script.plex/sign_in/digits/X.png | Bin 0 -> 4200 bytes .../media/script.plex/sign_in/digits/Y.png | Bin 0 -> 2372 bytes .../media/script.plex/sign_in/digits/Z.png | Bin 0 -> 2550 bytes .../script.plex/sign_in/generating-code.jpg | Bin 0 -> 110012 bytes .../script.plex/sign_in/linking-account.jpg | Bin 0 -> 113729 bytes .../media/script.plex/sign_in/pin-display.jpg | Bin 0 -> 131456 bytes .../media/script.plex/sign_in/plexpass.jpg | Bin 0 -> 147243 bytes .../media/script.plex/sign_in/pre-signin.jpg | Bin 0 -> 309135 bytes .../script.plex/sign_in/refresh-code.jpg | Bin 0 -> 128150 bytes .../skins/Main/media/script.plex/splash.png | Bin 0 -> 9464 bytes .../script.plex/square-rounded-shadow.png | Bin 0 -> 3941 bytes .../skins/Main/media/script.plex/stars/0.png | Bin 0 -> 679 bytes .../skins/Main/media/script.plex/stars/1.png | Bin 0 -> 700 bytes .../skins/Main/media/script.plex/stars/2.png | Bin 0 -> 699 bytes .../skins/Main/media/script.plex/stars/3.png | Bin 0 -> 697 bytes .../skins/Main/media/script.plex/stars/4.png | Bin 0 -> 686 bytes .../skins/Main/media/script.plex/stars/5.png | Bin 0 -> 568 bytes .../thumb_fallbacks/broken-photo-thumb.png | Bin 0 -> 98851 bytes .../thumb_fallbacks/broken-photo.png | Bin 0 -> 5551 bytes .../script.plex/thumb_fallbacks/movie.png | Bin 0 -> 13306 bytes .../script.plex/thumb_fallbacks/movie16x9.png | Bin 0 -> 17652 bytes .../script.plex/thumb_fallbacks/music.png | Bin 0 -> 16467 bytes .../script.plex/thumb_fallbacks/photo.png | Bin 0 -> 16984 bytes .../script.plex/thumb_fallbacks/role.png | Bin 0 -> 43891 bytes .../script.plex/thumb_fallbacks/show.png | Bin 0 -> 12438 bytes .../media/script.plex/transparent-6px.png | Bin 0 -> 160 bytes .../script.plex/user_select/admin-back.png | Bin 0 -> 719 bytes .../script.plex/user_select/admin-icon.png | Bin 0 -> 954 bytes .../user_select/avatar-background.png | Bin 0 -> 3476 bytes .../user_select/avatar-diffuse.png | Bin 0 -> 3224 bytes .../script.plex/user_select/backspace.png | Bin 0 -> 966 bytes .../script.plex/user_select/backspace_nf.png | Bin 0 -> 938 bytes .../user_select/item-background-bottom.png | Bin 0 -> 421 bytes .../user_select/item-background-top.png | Bin 0 -> 976 bytes .../user_select/item-background.png | Bin 0 -> 1022 bytes .../media/script.plex/user_select/plex.png | Bin 0 -> 5374 bytes .../user_select/protected-back.png | Bin 0 -> 719 bytes .../user_select/protected-icon.png | Bin 0 -> 688 bytes .../script.plex/white-outline-rounded.png | Bin 0 -> 537 bytes .../media/script.plex/white-square-1px.png | Bin 0 -> 146 bytes .../media/script.plex/white-square-6px.png | Bin 0 -> 155 bytes .../script.plex/white-square-left-rounded.png | Bin 0 -> 404 bytes .../script.plex/white-square-rounded-4r.png | Bin 0 -> 228 bytes .../white-square-rounded-top-padded.png | Bin 0 -> 464 bytes .../white-square-rounded-with-shadow.png | Bin 0 -> 3060 bytes .../script.plex/white-square-rounded.png | Bin 0 -> 457 bytes .../script.plex/white-square-tl-rounded.png | Bin 0 -> 365 bytes .../script.plex/white-square-top-rounded.png | Bin 0 -> 403 bytes .../Main/media/script.plex/white-square.png | Bin 0 -> 155 bytes script.plexmod/resources/skins/Main/skin.xml | 14 + script.plexmod/screensaver.py | 24 + script.plexmod/service.py | 21 + 459 files changed, 89420 insertions(+) create mode 100644 script.plexmod/.gitignore create mode 100644 script.plexmod/LICENSE.txt create mode 100644 script.plexmod/README.md create mode 100644 script.plexmod/TESTING_SQUAD.md create mode 100644 script.plexmod/addon.xml create mode 100644 script.plexmod/changelog.txt create mode 100644 script.plexmod/default.py create mode 100644 script.plexmod/fanart.jpg create mode 100644 script.plexmod/icon.png create mode 100644 script.plexmod/lib/__init__.py create mode 100644 script.plexmod/lib/_included_packages/__init__.py create mode 100644 script.plexmod/lib/_included_packages/icmplib/__init__.py create mode 100644 script.plexmod/lib/_included_packages/icmplib/exceptions.py create mode 100644 script.plexmod/lib/_included_packages/icmplib/models.py create mode 100644 script.plexmod/lib/_included_packages/icmplib/multiping.py create mode 100644 script.plexmod/lib/_included_packages/icmplib/ping.py create mode 100644 script.plexmod/lib/_included_packages/icmplib/sockets.py create mode 100644 script.plexmod/lib/_included_packages/icmplib/traceroute.py create mode 100644 script.plexmod/lib/_included_packages/icmplib/utils.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/__init__.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/asyncadapter.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/audio.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/audioobject.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/callback.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/captions.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/compat.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/exceptions.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/gdm.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/http.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/locks.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/media.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/mediachoice.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/mediadecisionengine.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/myplex.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/myplexaccount.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/myplexmanager.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/myplexrequest.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/myplexserver.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/netif/__init__.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/netif/getifaddrs.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/netif/ipconfig.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/netif/winpsif.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/nowplayingmanager.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/photo.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/playlist.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/playqueue.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexapp.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexconnection.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexlibrary.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexmedia.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexobjects.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexpart.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexplayer.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexrequest.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexresource.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexresult.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexserver.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexservermanager.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/plexstream.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/serverdecision.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/signalslot/__init__.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/__init__.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/__init__.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/task.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/test.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/signalslot/exceptions.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/signalslot/signal.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/signalslot/slot.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/signalslot/tests.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/signalsmixin.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/simpleobjects.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/threadutils.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/util.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/verlib.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/video.py create mode 100644 script.plexmod/lib/_included_packages/plexnet/videosession.py create mode 100644 script.plexmod/lib/backgroundthread.py create mode 100644 script.plexmod/lib/colors.py create mode 100644 script.plexmod/lib/compat.py create mode 100644 script.plexmod/lib/distro.py create mode 100644 script.plexmod/lib/exceptions.py create mode 100644 script.plexmod/lib/image.py create mode 100644 script.plexmod/lib/kodijsonrpc.py create mode 100644 script.plexmod/lib/main.py create mode 100644 script.plexmod/lib/metadata.py create mode 100644 script.plexmod/lib/playback_utils.py create mode 100644 script.plexmod/lib/player.py create mode 100644 script.plexmod/lib/plex.py create mode 100644 script.plexmod/lib/util.py create mode 100644 script.plexmod/lib/windows/__init__.py create mode 100644 script.plexmod/lib/windows/background.py create mode 100644 script.plexmod/lib/windows/busy.py create mode 100644 script.plexmod/lib/windows/currentplaylist.py create mode 100644 script.plexmod/lib/windows/dropdown.py create mode 100644 script.plexmod/lib/windows/episodes.py create mode 100644 script.plexmod/lib/windows/home.py create mode 100644 script.plexmod/lib/windows/info.py create mode 100644 script.plexmod/lib/windows/kodigui.py create mode 100644 script.plexmod/lib/windows/library.py create mode 100644 script.plexmod/lib/windows/mixins.py create mode 100644 script.plexmod/lib/windows/musicplayer.py create mode 100644 script.plexmod/lib/windows/opener.py create mode 100644 script.plexmod/lib/windows/optionsdialog.py create mode 100644 script.plexmod/lib/windows/pagination.py create mode 100644 script.plexmod/lib/windows/photos.py create mode 100644 script.plexmod/lib/windows/playbacksettings.py create mode 100644 script.plexmod/lib/windows/playerbackground.py create mode 100644 script.plexmod/lib/windows/playersettings.py create mode 100644 script.plexmod/lib/windows/playlist.py create mode 100644 script.plexmod/lib/windows/playlists.py create mode 100644 script.plexmod/lib/windows/preplay.py create mode 100644 script.plexmod/lib/windows/preplayutils.py create mode 100644 script.plexmod/lib/windows/search.py create mode 100644 script.plexmod/lib/windows/seekdialog.py create mode 100644 script.plexmod/lib/windows/settings.py create mode 100644 script.plexmod/lib/windows/signin.py create mode 100644 script.plexmod/lib/windows/slidehshow.py create mode 100644 script.plexmod/lib/windows/subitems.py create mode 100644 script.plexmod/lib/windows/tracks.py create mode 100644 script.plexmod/lib/windows/userselect.py create mode 100644 script.plexmod/lib/windows/videoplayer.py create mode 100644 script.plexmod/lib/windows/windowutils.py create mode 100644 script.plexmod/plugin.py create mode 100644 script.plexmod/pm4k_cache_template.xml create mode 100644 script.plexmod/resources/language/resource.language.cs_cz/strings.po create mode 100644 script.plexmod/resources/language/resource.language.de_de/strings.po create mode 100644 script.plexmod/resources/language/resource.language.en_gb/strings.po create mode 100644 script.plexmod/resources/language/resource.language.es_es/strings.po create mode 100644 script.plexmod/resources/language/resource.language.fr_fr/strings.po create mode 100644 script.plexmod/resources/language/resource.language.hu_hu/strings.po create mode 100644 script.plexmod/resources/language/resource.language.it_it/strings.po create mode 100644 script.plexmod/resources/language/resource.language.pl_pl/strings.po create mode 100644 script.plexmod/resources/language/resource.language.pt_br/strings.po create mode 100644 script.plexmod/resources/language/resource.language.pt_pt/strings.po create mode 100644 script.plexmod/resources/language/resource.language.ru_ru/strings.po create mode 100644 script.plexmod/resources/language/resource.language.zh_cn/strings.po create mode 100644 script.plexmod/resources/settings.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-album.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-artist.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-background.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-blank.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-busy.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-busy_msg.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-dropdown.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-dropdown_header.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-episodes.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-home.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-info.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9-chunked.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-listview-square-chunked.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-listview-square.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-music_current_playlist.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-music_player.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-options_dialog.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-photo.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-pin_login.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-playlist.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-playlists.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-plex_pass.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-posters-small.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-posters.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-pre_play.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-pre_signin.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-refresh_code.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-search.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-seasons.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-settings.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-settings_select_dialog.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-signin_background.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-signin_blank.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-slideshow.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-squares.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-track_context.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-user_select.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-video_current_playlist.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-video_player.xml create mode 100644 script.plexmod/resources/skins/Main/1080i/script-plex-video_settings_dialog.xml create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/busy-back.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/busy-diffuse.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/busy.gif create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/blank-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/blank.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/chapters-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/chapters.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/home-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/home.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/info-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/info.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/media-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/media.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/more-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/more-vertical.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/more.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/next-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/next.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/pause-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/pause.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/play-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/play.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/power.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/pqueue-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/pqueue.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/repeat-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/repeat-one-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/repeat-one.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/repeat.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/resume-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/resume.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/role-selected.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/role-shadow.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/rotate-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/rotate.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/search-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/search.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/settings-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/settings.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/shuffle-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/shuffle.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/skip-forward-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/skip-forward.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/square2x2-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/square2x2.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/stop-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/stop.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/subtitle-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/subtitle.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/tags-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/tags.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/trailer-focus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/buttons/trailer.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/0.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/1.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/10.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/11.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/12.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/13.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/14.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/15.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/2.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/3.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/4.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/5.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/6.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/7.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/8.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/circle-progress/9.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/drop-shadow.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/gray-square.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/avatar-diffuse.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/background-fallback.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/busy.gif create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/check.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/error.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/focus-refreshing.gif create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/focus-secure.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/focus-unknown.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/focus-unreachable.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/home.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/home_small.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/lock-24px.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/lock.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/plex.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/refreshing.gif create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/secure.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/unknown.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/device/unreachable.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/plex.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/selected-section.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/selected.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/type/artist.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/type/channels.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/type/home-selected.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/type/home.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/type/movie.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/type/photo.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/type/playlists.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/home/type/show.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/arrow-down.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/arrow-up.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/busy-photo.gif create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/camera.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/chevron-white-l.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/chevron-white.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/circle-152.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/circle-19.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/cornerbox.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/dropdown-triangle.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/info-sep.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/pause.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/player-selection-time.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/player-selection-time_arrow.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/player-selection-time_box.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/playing-circle.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/remove.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/replay.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/seek-selection-marker.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/spinner.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/unwatched-rounded.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/indicators/unwatched.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/masks/listview-16x9-backgroundmask.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/masks/role.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/player-fade.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/0.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/10.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/100.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/12.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/14.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/16.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/18.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/2.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/20.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/22.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/24.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/26.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/28.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/30.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/32.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/34.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/36.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/38.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/4.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/40.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/42.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/44.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/46.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/48.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/50.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/52.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/54.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/56.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/58.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/6.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/60.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/62.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/64.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/66.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/68.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/70.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/72.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/74.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/76.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/78.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/8.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/80.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/82.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/84.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/86.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/88.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/90.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/92.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/94.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/96.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/progress/98.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/ratings/imdb/image.rating.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/ratings/other/image.rating.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.certified.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.plus.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.ripe.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.rotten.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.spilled.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.upright.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/ratings/tmdb/image.rating.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/reviews/image.review.fresh.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/reviews/image.review.rotten.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/section_type/movie.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/section_type/music.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/section_type/photo.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/section_type/show.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/settings/checkbox.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/settings/checkmark.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/settings/expanded.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/back.jpg create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/0.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/1.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/2.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/3.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/4.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/5.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/6.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/7.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/8.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/9.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/A.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/B.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/C.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/D.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/E.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/F.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/G.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/H.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/I.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/J.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/K.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/L.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/M.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/N.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/O.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/P.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/Q.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/R.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/S.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/T.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/U.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/V.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/W.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/X.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/Y.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/Z.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/generating-code.jpg create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/linking-account.jpg create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/pin-display.jpg create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/plexpass.jpg create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/pre-signin.jpg create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/sign_in/refresh-code.jpg create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/splash.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/square-rounded-shadow.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/stars/0.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/stars/1.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/stars/2.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/stars/3.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/stars/4.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/stars/5.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/broken-photo-thumb.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/broken-photo.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/movie.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/movie16x9.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/music.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/photo.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/role.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/show.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/transparent-6px.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/admin-back.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/admin-icon.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/avatar-background.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/avatar-diffuse.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/backspace.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/backspace_nf.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/item-background-bottom.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/item-background-top.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/item-background.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/plex.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/protected-back.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/user_select/protected-icon.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-outline-rounded.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-square-1px.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-square-6px.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-square-left-rounded.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-square-rounded-4r.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-square-rounded-top-padded.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-square-rounded-with-shadow.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-square-rounded.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-square-tl-rounded.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-square-top-rounded.png create mode 100644 script.plexmod/resources/skins/Main/media/script.plex/white-square.png create mode 100644 script.plexmod/resources/skins/Main/skin.xml create mode 100644 script.plexmod/screensaver.py create mode 100644 script.plexmod/service.py diff --git a/script.plexmod/.gitignore b/script.plexmod/.gitignore new file mode 100644 index 0000000000..59f60a7f6f --- /dev/null +++ b/script.plexmod/.gitignore @@ -0,0 +1,3 @@ +/fixRepo.py +/resources/skins/Main/TexturePacker.exe +/resources/skins/Main/packtex.bat diff --git a/script.plexmod/LICENSE.txt b/script.plexmod/LICENSE.txt new file mode 100644 index 0000000000..6bcffb4610 --- /dev/null +++ b/script.plexmod/LICENSE.txt @@ -0,0 +1,492 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS +------------------------------------------------------------------------- + + +Some of this code has been modified from the PlexApi written by Michael Shepanski + +https://github.com/mjs7231/python-plexapi + +The license for that code follows: + +Copyright (c) 2010, Michael Shepanski +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name conky-pkmeter nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +------------------------------------------------------------------------- + +https://github.com/ValentinBELYN/icmplib + +GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + + +------------------------------------------------------------------------- +Fontawesome +https://fontawesome.com/license/free +CC BY 4.0 License: https://creativecommons.org/licenses/by/4.0/# diff --git a/script.plexmod/README.md b/script.plexmod/README.md new file mode 100644 index 0000000000..317bd7cab1 --- /dev/null +++ b/script.plexmod/README.md @@ -0,0 +1,33 @@ +# PlexMod (for Kodi) + +This is a modification of the official open-source Plex client for Kodi "plex-for-kodi" (Plex4Kodi) semi-maintained by me (pannal). + +Contrary to how this repository was handled before, this client does _not_ claim to adhere to the Plex Inc. design guidelines, all the time. + +It implements features that are not implemented in other official Plex clients and may implement others in non-conform ways. + +It is still based off of the original P4K source and critical bugfixes will be PR'd back. + +## Active branches +* [develop-kodi21](https://github.com/pannal/plex-for-kodi/tree/develop_kodi21) (Kodi 19, 20, 21 cross-compatible) +* [develop-kodi18](https://github.com/pannal/plex-for-kodi/tree/develop_kodi18) (legacy) + +Master branch is based off of the official plex-for-kodi master branch. + +## Installation + +### Via repository +* Add `https://pannal.github.io/dontpanickodi/` to your Kodi installation as a file source +* Go back to addons, choose zip file, choose the file source you added and install the repository +* Install Plex via Addons->Install from repository->Don’t Panic->Video add-ons->Plex +* Optional, recommended: Install Plextuary via Addons->Install from repository->Don’t Panic->Look and Feel->Skin->Plextuary + +### Manual +* Checkout any branch of this GitHub repository, rename to `script.plexmod` and use as an addon + + +## Help/Bug Reports +https://forums.plex.tv/t/plexmod-for-kodi-18-19-20-21/481208 + +## License +[LICENSE](https://github.com/plexinc/plex-for-kodi/blob/master/LICENSE.txt) diff --git a/script.plexmod/TESTING_SQUAD.md b/script.plexmod/TESTING_SQUAD.md new file mode 100644 index 0000000000..12506a8e37 --- /dev/null +++ b/script.plexmod/TESTING_SQUAD.md @@ -0,0 +1,2 @@ +## The Squad (TM) +@sonofdibnah @ecsjjgg @Unknown3899 @THGhost @bowlingbeeg @Buttzy10169 diff --git a/script.plexmod/addon.xml b/script.plexmod/addon.xml new file mode 100644 index 0000000000..cbda2b6cc8 --- /dev/null +++ b/script.plexmod/addon.xml @@ -0,0 +1,49 @@ + + + + + + + + + + video + + + executable + + + + PlexMod for Kodi + Unofficial Plex for Kodi add-on + GPL-2.0-only + https://forums.plex.tv/t/plexmod-for-kodi-18-19-20-21/481208 + https://www.plex.tv + https://github.com/pannal/plex-for-kodi + all + +- Fix: certain home hubs were limited to 10 items without pagination +- Fix: very rare infinite playback loop with enabled embedded subtitles (thanks @florinvlaicu for reporting) +- Fix: Partially fix issues when switching audio streams during Transcoded/DirectStream playback +- Fix: Fix error in ExtendHubTask +- Fix: Partially revert "Home: Increase section change timeout from 0.3s to 0.5s; re-jig section change handling to allow using ENTER/SELECT to immediately select a section below 0.5s wait time" due to instability +- Fix: Fix a couple of SyntaxWarnings for invalid escape sequences +- Fix: Unfocusable buttons throw focus errors occasionally on shutdown +- Fix: Laggy UI after playback/5 minutes due to requesting certain hubs without limits applied. Drastically improving UI smoothness even for smaller hubs (below 1000 items) + This also fixes crash and shutdown issues and by proxy should enable everyone to use a poster resolution scale of at least 200%. +- Fix: Depending on the situation, the home hubs update request could be sent multiple times while waiting for the first one to finish. (thanks @bowlingbeeg) +- Subtitles: Supply OpenSubtitles.com hash if possible and enabled +- Subtitles: Add setting to Audio/Subtitles to calculate the OpenSubtitles.com hash (default: off) +- Core: Advanced Settings: make default resolution scale a percentage; limit to 750% max (based on Plex max poster size) +- Core: Add more debug logging for player events +- Core: Add more debug logging details for hub refresh events + + + icon.png + fanart.jpg + + + diff --git a/script.plexmod/changelog.txt b/script.plexmod/changelog.txt new file mode 100644 index 0000000000..825da958f9 --- /dev/null +++ b/script.plexmod/changelog.txt @@ -0,0 +1,655 @@ +[- 0.7.3-rev2 -] +- Fix: certain home hubs were limited to 10 items without pagination +- Fix: very rare infinite playback loop with enabled embedded subtitles (thanks @florinvlaicu for reporting) +- Fix: Partially fix issues when switching audio streams during Transcoded/DirectStream playback +- Fix: Fix error in ExtendHubTask +- Fix: Partially revert "Home: Increase section change timeout from 0.3s to 0.5s; re-jig section change handling to allow using ENTER/SELECT to immediately select a section below 0.5s wait time" due to instability +- Fix: Fix a couple of SyntaxWarnings for invalid escape sequences +- Fix: Unfocusable buttons throw focus errors occasionally on shutdown +- Fix: Laggy UI after playback/5 minutes due to requesting certain hubs without limits applied. Drastically improving UI smoothness even for smaller hubs (<1000 items) + This also fixes crash and shutdown issues and by proxy should enable everyone to use a poster resolution scale of at least 200%. +- Fix: Depending on the situation, the home hubs update request could be sent multiple times while waiting for the first one to finish. (thanks @bowlingbeeg) +- Subtitles: Supply OpenSubtitles.com hash if possible and enabled +- Subtitles: Add setting to Audio/Subtitles to calculate the OpenSubtitles.com hash (default: off) +- Core: Advanced Settings: make default resolution scale a percentage; limit to 750% max (based on Plex max poster size) +- Core: Add more debug logging for player events +- Core: Add more debug logging details for hub refresh events + + +[- 0.7.2 -] +- Fix: playing next episode when episode played threshold was met when hitting STOP button +- Fix: Dropdown would roundrobin falsely onup item when initial item wasn't item 0 +- Fix: Movies: pressing back in a scrolled movie view with the header options open wouldn't back out properly +- Fix: Reset library filters when Role/Cast view opened +- Fix: Cast display in movies/preplay +- Fix: Apply dialog flicker fix in Role/Cast +- Fix: Dropdowns were broken sometimes (especially library view) +- Fix: Addon crash on non-default Kodi (e.g. OSMC) due to System.BuildVersion not matching Kodi's default +- Fix: Error on no data returned on PlexObject.reload (disconnect); Handle connection errors more gracefully +- Fix: Background of info page (thanks @bowlingbeeg) +- Fix: Rare SeekDialog crashes between episodes +- Fix: OpenSubtitles not finding subtitles for certain Movies + +- Core: Harden against network disconnects in multiple views, home and videoplayer/seekdialog +- Core: Re-enable backing out of videoplayer (inbetween screen) +- Core: Player: Alternative implementation of bingeMode auto-next; ignore stop events when triggering non-user-stop +- Core: Add setting for poster/thumbnail resolution scaling, implement everywhere sensible +- Core: Thumbnails/Art: use the same parameters as PlexWeb for images +- SeekDialog: Possible fix for OSD not coming up again in some scenarios + + +[- 0.7.1 -] +- Fix: Embedded subtitle could be set to the wrong one (edge case) +- Fix: Episodes: theme music error when clicking on seasons +- Possibly fix rare traceback when closing an episodes window while waiting for an episode reload task +- Fix: Core: only stop playback on screensaver if player is playing video (not audio, ...) +- Fix: rare UI crash for items before 1970-01-02 (yes, we've had media back then) + +- Set Accept-Language to Kodi's language setting when talking to the Plex Server, localizes subtitle titles, Library translations etc. +- Use extended title for subtitles (and add advanced/addon setting) +- Add: Show buffer state in stream info +- Reduce dialog flickering in certain situations (not fully, probably impossible) +- Player: bingeMode/autoskip credits/manual-next: avoid double-next in certain circumstances +- VideoPlayer: don't react to inputs while waiting for playback (AVStarted) to start (fixes early-back-out-crashes) +- SeekDialog: stop marker countdown on seek +- SeekDialog: auto-skip marker: ignore input while auto skipping to next video +- SeekDialog: only count down marker when OSD not shown +- SeekDialog: ignore input while handling next-video-pressed +- SeekDialog: hide OSD fast on ACTION_PAUSE/ACTION_PLAYER_PLAY/ACTION_PLAYER_PLAYPAUSE and OSD is shown +- Player/SeekDialog: Fix crash when handling SIGINT (alt+f4 on windows) +- Hubs: make all TV/movie hubs as hub types that receive updates after items being watched or marked (un) watched +- Settings: Disable alternative home hubs refresh by default +- ServerList: further hardening, list shouldn't visually "crash" anymore in certain conditions +- Pagination/Episodes: allow right round-robin on paginated long item lists (>26) +- Movies: Reorder Cast/Related/Extras according to PlexWeb +- Movies: Add reviews +- Cast: Increase Cast picture quality everywhere +- Core/Settings: Adjust recommended cache/buffer/readfactor values for different Kodi versions, starting with 21.0-BETA2 (20.90.821) +- Core/Settings: Incorporate new Kodi cache/readfactor values; clamp cache values to divisible by 16 +- Serverlist: allow roundrobin at the bottom boundary +- StreamInfo: hide OSD after closing streaminfo +- Settings: Add setting to use Kodi keyboard for searching (default: off) +- Main: harden main loop (still not exiting properly when exiting fast after server change; reinits previously inited windows on exit, sometimes) +- SubtitleDownload/OpenSubtitles.com: set global videoinfo infoLabels to improve subtitle search hinting (waiting for PR to be accepted) + + +[- 0.7.0 -] +- Fix kiosk mode startup issue when other modal dialogs were active when PM4K was trying to start in kiosk mode +- Fix video OSD hiding too fast in certain circumstances +- Fix photoplayer issues; skip ugly initial loading image; show loading state only when it takes longer than 500ms; fix prev/next not always working; increase speed by x10 +- Fix episodes view replaying the theme music when returning from a different-season-view +- Fix mediaBufferSize reported to the Plex MDE endpoint was always empty (resulting in Plex assuming we only have 5 MB cache, leading to all sorts of buffer issues) +- Fix pin entry with J characters looking like an uppercase i +- Fix episode regularly ending in bingeMode (not credits skipped) still showing post play +- Fix enabled subtitles always leading to a transcode (and subtitle burn-in) of the video stream in DirectStream scenarios +- Fix player UI for transcoded/DirectStream sessions + +- UI: background/transition/rendering core rework, reducing flickering, "bouncy" background fades, improving overall snappiness of the interface (dialog transition flicker not solved) +- UI: remove the [...]-loading-spinner for everything that takes under 500ms, making the UI more natural +- UI: crossfade backgrounds before entering a view, if possible, reducing the animation load between view transitions +- UI: support more elements as background-providers (e.g. photos) +- Add advanced/plugin setting to enable/disable background crossfading altogether +- Add setting to stop video playback when screensaver (Kodi) is activated +- Add setting to stop video playback after a set idle time +- Increase home section change timeout from 0.3s to 0.5s and allow immediate section selection using ENTER + +- Completely rework the AC3 handling, allowing to select in which channel configurations one wants to transcode to AC3 +- Allow subtitles to be DirectStreamed; resulting in possibly ONLY the audio being transcoded +- Add setting to burn in SSA/ASS subtitles when DirectStreaming. When disabled, they're converted to raw text and DirectStreamed, if enabled (previous default), they lead to the video stream being transcoded +- Enable markers (intro/credits) functionality in transcoded/DirectStream sessions +- Harden chapter selection logic in player UI +- SeekDialog: Unify time formatting as much as possible between transcoded and directplay modes +- Add setting to allow or deny auto-skip functionality when transcoding/DirectStreaming +- Movies preplay: raise the ratings up by 70 pixels to be in line with the title, fixes issues with certain skins +- Core: improve skin compatibility: font30 is no more as we're not using Confluence but Estuary as default. Replace with its fallback, font13 +- Core: improve skin compatibility: font16 is no more as we're not using Confluence but Estuary as default. Replace with its fallback, font13 +- Core: allow DirectStreaming of webvtt subtitles in Kodi >= 20 +- AdvancedSettings: reset background blur and opacity to their new defaults +- BGM: store last "good" audio volume before playing theme music, and apply it upon start of the addon, in case the volume reset after BGM failed/was skipped +- Core: Harden and speed up server change + + +[- 0.6.5+rev5 -] +- Add support for urllib3 >= 2.1.0 + + +[- 0.6.5+rev4 -] +- Fix dropdown roundrobin needing two UPs if first selected item is item 0, introduced in 0.6.5 +- Theme music: Harden BGM handler; wait for correct volume to be re-set, might fix not-so-rare stale volume issue +- Episodes: Show TV Show's other seasons in episodes window + + +[- 0.6.5 -] +- Fix rare postplay still shown on bingemode/autoskip credits +- Fix quick subtitle selection when override forced advanced setting is active +- Fix rare round robin case skipping item 0 onup in dropdowns +- Fix episode progress and time remaining not updating (thanks @bowlingbeeg) +- Fix embedded subtitle display delay when Cycling/using buttons to switch subtitles +- Fix rare subtitles not shown issue + +- Add: Allow video player UI buttons customization via settings; remove a couple of player navbar buttons by default +- Add "Previous Subtitle" to quick subtitles nav item +- Remember subtitle actions (prev, next, download, delay) via quick nav +- Use our own CycleSubtitles/ShowSubtitles implementation; +- Rely even less on Kodi's Player states for subtitles +- Parse and show SDH/HI flag for subtitle streams +- Hide OSD faster after closing settings; try hiding OSD faster in general if necessary +- Lose orange fallback BG on userselect as well by default +- Settings: rename Player to Player UI, rename Player (user-specific) to Playback (user-specific) +- Settings: Move forced subtitles fix from plugin settings to settings interface audio/subtitles +- Store last background URL in settings if dynamic backgrounds is active; use last BG url on startup to prevent blank BG +- Reduce embedded subtitle display backseek to 100ms +- Use episode thumbnails in continue hub if available, by default; add advanced setting +- Set default background blur to 0 (was 4), background opacity to 20 (was 30) +- Disable legacy background image fallback by default; add advanced setting +- Core improvements + + +[- 0.6.4 -] +- Fix preplay mediachoice issues +- Fix seeking with auto-skip scenarios on slower devices +- Fix online/trailer quality issues (was always using a low quality before) +- Fix round-robining in episode view +- Fix Kodi 18 +- Fix some rare Kodi playback errors in logs, mostly cosmetic +- Fix player sometimes not sending the last timeline state after playback ends +- Fix playback issues when multiple versions exist but one of them is missing +- Fix embedded subtitle display delays on playback start and on subtitle change while playing back (backseeks 1 second) +- Fix double-back-button necessary to exit when cancelling autoskip +- Fix chapters not showing when no markers present +- Fix User Pin entry not showing errors +- Fix reactivating addon after minimize +- Fix autoskip marker continuing to count down when paused; don't hide autoskip marker when paused + +- Add support for multiple media versions and fix individual stream selection support +- Add support for stream selection in trailers/extras +- Add current cache/buffer state to progress bar +- Add video/audio/subtitle stream selection for trailers +- Add zero drift playback timers for current time, time left, ends at +- Add minimize option to exit +- Add playback settings manager to enable full settings per TV show instead of just binge mode toggle; +- Add slow connection support (e.g. in a hotel); waits for the buffer to fill to a reasonable amount until playback; sets readfactor to 20 (don't use with passthrough) +Migrate previous binge mode data to new extensible format, stored as addon_data/playback_settings.json + +- Player: Better/more immediate intro-auto-skip implementation +- Cache/Buffer: Allow 26% and 30% "overcommit" (+android 23%) +- Cache/Buffer: Add readfactor to settings (needs Kodi restart) +- Cache/Buffer: Add support for new kodi-omega-master Cache/Buffer GUI settings +- Harden next/prev episode handling in auto-skip scenarios +- Harden next/prev button handling +- Settings: allow vertical round-robining for settings and options lists +- User Switch: Allow cancellation of switch; select the current user by default when switching + + +[- 0.6.2 -] +- Add system setting to execute action upon sleep event (e.g. exit Kodi when display goes to sleep; fixes passthrough issues on SHIELD) +- Allow canceling postplay timeout with enter/OK +- Binge mode: show postplay if video was exited manually +- Show local/LAN server status in status bar and server list via new icon; server list is live now +- Discover local/LAN servers automatically (if any of the plex.tv/resource's DNS points to a local IP and is reachable) +- plexapp/account/main: init account earlier to pick up ID early; slightly reorder initialization sequence to pick up preferred servers earlier +- Connection logic: refactor connection significance; wait for manual connections if necessary/wanted; add way more logging (as this might break things) +- Remember last used server per user +- Refactor seekdialog autoskip handling and chapter/marker display logic +- Harden the episodeswindow's paginator, making it less easy to generate a huge amount of requests when paging quickly (holding down left/right) +- Harden chapter/marker autoskip +- Add "combined chapters", intelligently merging chapters and markers into one, if available +- Add BIF preview images to markers if available ("Enable video preview thumbnails" needs to be enabled on server and library) +- Add separate "show autoskip info early" offset to addon settings (default: 2.5s) +- Add countdown to autoskip info button, informing the user that we're about to auto skip the next marker (intro/credits) +- Set skip intro button show early threshold to 60s (was 120s) to skip recaps but only those +- Seek as fast as possible on immediately occurring intro; skip directly to next video if possible on last credits with autoskip enabled +- Add separate connectivity check timeout; properly set up timeouts for async requests; log ping in local network tests +- Harden server discovery; further improvements to preferring local over secure +- Update reachability of servers live in server list; +- Remove server refresh button due to issues; +- Add fontawesome license +- Show busy dialog when selecting a new user, preventing errors +- Trigger force available servers/connections refresh when changing network settings; + +- Fix Bingemode not properly stored per user +- Fix multiple credits naming in seekdialog +- Fix error upon episodes window reinit; catch error upon missing listitem +- Remove time left tag after watching more than one episode +- Add some missing advanced/addon setting descriptions; cleanup +- Disable GDM discovery by default +- Fix late display of embedded subtitles; the change has been forgotten, sorry; fixes #54 + + +[- 0.6.0-rc1 -] +- Add Kodi Buffer/Cache settings to new System tab +- Add pm4k_cache_template.xml to allow further customization (copy to profile folder) +- Add addon path and Kodi profile path to Settings/About +- Add advanced/addon setting to set (Plex) HTTP request timeouts; change default from 10 to 5 (on display/crash issues, increase timeout) +- Add explicit LAN check for servers (docker-based ones won't show as local by default); only works on Kodi 19 and above; add icmplib and license +- Add setting to specify LAN check connection timeout (default 10ms) +- If desired, prefer an insecure local server over a secure one after switching users, as well +- Add warning when preferring local server connections over secure ones +- Add long timeout for essential plex.tv requests +- Add force server list refresh button to server list (allows reloading the available servers after changing PMS network settings) +- Add setting to verify local/LAN connections even if plex.tv doesn't think they're local +- Add setting to prefer local connections over secure ones, enabling enforced manual servers +- Add advanced/addon setting to add an offset to intro/credits autoskip, as the Plex markers might be a little early (default +2 seconds) + +- Show video chapters if available in playback instead of bigSeek (also add a setting) +- Show virtual chapters in playback (from Plex markers, intro, credits etc.) if no chapters exist for a video file +- Reload items properly with chapters upon preplay-reinit +- Reorder settings, advanced is now system, add network settings +- Show chapters and/or markers in info view of a video item + +- Implement TV binge mode (auto skip intros if not first EP of season; auto skip credits; skip postplay) +- Implement per-user settings +- Make Binge-mode overridable per show +- Make Binge-mode, all auto-skip and whether to display chapters or markers a per-user setting + +- Fix focusing the wrong episode after opening the info screen +- Fix reloading episodes list after watching multiple episodes +- Strip out MP4 file name in stream URL to prevent subtitles trying to be downloaded, fixing long wait time (thanks @microadam) +- Fix failure on video with no audio stream +- Optimize remaining time calculations for preplay screen + + +[- 0.5.5-rev2 -] +- Fix auto intro skip not working after skipping to next episode +- Skip postplay when skipping to next video from player +- Limit early-show-intro-skip to intros occurring in the first 2 minutes; +- add advanced setting to customize this value +- Add option to show and episodes-windows (they toggle their show) to override the global auto-skip-intro setting for a show + + +[- 0.5.5 -] +- Add main setting to show the intro skip button early; enables recap skipping; works with auto-intro-skip! +- Move some boolean settings from Main>Advanced to Main +- Add main setting to use alternative home hubs refresh method introduced by @bowlingbeeg; default on +- Add main setting to specify item-played-threshold in main settings, please sync with your Plex Server; possibly fixes edge cases (postplay/next-overskip issues) +- Fix postplay timer-circle display on later (Nexus++?) Kodi versions +- Rework time formatting and hour padding detection for "Ends at" display completely +- Change watched status to also look at resume offset (thanks @bowlingbeeg) +- Fix crash when background threads are still running on library exit (thanks @bowlingbeeg) +- Fix playlist issues (thanks @bowlingbeeg) +- Change look of letter jump list (thanks @bowlingbeeg) +- Fix sorting/filtering issues (thanks @bowlingbeeg) +- Add second view type for episodes and albums (thanks @bowlingbeeg) +- Support showing collections inline (thanks @bowlingbeeg) +- Add support for smaller poster size view (thanks @bowlingbeeg) + + +[- 0.5.4 -] +- Store user thumbnail in cache (improves home "load" time) +- Change client identifier from Plex-for-Kodi to PM4K; + possibly fix "PlexNet" entries in Authorized Devices; might also break stuff, please report back +- fix closing quote in chinese translation +- Add missing German translations +- Add "Ends at" to player ends-at time by default; add option to disable this label +- Add fallback for missing audiooutput.channels setting (seems to affect libreelec only); relates to #48 +- Change resume dialog to show resume time (thanks @bowlingbeeg) +- Add unwatched status to pre-play screen and add progress bars to more hubs (thanks @bowlingbeeg) +- Fix missing parameters on Plex API queries (thanks @bowlingbeeg) +- Add time left to pre-play screen (thanks @bowlingbeeg) +- Fix audio/subtitle selection not updating correctly in pre-play screen (thanks @bowlingbeeg) + + +[- 0.5.3 -] +- Inhibit screensaver when in photo slideshow (Kodi 19 and above) +- Add addon setting to use old profile from P4K instead of the optimized one (might fix 3D issues with DP; not sure why?); default: off +- Show video stream render type in preplay/epidoses screen (SDR/HDR/DV/HLG) +- Adjust default background image blur/opacity from 0/40 to 4/30 +- Add addon setting to set solid background colour instead of pictures (Kodi 19 and above) +- Add addon setting to hide when current media will end (default: shown, as before) +- Split filename in info screen to avoid overflow +- Don't show "no content" on home; amended PR #43 +- Bad temporary fix for photo playqueues containing videos +- Photos: Use Kodi slideshow interval; fixes #41 +- Add Simplified Chinese Translation (thanks @Liqianyu) +- Fix AV1 setting description +- Fix single-season pagination (anime) +- Update german translation (thanks @jamal2362) +- Fix issue when displaying a library that has no hubs to display (thanks @bowlingbeeg) +- Fixed an issue with video playlists and the general play button not working (thanks @bowlingbeeg) +- Fixed a couple of places that require integer division (thanks @bowlingbeeg) + + +[- 0.5.2-beta0.1 -] +re-add support for leia (Kodi 18) + + +[- 0.5.1 -] +add media/part/stream info to info screen +read and honor advancedsettings/memorysize + + +[- 0.5.0 -] +implement multiple markers per video file +add skip credits Plex-style (skip to post-credit scene if applicable or skip to end) +add auto skip credits feature +actually respect DirectPlay=Off and DirectStream=Off +fix directstream/transcoding (DS never worked apart from h264) +fix transcoded audio always being MP3 +deviate from Web-client-based profile to own dynamic profile +allow directplay/stream/transcode of virtually anything on Kodi +add settings to force directstream/transcoded audio to AC3 and/or DTS (for passthrough) +add setting to limit directstream/transcoded audio to original audio bitrate/channels +add setting to limit directstream/transcoded audio to Kodi audio channel setting +prevent PMS transcoding audio to higher channel count than original audio +show video codec in preplay screen +settings: round-robin when at the end of the left heading list +stream status dialog: show HW encoding state +replace progressive jpg files (thanks @shyzus) + +note: massive thanks to @hbbs for reporting the MP3 issue and sticking with me for the whole process of figuring out how to do audio stuff in a Plex client + + +[- 0.4.6 -] +add more sort options for ratings where applicable (rating, audienceRating, contentRating, userRating) +add smart desc/asc default sort (need feedback) +use PlexWeb sort field naming (except for PlexWeb Rating=My Rating which is clearer) +note: TV shows "By Audience Rating" seems to be broken in Plex +previous beta fixes +small bugfixes + + +[- 0.4.5-beta1.3 -] +properly refocus after stopping music via the mini player fix msgstr +reset autoseektimer prematurely before auto skipping intro +stream details: don't show unknown values +some music fixes; internals +auto intro skip: skip only once, show manual skipping otherwise, measures for preventing wrong jump +fix HEVC default + + +[- 0.4.5-beta1.2 -] +fix music and photo handlers (thanks @Buttzy10169) +fix next/prev handlers in general +fix previous release's issues +use different photos temp path resolution +enable HEVC by default + + +[- 0.4.4 -] +community fixes (thanks @Buttzy10169 @fvlaicu) +add auto-skip intro setting (default: off) +add addon-setting to customize how long skip-intro button is shown (default: 10s) + + +[- 0.4.3 -] +Allow skip-intro for users on a plexpass enabled server (thanks @fvlaicu) +Fix visual issues (due to botched addon rename) +Make AV1 setting Kodi major version dependant; pave way for hybrid codebase for 19/20 +Implement new network discovery mech on windows (GDM) using powershell (experimental) +Possibly fix GDM on windows (especially on non-english variants) +Possibly fix GDM on Linux (non-BSD) + + +[- 0.4.2 -] +Fix skip intro button +Fix duplicate addon setting +Enable dynamic backgrounds by default set defaults for dynamic backgrounds: blur=0, opacity=40 +Fix kiosk mode (autorun plex on kodi startup) +Fix music playback +Fix theme music playback; set default theme music volume to 50% + + +[- 0.4.1 -] +Initial PlexMod for Kodi release, based on my plex-for-kodi fork's develop branch +Add support for Kodi Nexus (20) on LibreELEC and Android +Add AV1 toggle and AV1 direct play support +Rename addon to "script.plexmod" +Add all non-plex-conform features of the develop branch as default features + +[- 0.2.3 -] + +Fix error causing playback to fail + +[- 0.2.2 -] + +Added support for collections in library views +Update Polish strings (thanks to Zachar) +Fix GDM issue (thanks to MrPumo) +Fix Python 3 issues (thanks to MrPumo and pannal) + +[- 0.2.1 -] + +Added Skip Intro (thanks to pannal) +Use device name for friendly name +Fix some hubs not displaying +Added title scrolling when focused on some items +Show playback speed on OSD +Fix possible error on playlists window + +[- 0.2.0 -] + +Bump version to 0.2.0 to differentiate from deprecated Kodi 17 0.1.x versions + +[- 0.1.8 -] + +Fix seek resetting when clicking select on seek bar with OSD visible +Add Spanish translations (thanks to rdcalle) +Add Portuguese (Portugal) translations (thanks to Generator) +Make python 3 compatible (thanks to pannal) + +[- 0.1.7 -] + +Fix transcode failures on Windows (possibly other platforms) +Add Italian translations (thanks to iz8mbw) +Use Kodi time format setting (Issue #90) (thanks to pannal) +Restore last window when starting the add-on while it is running (Issue #126) +Add Portuguese (Brazil) translations (thanks to DiogoAbu) +Add ability to exit search edit box with previous menu (escape) button (Issue #194) (thanks to pannal) +Only play unwatched media when pressing play or shuffle and filtering for unwatched (thanks to tlt21) +Fix issue with duplicated icons when fast-scrolling a hub (Issue #177) (thanks to pannal) +Fixed GUI not responding after public IP renewal (thanks to pannal and mkliche) +Advanced setting: Automatically seek selected position after a delay (Issue #172) (thanks to pannal) +Advanced setting: Use skip step settings from Kodi (Issue #133) (thanks to pannal) +Advanced setting: Use Plex/Kodi steps for timeline (Issue #133) (thanks to pannal) +OSD-Autohide improvements (thanks to pannal) +Show post play on user stop when item is considered played (thanks to pannal) +Use Unplayed/Played instead of Unwatched/Watched (thanks to pannal) +Fix issue with cast popup displaying partially offscreen (thanks to pannal) +Various fixes for incorrectly transcoded playback (Issue #201) (thanks to pannal) +Support new subtitles menu in playback for Leia (thanks to pannal) +Make sure progress bar is visible on items with less than 2% watched (thanks to pannal) +Fix focus issues caused when hubs are removed, i.e. On Deck, Continue Watching (thanks to pannal) +Fix issues with flattened seasons +Allow Kodi info display to be visible when hitting the info button +Fixes hubs not updating and some crash issues +More fixes for Kodi 18, ex. missing letters list (Issue #265) +Fix resume behavior with DSPlayer (thanks to pannal) +Add Polish translations (thanks to Zachar2) +Playlist and album view tweaks (thanks to pannal) +Quality selection clean up and fixes (thanks to pannal) +Fix to allow 3D mode selection +Add advanced option to skip the header when going back (thanks to pannal) +Ensure paused state is retained after seeking or changing video settings (thanks to pannal) +Allow closing of the options header in scrolled views using context menu button (thanks to pannal) +Some direct playback fixes (thanks to pannal) +Some shutdown fixes (thanks to pannal) +Show play state indicators to related items in preplays and On Deck in postplay (thanks to pannal) +Fix some resume issues (thanks to pannal) + +[- 0.1.6 -] + +Fix issues when selecting subtitles for users of certain languages (Issue #188) + +[- 0.1.5 -] + +Allow direct playback of episodes and movies using the play button on hub screen (thanks to pannal) +In progress watched items had the 'Mark unwatched' option instead of 'Mark watched' +Fix an issue causing the home window to start slightly scrolled down if it was closed scolled down +Fix an issue causing an error when sort was sort was "BY UNWATCHED" and the filtering "UNWATCHED" (Issue #187) +Fix issue with letter shortcuts sometimes being shown/not shown incorrectly +Fix a bug causing crash and reboot on startup on Raspberry Pi (LibreElec specific?) - Reverts "Fix autostart to work with profiles" + +[- 0.1.4 -] + +Kodi v18: Fix skin compatability issues +Kodi v18: Fix incompatibility with requests module update +Kodi v18: Fix issue with playback not resuming properly when direct playing +Kodi v18: Fix issue with progress bar not moving on music player/music playlist screens +Fix album display on artist screen +Fix bug causing failure to show audio player when clicking the mini player from some screens +Show original artist when available (Issue #143) +Improve centering over label backgrounds on pre-play screens +Fix some spots where tokens could still be logged +Play correct track when playing a multi-disc album (Issue #148) +Improve headers for better identification in 'Now Playing' and future server profile +Updated German language strings (thanks to coffinbearer) +Fix French translations file (thanks to coffinbearer) +Fix some Hungarian translations (thanks to vampywiz17) +Add Russian translations (thanks to shady2k) +Fix autostart to work with profiles (thanks to pannal) +Fix focus loss on home screen due to error (Issue #169) +Fix "No Servers Found" when preferred server is unavailable (Issue #159) +Fix system keyboard not working for search (Kodi 17+)(Issue #165) +Fix issue causing hubs to scroll up when settings were opened +Fix failure to sign in when signed off externally (Issue #110 & #117) + +[- 0.1.3 -] + +Fix incompatibility with requests module update + +[- 0.1.2 -] + +Fix issue with hubs not showing with (newer?) server versions + +[- 0.1.1 -] + +Remove PlexPass disclaimer from add-on info + +[- 0.1.0 -] + +Improved hub vertical scrolling animation +Fix (#87): Switching between managed users causes Kodi to crash +Fix (#119): Occasional crashes when exiting the add-on +Remove PlexPass requirement + +[- 0.0.102 -] + +Handle connection errors on link screen polling +Handle skip next/prev when playing video playlists +Home Screen: Navigating to the 'More' button now causes an update for all movement +Add ability to view episodes/albums in library view +Add German translation (thanks to coffinbearer) +Add Czech translation (thanks to Pavuucek) +Add Hungarian translation (thanks to vampywiz17) +Add French translation (thanks to raffoul/rlimbach) +Fix issue #64 (multi part movies won't playback) +Improve timeline reporting +Friendly name now includes hostname to differentiate Kodi devices +Possible fix for issue #102 +Fix a bug causing an error on server decisions +Fix errors caused by localization on episodes and pre-play screens +Fix some errors caused when no internet + +[- 0.0.101 -] + +Fix (Issue #68): Artist screen options button was showing Mark Unwatched +Fix (Issue #65): When returning from playback episode pre-play did not update the selected episode +Fix: Codec info button ('o') handling on Krypton+ +Remove mkv/hls testing option in add-on Kodi settings +Add Debug Logging option to Advanced Settings +Fix: Post-play after the last item in the playlist was replaying the last item instead of the displayed up next item + +[- 0.0.100 -] + +Fix some stability issues +Fix encoding error on startup +Improve fallbaack background quality +Fix an error causing opening of photo directories to fail +Disable debug logging by default +Make Home hub square items smaller +Improve startup and shutdown times +Fix some server reachability testing bugs and improve performance +Possible fix for crashing when shutting down Kodi while the add-on is running +Add workaround to allow launching from My Add-ons and shortcuts +Fix text cutoff for post-play in Estuary +Prevent the add-on from starting another instance on update +Skip user select in offline mode +Show 'Offline Mode' item in user options when in offline mode - selecting attempts going online + +[- 0.0.99 -] + +Fix: Episodes were not resuming + +[- 0.0.98 -] + +Fix: Was allowing non-Plex-Pass users +Fix: Some videos failed to play with certain audio stream selections +Fix: Some videos failed to play due to a logging error + +[- 0.0.97 -] + +Add 'Play Version...' to the pre-play options (Issue #34) +Added spring loaded playlists to Playlist section on Home screen (Issue #28) +Fix playlist composite images +Fix: Extending a hub again after a section change was starting where the previous extension left off +Handle no content and 404 for section hubs on Home screen (Issue #52) +Handle no content or no content for filter on library screen +Handle videos without duration set +Some Home screen hub loading optimization + +[- 0.0.96 -] + +Remove PIL usage +Use plex.tv instead of my.plexapp.com when requesting pin (Issue #50) + +[- 0.0.95 -] + +Now remembers unwatched filter state and sorting selection on library views (Issue #44) +Fix: Local media was being treated as remote media for playback decisions +Added a dialog to search for when selected playlists are not accessible by the current user (Issue #42) +Fixed font issues on episode/movie pre-plays and settings screens (Issue #45) + +[- 0.0.94 -] + +Fix: Filtering for unwatched movies was causing nothing to be displayed (regression) +Fix (Issue #41): Incorrect strings were being displayed on the episode pre-play delete dialog +Playlists now load in progressively in the background (Issue #35) +Added a dialog on failure to connect when getting sign-in pin (Issue #32) +Change posters view so that two rows are always visible + +[- 0.0.93 -] + +Fix: (Issue #20) Filtering by unwatched still showed watched items +Fix: (Issue #33) Photo directories were failing to open from the Home screen +Fix: (Issue #33) Some photos failed to open from the Home screen +Fix: Disabling the 'Allow HEVC' setting had no effect +Added a busy indicator while photos are loading +Fixes for DVR episodes without episode numbers + +[- 0.0.92 -] + +Official Kodi repo submission +Only change audio streams when necessary + +[- 0.0.91 -] + +Fix (Issue #23): Pressing a play on a show was not starting on the first unwatched or in progress episode +Implement (Issue #30): Decision endpoint handling for proper interaaction with streaming brain - fixes related failed playback issues +Various minor bug fixes causing fanart screen stalls, etc + +[- 0.0.90 -] + +Fix: (Issue #13) Errors caused by encoding issues in episodes pre-play and track playback +Fix: Player settings dialog would sometimes not close without some user input +Fix: (Issue #25) Increased music playback thumbnail resolution - affects add-on player screen and skin views outside the addon +Fix: (Issue #24) Items in movie playlists were not playable +Change: Player settings dialog now puts focus on the selected setting when displaying setting lists +Change: (Issue #21) Now back button only jumps to top bar when top bar is off screen + +[- 0.0.89 -] + +Fix: Selecting non plex pass not managed users caused sign out on addon restart +Fix: Playlists view showed empty space when no audio playlists were present and prevented focus + +[- 0.0.88 -] + +Fix: Starting a video while audio was playing triggered an error causing issues with OSD/control +Fix: Selected audio track was not being played with direct play + +[- 0.0.87 -] + +Initial public beta + +[- 0.0.1 -] + +Initial development \ No newline at end of file diff --git a/script.plexmod/default.py b/script.plexmod/default.py new file mode 100644 index 0000000000..3f0bb5be7e --- /dev/null +++ b/script.plexmod/default.py @@ -0,0 +1,5 @@ +from __future__ import absolute_import +from lib import main + + +main.main() diff --git a/script.plexmod/fanart.jpg b/script.plexmod/fanart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7548349f6a1dd3633c2dc7262c386ec461f361cb GIT binary patch literal 71213 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/icon.png b/script.plexmod/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1a6ba14690a461e957c9b27a7b50b959928feb12 GIT binary patch literal 25724 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 2.1.0 + pass + +from . import compat +from . import _included_packages diff --git a/script.plexmod/lib/_included_packages/__init__.py b/script.plexmod/lib/_included_packages/__init__.py new file mode 100644 index 0000000000..52d8b592a6 --- /dev/null +++ b/script.plexmod/lib/_included_packages/__init__.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import +import os +import sys +import inspect + +cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0])) +if cmd_folder not in sys.path: + sys.path.insert(0, cmd_folder) diff --git a/script.plexmod/lib/_included_packages/icmplib/__init__.py b/script.plexmod/lib/_included_packages/icmplib/__init__.py new file mode 100644 index 0000000000..6770e6988e --- /dev/null +++ b/script.plexmod/lib/_included_packages/icmplib/__init__.py @@ -0,0 +1,44 @@ +''' + icmplib + ~~~~~~~ + + Easily forge ICMP packets and make your own ping and traceroute. + + https://github.com/ValentinBELYN/icmplib + + :copyright: Copyright 2017-2023 Valentin BELYN. + :license: GNU LGPLv3, see the LICENSE for details. + + ~~~~~~~ + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program. If not, see + . +''' + +from .sockets import ICMPv4Socket, ICMPv6Socket, AsyncSocket +from .models import ICMPRequest, ICMPReply, Host, Hop +from .ping import ping, async_ping +from .multiping import multiping, async_multiping +from .traceroute import traceroute +from .exceptions import * +from .utils import is_hostname, is_ipv4_address, is_ipv6_address +from .utils import PID, resolve, async_resolve + + +__author__ = 'Valentin BELYN' +__copyright__ = 'Copyright 2017-2023 Valentin BELYN' +__license__ = 'GNU Lesser General Public License v3.0' + +__version__ = '3.0.4' +__build__ = '231010' diff --git a/script.plexmod/lib/_included_packages/icmplib/exceptions.py b/script.plexmod/lib/_included_packages/icmplib/exceptions.py new file mode 100644 index 0000000000..b37646bfaa --- /dev/null +++ b/script.plexmod/lib/_included_packages/icmplib/exceptions.py @@ -0,0 +1,214 @@ +''' + icmplib + ~~~~~~~ + + Easily forge ICMP packets and make your own ping and traceroute. + + https://github.com/ValentinBELYN/icmplib + + :copyright: Copyright 2017-2023 Valentin BELYN. + :license: GNU LGPLv3, see the LICENSE for details. + + ~~~~~~~ + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program. If not, see + . +''' + + +class ICMPLibError(Exception): + ''' + Exception class for the icmplib package. + + ''' + + +class NameLookupError(ICMPLibError): + ''' + Raised when the requested name does not exist or cannot be resolved. + This concerns both Fully Qualified Domain Names and hostnames. + + ''' + def __init__(self, name): + message = f'The name \'{name}\' cannot be resolved' + super().__init__(message) + + +class ICMPSocketError(ICMPLibError): + ''' + Base class for ICMP sockets exceptions. + + ''' + + +class SocketAddressError(ICMPSocketError): + ''' + Raised when the requested address cannot be assigned to the socket. + + ''' + def __init__(self, address): + message = f'The requested address ({address}) cannot be ' \ + 'assigned to the socket' + super().__init__(message) + + +class SocketPermissionError(ICMPSocketError): + ''' + Raised when the privileges are insufficient to create the socket. + + ''' + def __init__(self, privileged): + if privileged: + message = 'Root privileges are required to create the socket' + else: + message = 'A prior configuration of your OS is required ' \ + 'to use ICMP sockets without root privileges. ' \ + 'Read more on https://github.com/ValentinBELYN' \ + '/icmplib' + + super().__init__(message) + + +class SocketUnavailableError(ICMPSocketError): + ''' + Raised when an action is performed while the socket is closed. + + ''' + def __init__(self): + message = 'The socket can no longer be used after its closure' + super().__init__(message) + + +class SocketBroadcastError(ICMPSocketError): + ''' + Raised when a broadcast address is used and the corresponding option + is not enabled on the socket. + + ''' + def __init__(self): + message = 'Broadcast is not allowed: ' \ + 'please use the \'broadcast\' property to allow it' + super().__init__(message) + + +class TimeoutExceeded(ICMPSocketError): + ''' + Raised when a timeout occurs on a socket. + + ''' + def __init__(self, timeout): + message = f'The timeout has been reached ({timeout}s)' + super().__init__(message) + + +class ICMPError(ICMPLibError): + ''' + Base class for ICMP error messages. + + ''' + def __init__(self, message, reply): + super().__init__(message) + self._reply = reply + + @property + def reply(self): + return self._reply + + +class DestinationUnreachable(ICMPError): + ''' + Base class for ICMP Destination Unreachable messages. + + Destination Unreachable message is generated by the host or its + inbound gateway to inform the client that the destination is + unreachable for some reason. + + ''' + _CODES = {} + + def __init__(self, reply): + if reply.code in self._CODES: + message = self._CODES[reply.code] + else: + message = f'Destination unreachable, bad code: {reply.code}' + + super().__init__(message, reply) + + +class ICMPv4DestinationUnreachable(DestinationUnreachable): + _CODES = { + 0: 'Destination network unreachable', + 1: 'Destination host unreachable', + 2: 'Destination protocol unreachable', + 3: 'Destination port unreachable', + 4: 'Fragmentation needed and DF set', + 5: 'Source route failed', + 6: 'Destination network unknown', + 7: 'Destination host unknown', + 8: 'Source host isolated', + 9: 'Destination network prohibed', + 10: 'Destination host prohibed', + 11: 'Destination network unreachable for ToS', + 12: 'Destination host unreachable for ToS', + 13: 'Packet filtered', + 14: 'Precedence violation', + 15: 'Precedence cutoff' + } + + +class ICMPv6DestinationUnreachable(DestinationUnreachable): + _CODES = { + 0: 'No route to destination', + 1: 'Communication with destination administratively prohibited', + 2: 'Beyond scope of source address', + 3: 'Address unreachable', + 4: 'Port unreachable', + 5: 'Source address failed ingress/egress policy', + 6: 'Reject route to destination' + } + + +class TimeExceeded(ICMPError): + ''' + Base class for ICMP Time Exceeded messages. + + Time Exceeded message is generated by a gateway to inform the source + of a discarded datagram due to the time to live field reaching zero. + A Time Exceeded message may also be sent by a host if it fails to + reassemble a fragmented datagram within its time limit. + + ''' + _CODES = {} + + def __init__(self, reply): + if reply.code in self._CODES: + message = self._CODES[reply.code] + else: + message = f'Time exceeded, bad code: {reply.code}' + + super().__init__(message, reply) + + +class ICMPv4TimeExceeded(TimeExceeded): + _CODES = { + 0: 'Time to live exceeded', + 1: 'Fragment reassembly time exceeded' + } + + +class ICMPv6TimeExceeded(TimeExceeded): + _CODES = { + 0: 'Hop limit exceeded', + 1: 'Fragment reassembly time exceeded' + } diff --git a/script.plexmod/lib/_included_packages/icmplib/models.py b/script.plexmod/lib/_included_packages/icmplib/models.py new file mode 100644 index 0000000000..c055fdf139 --- /dev/null +++ b/script.plexmod/lib/_included_packages/icmplib/models.py @@ -0,0 +1,491 @@ +''' + icmplib + ~~~~~~~ + + Easily forge ICMP packets and make your own ping and traceroute. + + https://github.com/ValentinBELYN/icmplib + + :copyright: Copyright 2017-2023 Valentin BELYN. + :license: GNU LGPLv3, see the LICENSE for details. + + ~~~~~~~ + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program. If not, see + . +''' + +from .exceptions import * +from .utils import random_byte_message + + +class ICMPRequest: + ''' + A user-created object that represents an ICMP Echo Request. + + :type destination: str + :param destination: The IP address of the host to which the message + should be sent. + + :type id: int + :param id: The identifier of the request. Used to match the reply + with the request. In practice, a unique identifier is used for + every ping process. On Linux, this identifier is automatically + replaced if the request is sent from an unprivileged socket. + + :type sequence: int + :param sequence: The sequence number. Used to match the reply with + the request. Typically, the sequence number is incremented for + each packet sent during the process. + + :type payload: bytes, optional + :param payload: The payload content in bytes. A random payload is + used by default. + + :type payload_size: int, optional + :param payload_size: The payload size. Ignored when the `payload` + parameter is set. Default to 56. + + :type ttl: int, optional + :param ttl: The time to live of the packet in terms of hops. + Default to 64. + + :type traffic_class: int, optional + :param traffic_class: The traffic class of the ICMP packet. + Provides a defined level of service to the packet by setting the + DS Field (formerly TOS) or the Traffic Class field of the IP + header. Packets are delivered with the minimum priority by + default (Best-effort delivery). + Intermediate routers must be able to support this feature. + Only available on Unix systems. Ignored on Windows. + + ''' + __slots__ = '_destination', '_id', '_sequence', '_payload', \ + '_payload_size', '_ttl', '_traffic_class', '_time' + + def __init__(self, destination, id, sequence, payload=None, + payload_size=56, ttl=64, traffic_class=0): + + if payload: + payload_size = len(payload) + + self._destination = destination + self._id = id & 0xffff + self._sequence = sequence & 0xffff + self._payload = payload + self._payload_size = payload_size + self._ttl = ttl + self._traffic_class = traffic_class + self._time = 0 + + def __repr__(self): + return f'' + + @property + def destination(self): + ''' + The IP address of the host to which the message should be sent. + + ''' + return self._destination + + @property + def id(self): + ''' + The identifier of the request. + Used to match the reply with the request. + + ''' + return self._id + + @property + def sequence(self): + ''' + The sequence number. + Used to match the reply with the request. + + ''' + return self._sequence + + @property + def payload(self): + ''' + The payload content in bytes. + Return a random payload if not defined. + + ''' + return self._payload or random_byte_message(self._payload_size) + + @property + def payload_size(self): + ''' + The payload size. + + ''' + return self._payload_size + + @property + def ttl(self): + ''' + The time to live of the packet in terms of hops. + + ''' + return self._ttl + + @property + def traffic_class(self): + ''' + The traffic class of the packet. + + ''' + return self._traffic_class + + @property + def time(self): + ''' + The timestamp of the ICMP request. + + Initialized to zero when creating the request and replaced by + the `send` method of an ICMP socket with the time of sending. + + ''' + return self._time + + +class ICMPReply: + ''' + A class that represents an ICMP reply. Generated from an ICMP socket. + + :type source: str + :param source: The IP address of the host that composes the ICMP + message. + + :type family: int + :param family: The address family. Can be set to `4` for IPv4 or `6` + for IPv6 addresses. + + :type id: int + :param id: The identifier of the reply. Used to match the reply with + the request. + + :type sequence: int + :param sequence: The sequence number. Used to match the reply with + the request. + + :type type: int + :param type: The type of ICMP message. + + :type code: int + :param code: The ICMP error code. + + :type bytes_received: int + :param bytes_received: The number of bytes received. + + :type time: float + :param time: The timestamp of the ICMP reply. + + ''' + __slots__ = '_source', '_family', '_id', '_sequence', '_type', \ + '_code', '_bytes_received', '_time' + + def __init__(self, source, family, id, sequence, type, code, + bytes_received, time): + + self._source = source + self._family = family + self._id = id + self._sequence = sequence + self._type = type + self._code = code + self._bytes_received = bytes_received + self._time = time + + def __repr__(self): + return f'' + + def raise_for_status(self): + ''' + Throw an exception if the reply is not an ICMP Echo Reply. + Otherwise, do nothing. + + :raises DestinationUnreachable: If the destination is + unreachable for some reason. + :raises TimeExceeded: If the time to live field of the ICMP + request has reached zero. + :raises ICMPError: Raised for any other type and ICMP error + code, except ICMP Echo Reply messages. + + ''' + if self._family == 6: + if self._type == 1: + raise ICMPv6DestinationUnreachable(self) + + if self._type == 3: + raise ICMPv6TimeExceeded(self) + else: + if self._type == 3: + raise ICMPv4DestinationUnreachable(self) + + if self._type == 11: + raise ICMPv4TimeExceeded(self) + + if (self._family == 4 and self._type != 0 or + self._family == 6 and self._type != 129): + message = f'Error type: {self._type}, code: {self._code}' + raise ICMPError(message, self) + + @property + def source(self): + ''' + The IP address of the host that composes the ICMP message. + + ''' + return self._source + + @property + def id(self): + ''' + The identifier of the reply. + Used to match the reply with the request. + + ''' + return self._id + + @property + def sequence(self): + ''' + The sequence number. + Used to match the reply with the request. + + ''' + return self._sequence + + @property + def type(self): + ''' + The type of ICMP message. + + ''' + return self._type + + @property + def code(self): + ''' + The ICMP error code. + + ''' + return self._code + + @property + def bytes_received(self): + ''' + The number of bytes received. + + ''' + return self._bytes_received + + @property + def time(self): + ''' + The timestamp of the ICMP reply. + + ''' + return self._time + + +class Host: + ''' + A class that represents a host. It simplifies the use of the results + from the `ping`, `multiping` and `traceroute` functions. + + :type address: str + :param address: The IP address of the host that responded to the + request. + + :type packets_sent: int + :param packets_sent: The number of packets transmitted to the + destination host. + + :type rtts: list[float] + :param rtts: The list of round-trip times expressed in milliseconds. + + ''' + __slots__ = '_address', '_packets_sent', '_rtts' + + def __init__(self, address, packets_sent, rtts): + self._address = address + self._packets_sent = packets_sent + self._rtts = rtts + + def __repr__(self): + return f'' + + def __str__(self): + return f' {self._address}\n' + '-' * 60 + '\n' \ + f' Packets sent: {self._packets_sent}\n' \ + f' Packets received: {self.packets_received}\n' \ + f' Packet loss: {self.packet_loss * 100}%\n' \ + f' Round-trip times: {self.min_rtt} ms / ' \ + f'{self.avg_rtt} ms / {self.max_rtt} ms\n' \ + f' Jitter: {self.jitter} ms\n' + '-' * 60 + + @property + def address(self): + ''' + The IP address of the host that responded to the request. + + ''' + return self._address + + @property + def min_rtt(self): + ''' + The minimum round-trip time in milliseconds. + + ''' + if not self._rtts: + return 0.0 + + return round(min(self._rtts), 3) + + @property + def avg_rtt(self): + ''' + The average round-trip time in milliseconds. + + ''' + if not self._rtts: + return 0.0 + + return round(sum(self._rtts) / len(self._rtts), 3) + + @property + def max_rtt(self): + ''' + The maximum round-trip time in milliseconds. + + ''' + if not self._rtts: + return 0.0 + + return round(max(self._rtts), 3) + + @property + def rtts(self): + ''' + The list of round-trip times expressed in milliseconds. + + ''' + return self._rtts + + @property + def packets_sent(self): + ''' + The number of requests transmitted to the remote host. + + ''' + return self._packets_sent + + @property + def packets_received(self): + ''' + The number of ICMP responses received from the remote host. + + ''' + return len(self._rtts) + + @property + def packet_loss(self): + ''' + Packet loss occurs when packets fail to reach their destination. + Return a `float` between 0 and 1 (all packets are lost). + + ''' + if not self._packets_sent: + return 0.0 + + return round(1 - len(self._rtts) / self._packets_sent, 2) + + @property + def jitter(self): + ''' + The jitter in milliseconds, defined as the variance of the + latency of packets flowing through the network. + + At least two ICMP responses are required to calculate the + jitter. + + ''' + sum_deltas = 0.0 + num_deltas = len(self._rtts) - 1 + + if num_deltas < 1: + return 0.0 + + for i in range(num_deltas): + sum_deltas += abs(self._rtts[i] - self._rtts[i + 1]) + + return round(sum_deltas / num_deltas, 3) + + @property + def is_alive(self): + ''' + Indicate whether the host is reachable. + Return a `boolean`. + + ''' + return len(self._rtts) > 0 + + +class Hop(Host): + ''' + A class that represents a hop. It extends the `Host` class and adds + some features for the `traceroute` function. + + :type address: str + :param address: The IP address of the gateway or host that responded + to the request. + + :type packets_sent: int + :param packets_sent: The number of packets transmitted to the + destination host. + + :type rtts: list[float] + :param rtts: The list of round-trip times expressed in milliseconds. + + :type distance: int + :param distance: The distance, in terms of hops, that separates the + remote host from the current machine. + + ''' + __slots__ = '_address', '_packets_sent', '_rtts', '_distance' + + def __init__(self, address, packets_sent, rtts, distance): + super().__init__(address, packets_sent, rtts) + self._distance = distance + + def __repr__(self): + return f'' + + def __str__(self): + return f' #{self._distance:<2} {super().__str__()[2:]}' + + @property + def distance(self): + ''' + The distance, in terms of hops, that separates the remote host + from the current machine. + + ''' + return self._distance diff --git a/script.plexmod/lib/_included_packages/icmplib/multiping.py b/script.plexmod/lib/_included_packages/icmplib/multiping.py new file mode 100644 index 0000000000..0705b281db --- /dev/null +++ b/script.plexmod/lib/_included_packages/icmplib/multiping.py @@ -0,0 +1,277 @@ +''' + icmplib + ~~~~~~~ + + Easily forge ICMP packets and make your own ping and traceroute. + + https://github.com/ValentinBELYN/icmplib + + :copyright: Copyright 2017-2023 Valentin BELYN. + :license: GNU LGPLv3, see the LICENSE for details. + + ~~~~~~~ + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program. If not, see + . +''' + +import asyncio + +from .ping import async_ping + + +async def async_multiping(addresses, count=2, interval=0.5, timeout=2, + concurrent_tasks=50, source=None, family=None, privileged=True, + **kwargs): + ''' + Send ICMP Echo Request packets to several network hosts. + + This function is non-blocking. + + :type addresses: list[str] + :param addresses: The IP addresses of the hosts to which messages + should be sent. Hostnames and FQDNs are allowed but not + recommended. You can easily retrieve their IP address by calling + the built-in `async_resolve` function. + + :type count: int, optional + :param count: The number of ping to perform per address. + Default to 2. + + :type interval: int or float, optional + :param interval: The interval in seconds between sending each packet. + Default to 0.5. + + :type timeout: int or float, optional + :param timeout: The maximum waiting time for receiving a reply in + seconds. Default to 2. + + :type concurrent_tasks: int, optional + :param concurrent_tasks: The maximum number of concurrent tasks to + speed up processing. This value cannot exceed the maximum number + of file descriptors configured on the operating system. + Default to 50. + + :type source: str, optional + :param source: The IP address from which you want to send packets. + By default, the interface is automatically chosen according to + the specified destinations. This parameter should not be used if + you are passing both IPv4 and IPv6 addresses to this function. + + :type family: int, optional + :param family: The address family if a hostname or FQDN is specified. + Can be set to `4` for IPv4 or `6` for IPv6 addresses. By default, + this function searches for IPv4 addresses first before searching + for IPv6 addresses. + + :type privileged: bool, optional + :param privileged: When this option is enabled, this library fully + manages the exchanges and the structure of ICMP packets. + Disable this option if you want to use this function without + root privileges and let the kernel handle ICMP headers. + Default to True. + Only available on Unix systems. Ignored on Windows. + + Advanced (**kwags): + + :type payload: bytes, optional + :param payload: The payload content in bytes. A random payload is + used by default. + + :type payload_size: int, optional + :param payload_size: The payload size. Ignored when the `payload` + parameter is set. Default to 56. + + :type traffic_class: int, optional + :param traffic_class: The traffic class of ICMP packets. + Provides a defined level of service to packets by setting the DS + Field (formerly TOS) or the Traffic Class field of IP headers. + Packets are delivered with the minimum priority by default + (Best-effort delivery). + Intermediate routers must be able to support this feature. + Only available on Unix systems. Ignored on Windows. + + :rtype: list[Host] + :returns: A list of `Host` objects containing statistics about the + desired destinations. The list is sorted in the same order as + the addresses passed in parameters. + + :raises NameLookupError: If you pass a hostname or FQDN in + parameters and it does not exist or cannot be resolved. + :raises SocketPermissionError: If the privileges are insufficient to + create the socket. + :raises SocketAddressError: If the source address cannot be assigned + to the socket. + :raises ICMPSocketError: If another error occurs. See the + `ICMPv4Socket` or `ICMPv6Socket` class for details. + + Usage:: + + >>> import asyncio + >>> from icmplib import async_multiping + >>> hosts = asyncio.run(async_multiping(['10.0.0.5', '::1'])) + + >>> for host in hosts: + ... if host.is_alive: + ... print(f'{host.address} is up!') + ... else: + ... print(f'{host.address} is down!') + + 10.0.0.5 is down! + ::1 is up! + + See the `Host` class for details. + + ''' + loop = asyncio.get_running_loop() + tasks = [] + tasks_pending = set() + + for address in addresses: + if len(tasks_pending) >= concurrent_tasks: + _, tasks_pending = await asyncio.wait( + tasks_pending, + return_when=asyncio.FIRST_COMPLETED) + + task = loop.create_task( + async_ping( + address=address, + count=count, + interval=interval, + timeout=timeout, + source=source, + family=family, + privileged=privileged, + **kwargs)) + + tasks.append(task) + tasks_pending.add(task) + + await asyncio.wait(tasks_pending) + + return [task.result() for task in tasks] + + +def multiping(addresses, count=2, interval=0.5, timeout=2, + concurrent_tasks=50, source=None, family=None, privileged=True, + **kwargs): + ''' + Send ICMP Echo Request packets to several network hosts. + + :type addresses: list[str] + :param addresses: The IP addresses of the hosts to which messages + should be sent. Hostnames and FQDNs are allowed but not + recommended. You can easily retrieve their IP address by calling + the built-in `resolve` function. + + :type count: int, optional + :param count: The number of ping to perform per address. + Default to 2. + + :type interval: int or float, optional + :param interval: The interval in seconds between sending each packet. + Default to 0.5. + + :type timeout: int or float, optional + :param timeout: The maximum waiting time for receiving a reply in + seconds. Default to 2. + + :type concurrent_tasks: int, optional + :param concurrent_tasks: The maximum number of concurrent tasks to + speed up processing. This value cannot exceed the maximum number + of file descriptors configured on the operating system. + Default to 50. + + :type source: str, optional + :param source: The IP address from which you want to send packets. + By default, the interface is automatically chosen according to + the specified destinations. This parameter should not be used if + you are passing both IPv4 and IPv6 addresses to this function. + + :type family: int, optional + :param family: The address family if a hostname or FQDN is specified. + Can be set to `4` for IPv4 or `6` for IPv6 addresses. By default, + this function searches for IPv4 addresses first before searching + for IPv6 addresses. + + :type privileged: bool, optional + :param privileged: When this option is enabled, this library fully + manages the exchanges and the structure of ICMP packets. + Disable this option if you want to use this function without + root privileges and let the kernel handle ICMP headers. + Default to True. + Only available on Unix systems. Ignored on Windows. + + Advanced (**kwags): + + :type payload: bytes, optional + :param payload: The payload content in bytes. A random payload is + used by default. + + :type payload_size: int, optional + :param payload_size: The payload size. Ignored when the `payload` + parameter is set. Default to 56. + + :type traffic_class: int, optional + :param traffic_class: The traffic class of ICMP packets. + Provides a defined level of service to packets by setting the DS + Field (formerly TOS) or the Traffic Class field of IP headers. + Packets are delivered with the minimum priority by default + (Best-effort delivery). + Intermediate routers must be able to support this feature. + Only available on Unix systems. Ignored on Windows. + + :rtype: list[Host] + :returns: A list of `Host` objects containing statistics about the + desired destinations. The list is sorted in the same order as + the addresses passed in parameters. + + :raises NameLookupError: If you pass a hostname or FQDN in + parameters and it does not exist or cannot be resolved. + :raises SocketPermissionError: If the privileges are insufficient to + create the socket. + :raises SocketAddressError: If the source address cannot be assigned + to the socket. + :raises ICMPSocketError: If another error occurs. See the + `ICMPv4Socket` or `ICMPv6Socket` class for details. + + Usage:: + + >>> from icmplib import multiping + >>> hosts = multiping(['10.0.0.5', '127.0.0.1', '::1']) + + >>> for host in hosts: + ... if host.is_alive: + ... print(f'{host.address} is up!') + ... else: + ... print(f'{host.address} is down!') + + 10.0.0.5 is down! + 127.0.0.1 is up! + ::1 is up! + + See the `Host` class for details. + + ''' + return asyncio.run( + async_multiping( + addresses=addresses, + count=count, + interval=interval, + timeout=timeout, + concurrent_tasks=concurrent_tasks, + source=source, + family=family, + privileged=privileged, + **kwargs)) diff --git a/script.plexmod/lib/_included_packages/icmplib/ping.py b/script.plexmod/lib/_included_packages/icmplib/ping.py new file mode 100644 index 0000000000..5ba1efc8b0 --- /dev/null +++ b/script.plexmod/lib/_included_packages/icmplib/ping.py @@ -0,0 +1,298 @@ +''' + icmplib + ~~~~~~~ + + Easily forge ICMP packets and make your own ping and traceroute. + + https://github.com/ValentinBELYN/icmplib + + :copyright: Copyright 2017-2023 Valentin BELYN. + :license: GNU LGPLv3, see the LICENSE for details. + + ~~~~~~~ + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program. If not, see + . +''' + +import asyncio +from time import sleep + +from .sockets import ICMPv4Socket, ICMPv6Socket, AsyncSocket +from .models import ICMPRequest, Host +from .exceptions import ICMPLibError +from .utils import * + + +def ping(address, count=4, interval=1, timeout=2, id=None, source=None, + family=None, privileged=True, **kwargs): + ''' + Send ICMP Echo Request packets to a network host. + + :type address: str + :param address: The IP address, hostname or FQDN of the host to + which messages should be sent. For deterministic behavior, + prefer to use an IP address. + + :type count: int, optional + :param count: The number of ping to perform. Default to 4. + + :type interval: int or float, optional + :param interval: The interval in seconds between sending each packet. + Default to 1. + + :type timeout: int or float, optional + :param timeout: The maximum waiting time for receiving a reply in + seconds. Default to 2. + + :type id: int, optional + :param id: The identifier of ICMP requests. Used to match the + responses with requests. In practice, a unique identifier should + be used for every ping process. On Linux, this identifier is + ignored when the `privileged` parameter is disabled. The library + handles this identifier itself by default. + + :type source: str, optional + :param source: The IP address from which you want to send packets. + By default, the interface is automatically chosen according to + the specified destination. + + :type family: int, optional + :param family: The address family if a hostname or FQDN is specified. + Can be set to `4` for IPv4 or `6` for IPv6 addresses. By default, + this function searches for IPv4 addresses first before searching + for IPv6 addresses. + + :type privileged: bool, optional + :param privileged: When this option is enabled, this library fully + manages the exchanges and the structure of ICMP packets. + Disable this option if you want to use this function without + root privileges and let the kernel handle ICMP headers. + Default to True. + Only available on Unix systems. Ignored on Windows. + + Advanced (**kwags): + + :type payload: bytes, optional + :param payload: The payload content in bytes. A random payload is + used by default. + + :type payload_size: int, optional + :param payload_size: The payload size. Ignored when the `payload` + parameter is set. Default to 56. + + :type traffic_class: int, optional + :param traffic_class: The traffic class of ICMP packets. + Provides a defined level of service to packets by setting the DS + Field (formerly TOS) or the Traffic Class field of IP headers. + Packets are delivered with the minimum priority by default + (Best-effort delivery). + Intermediate routers must be able to support this feature. + Only available on Unix systems. Ignored on Windows. + + :rtype: Host + :returns: A `Host` object containing statistics about the desired + destination. + + :raises NameLookupError: If you pass a hostname or FQDN in + parameters and it does not exist or cannot be resolved. + :raises SocketPermissionError: If the privileges are insufficient to + create the socket. + :raises SocketAddressError: If the source address cannot be assigned + to the socket. + :raises ICMPSocketError: If another error occurs. See the + `ICMPv4Socket` or `ICMPv6Socket` class for details. + + Usage:: + + >>> from icmplib import ping + >>> host = ping('1.1.1.1') + >>> host.avg_rtt + 13.2 + >>> host.is_alive + True + + See the `Host` class for details. + + ''' + if is_hostname(address): + address = resolve(address, family)[0] + + if is_ipv6_address(address): + _Socket = ICMPv6Socket + else: + _Socket = ICMPv4Socket + + id = id or unique_identifier() + packets_sent = 0 + rtts = [] + + with _Socket(source, privileged) as sock: + for sequence in range(count): + if sequence > 0: + sleep(interval) + + request = ICMPRequest( + destination=address, + id=id, + sequence=sequence, + **kwargs) + + try: + sock.send(request) + packets_sent += 1 + + reply = sock.receive(request, timeout) + reply.raise_for_status() + + rtt = (reply.time - request.time) * 1000 + rtts.append(rtt) + + except ICMPLibError: + pass + + return Host(address, packets_sent, rtts) + + +async def async_ping(address, count=4, interval=1, timeout=2, id=None, + source=None, family=None, privileged=True, **kwargs): + ''' + Send ICMP Echo Request packets to a network host. + + This function is non-blocking. + + :type address: str + :param address: The IP address, hostname or FQDN of the host to + which messages should be sent. For deterministic behavior, + prefer to use an IP address. + + :type count: int, optional + :param count: The number of ping to perform. Default to 4. + + :type interval: int or float, optional + :param interval: The interval in seconds between sending each packet. + Default to 1. + + :type timeout: int or float, optional + :param timeout: The maximum waiting time for receiving a reply in + seconds. Default to 2. + + :type id: int, optional + :param id: The identifier of ICMP requests. Used to match the + responses with requests. In practice, a unique identifier should + be used for every ping process. On Linux, this identifier is + ignored when the `privileged` parameter is disabled. The library + handles this identifier itself by default. + + :type source: str, optional + :param source: The IP address from which you want to send packets. + By default, the interface is automatically chosen according to + the specified destination. + + :type family: int, optional + :param family: The address family if a hostname or FQDN is specified. + Can be set to `4` for IPv4 or `6` for IPv6 addresses. By default, + this function searches for IPv4 addresses first before searching + for IPv6 addresses. + + :type privileged: bool, optional + :param privileged: When this option is enabled, this library fully + manages the exchanges and the structure of ICMP packets. + Disable this option if you want to use this function without + root privileges and let the kernel handle ICMP headers. + Default to True. + Only available on Unix systems. Ignored on Windows. + + Advanced (**kwags): + + :type payload: bytes, optional + :param payload: The payload content in bytes. A random payload is + used by default. + + :type payload_size: int, optional + :param payload_size: The payload size. Ignored when the `payload` + parameter is set. Default to 56. + + :type traffic_class: int, optional + :param traffic_class: The traffic class of ICMP packets. + Provides a defined level of service to packets by setting the DS + Field (formerly TOS) or the Traffic Class field of IP headers. + Packets are delivered with the minimum priority by default + (Best-effort delivery). + Intermediate routers must be able to support this feature. + Only available on Unix systems. Ignored on Windows. + + :rtype: Host + :returns: A `Host` object containing statistics about the desired + destination. + + :raises NameLookupError: If you pass a hostname or FQDN in + parameters and it does not exist or cannot be resolved. + :raises SocketPermissionError: If the privileges are insufficient to + create the socket. + :raises SocketAddressError: If the source address cannot be assigned + to the socket. + :raises ICMPSocketError: If another error occurs. See the + `ICMPv4Socket` or `ICMPv6Socket` class for details. + + Usage:: + + >>> import asyncio + >>> from icmplib import async_ping + >>> host = asyncio.run(async_ping('1.1.1.1')) + >>> host.avg_rtt + 13.2 + >>> host.is_alive + True + + See the `Host` class for details. + + ''' + if is_hostname(address): + address = (await async_resolve(address, family))[0] + + if is_ipv6_address(address): + _Socket = ICMPv6Socket + else: + _Socket = ICMPv4Socket + + id = id or unique_identifier() + packets_sent = 0 + rtts = [] + + with AsyncSocket(_Socket(source, privileged)) as sock: + for sequence in range(count): + if sequence > 0: + await asyncio.sleep(interval) + + request = ICMPRequest( + destination=address, + id=id, + sequence=sequence, + **kwargs) + + try: + sock.send(request) + packets_sent += 1 + + reply = await sock.receive(request, timeout) + reply.raise_for_status() + + rtt = (reply.time - request.time) * 1000 + rtts.append(rtt) + + except ICMPLibError: + pass + + return Host(address, packets_sent, rtts) diff --git a/script.plexmod/lib/_included_packages/icmplib/sockets.py b/script.plexmod/lib/_included_packages/icmplib/sockets.py new file mode 100644 index 0000000000..130f55a3ab --- /dev/null +++ b/script.plexmod/lib/_included_packages/icmplib/sockets.py @@ -0,0 +1,806 @@ +''' + icmplib + ~~~~~~~ + + Easily forge ICMP packets and make your own ping and traceroute. + + https://github.com/ValentinBELYN/icmplib + + :copyright: Copyright 2017-2023 Valentin BELYN. + :license: GNU LGPLv3, see the LICENSE for details. + + ~~~~~~~ + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program. If not, see + . +''' + +import socket, asyncio +from struct import pack, unpack +from time import time + +from .models import ICMPReply +from .exceptions import * +from .utils import PLATFORM_LINUX, PLATFORM_MACOS, PLATFORM_WINDOWS + + +class ICMPSocket: + ''' + Base class for ICMP sockets. + + :type address: str, optional + :param address: The IP address from which you want to listen and + send packets. By default, the socket listens on all interfaces. + + :type privileged: bool, optional + :param privileged: When this option is enabled, the socket fully + manages the exchanges and the structure of the ICMP packets. + Disable this option if you want to instantiate and use the + socket without root privileges and let the kernel handle ICMP + headers. Default to True. + Only available on Unix systems. Ignored on Windows. + + :raises SocketPermissionError: If the privileges are insufficient to + create the socket. + :raises SocketAddressError: If the requested address cannot be + assigned to the socket. + :raises ICMPSocketError: If another error occurs while creating the + socket. + + ''' + __slots__ = '_sock', '_address', '_privileged' + + _IP_VERSION = -1 + _ICMP_HEADER_OFFSET = -1 + _ICMP_HEADER_REAL_OFFSET = -1 + + _ICMP_CODE_OFFSET = _ICMP_HEADER_OFFSET + 1 + _ICMP_CHECKSUM_OFFSET = _ICMP_HEADER_OFFSET + 2 + _ICMP_ID_OFFSET = _ICMP_HEADER_OFFSET + 4 + _ICMP_SEQUENCE_OFFSET = _ICMP_HEADER_OFFSET + 6 + _ICMP_PAYLOAD_OFFSET = _ICMP_HEADER_OFFSET + 8 + + _ICMP_ECHO_REQUEST = -1 + _ICMP_ECHO_REPLY = -1 + + def __init__(self, address=None, privileged=True): + self._sock = None + self._address = address + + # The Linux kernel allows unprivileged users to use datagram + # sockets (SOCK_DGRAM) to send ICMP requests. This feature is + # now supported by the majority of Unix systems. + # Windows is not compatible. + self._privileged = privileged or PLATFORM_WINDOWS + + try: + self._sock = self._create_socket( + socket.SOCK_RAW if self._privileged else + socket.SOCK_DGRAM) + + if address: + self._sock.bind((address, 0)) + + except OSError as err: + if err.errno in (1, 13, 10013): + raise SocketPermissionError(privileged) + + if err.errno in (-9, 49, 99, 10049, 11001): + raise SocketAddressError(address) + + raise ICMPSocketError(str(err)) + + def __enter__(self): + ''' + Return this object. + + ''' + return self + + def __exit__(self, type, value, traceback): + ''' + Call the `close` method. + + ''' + self.close() + + def __del__(self): + ''' + Call the `close` method. + + ''' + self.close() + + def _create_socket(self, type): + ''' + Create and return a new socket. Must be overridden. + + ''' + raise NotImplementedError + + def _set_ttl(self, ttl): + ''' + Set the time to live of every IP packet originating from this + socket. Must be overridden. + + ''' + raise NotImplementedError + + def _set_traffic_class(self, traffic_class): + ''' + Set the DS Field (formerly TOS) or the Traffic Class field of + every IP packet originating from this socket. Must be + overridden. + + ''' + raise NotImplementedError + + def _checksum(self, data): + ''' + Compute the checksum of an ICMP packet. Checksums are used to + verify the integrity of packets. + + ''' + sum = 0 + data += b'\x00' + + for i in range(0, len(data) - 1, 2): + sum += (data[i] << 8) + data[i + 1] + sum = (sum & 0xffff) + (sum >> 16) + + sum = ~sum & 0xffff + + return sum + + def _create_packet(self, id, sequence, payload): + ''' + Build an ICMP packet from an identifier, a sequence number and + a payload. + + This method returns the newly created ICMP header concatenated + to the payload passed in parameters. + + ''' + checksum = 0 + + # Temporary ICMP header to compute the checksum + header = pack('!2B3H', self._ICMP_ECHO_REQUEST, 0, checksum, + id, sequence) + + checksum = self._checksum(header + payload) + + # Definitive ICMP header + header = pack('!2B3H', self._ICMP_ECHO_REQUEST, 0, checksum, + id, sequence) + + return header + payload + + def _parse_reply(self, packet, source, current_time): + ''' + Parse an ICMP reply from bytes. + + This method returns an `ICMPReply` object or `None` if the reply + cannot be parsed. + + ''' + # On Linux, the IP header is missing when a datagram socket is + # used (SOCK_DGRAM). To keep the same behavior on all operating + # systems including macOS which has this header, we add a + # padding of the size of the missing IP header. + if not self._privileged and PLATFORM_LINUX: + packet = b'\x00' * self._ICMP_HEADER_OFFSET + packet + + bytes_received = len(packet) - self._ICMP_HEADER_OFFSET + + if len(packet) < self._ICMP_CHECKSUM_OFFSET: + return None + + type, code = unpack('!2B', packet[ + self._ICMP_HEADER_OFFSET: + self._ICMP_CHECKSUM_OFFSET]) + + if type != self._ICMP_ECHO_REPLY: + packet = packet[ + self._ICMP_PAYLOAD_OFFSET + - self._ICMP_HEADER_OFFSET + + self._ICMP_HEADER_REAL_OFFSET:] + + if len(packet) < self._ICMP_PAYLOAD_OFFSET: + return None + + id, sequence = unpack('!2H', packet[ + self._ICMP_ID_OFFSET: + self._ICMP_PAYLOAD_OFFSET]) + + return ICMPReply( + source=source, + family=self._IP_VERSION, + id=id, + sequence=sequence, + type=type, + code=code, + bytes_received=bytes_received, + time=current_time) + + def send(self, request): + ''' + Send an ICMP request message over the network to a remote host. + + This operation is non-blocking. Use the `receive` method to get + the reply. + + :type request: ICMPRequest + :param request: The ICMP request you have created. If the socket + is used in non-privileged mode on a Linux system, the + identifier defined in the request will be replaced by the + kernel. + + :raises SocketBroadcastError: If a broadcast address is used and + the corresponding option is not enabled on the socket + (ICMPv4 only). + :raises SocketUnavailableError: If the socket is closed. + :raises ICMPSocketError: If another error occurs while sending. + + ''' + if not self._sock: + raise SocketUnavailableError + + try: + sock_destination = socket.getaddrinfo( + host=request.destination, + port=None, + family=self._sock.family, + type=self._sock.type)[0][4] + + packet = self._create_packet( + id=request.id, + sequence=request.sequence, + payload=request.payload) + + self._set_ttl(request.ttl) + self._set_traffic_class(request.traffic_class) + + request._time = time() + self._sock.sendto(packet, sock_destination) + + # On Linux, the ICMP request identifier is replaced by the + # kernel with a random port number when a datagram socket is + # used (SOCK_DGRAM). So, we update the request created by + # the user to take this new identifier into account. + if not self._privileged and PLATFORM_LINUX: + request._id = self._sock.getsockname()[1] + + except PermissionError: + raise SocketBroadcastError + + except OSError as err: + raise ICMPSocketError(str(err)) + + def receive(self, request=None, timeout=2): + ''' + Receive an ICMP reply message from the socket. + + This method can be called multiple times if you expect several + responses as with a broadcast address. + + :type request: ICMPRequest, optional + :param request: The ICMP request to use to match the response. + By default, all ICMP packets arriving on the socket are + returned. + + :type timeout: int or float, optional + :param timeout: The maximum waiting time for receiving the + response in seconds. Default to 2. + + :rtype: ICMPReply + :returns: An `ICMPReply` object representing the response of the + desired destination or an upstream gateway. See the + `ICMPReply` class for details. + + :raises TimeoutExceeded: If no response is received before the + timeout specified in parameters. + :raises SocketUnavailableError: If the socket is closed. + :raises ICMPSocketError: If another error occurs while receiving. + + ''' + if not self._sock: + raise SocketUnavailableError + + self._sock.settimeout(timeout) + time_limit = time() + timeout + + try: + while True: + response = self._sock.recvfrom(1024) + current_time = time() + + packet = response[0] + source = response[1][0] + + if current_time > time_limit: + raise socket.timeout + + reply = self._parse_reply( + packet=packet, + source=source, + current_time=current_time) + + if (reply and not request or + reply and request.id == reply.id and + request.sequence == reply.sequence): + return reply + + except socket.timeout: + raise TimeoutExceeded(timeout) + + except OSError as err: + raise ICMPSocketError(str(err)) + + def close(self): + ''' + Close the socket. It cannot be used after this call. + + ''' + if self._sock: + self._sock.close() + self._sock = None + + @property + def sock(self): + ''' + Return the underlying socket (`socket.socket` object) or `None` + if the socket is closed. + + This property should only be used if the feature you want is not + yet implemented. Some changes made to this socket may cause + unexpected behavior or be incompatible with later versions of + the library. + + Prefer to use the other methods and properties defined within + this class if possible. + + ''' + return self._sock + + @property + def blocking(self): + ''' + Indicate whether the socket is in blocking mode. + Return a `boolean`. + + ''' + return self._sock.getblocking() + + @blocking.setter + def blocking(self, enable): + return self._sock.setblocking(enable) + + @property + def address(self): + ''' + The IP address from which the socket listens and sends packets. + Return `None` if the socket listens on all interfaces. + + ''' + return self._address + + @property + def is_privileged(self): + ''' + Indicate whether the socket is running in privileged mode. + Return a `boolean`. + + ''' + return self._privileged + + @property + def is_closed(self): + ''' + Indicate whether the socket is closed. + Return a `boolean`. + + ''' + return self._sock is None + + +# Echo Request and Echo Reply messages RFC 792 +# +# 0 1 2 3 +# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Type | Code | Checksum | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Identifier | Sequence Number | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Data ... +# +-+-+-+-+- +# +# ICMPv4 Error message RFC 792 +# +# 0 1 2 3 +# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Type | Code | Checksum | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Unused / Depends on the error | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Internet Header + 64 bits of Original Data Datagram | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +class ICMPv4Socket(ICMPSocket): + ''' + Class for sending and receiving ICMPv4 packets. + + :type address: str, optional + :param address: The IP address from which you want to listen and + send packets. By default, the socket listens on all interfaces. + + :type privileged: bool, optional + :param privileged: When this option is enabled, the socket fully + manages the exchanges and the structure of the ICMP packets. + Disable this option if you want to instantiate and use the + socket without root privileges and let the kernel handle ICMP + headers. Default to True. + Only available on Unix systems. Ignored on Windows. + + :raises SocketPermissionError: If the privileges are insufficient to + create the socket. + :raises SocketAddressError: If the requested address cannot be + assigned to the socket. + :raises ICMPSocketError: If another error occurs while creating the + socket. + + ''' + __slots__ = '_sock', '_address', '_privileged' + + _IP_VERSION = 4 + _ICMP_HEADER_OFFSET = 20 + _ICMP_HEADER_REAL_OFFSET = 20 + + _ICMP_CODE_OFFSET = _ICMP_HEADER_OFFSET + 1 + _ICMP_CHECKSUM_OFFSET = _ICMP_HEADER_OFFSET + 2 + _ICMP_ID_OFFSET = _ICMP_HEADER_OFFSET + 4 + _ICMP_SEQUENCE_OFFSET = _ICMP_HEADER_OFFSET + 6 + _ICMP_PAYLOAD_OFFSET = _ICMP_HEADER_OFFSET + 8 + + _ICMP_ECHO_REQUEST = 8 + _ICMP_ECHO_REPLY = 0 + + def _create_socket(self, type): + ''' + Create and return a new socket. + + ''' + return socket.socket( + family=socket.AF_INET, + type=type, + proto=socket.IPPROTO_ICMP) + + def _set_ttl(self, ttl): + ''' + Set the time to live of every IP packet originating from this + socket. + + ''' + self._sock.setsockopt( + socket.IPPROTO_IP, + socket.IP_TTL, + ttl) + + def _set_traffic_class(self, traffic_class): + ''' + Set the DS Field (formerly TOS) of every IP packet originating + from this socket. + + Only available on Unix systems. Ignored on Windows. + + ''' + # Not available on Windows + if PLATFORM_WINDOWS: + return + + self._sock.setsockopt( + socket.IPPROTO_IP, + socket.IP_TOS, + traffic_class) + + @property + def broadcast(self): + ''' + Indicate whether broadcast support is enabled on the socket. + Return a `boolean`. + + .. note:: + To enable broadcast support: + icmp_socket.broadcast = True + + ''' + return self._sock.getsockopt( + socket.SOL_SOCKET, + socket.SO_BROADCAST) > 0 + + @broadcast.setter + def broadcast(self, enable): + self._sock.setsockopt( + socket.SOL_SOCKET, + socket.SO_BROADCAST, + enable) + + +# Echo Request and Echo Reply messages RFC 4443 +# +# 0 1 2 3 +# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Type | Code | Checksum | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Identifier | Sequence Number | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Data ... +# +-+-+-+-+- +# +# ICMPv6 Error message RFC 4443 +# +# 0 1 2 3 +# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Type | Code | Checksum | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Unused / Depends on the error | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Original packet without exceed the minimum IPv6 MTU | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +# Windows IPv6 compatibility +if PLATFORM_WINDOWS: + socket.IPPROTO_IPV6 = 41 + socket.IPPROTO_ICMPV6 = 58 + + +class ICMPv6Socket(ICMPSocket): + ''' + Class for sending and receiving ICMPv6 packets. + + :type address: str, optional + :param address: The IP address from which you want to listen and + send packets. By default, the socket listens on all interfaces. + + :type privileged: bool, optional + :param privileged: When this option is enabled, the socket fully + manages the exchanges and the structure of the ICMP packets. + Disable this option if you want to instantiate and use the + socket without root privileges and let the kernel handle ICMP + headers. Default to True. + Only available on Unix systems. Ignored on Windows. + + :raises SocketPermissionError: If the privileges are insufficient to + create the socket. + :raises SocketAddressError: If the requested address cannot be + assigned to the socket. + :raises ICMPSocketError: If another error occurs while creating the + socket. + + ''' + __slots__ = '_sock', '_address', '_privileged' + + _IP_VERSION = 6 + _ICMP_HEADER_OFFSET = 0 + _ICMP_HEADER_REAL_OFFSET = 40 + + _ICMP_CODE_OFFSET = _ICMP_HEADER_OFFSET + 1 + _ICMP_CHECKSUM_OFFSET = _ICMP_HEADER_OFFSET + 2 + _ICMP_ID_OFFSET = _ICMP_HEADER_OFFSET + 4 + _ICMP_SEQUENCE_OFFSET = _ICMP_HEADER_OFFSET + 6 + _ICMP_PAYLOAD_OFFSET = _ICMP_HEADER_OFFSET + 8 + + _ICMP_ECHO_REQUEST = 128 + _ICMP_ECHO_REPLY = 129 + + def _create_socket(self, type): + ''' + Create and return a new socket. + + ''' + return socket.socket( + family=socket.AF_INET6, + type=type, + proto=socket.IPPROTO_ICMPV6) + + def _set_ttl(self, ttl): + ''' + Set the time to live of every IP packet originating from this + socket. + + ''' + # Not available on macOS when the privileged param. is disabled + if PLATFORM_MACOS and not self._privileged: + return + + self._sock.setsockopt( + socket.IPPROTO_IPV6, + socket.IPV6_UNICAST_HOPS, + ttl) + + def _set_traffic_class(self, traffic_class): + ''' + Set the Traffic Class field of every IP packet originating from + this socket. + + Only available on Unix systems. Ignored on Windows. + + ''' + # Not available on Windows + if PLATFORM_WINDOWS: + return + + # Not available on macOS when the privileged param. is disabled + if PLATFORM_MACOS and not self._privileged: + return + + self._sock.setsockopt( + socket.IPPROTO_IPV6, + socket.IPV6_TCLASS, + traffic_class) + + +class AsyncSocket: + ''' + A wrapper for ICMP sockets which makes them asynchronous. + + :type icmp_sock: ICMPSocket + :param icmp_sock: An ICMP socket. Once the wrapper is instantiated, + this socket should no longer be used directly. + + ''' + __slots__ = '_icmp_sock' + + def __init__(self, icmp_sock): + self._icmp_sock = icmp_sock + self._icmp_sock.blocking = False + + def __getattr__(self, name): + ''' + Return the specified attribute of the underlying ICMP socket. + + ''' + if not self._icmp_sock: + raise SocketUnavailableError + + return getattr(self._icmp_sock, name) + + def __enter__(self): + ''' + Return this object. + + ''' + return self + + def __exit__(self, type, value, traceback): + ''' + Call the `close` method. + + ''' + self.close() + + def __del__(self): + ''' + Call the `close` method. + + ''' + self.close() + + async def receive(self, request=None, timeout=2): + ''' + Receive an ICMP reply message from the socket. + + This method can be called multiple times if you expect several + responses as with a broadcast address. + + This method is non-blocking. + + :type request: ICMPRequest, optional + :param request: The ICMP request to use to match the response. + By default, all ICMP packets arriving on the socket are + returned. + + :type timeout: int or float, optional + :param timeout: The maximum waiting time for receiving the + response in seconds. Default to 2. + + :rtype: ICMPReply + :returns: An `ICMPReply` object representing the response of the + desired destination or an upstream gateway. See the + `ICMPReply` class for details. + Unlike the `reveive` method of synchronous ICMP sockets, the + returned `ICMPReply` object does not specify the IP address + of the host that replied to the request message. + + :raises TimeoutExceeded: If no response is received before the + timeout specified in parameters. + :raises SocketUnavailableError: If the socket is closed. + :raises ICMPSocketError: If another error occurs while receiving. + + ''' + if not self._icmp_sock or not self._icmp_sock._sock: + raise SocketUnavailableError + + loop = asyncio.get_running_loop() + time_limit = time() + timeout + remaining_time = timeout + + try: + while True: + packet = await asyncio.wait_for( + loop.sock_recv(self._icmp_sock._sock, 1024), + remaining_time) + + current_time = time() + + if current_time > time_limit: + raise asyncio.TimeoutError + + reply = self._parse_reply( + packet=packet, + source=None, + current_time=current_time) + + if (reply and not request or + reply and request.id == reply.id and + request.sequence == reply.sequence): + return reply + + remaining_time = time_limit - current_time + + except asyncio.TimeoutError: + raise TimeoutExceeded(timeout) + + except OSError as err: + raise ICMPSocketError(str(err)) + + finally: + if isinstance(loop, asyncio.SelectorEventLoop): + loop.remove_reader(self._icmp_sock._sock) + + def detach(self): + ''' + Detach the socket from the wrapper and return it. The wrapper + cannot be used after this call but the socket can be reused for + other purposes. + + ''' + icmp_sock = self._icmp_sock + + if self._icmp_sock: + self._icmp_sock = None + + return icmp_sock + + def close(self): + ''' + Detach the underlying socket from the wrapper and close it. Both + cannot be used after this call. + + ''' + if self._icmp_sock: + self.detach().close() + + @property + def is_closed(self): + ''' + Indicate whether the underlying socket is closed or detached + from this wrapper. Return a `boolean`. + + ''' + return self._icmp_sock is None diff --git a/script.plexmod/lib/_included_packages/icmplib/traceroute.py b/script.plexmod/lib/_included_packages/icmplib/traceroute.py new file mode 100644 index 0000000000..7dd45f8760 --- /dev/null +++ b/script.plexmod/lib/_included_packages/icmplib/traceroute.py @@ -0,0 +1,212 @@ +''' + icmplib + ~~~~~~~ + + Easily forge ICMP packets and make your own ping and traceroute. + + https://github.com/ValentinBELYN/icmplib + + :copyright: Copyright 2017-2023 Valentin BELYN. + :license: GNU LGPLv3, see the LICENSE for details. + + ~~~~~~~ + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program. If not, see + . +''' + +from time import sleep + +from .sockets import ICMPv4Socket, ICMPv6Socket +from .models import ICMPRequest, Hop +from .exceptions import TimeExceeded, ICMPLibError +from .utils import * + + +def traceroute(address, count=2, interval=0.05, timeout=2, first_hop=1, + max_hops=30, fast=False, id=None, source=None, family=None, + **kwargs): + ''' + Determine the route to a destination host. + + The Internet is a large and complex aggregation of network hardware, + connected together by gateways. Tracking the route one's packets + follow can be difficult. This function uses the IP protocol time to + live field and attempts to elicit an ICMP Time Exceeded response + from each gateway along the path to some host. + + This function requires root privileges to run. + + :type address: str + :param address: The IP address, hostname or FQDN of the host to + reach. For deterministic behavior, prefer to use an IP address. + + :type count: int, optional + :param count: The number of ping to perform per hop. Default to 2. + + :type interval: int or float, optional + :param interval: The interval in seconds between sending each packet. + Default to 0.05. + + :type timeout: int or float, optional + :param timeout: The maximum waiting time for receiving a reply in + seconds. Default to 2. + + :type first_hop: int, optional + :param first_hop: The initial time to live value used in outgoing + probe packets. Default to 1. + + :type max_hops: int, optional + :param max_hops: The maximum time to live (max number of hops) used + in outgoing probe packets. Default to 30. + + :type fast: bool, optional + :param fast: When this option is enabled and an intermediate router + has been reached, skip to the next hop rather than perform + additional requests. The `count` parameter then becomes the + maximum number of requests in the event of no response. + Default to False. + + :type id: int, optional + :param id: The identifier of ICMP requests. Used to match the + responses with requests. In practice, a unique identifier should + be used for every traceroute process. The library handles this + identifier itself by default. + + :type source: str, optional + :param source: The IP address from which you want to send packets. + By default, the interface is automatically chosen according to + the specified destination. + + :type family: int, optional + :param family: The address family if a hostname or FQDN is specified. + Can be set to `4` for IPv4 or `6` for IPv6 addresses. By default, + this function searches for IPv4 addresses first before searching + for IPv6 addresses. + + Advanced (**kwags): + + :type payload: bytes, optional + :param payload: The payload content in bytes. A random payload is + used by default. + + :type payload_size: int, optional + :param payload_size: The payload size. Ignored when the `payload` + parameter is set. Default to 56. + + :type traffic_class: int, optional + :param traffic_class: The traffic class of ICMP packets. + Provides a defined level of service to packets by setting the DS + Field (formerly TOS) or the Traffic Class field of IP headers. + Packets are delivered with the minimum priority by default + (Best-effort delivery). + Intermediate routers must be able to support this feature. + Only available on Unix systems. Ignored on Windows. + + :rtype: list[Hop] + :returns: A list of `Hop` objects representing the route to the + desired destination. The list is sorted in ascending order + according to the distance, in terms of hops, that separates the + remote host from the current machine. Gateways that do not + respond to requests are not added to this list. + + :raises NameLookupError: If you pass a hostname or FQDN in + parameters and it does not exist or cannot be resolved. + :raises SocketPermissionError: If the privileges are insufficient to + create the socket. + :raises SocketAddressError: If the source address cannot be assigned + to the socket. + :raises ICMPSocketError: If another error occurs. See the + `ICMPv4Socket` or `ICMPv6Socket` class for details. + + Usage:: + + >>> from icmplib import traceroute + >>> hops = traceroute('1.1.1.1') + >>> last_distance = 0 + + >>> for hop in hops: + ... if last_distance + 1 != hop.distance: + ... print('Some gateways are not responding') + ... + ... print(f'{hop.distance} {hop.address} {hop.avg_rtt} ms') + ... + ... last_distance = hop.distance + + 1 10.0.0.1 5.196 ms + 2 194.149.169.49 7.552 ms + 3 194.149.166.54 12.21 ms + * Some gateways are not responding + 5 212.73.205.22 22.15 ms + 6 1.1.1.1 13.59 ms + + See the `Hop` class for details. + + ''' + if is_hostname(address): + address = resolve(address, family)[0] + + if is_ipv6_address(address): + _Socket = ICMPv6Socket + else: + _Socket = ICMPv4Socket + + id = id or unique_identifier() + ttl = first_hop + host_reached = False + hops = [] + + with _Socket(source) as sock: + while not host_reached and ttl <= max_hops: + reply = None + packets_sent = 0 + rtts = [] + + for sequence in range(count): + request = ICMPRequest( + destination=address, + id=id, + sequence=sequence, + ttl=ttl, + **kwargs) + + try: + sock.send(request) + packets_sent += 1 + + reply = sock.receive(request, timeout) + rtt = (reply.time - request.time) * 1000 + rtts.append(rtt) + + reply.raise_for_status() + host_reached = True + + except TimeExceeded: + sleep(interval) + + except ICMPLibError: + break + + if reply: + hop = Hop( + address=reply.source, + packets_sent=packets_sent, + rtts=rtts, + distance=ttl) + + hops.append(hop) + + ttl += 1 + + return hops diff --git a/script.plexmod/lib/_included_packages/icmplib/utils.py b/script.plexmod/lib/_included_packages/icmplib/utils.py new file mode 100644 index 0000000000..00e2664dbb --- /dev/null +++ b/script.plexmod/lib/_included_packages/icmplib/utils.py @@ -0,0 +1,199 @@ +''' + icmplib + ~~~~~~~ + + Easily forge ICMP packets and make your own ping and traceroute. + + https://github.com/ValentinBELYN/icmplib + + :copyright: Copyright 2017-2023 Valentin BELYN. + :license: GNU LGPLv3, see the LICENSE for details. + + ~~~~~~~ + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program. If not, see + . +''' + +import socket, asyncio + +from threading import Lock +from sys import platform +from os import getpid +from re import match +from random import choices + +from .exceptions import NameLookupError + + +PID = getpid() +PLATFORM_LINUX = platform == 'linux' +PLATFORM_MACOS = platform == 'darwin' +PLATFORM_WINDOWS = platform == 'win32' + +_lock_id = Lock() +_current_id = PID + + +def random_byte_message(size): + ''' + Generate a random byte sequence of the specified size. + + ''' + sequence = choices( + b'abcdefghijklmnopqrstuvwxyz' + b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + b'1234567890', k=size) + + return bytes(sequence) + + +def unique_identifier(): + ''' + Generate a unique identifier between 0 and 65535. + The first number generated will be equal to the PID + 1. + + ''' + global _current_id + + with _lock_id: + _current_id += 1 + _current_id &= 0xffff + + return _current_id + + +def resolve(name, family=None): + ''' + Resolve a hostname or FQDN to an IP address. Depending on the name + specified in parameters, several IP addresses may be returned. + + This function relies on the DNS name server configured on your + operating system. + + :type name: str + :param name: A hostname or a Fully Qualified Domain Name (FQDN). + + :type family: int, optional + :param family: The address family. Can be set to `4` for IPv4 or `6` + for IPv6 addresses. By default, this function searches for IPv4 + addresses first for compatibility reasons (A DNS lookup) before + searching for IPv6 addresses (AAAA DNS lookup). + + :rtype: list[str] + :returns: A list of IP addresses corresponding to the name passed as + a parameter. + + :raises NameLookupError: If the requested name does not exist or + cannot be resolved. + + ''' + try: + if family == 6: + _family = socket.AF_INET6 + else: + _family = socket.AF_INET + + lookup = socket.getaddrinfo( + host=name, + port=None, + family=_family, + type=socket.SOCK_DGRAM) + + return [address[4][0] for address in lookup] + + except OSError: + if not family: + return resolve(name, 6) + + raise NameLookupError(name) + + +async def async_resolve(name, family=None): + ''' + Resolve a hostname or FQDN to an IP address. Depending on the name + specified in parameters, several IP addresses may be returned. + + This function relies on the DNS name server configured on your + operating system. + + This function is non-blocking. + + :type name: str + :param name: A hostname or a Fully Qualified Domain Name (FQDN). + + :type family: int, optional + :param family: The address family. Can be set to `4` for IPv4 or `6` + for IPv6 addresses. By default, this function searches for IPv4 + addresses first for compatibility reasons (A DNS lookup) before + searching for IPv6 addresses (AAAA DNS lookup). + + :rtype: list[str] + :returns: A list of IP addresses corresponding to the name passed as + a parameter. + + :raises NameLookupError: If the requested name does not exist or + cannot be resolved. + + ''' + try: + if family == 6: + _family = socket.AF_INET6 + else: + _family = socket.AF_INET + + loop = asyncio.get_running_loop() + + lookup = await loop.getaddrinfo( + host=name, + port=None, + family=_family, + type=socket.SOCK_DGRAM) + + return [address[4][0] for address in lookup] + + except OSError: + if not family: + return await async_resolve(name, 6) + + raise NameLookupError(name) + + +def is_hostname(name): + ''' + Indicate whether the specified name is a hostname or an FQDN. + Return a `boolean`. + + ''' + pattern = r'(?i)^([a-z0-9-]+|([a-z0-9_-]+[.])+[a-z]+)$' + return match(pattern, name) is not None + + +def is_ipv4_address(address): + ''' + Indicate whether the specified address is an IPv4 address. + Return a `boolean`. + + ''' + pattern = r'^([0-9]{1,3}[.]){3}[0-9]{1,3}$' + return match(pattern, address) is not None + + +def is_ipv6_address(address): + ''' + Indicate whether the specified address is an IPv6 address. + Return a `boolean`. + + ''' + return ':' in address diff --git a/script.plexmod/lib/_included_packages/plexnet/__init__.py b/script.plexmod/lib/_included_packages/plexnet/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/script.plexmod/lib/_included_packages/plexnet/asyncadapter.py b/script.plexmod/lib/_included_packages/plexnet/asyncadapter.py new file mode 100644 index 0000000000..97fbcd741b --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/asyncadapter.py @@ -0,0 +1,338 @@ +from __future__ import absolute_import +import time +import socket +import six + +import requests +import six + +from requests.packages.urllib3 import HTTPConnectionPool, HTTPSConnectionPool +from requests.packages.urllib3.connection import HTTPConnection +from requests.packages.urllib3.poolmanager import PoolManager, proxy_from_url +try: + from requests.packages.urllib3.connectionpool import VerifiedHTTPSConnection +except ImportError: + # urllib3 >= 2.1.0 + from requests.packages.urllib3.connection import HTTPSConnection as VerifiedHTTPSConnection + +from requests.adapters import HTTPAdapter +from requests.compat import urlparse + +#from six.moves.http_client import HTTPConnection +import errno + +DEFAULT_POOLBLOCK = False +SSL_KEYWORDS = ('key_file', 'cert_file', 'cert_reqs', 'ca_certs', + 'ssl_version') + +WIN_WSAEINVAL = 10022 +WIN_EWOULDBLOCK = 10035 +WIN_ECONNRESET = 10054 +WIN_EISCONN = 10056 +WIN_ENOTCONN = 10057 +WIN_EHOSTUNREACH = 10065 + + +def ABORT_FLAG_FUNCTION(): + return False + + +class TimeoutException(Exception): + pass + + +class CanceledException(Exception): + pass + + +class AsyncTimeout(float): + def __repr__(self): + return '{0}({1})'.format(float(self), self.getConnectTimeout()) + + def __str__(self): + return repr(self) + + @classmethod + def fromTimeout(cls, t): + if isinstance(t, AsyncTimeout): + return t + + try: + return AsyncTimeout(float(t)) or DEFAULT_TIMEOUT + except TypeError: + return DEFAULT_TIMEOUT + + def setConnectTimeout(self, val): + self._connectTimout = val + return self + + def getConnectTimeout(self): + if hasattr(self, '_connectTimout'): + return self._connectTimout + + return self + + +DEFAULT_TIMEOUT = AsyncTimeout(10).setConnectTimeout(10) + + +class AsyncVerifiedHTTPSConnection(VerifiedHTTPSConnection): + def __init__(self, *args, **kwargs): + VerifiedHTTPSConnection.__init__(self, *args, **kwargs) + self._canceled = False + self.deadline = 0 + self._timeout = AsyncTimeout(DEFAULT_TIMEOUT) + + def _check_timeout(self): + if time.time() > self.deadline: + raise TimeoutException('connection timed out') + + def create_connection(self, address, timeout=None, source_address=None): + """Connect to *address* and return the socket object. + + Convenience function. Connect to *address* (a 2-tuple ``(host, + port)``) and return the socket object. Passing the optional + *timeout* parameter will set the timeout on the socket instance + before attempting to connect. If no *timeout* is supplied, the + global default timeout setting returned by :func:`getdefaulttimeout` + is used. If *source_address* is set it must be a tuple of (host, port) + for the socket to bind as a source address before making the connection. + An host of '' or port 0 tells the OS to use the default. + """ + timeout = AsyncTimeout.fromTimeout(timeout) + self._timeout = timeout + + host, port = address + err = None + for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket.socket(af, socktype, proto) + sock.setblocking(False) # this is obviously critical + self.deadline = time.time() + timeout.getConnectTimeout() + # sock.settimeout(timeout) + + if source_address: + sock.bind(source_address) + for msg in self._connect(sock, sa): + if self._canceled or ABORT_FLAG_FUNCTION(): + raise CanceledException('Request canceled') + sock.setblocking(True) + return sock + + except socket.error as _: + err = _ + if sock is not None: + sock.shutdown(socket.SHUT_RDWR) + sock.close() + + if err is not None: + raise err + else: + raise socket.error("getaddrinfo returns an empty list") + + def _connect(self, sock, sa): + while not self._canceled and not ABORT_FLAG_FUNCTION(): + time.sleep(0.01) + self._check_timeout() # this should be done at the beginning of each loop + status = sock.connect_ex(sa) + if not status or status in (errno.EISCONN, WIN_EISCONN): + break + elif status in (errno.EINPROGRESS, WIN_EWOULDBLOCK): + self.deadline = time.time() + self._timeout.getConnectTimeout() + # elif status in (errno.EWOULDBLOCK, errno.EALREADY) or (os.name == 'nt' and status == errno.WSAEINVAL): + # pass + yield + + if self._canceled or ABORT_FLAG_FUNCTION(): + raise CanceledException('Request canceled') + + error = sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) + if error: + # TODO: determine when this case can actually happen + raise socket.error((error,)) + + def _new_conn(self): + sock = self.create_connection( + address=(self.host, self.port), + timeout=self.timeout + ) + + return sock + + def cancel(self): + self._canceled = True + + +class AsyncHTTPConnection(HTTPConnection): + def __init__(self, *args, **kwargs): + HTTPConnection.__init__(self, *args, **kwargs) + self._canceled = False + self.deadline = 0 + + def cancel(self): + self._canceled = True + + +class AsyncHTTPConnectionPool(HTTPConnectionPool): + def __init__(self, *args, **kwargs): + HTTPConnectionPool.__init__(self, *args, **kwargs) + self.connections = [] + + def _new_conn(self): + """ + Return a fresh :class:`httplib.HTTPConnection`. + """ + self.num_connections += 1 + + extra_params = {} + if six.PY2: + extra_params['strict'] = self.strict + + conn = AsyncHTTPConnection(host=self.host, port=self.port, timeout=self.timeout.connect_timeout, **extra_params) + + # Backport fix LP #1412545 + if getattr(conn, '_tunnel_host', None): + # TODO: Fix tunnel so it doesn't depend on self.sock state. + conn._tunnel() + # Mark this connection as not reusable + conn.auto_open = 0 + + self.connections.append(conn) + + return conn + + def cancel(self): + for c in self.connections: + c.cancel() + + +class AsyncHTTPSConnectionPool(HTTPSConnectionPool): + def __init__(self, *args, **kwargs): + HTTPSConnectionPool.__init__(self, *args, **kwargs) + self.connections = [] + + def _new_conn(self): + """ + Return a fresh :class:`httplib.HTTPSConnection`. + """ + self.num_connections += 1 + + actual_host = self.host + actual_port = self.port + if self.proxy is not None: + actual_host = self.proxy.host + actual_port = self.proxy.port + + connection_class = AsyncVerifiedHTTPSConnection + + extra_params = {} + if six.PY2: + extra_params['strict'] = self.strict + connection = connection_class(host=actual_host, port=actual_port, timeout=self.timeout.connect_timeout, **extra_params) + + self.connections.append(connection) + + try: + return self._prepare_conn(connection) + except AttributeError: + # urllib3 2.1.0 + return connection + + def cancel(self): + for c in self.connections: + c.cancel() + + +pool_classes_by_scheme = { + 'http': AsyncHTTPConnectionPool, + 'https': AsyncHTTPSConnectionPool, +} + + +class AsyncPoolManager(PoolManager): + def _new_pool(self, scheme, host, port, request_context=None): + """ + Create a new :class:`ConnectionPool` based on host, port and scheme. + + This method is used to actually create the connection pools handed out + by :meth:`connection_from_url` and companion methods. It is intended + to be overridden for customization. + """ + pool_cls = pool_classes_by_scheme[scheme] + kwargs = self.connection_pool_kw + if scheme == 'http': + kwargs = self.connection_pool_kw.copy() + for kw in SSL_KEYWORDS: + kwargs.pop(kw, None) + + return pool_cls(host, port, **kwargs) + + +class AsyncHTTPAdapter(HTTPAdapter): + def cancel(self): + for c in self.connections: + c.cancel() + + def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK): + """Initializes a urllib3 PoolManager. This method should not be called + from user code, and is only exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param connections: The number of urllib3 connection pools to cache. + :param maxsize: The maximum number of connections to save in the pool. + :param block: Block when no free connections are available. + """ + # save these values for pickling + self._pool_connections = connections + self._pool_maxsize = maxsize + self._pool_block = block + + self.poolmanager = AsyncPoolManager(num_pools=connections, maxsize=maxsize, block=block) + self.connections = [] + + def get_connection(self, url, proxies=None): + """Returns a urllib3 connection for the given URL. This should not be + called from user code, and is only exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param url: The URL to connect to. + :param proxies: (optional) A Requests-style dictionary of proxies used on this request. + """ + proxies = proxies or {} + proxy = proxies.get(urlparse(url.lower()).scheme) + + if proxy: + proxy_headers = self.proxy_headers(proxy) + + if proxy not in self.proxy_manager: + self.proxy_manager[proxy] = proxy_from_url( + proxy, + proxy_headers=proxy_headers, + num_pools=self._pool_connections, + maxsize=self._pool_maxsize, + block=self._pool_block + ) + + conn = self.proxy_manager[proxy].connection_from_url(url) + else: + # Only scheme should be lower case + parsed = urlparse(url) + url = parsed.geturl() + conn = self.poolmanager.connection_from_url(url) + + self.connections.append(conn) + return conn + + +class Session(requests.Session): + def __init__(self, *args, **kwargs): + requests.Session.__init__(self, *args, **kwargs) + self.mount('https://', AsyncHTTPAdapter()) + self.mount('http://', AsyncHTTPAdapter()) + + def cancel(self): + for v in self.adapters.values(): + v.close() + v.cancel() diff --git a/script.plexmod/lib/_included_packages/plexnet/audio.py b/script.plexmod/lib/_included_packages/plexnet/audio.py new file mode 100644 index 0000000000..251c19b5e1 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/audio.py @@ -0,0 +1,153 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from . import plexobjects +from . import plexmedia +from . import media + + +class Audio(media.MediaItem): + def __init__(self, *args, **kwargs): + self._settings = None + media.MediaItem.__init__(self, *args, **kwargs) + + def __eq__(self, other): + return self.ratingKey == other.ratingKey + + def __ne__(self, other): + return not self.__eq__(other) + + def _setData(self, data): + for k, v in data.attrib.items(): + setattr(self, k, plexobjects.PlexValue(v, self)) + + self.key = plexobjects.PlexValue(self.key.replace('/children', ''), self) + + def isMusicItem(self): + return True + + +@plexobjects.registerLibType +class Artist(Audio): + TYPE = 'artist' + + def _setData(self, data): + Audio._setData(self, data) + if self.isFullObject(): + self.countries = plexobjects.PlexItemList(data, media.Country, media.Country.TYPE, server=self.server) + self.genres = plexobjects.PlexItemList(data, media.Genre, media.Genre.TYPE, server=self.server) + self.similar = plexobjects.PlexItemList(data, media.Similar, media.Similar.TYPE, server=self.server) + + def albums(self): + path = '%s/children' % self.key + return plexobjects.listItems(self.server, path, Album.TYPE) + + def album(self, title): + path = '%s/children' % self.key + return plexobjects.findItem(self.server, path, title) + + def tracks(self, watched=None): + leavesKey = '/library/metadata/%s/allLeaves' % self.ratingKey + return plexobjects.listItems(self.server, leavesKey, watched=watched) + + def all(self): + return self.tracks() + + def track(self, title): + path = '/library/metadata/%s/allLeaves' % self.ratingKey + return plexobjects.findItem(self.server, path, title) + + def isFullObject(self): + # plex bug? http://bit.ly/1Sc2J3V + fixed_key = self.key.replace('/children', '') + return self.initpath == fixed_key + + def refresh(self): + self.server.query('/library/metadata/%s/refresh' % self.ratingKey) + + +@plexobjects.registerLibType +class Album(Audio): + TYPE = 'album' + + def _setData(self, data): + Audio._setData(self, data) + if self.isFullObject(): + self.genres = plexobjects.PlexItemList(data, media.Genre, media.Genre.TYPE, server=self.server) + + @property + def defaultTitle(self): + return self.parentTitle or self.title + + def tracks(self, watched=None): + path = '%s/children' % self.key + return plexobjects.listItems(self.server, path, watched=watched) + + def track(self, title): + path = '%s/children' % self.key + return plexobjects.findItem(self.server, path, title) + + def all(self): + return self.tracks() + + def isFullObject(self): + # plex bug? http://bit.ly/1Sc2J3V + fixed_key = self.key.replace('/children', '') + return self.initpath == fixed_key + + def artist(self): + return plexobjects.listItems(self.server, self.parentKey)[0] + + def watched(self): + return self.tracks(watched=True) + + def unwatched(self): + return self.tracks(watched=False) + + +@plexobjects.registerLibType +class Track(Audio): + TYPE = 'track' + + def _setData(self, data): + Audio._setData(self, data) + if self.isFullObject(): + self.moods = plexobjects.PlexItemList(data, media.Mood, media.Mood.TYPE, server=self.server) + self.media = plexobjects.PlexMediaItemList(data, plexmedia.PlexMedia, media.Media.TYPE, initpath=self.initpath, server=self.server, media=self) + + # data for active sessions + self.user = self._findUser(data) + self.player = self._findPlayer(data) + self.transcodeSession = self._findTranscodeSession(data) + + @property + def defaultTitle(self): + return self.parentTitle or self.title + + @property + def settings(self): + if not self._settings: + from . import plexapp + self._settings = plexapp.PlayerSettingsInterface() + + return self._settings + + @property + def thumbUrl(self): + return self.server.url(self.parentThumb) + + def album(self): + return plexobjects.listItems(self.server, self.parentKey)[0] + + def artist(self): + return plexobjects.listItems(self.server, self.grandparentKey)[0] + + def getStreamURL(self, **params): + return self._getStreamURL(**params) + + @property + def defaultThumb(self): + return self.__dict__.get('thumb') or self.__dict__.get('parentThumb') or self.get('grandparentThumb') + + @property + def defaultArt(self): + return self.__dict__.get('art') or self.get('grandparentArt') diff --git a/script.plexmod/lib/_included_packages/plexnet/audioobject.py b/script.plexmod/lib/_included_packages/plexnet/audioobject.py new file mode 100644 index 0000000000..453e5e6042 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/audioobject.py @@ -0,0 +1,83 @@ +from __future__ import absolute_import +from . import http +from . import mediadecisionengine +from . import util + + +class AudioObjectClass(object): + def __init__(self, item): + self.containerFormats = { + 'aac': "es.aac-adts" + } + + self.item = item + self.choice = mediadecisionengine.MediaDecisionEngine().chooseMedia(item) + if self.choice: + self.media = self.choice.media + self.lyrics = None # createLyrics(item, self.media) + + def build(self, directPlay=None): + directPlay = directPlay or self.choice.isDirectPlayable + + obj = util.AttributeDict() + + # TODO(schuyler): Do we want/need to add anything generic here? Title? Duration? + + if directPlay: + obj = self.buildDirectPlay(obj) + else: + obj = self.buildTranscode(obj) + + self.metadata = obj + + util.LOG("Constructed audio item for playback: {0}".format(obj)) + + return self.metadata + + def buildTranscode(self, obj): + transcodeServer = self.item.getTranscodeServer(True, "audio") + if not transcodeServer: + return None + + obj.streamFormat = "mp3" + obj.isTranscoded = True + obj.transcodeServer = transcodeServer + + builder = http.HttpRequest(transcodeServer.buildUrl("/music/:/transcode/universal/start.m3u8", True)) + builder.addParam("protocol", "http") + builder.addParam("path", self.item.getAbsolutePath("key")) + builder.addParam("session", self.item.getGlobal("clientIdentifier")) + builder.addParam("directPlay", "0") + builder.addParam("directStream", "0") + + obj.url = builder.getUrl() + + return obj + + def buildDirectPlay(self, obj): + if self.choice.part: + obj.url = self.item.getServer().buildUrl(self.choice.part.getAbsolutePath("key"), True) + + # Set and override the stream format if applicable + obj.streamFormat = self.choice.media.container or 'mp3' + if self.containerFormats.get(obj.streamFormat): + obj.streamFormat = self.containerFormats[obj.streamFormat] + + # If we're direct playing a FLAC, bitrate can be required, and supposedly + # this is the only way to do it. plexinc/roku-client#48 + # + bitrate = self.choice.media.getInt("bitrate") + if bitrate > 0: + obj.streams = [{'url': obj.url, 'bitrate': bitrate}] + + return obj + + # We may as well fallback to transcoding if we could not direct play + return self.buildTranscode(obj) + + def getLyrics(self): + return self.lyrics + + def hasLyrics(self): + return False + # return self.lyrics.isAvailable() diff --git a/script.plexmod/lib/_included_packages/plexnet/callback.py b/script.plexmod/lib/_included_packages/plexnet/callback.py new file mode 100644 index 0000000000..d99a86f50e --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/callback.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import +import threading + + +class Callable(object): + _currID = 0 + + def __init__(self, func, forcedArgs=None, ID=None): + self.func = func + self.forcedArgs = forcedArgs + + self.ID = ID or id(func) + + if not self.ID: + self.ID = Callable.nextID() + + def __repr__(self): + return ''.format(repr(self.func).strip('<>')) + + def __eq__(self, other): + if not other: + return False + + if self.__class__ != other.__class__: + return False + + return self.ID and self.ID == other.ID + + def __ne__(self, other): + return not self.__eq__(other) + + def __call__(self, *args, **kwargs): + args = args or [] + if self.forcedArgs: + args = self.forcedArgs + + self.func(*args, **kwargs) + + @property + def context(self): + return self.func.__self__ + + @classmethod + def nextID(cls): + cls._currID += 1 + return cls._currID + + def deferCall(self, timeout=0.1): + timer = threading.Timer(timeout, self.onDeferCallTimer) + timer.name = 'ONDEFERCALLBACK-TIMER:{0}'.format(self.func) + timer.start() + + def onDeferCallTimer(self): + self() diff --git a/script.plexmod/lib/_included_packages/plexnet/captions.py b/script.plexmod/lib/_included_packages/plexnet/captions.py new file mode 100644 index 0000000000..e3b49fe21b --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/captions.py @@ -0,0 +1,80 @@ +from __future__ import absolute_import +from . import plexapp +from . import util + + +class Captions(object): + def __init__(self): + self.deviceInfo = util.INTERFACE.getGlobal("deviceInfo") + + self.textSize = util.AttributeDict({ + 'extrasmall': 15, + 'small': 20, + 'medium': 30, + 'large': 45, + 'extralarge': 65, + }) + + self.burnedSize = util.AttributeDict({ + 'extrasmall': "60", + 'small': "80", + 'medium': "100", + 'large': "135", + 'extralarge': "200" + }) + + self.colors = util.AttributeDict({ + 'white': 0xffffffff, + 'black': 0x000000ff, + 'red': 0xff0000ff, + 'green': 0x008000ff, + 'blue': 0x0000ffff, + 'yellow': 0xffff00ff, + 'magenta': 0xff00ffff, + 'cyan': 0x00ffffff, + }) + + self.defaults = util.AttributeDict({ + 'textSize': self.textSize.medium, + 'textColor': self.colors.white, + 'textOpacity': 80, + 'backgroundColor': self.colors.black, + 'backgroundOpacity': 70, + 'burnedSize': None + }) + + def getTextSize(self): + value = self.getOption("Text/Size") + return self.textSize.get(value) or self.defaults.textSize + + def getTextColor(self): + value = self.getOption("Text/Color") + return self.colors.get(value) or self.defaults.textColor + + def getTextOpacity(self): + value = self.getOption("Text/Opacity") + if value is None or value == "default": + return self.defaults.textOpacity + else: + return int(value) + + def getBackgroundColor(self): + value = self.getOption("Background/Color") + return self.colors.get(value) or self.defaults.backgroundColor + + def getBackgroundOpacity(self): + value = self.getOption("Background/Opacity") + if value is None or value == "default": + return self.defaults.backgroundOpacity + else: + return int(value) + + def getBurnedSize(self): + value = self.getOption("Text/Size") + return self.burnedSize.get(value) or self.defaults.burnedSize + + def getOption(self, key): + opt = self.deviceInfo.getCaptionsOption(key) + return opt is not None and opt.lower().replace(' ', '') or None + +CAPTIONS = Captions() diff --git a/script.plexmod/lib/_included_packages/plexnet/compat.py b/script.plexmod/lib/_included_packages/plexnet/compat.py new file mode 100644 index 0000000000..96b0d7fce9 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/compat.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +""" +Python 2/3 compatability +Always try Py3 first +""" + +from __future__ import absolute_import +try: + from urllib.parse import urlencode +except ImportError: + from six.moves.urllib.parse import urlencode + +try: + from urllib.parse import quote +except ImportError: + from six.moves.urllib.parse import quote + +try: + from urllib.parse import quote_plus +except ImportError: + from six.moves.urllib.parse import quote_plus + +try: + from configparser import ConfigParser +except ImportError: + from six.moves.configparser import ConfigParser diff --git a/script.plexmod/lib/_included_packages/plexnet/exceptions.py b/script.plexmod/lib/_included_packages/plexnet/exceptions.py new file mode 100644 index 0000000000..a3adf39e8a --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/exceptions.py @@ -0,0 +1,22 @@ +class BadRequest(Exception): + pass + + +class NotFound(Exception): + pass + + +class UnknownType(Exception): + pass + + +class Unsupported(Exception): + pass + + +class Unauthorized(Exception): + pass + + +class ServerNotOwned(Exception): + pass diff --git a/script.plexmod/lib/_included_packages/plexnet/gdm.py b/script.plexmod/lib/_included_packages/plexnet/gdm.py new file mode 100644 index 0000000000..90b9eba7ad --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/gdm.py @@ -0,0 +1,347 @@ +from __future__ import absolute_import +import threading +import socket +import traceback +import time +from . import util +from . import netif + +from . import plexconnection + +DISCOVERY_PORT = 32414 +WIN_NL = chr(13) + chr(10) + + +class GDMDiscovery(object): + def __init__(self): + self._close = False + self.thread = None + + # def isActive(self): + # util.LOG('GDMDiscovery().isActive() - NOT IMPLEMENTED') + # return False + + # def discover(self): + # util.LOG('GDMDiscovery().discover() - NOT IMPLEMENTED') + + def isActive(self): + from . import plexapp + return util.INTERFACE.getPreference("gdm_discovery", True) and self.thread and self.thread.is_alive() + + ''' + def discover(self): + # Only allow discovery if enabled and not currently running + self._close = False + import plexapp + if not util.INTERFACE.getPreference("gdm_discovery", True) or self.isActive(): + return + + ifaces = netif.getInterfaces() + + message = "M-SEARCH * HTTP/1.1" + WIN_NL + WIN_NL + + # Broadcasting to 255.255.255.255 only works on some Rokus, but we + # can't reliably determine the broadcast address for our current + # interface. Try assuming a /24 network, and then fall back to the + # multicast address if that doesn't work. + + multicast = "239.0.0.250" + ip = multicast + subnetRegex = re.compile("((\d+)\.(\d+)\.(\d+)\.)(\d+)") + addr = getFirstIPAddress() # TODO:: -------------------------------------------------------------------------------------------------------- HANDLE + if addr: + match = subnetRegex.search(addr) + if match: + ip = match.group(1) + "255" + util.DEBUG_LOG("Using broadcast address {0}".format()) + + # Socket things sometimes fail for no good reason, so try a few times. + attempt = 0 + success = False + + while attempt < 5 and not success: + udp = CreateObject("roDatagramSocket") + udp.setMessagePort(Application().port) + udp.setBroadcast(true) + + # More things that have been observed to be flaky. + for i in range(5): + addr = CreateObject("roSocketAddress") + addr.setHostName(ip) + addr.setPort(32414) + udp.setSendToAddress(addr) + + sendTo = udp.getSendToAddress() + if sendTo: + sendToStr = str(sendTo.getAddress()) + addrStr = str(addr.getAddress()) + util.DEBUG_LOG("GDM sendto address: " + sendToStr + " / " + addrStr) + if sendToStr == addrStr: + break + + util.ERROR_LOG("Failed to set GDM sendto address") + + udp.notifyReadable(true) + bytesSent = udp.sendStr(message) + util.DEBUG_LOG("Sent " + str(bytesSent) + " bytes") + if bytesSent > 0: + success = udp.eOK() + else: + success = False + if bytesSent == 0 and ip != multicast: + util.LOG("Falling back to multicast address") + ip = multicast + attempt = 0 + + if success: + break + elif attempt == 4 and ip != multicast: + util.LOG("Falling back to multicast address") + ip = multicast + attempt = 0 + else: + time.sleep(500) + util.WARN_LOG("Retrying GDM, errno=" + str(udp.status())) + attempt += 1 + + if success: + util.DEBUG_LOG("Successfully sent GDM discovery message, waiting for servers") + self.servers = [] + self.timer = plexapp.createTimer(5000, self.onTimer) + self.socket = udp + Application().AddSocketCallback(udp, createCallable("OnSocketEvent", m)) + util.APP.addTimer(self.timer) + else: + util.ERROR_LOG("Failed to send GDM discovery message") + import plexapp + import plexresource + plexapp.SERVERMANAGER.UpdateFromConnectionType([], plexresource.ResourceConnection.SOURCE_DISCOVERED) + self.socket = None + self.timer = None + ''' + + def discover(self): + from . import plexapp + if not util.INTERFACE.getPreference("gdm_discovery", True) or self.isActive(): + return + + self.thread = threading.Thread(target=self._discover) + self.thread.start() + + def _discover(self): + ifaces = netif.getInterfaces() + sockets = [] + self.servers = [] + + packet = ("M-SEARCH * HTTP/1.1" + WIN_NL + WIN_NL).encode("utf-8") + + for i in ifaces: + if not i.broadcast: + continue + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.settimeout(0.01) # 10ms + s.bind((i.ip, 0)) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + sockets.append((s, i)) + + success = False + + for attempt in (0, 1): + for s, i in sockets: + if self._close: + return + util.DEBUG_LOG(' o-> Broadcasting to {0}: {1}'.format(i.name, i.broadcast)) + try: + s.sendto(packet, (i.broadcast, DISCOVERY_PORT)) + success = True + except: + util.ERROR() + + if success: + break + + end = time.time() + 5 + + while time.time() < end: + for s, i in sockets: + if self._close: + return + try: + message, address = s.recvfrom(4096) + self.onSocketEvent(message, address) + except socket.timeout: + pass + except: + traceback.print_exc() + + self.discoveryFinished() + + def onSocketEvent(self, message, addr): + util.DEBUG_LOG('Received GDM message:\n' + str(message)) + + hostname = addr[0] # socket.gethostbyaddr(addr[0])[0] + + name = parseFieldValue(message, b"Name: ") + port = parseFieldValue(message, b"Port: ") or b"32400" + machineID = parseFieldValue(message, b"Resource-Identifier: ") + secureHost = parseFieldValue(message, b"Host: ") + + util.DEBUG_LOG("Received GDM response for " + repr(name) + " at http://" + hostname + ":" + port) + + if not name or not machineID: + return + + from . import plexserver + conn = plexconnection.PlexConnection(plexconnection.PlexConnection.SOURCE_DISCOVERED, "http://" + hostname + ":" + port, True, None, bool(secureHost)) + server = plexserver.createPlexServerForConnection(conn) + server.uuid = machineID + server.name = name + server.sameNetwork = True + + # If the server advertised a secure hostname, add a secure connection as well, and + # set the http connection as a fallback. + # + if secureHost: + server.connections.insert( + 0, + plexconnection.PlexConnection( + plexconnection.PlexConnection.SOURCE_DISCOVERED, "https://" + hostname.replace(".", "-") + "." + secureHost + ":" + port, True, None + ) + ) + + self.servers.append(server) + + def discoveryFinished(self, *args, **kwargs): + # Time's up, report whatever we found + self.close() + + if self.servers: + util.LOG("Finished GDM discovery, found {0} server(s)".format(len(self.servers))) + from . import plexapp + plexapp.SERVERMANAGER.updateFromConnectionType(self.servers, plexconnection.PlexConnection.SOURCE_DISCOVERED) + self.servers = None + + def close(self): + self._close = True + + +def parseFieldValue(message, label): + if label not in message: + return None + + return message.split(label, 1)[-1].split(chr(13).encode())[0].decode() + + +DISCOVERY = GDMDiscovery() + +''' +# GDM Advertising + +class GDMAdvertiser(object): + + def __init__(self): + self.responseString = None + + def createSocket() + listenAddr = CreateObject("roSocketAddress") + listenAddr.setPort(32412) + listenAddr.setAddress("0.0.0.0") + + udp = CreateObject("roDatagramSocket") + + if not udp.setAddress(listenAddr) then + Error("Failed to set address on GDM advertiser socket") + return + end if + + if not udp.setBroadcast(true) then + Error("Failed to set broadcast on GDM advertiser socket") + return + end if + + udp.notifyReadable(true) + udp.setMessagePort(Application().port) + + m.socket = udp + + Application().AddSocketCallback(udp, createCallable("OnSocketEvent", m)) + + Debug("Created GDM player advertiser") + + + def refresh() + # Always regenerate our response, even if it might not have changed, it's + # just not that expensive. + m.responseString = invalid + + enabled = AppSettings().GetBoolPreference("remotecontrol") + if enabled AND m.socket = invalid then + m.CreateSocket() + else if not enabled AND m.socket <> invalid then + m.Close() + end if + + + def cleanup() + m.Close() + fn = function() :m.GDMAdvertiser = invalid : + fn() + + + def onSocketEvent(msg as object) + # PMS polls every five seconds, so this is chatty when not debugging. + # Debug("Got a GDM advertiser socket event, is readable: " + tostr(m.socket.isReadable())) + + if m.socket.isReadable() then + message = m.socket.receiveStr(4096) + endIndex = instr(1, message, chr(13)) - 1 + if endIndex <= 0 then endIndex = message.Len() + line = Mid(message, 1, endIndex) + + if line = "M-SEARCH * HTTP/1.1" then + response = m.GetResponseString() + + # Respond directly to whoever sent the search message. + sock = CreateObject("roDatagramSocket") + sock.setSendToAddress(m.socket.getReceivedFromAddress()) + bytesSent = sock.sendStr(response) + sock.Close() + if bytesSent <> Len(response) then + Error("GDM player response only sent " + tostr(bytesSent) + " bytes out of " + tostr(Len(response))) + end if + else + Error("Received unexpected message on GDM advertiser socket: " + tostr(line) + ";") + end if + end if + + + def getResponseString() as string + if m.responseString = invalid then + buf = box("HTTP/1.0 200 OK" + WinNL()) + + settings = AppSettings() + + appendNameValue(buf, "Name", settings.GetGlobal("friendlyName")) + appendNameValue(buf, "Port", WebServer().port.tostr()) + appendNameValue(buf, "Product", "Plex for Roku") + appendNameValue(buf, "Content-Type", "plex/media-player") + appendNameValue(buf, "Protocol", "plex") + appendNameValue(buf, "Protocol-Version", "1") + appendNameValue(buf, "Protocol-Capabilities", "timeline,playback,navigation,playqueues") + appendNameValue(buf, "Version", settings.GetGlobal("appVersionStr")) + appendNameValue(buf, "Resource-Identifier", settings.GetGlobal("clientIdentifier")) + appendNameValue(buf, "Device-Class", "stb") + + m.responseString = buf + + Debug("Built GDM player response:" + m.responseString) + end if + + return m.responseString + + + sub appendNameValue(buf, name, value) + line = name + ": " + value + WinNL() + buf.AppendString(line, Len(line)) + +''' diff --git a/script.plexmod/lib/_included_packages/plexnet/http.py b/script.plexmod/lib/_included_packages/plexnet/http.py new file mode 100644 index 0000000000..d3df0b98d8 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/http.py @@ -0,0 +1,329 @@ +from __future__ import absolute_import +import sys +import os +import re +import traceback +import requests +import socket +import urllib3 +from . import threadutils +import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error +import mimetypes +from . import plexobjects +from xml.etree import ElementTree + +from . import asyncadapter + +from . import callback +from . import util + + +codes = requests.codes +status_codes = requests.status_codes._codes + + +DEFAULT_TIMEOUT = asyncadapter.AsyncTimeout(util.TIMEOUT).setConnectTimeout(util.TIMEOUT) + + +def GET(*args, **kwargs): + return requests.get(*args, headers=util.BASE_HEADERS.copy(), timeout=util.TIMEOUT, **kwargs) + + +def POST(*args, **kwargs): + return requests.post(*args, headers=util.BASE_HEADERS.copy(), timeout=util.TIMEOUT, **kwargs) + + +def Session(): + s = asyncadapter.Session() + s.headers = util.BASE_HEADERS.copy() + s.timeout = util.TIMEOUT + + return s + + +class RequestContext(dict): + def __getattr__(self, attr): + return self.get(attr) + + def __setattr__(self, attr, value): + self[attr] = value + + +class HttpRequest(object): + _cancel = False + + def __init__(self, url, method=None, forceCertificate=False): + self.server = None + self.path = None + self.hasParams = '?' in url + self.ignoreResponse = False + self.session = asyncadapter.Session() + self.session.headers = util.BASE_HEADERS.copy() + self.currentResponse = None + self.method = method + self.url = url + self.thread = None + + # Use our specific plex.direct CA cert if applicable to improve performance + # if forceCertificate or url[:5] == "https": # TODO: ---------------------------------------------------------------------------------IMPLEMENT + # certsPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'certs') + # if "plex.direct" in url: + # self.session.cert = os.path.join(certsPath, 'plex-bundle.crt') + # else: + # self.session.cert = os.path.join(certsPath, 'ca-bundle.crt') + + def removeAsPending(self): + from . import plexapp + util.APP.delRequest(self) + + def startAsync(self, *args, **kwargs): + self.thread = threadutils.KillableThread(target=self._startAsync, args=args, kwargs=kwargs, name='HTTP-ASYNC:{0}'.format(self.url)) + self.thread.start() + return True + + def _startAsync(self, body=None, contentType=None, context=None): + timeout = context and context.timeout or DEFAULT_TIMEOUT + self.logRequest(body, timeout) + if self._cancel: + return + try: + if self.method == 'PUT': + res = self.session.put(self.url, timeout=timeout, stream=True) + elif self.method == 'DELETE': + res = self.session.delete(self.url, timeout=timeout, stream=True) + elif self.method == 'HEAD': + res = self.session.head(self.url, timeout=timeout, stream=True) + elif self.method == 'POST' or body is not None: + if not contentType: + self.session.headers["Content-Type"] = "application/x-www-form-urlencoded" + else: + self.session.headers["Content-Type"] = mimetypes.guess_type(contentType) + + res = self.session.post(self.url, data=body or None, timeout=timeout, stream=True) + else: + res = self.session.get(self.url, timeout=timeout, stream=True) + self.currentResponse = res + + if self._cancel: + return + except asyncadapter.TimeoutException: + from . import plexapp + plexapp.util.APP.onRequestTimeout(context) + self.removeAsPending() + return + except asyncadapter.CanceledException: + return + except (urllib3.exceptions.ProtocolError, requests.exceptions.ConnectionError): + self.removeAsPending() + return + except Exception as e: + util.ERROR('Request failed {0}'.format(util.cleanToken(self.url))) + if not hasattr(e, 'response'): + return + res = e.response + + self.onResponse(res, context) + + self.removeAsPending() + + def getWithTimeout(self, seconds=DEFAULT_TIMEOUT): + return HttpObjectResponse(self.getPostWithTimeout(seconds), self.path, self.server) + + def postWithTimeout(self, seconds=DEFAULT_TIMEOUT, body=None): + self.method = 'POST' + return HttpObjectResponse(self.getPostWithTimeout(seconds, body), self.path, self.server) + + def getToStringWithTimeout(self, seconds=DEFAULT_TIMEOUT): + res = self.getPostWithTimeout(seconds) + if not res: + return '' + return res.text.encode('utf8') + + def postToStringWithTimeout(self, body=None, seconds=DEFAULT_TIMEOUT): + self.method = 'POST' + res = self.getPostWithTimeout(seconds, body) + if not res: + return '' + return res.text.encode('utf8') + + def getPostWithTimeout(self, seconds=DEFAULT_TIMEOUT, body=None): + if self._cancel: + return + + self.logRequest(body, seconds, False) + try: + if self.method == 'PUT': + res = self.session.put(self.url, timeout=seconds, stream=True) + elif self.method == 'DELETE': + res = self.session.delete(self.url, timeout=seconds, stream=True) + elif self.method == 'HEAD': + res = self.session.head(self.url, timeout=seconds, stream=True) + elif self.method == 'POST' or body is not None: + res = self.session.post(self.url, data=body, timeout=seconds, stream=True) + else: + res = self.session.get(self.url, timeout=seconds, stream=True) + + self.currentResponse = res + + if self._cancel: + return None + + util.LOG("Got a {0} from {1}".format(res.status_code, util.cleanToken(self.url))) + # self.event = msg + return res + except Exception as e: + info = traceback.extract_tb(sys.exc_info()[2])[-1] + util.WARN_LOG( + "Request errored out - URL: {0} File: {1} Line: {2} Msg: {3}".format(util.cleanToken(self.url), os.path.basename(info[0]), info[1], getattr(e, 'message', '')) + ) + + return None + + def wasOK(self): + return self.currentResponse and self.currentResponse.ok + + def wasNotFound(self): + return self.currentResponse is not None and self.currentResponse.status_code == requests.codes.not_found + + def getIdentity(self): + return str(id(self)) + + def getUrl(self): + return self.url + + def getRelativeUrl(self): + url = self.getUrl() + m = re.match(r'^\w+://.+?(/.+)', url) + if m: + return m.group(1) + return url + + def killSocket(self): + if not self.currentResponse: + return + + try: + socket.fromfd(self.currentResponse.raw.fileno(), socket.AF_INET, socket.SOCK_STREAM).shutdown(socket.SHUT_RDWR) + return + except AttributeError: + pass + except Exception as e: + util.ERROR(err=e) + + try: + self.currentResponse.raw._fp.fp._sock.shutdown(socket.SHUT_RDWR) + except AttributeError: + pass + except Exception as e: + util.ERROR(err=e) + + def cancel(self): + self._cancel = True + self.session.cancel() + self.removeAsPending() + self.killSocket() + + def addParam(self, encodedName, value): + if self.hasParams: + self.url += "&" + encodedName + "=" + six.moves.urllib.parse.quote_plus(value) + else: + self.hasParams = True + self.url += "?" + encodedName + "=" + six.moves.urllib.parse.quote_plus(value) + + def addHeader(self, name, value): + self.session.headers[name] = value + + def createRequestContext(self, requestType, callback_=None, timeout=None): + context = RequestContext() + context.requestType = requestType + context.timeout = timeout or DEFAULT_TIMEOUT + + if callback_: + context.callback = callback.Callable(self.onResponse) + context.completionCallback = callback_ + context.callbackCtx = callback_.context + + return context + + def onResponse(self, event, context): + if context.completionCallback: + response = HttpResponse(event) + context.completionCallback(self, response, context) + + def logRequest(self, body, timeout=None, _async=True): + # Log the real request method + method = self.method + if not method: + method = body is not None and "POST" or "GET" + util.LOG( + "Starting request: {0} {1} (async={2} timeout={3})".format(method, util.cleanToken(self.url), + _async, timeout) + ) + + +class HttpResponse(object): + def __init__(self, event): + self.event = event + if not self.event is None: + self.event.content # force data to be read + self.event.close() + + def isSuccess(self): + if not self.event: + return False + return self.event.status_code >= 200 and self.event.status_code < 300 + + def isError(self): + return not self.isSuccess() + + def getStatus(self): + if self.event is None: + return 0 + return self.event.status_code + + def getBodyString(self): + if self.event is None: + return '' + return self.event.text.encode('utf-8') + + def getErrorString(self): + if self.event is None: + return '' + return self.event.reason + + def getBodyXml(self): + if not self.event is None: + return ElementTree.fromstring(self.getBodyString()) + + return None + + def getResponseHeader(self, name): + if self.event is None: + return None + return self.event.headers.get(name) + + +class HttpObjectResponse(HttpResponse, plexobjects.PlexContainer): + def __init__(self, response, path, server=None): + self.event = response + if self.event: + self.event.content # force data to be read + self.event.close() + + data = self.getBodyXml() + + plexobjects.PlexContainer.__init__(self, data, initpath=path, server=server, address=path) + self.container = self + + self.items = plexobjects.listItems(server, path, data=data, container=self) + + +def addRequestHeaders(transferObj, headers=None): + if isinstance(headers, dict): + for header in headers: + transferObj.addHeader(header, headers[header]) + util.DEBUG_LOG("Adding header to {0}: {1}: {2}".format(transferObj, header, headers[header])) + + +def addUrlParam(url, param): + return url + ('?' in url and '&' or '?') + param diff --git a/script.plexmod/lib/_included_packages/plexnet/locks.py b/script.plexmod/lib/_included_packages/plexnet/locks.py new file mode 100644 index 0000000000..5e309f4ee4 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/locks.py @@ -0,0 +1,67 @@ +# Generic Locks. These are only virtual. You will need to check for the lock to +# ignore processing depending on the lockName. +# * Locks().Lock("lockName") : creates virtual lock +# * Locks().IsLocked("lockName") : returns true if locked +# * Locks().Unlock("lockName") : return true if existed & removed +from __future__ import absolute_import +from . import util + + +class Locks(object): + def __init__(self): + self.locks = {} + self.oneTimeLocks = {} + + def lock(self, name): + self.locks[name] = (self.locks.get(name) or 0) + 1 + util.DEBUG_LOG("Lock {0}, total={0}".format(name, self.locks[name])) + + def lockOnce(self, name): + util.DEBUG_LOG("Locking once {0}".format(name)) + self.oneTimeLocks[name] = True + + def unlock(self, name, forceUnlock=False): + oneTime = False + if name in self.oneTimeLocks: + del self.oneTimeLocks[name] + oneTime = True + normal = (self.locks.get(name) or 0) > 0 + + if normal: + if forceUnlock: + self.locks[name] = 0 + else: + self.locks[name] -= 1 + + if self.locks[name] <= 0: + del self.locks[name] + else: + normal = False + + unlocked = (normal or oneTime) + util.DEBUG_LOG("Unlock {0}, total={1}, unlocked={2}".format(name, self.locks.get(name) or 0, unlocked)) + + return unlocked + + def isLocked(self, name): + return name in self.oneTimeLocks or name in self.locks + # return (self.oneTimeLocks.Delete(name) or self.locks.DoesExist(name)) + + +# lock helpers +def disableBackButton(): + LOCKS.lock("BackButton") + + +def enableBackButton(): + LOCKS.unlock("BackButton", True) + + +def disableRemoteControl(): + LOCKS.lock("roUniversalControlEvent") + + +def enableRemoteControl(): + LOCKS.unlock("roUniversalControlEvent", True) + +LOCKS = Locks() diff --git a/script.plexmod/lib/_included_packages/plexnet/media.py b/script.plexmod/lib/_included_packages/plexnet/media.py new file mode 100644 index 0000000000..56d70eb024 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/media.py @@ -0,0 +1,258 @@ +from __future__ import absolute_import +from . import plexobjects +from . import plexstream +from . import util + +METADATA_RELATED_TRAILER = 1 +METADATA_RELATED_DELETED_SCENE = 2 +METADATA_RELATED_INTERVIEW = 3 +METADATA_RELATED_MUSIC_VIDEO = 4 +METADATA_RELATED_BEHIND_THE_SCENES = 5 +METADATA_RELATED_SCENE_OR_SAMPLE = 6 +METADATA_RELATED_LIVE_MUSIC_VIDEO = 7 +METADATA_RELATED_LYRIC_MUSIC_VIDEO = 8 +METADATA_RELATED_CONCERT = 9 +METADATA_RELATED_FEATURETTE = 10 +METADATA_RELATED_SHORT = 11 +METADATA_RELATED_OTHER = 12 + + +class MediaItem(plexobjects.PlexObject): + def getIdentifier(self): + identifier = self.get('identifier') or None + + if identifier is None: + identifier = self.container.identifier + + # HACK + # PMS doesn't return an identifier for playlist items. If we haven't found + # an identifier and the key looks like a library item, then we pretend like + # the identifier was set. + # + if identifier is None: # Modified from Roku code which had no check for None with iPhoto - is that right? + if self.key.startswith('/library/metadata'): + identifier = "com.plexapp.plugins.library" + elif self.isIPhoto(): + identifier = "com.plexapp.plugins.iphoto" + + return identifier + + def getQualityType(self, server=None): + if self.isOnlineItem(): + return util.QUALITY_ONLINE + + if not server: + server = self.getServer() + + return util.QUALITY_LOCAL if server.isLocalConnection() else util.QUALITY_REMOTE + + def delete(self): + if not self.ratingKey: + return + + from . import plexrequest + req = plexrequest.PlexRequest(self.server, '/library/metadata/{0}'.format(self.ratingKey), method='DELETE') + req.getToStringWithTimeout(10) + self.deleted = req.wasOK() + return self.deleted + + def exists(self): + if self.deleted or self.deletedAt: + return False + + data = self.server.query('/library/metadata/{0}'.format(self.ratingKey)) + return data is not None and data.attrib.get('size') != '0' + # req = plexrequest.PlexRequest(self.server, '/library/metadata/{0}'.format(self.ratingKey), method='HEAD') + # req.getToStringWithTimeout(10) + # return not req.wasNotFound() + + def fixedDuration(self): + duration = self.duration.asInt() + if duration < 1000: + duration *= 60000 + return duration + + +class Media(plexobjects.PlexObject): + TYPE = 'Media' + + def __init__(self, data, initpath=None, server=None, video=None): + plexobjects.PlexObject.__init__(self, data, initpath=initpath, server=server) + self.video = video + self.parts = [MediaPart(elem, initpath=self.initpath, server=self.server, media=self) for elem in data] + + def __repr__(self): + title = self.video.title.replace(' ', '.')[0:20] + return '<%s:%s>' % (self.__class__.__name__, title.encode('utf8')) + + +class MediaPart(plexobjects.PlexObject): + TYPE = 'Part' + + def __init__(self, data, initpath=None, server=None, media=None): + plexobjects.PlexObject.__init__(self, data, initpath=initpath, server=server) + self.media = media + self.streams = [MediaPartStream.parse(e, initpath=self.initpath, server=server, part=self) for e in data if e.tag == 'Stream'] + + def __repr__(self): + return '<%s:%s>' % (self.__class__.__name__, self.id) + + def selectedStream(self, stream_type): + streams = [x for x in self.streams if stream_type == x.type] + selected = list([x for x in streams if x.selected is True]) + if len(selected) == 0: + return None + return selected[0] + + +class MediaPartStream(plexstream.PlexStream): + TYPE = None + STREAMTYPE = None + + def __init__(self, data, initpath=None, server=None, part=None): + plexobjects.PlexObject.__init__(self, data, initpath, server) + self.part = part + + @staticmethod + def parse(data, initpath=None, server=None, part=None): + STREAMCLS = { + 1: VideoStream, + 2: AudioStream, + 3: SubtitleStream + } + stype = int(data.attrib.get('streamType')) + cls = STREAMCLS.get(stype, MediaPartStream) + return cls(data, initpath=initpath, server=server, part=part) + + def __repr__(self): + return '<%s:%s>' % (self.__class__.__name__, self.id) + + +class VideoStream(MediaPartStream): + TYPE = 'videostream' + STREAMTYPE = plexstream.PlexStream.TYPE_VIDEO + + +class AudioStream(MediaPartStream): + TYPE = 'audiostream' + STREAMTYPE = plexstream.PlexStream.TYPE_AUDIO + + +class SubtitleStream(MediaPartStream): + TYPE = 'subtitlestream' + STREAMTYPE = plexstream.PlexStream.TYPE_SUBTITLE + + +class TranscodeSession(plexobjects.PlexObject): + TYPE = 'TranscodeSession' + + +class MediaTag(plexobjects.PlexObject): + TYPE = None + ID = 'None' + + def __repr__(self): + tag = self.tag.replace(' ', '.')[0:20] + return '<%s:%s:%s>' % (self.__class__.__name__, self.id, tag) + + def __eq__(self, other): + if other.__class__ != self.__class__: + return False + + return self.id == other.id + + def __ne__(self, other): + return not self.__eq__(other) + + +class Collection(MediaTag): + TYPE = 'Collection' + FILTER = 'collection' + + +class Country(MediaTag): + TYPE = 'Country' + FILTER = 'country' + + +class Director(MediaTag): + TYPE = 'Director' + FILTER = 'director' + ID = '4' + + +class Genre(MediaTag): + TYPE = 'Genre' + FILTER = 'genre' + ID = '1' + + +class Mood(MediaTag): + TYPE = 'Mood' + FILTER = 'mood' + + +class Producer(MediaTag): + TYPE = 'Producer' + FILTER = 'producer' + + +class Role(MediaTag): + TYPE = 'Role' + FILTER = 'actor' + ID = '6' + + def sectionRoles(self): + hubs = self.server.hubs(count=10, search_query=self.tag) + for hub in hubs: + if hub.type == 'actor': + break + else: + return None + + roles = [] + + for actor in hub.items: + if actor.id == self.id: + roles.append(actor) + + return roles or None + + +class Similar(MediaTag): + TYPE = 'Similar' + FILTER = 'similar' + + +class Writer(MediaTag): + TYPE = 'Writer' + FILTER = 'writer' + + +class Chapter(MediaTag): + TYPE = 'Chapter' + + def startTime(self): + return self.get('startTimeOffset', -1).asInt() + + +class Bandwidth(plexobjects.PlexObject): + TYPE = 'Bandwidth' + + +class Marker(MediaTag): + TYPE = 'Marker' + FILTER = 'Marker' + + +class Review(MediaTag): + TYPE = 'Review' + FILTER = 'Review' + + def ratingImage(self): + # only rottentomatoes currently supported + img = str(self.image) + if not img or not img.startswith("rottentomatoes://"): + return '' + + return img.split('rottentomatoes://')[1] diff --git a/script.plexmod/lib/_included_packages/plexnet/mediachoice.py b/script.plexmod/lib/_included_packages/plexnet/mediachoice.py new file mode 100644 index 0000000000..a41f5c7c89 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/mediachoice.py @@ -0,0 +1,55 @@ +from __future__ import absolute_import +from . import plexstream +from . import util + + +class MediaChoice(object): + SUBTITLES_DEFAULT = 0 + SUBTITLES_BURN = 1 + SUBTITLES_SOFT_DP = 2 + SUBTITLES_SOFT_ANY = 3 + + def __init__(self, media=None, partIndex=0): + self.media = media + self.part = None + self.forceTranscode = False + self.isDirectPlayable = False + self.videoStream = None + self.audioStream = None + self.subtitleStream = None + self.isSelected = False + self.subtitleDecision = self.SUBTITLES_DEFAULT + + self.sorts = util.AttributeDict() + + if media: + self.indirectHeaders = media.indirectHeaders + self.part = media.parts[partIndex] + if not self.part: + for part in media.parts: + if part.isAccessible(): + self.part = part + + if self.part: + # We generally just rely on PMS to have told us selected streams, so + # initialize our streams accordingly. + + self.videoStream = self.part.getSelectedStreamOfType(plexstream.PlexStream.TYPE_VIDEO) + self.audioStream = self.part.getSelectedStreamOfType(plexstream.PlexStream.TYPE_AUDIO) + self.subtitleStream = self.part.getSelectedStreamOfType(plexstream.PlexStream.TYPE_SUBTITLE) + else: + util.WARN_LOG("Media does not contain a valid part") + + util.LOG("Choice media: {0} part:{1}".format(media, partIndex)) + for streamType in ("videoStream", "audioStream", "subtitleStream"): + attr = getattr(self, streamType) + if attr: + util.LOG("Choice {0}: {1}".format(streamType, repr(attr))) + else: + util.WARN_LOG("Could not create media choice for invalid media") + + def __str__(self): + return "direct playable={0} version={1}".format(self.isDirectPlayable, self.media) + + def __repr__(self): + return self.__str__() diff --git a/script.plexmod/lib/_included_packages/plexnet/mediadecisionengine.py b/script.plexmod/lib/_included_packages/plexnet/mediadecisionengine.py new file mode 100644 index 0000000000..ffda4ef5ac --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/mediadecisionengine.py @@ -0,0 +1,510 @@ +from __future__ import absolute_import +from . import mediachoice +from . import serverdecision +from . import plexapp +from . import util +import six +from six.moves import range + + +class MediaDecisionEngine(object): + proxyTypes = util.AttributeDict({ + 'NORMAL': 0, + 'LOCAL': 42, + 'CLOUD': 43 + }) + + def __init__(self): + self.softSubLanguages = None + + # TODO(schuyler): Do we need to allow this to be async? We may have to request + # the media again to fetch details, and we may need to make multiple requests to + # resolve an indirect. We can do it all async, we can block, or we can allow + # both. + + def chooseMedia(self, item, forceUpdate=False): + # If we've already evaluated this item, use our previous choice. + if not forceUpdate and item.mediaChoice is not None and item.mediaChoice.media is not None and not item.mediaChoice.media.isIndirect(): + return item.mediaChoice + + # See if we're missing media/stream details for this item. + if item.isLibraryItem() and item.isVideoItem() and len(item.media) > 0 and not item.media[0].hasStreams(): + # TODO(schuyler): Fetch the details + util.WARN_LOG("Can't make media choice, missing details") + + # Take a first pass through the media items to create an array of candidates + # that we'll evaluate more completely. If we find a forced item, we use it. + # If we find an indirect, we only keep a single candidate. + indirect = False + candidates = [] + maxResolution = item.settings.getMaxResolution(item.getQualityType()) + for mediaIndex in range(len(item.media)): + media = item.media[mediaIndex] + media.mediaIndex = mediaIndex + if media.isSelected(): + candidates = [] + candidates.append(media) + break + if media.isIndirect(): + # Only add indirect media if the resolution fits. We cannot + # exit early as the user may have selected media. + + indirect = True + if media.getVideoResolution() <= maxResolution: + candidates.append(media) + + elif media.isAccessible(): + # Only consider testing available media + candidates.append(media) + + # Only use the first indirect media item + if indirect and candidates: + candidates = candidates[0] + + # Make sure we have at least one valid item, regardless of availability + if len(candidates) == 0: + candidates.append(item.media[0]) + + # Now that we have an array of candidates, evaluate them completely. + choices = [] + for media in candidates: + choice = None + if media is not None: + if item.isVideoItem(): + choice = self.evaluateMediaVideo(item, media) + elif item.isMusicItem(): + choice = self.evaluateMediaMusic(item, media) + else: + choice = mediachoice.MediaChoice(media) + choices.append(choice) + item.mediaChoice = self.sortChoices(choices)[-1] + util.LOG("MDE: MediaChoice: {0}".format(item.mediaChoice)) + return item.mediaChoice + + def sortChoices(self, choices): + if choices is None: + return [] + + if len(choices) > 1: + self.sort(choices, "bitrate") + self.sort(choices, "audioChannels") + self.sort(choices, "audioDS") + self.sort(choices, "resolution") + self.sort(choices, "videoDS") + self.sort(choices, "directPlay") + self.sort(choices, self.higherResIfCapable) + self.sort(choices, self.cloudIfRemote) + + return choices + + def evaluateMediaVideo(self, item, media, partIndex=0): + # Resolve indirects before doing anything else. + if media.isIndirect(): + util.LOG("Resolve indirect media for {0}".format(item)) + media = media.resolveIndirect() + + choice = mediachoice.MediaChoice(media, partIndex) + server = item.getServer() + + if not media: + return choice + + choice.isSelected = media.isSelected() + choice.protocol = media.protocol("http") + + maxResolution = item.settings.getMaxResolution(item.getQualityType(), self.isSupported4k(media, choice.videoStream)) + maxBitrate = item.settings.getMaxBitrate(item.getQualityType()) + + choice.resolution = media.getVideoResolution() + if choice.resolution > maxResolution or media.bitrate.asInt() > maxBitrate: + choice.forceTranscode = True + + if choice.subtitleStream: + choice.subtitleDecision = self.evaluateSubtitles(choice.subtitleStream) + choice.hasBurnedInSubtitles = (choice.subtitleDecision != choice.SUBTITLES_SOFT_DP and choice.subtitleDecision != choice.SUBTITLES_SOFT_ANY) + else: + choice.hasBurnedInSubtitles = False + + # For evaluation purposes, we only care about the first part + part = media.parts[partIndex] + if not part: + return choice + + # Although PMS has already told us which streams are selected, we can't + # necessarily tell the video player which streams we want. So we need to + # iterate over the streams and see if there are any red flags that would + # prevent direct play. If there are multiple video streams, we're hosed. + # For audio streams, we have a fighting chance if the selected stream can + # be selected by language, but we need to be careful about guessing which + # audio stream the Roku will pick for a given language. + + numVideoStreams = 0 + problematicAudioStream = False + + if part.get('hasChapterVideoStream').asBool(): + numVideoStreams = 1 + + for stream in part.streams: + streamType = stream.streamType.asInt() + if streamType == stream.TYPE_VIDEO: + numVideoStreams = numVideoStreams + 1 + + if stream.codec == "h264" or ( + stream.codec == "hevc" and item.settings.getPreference("allow_hevc", True) + ) or ( + stream.codec == "av1" and item.settings.getPreference("allow_av1", False) + ) or ( + stream.codec == "vp9" and item.settings.getGlobal("vp9Support") + ): + choice.sorts.videoDS = 1 + + # Special cases to force direct play + forceDirectPlay = False + if choice.protocol == "hls": + util.LOG("MDE: Assuming HLS is direct playable") + forceDirectPlay = True + elif not server.supportsVideoTranscoding: + # See if we can use another server to transcode, otherwise force direct play + transcodeServer = item.getTranscodeServer(True, "video") + if not transcodeServer or not transcodeServer.supportsVideoTranscoding: + util.LOG("MDE: force direct play because the server does not support video transcoding") + forceDirectPlay = True + + # See if we found any red flags based on the streams. Otherwise, go ahead + # with our codec checks. + + if forceDirectPlay: + # Consider the choice DP, but continue to allow the + # choice to have the sorts set properly. + choice.isDirectPlayable = True + elif choice.hasBurnedInSubtitles: + util.LOG("MDE: Need to burn in subtitles") + elif choice.protocol != "http": + util.LOG("MDE: " + choice.protocol + " not supported") + # elif numVideoStreams > 1: + # util.LOG("MDE: Multiple video streams, won't try to direct play") + elif problematicAudioStream: + util.LOG("MDE: Problematic AAC stream with more than 2 channels prevents direct play") + elif self.canDirectPlay(item, choice): + choice.isDirectPlayable = True + elif item.isMediaSynthesized: + util.LOG("MDE: assuming synthesized media can direct play") + choice.isDirectPlayable = True + + # Check for a server decision. This is authority as it's the only playback type + # the server will allow. This will also support forcing direct play, overriding + # only our local MDE checks based on the user pref, and only if the server + # agrees. + decision = part.get("decision") + if decision: + if decision != serverdecision.ServerDecision.DECISION_DIRECT_PLAY: + util.LOG("MDE: Server has decided this cannot direct play") + choice.isDirectPlayable = False + else: + util.LOG("MDE: Server has allowed direct play") + choice.isDirectPlayable = True + + # Setup sorts + if choice.videoStream is not None: + choice.sorts.bitrate = choice.videoStream.bitrate.asInt() + elif choice.media is not None: + choice.sorts.bitrate = choice.media.bitrate.asInt() + else: + choice.sorts.bitrate = 0 + + if choice.audioStream is not None: + choice.sorts.audioChannels = choice.audioStream.channels.asInt() + elif choice.media is not None: + choice.sorts.audioChannels = choice.media.audioChannels.asInt() + else: + choice.sorts.audioChannels = 0 + + AC3Cond = item.settings.getPreference("audio_force_ac3_cond", 'never') + + if AC3Cond != 'never': + allowed = ["ac3"] + if item.settings.getPreference("audio_ac3dts", False): + allowed.append("dca") + + if AC3Cond == 'always' and choice.audioStream.codec not in allowed: + util.LOG("MDE: Codec {} can't be direct played due to user settings".format(choice.audioStream.codec)) + choice.isDirectPlayable = False + + elif AC3Cond in ('2', '5'): + ch = int(AC3Cond) + ach = choice.sorts.audioChannels + + # got AC3/DTS but channels don't match + if choice.audioStream.codec in allowed and ach > ch: + util.LOG("MDE: {}-channel AC3/DTS can't be direct played due " + "to user settings ({} ch)".format(ach, ch)) + choice.isDirectPlayable = False + # other codec and channels don't match + elif ach > ch: + util.LOG("MDE: {}-channel {} can't be direct played due to " + "user settings ({} ch)".format(ach, choice.audioStream.codec, ch)) + choice.isDirectPlayable = False + + choice.sorts.videoDS = not ( + choice.sorts.videoDS is None or choice.forceTranscode is True) and choice.sorts.videoDS or 0 + choice.sorts.resolution = choice.resolution + + # Server properties probably don't need to be associated with each choice + choice.sorts.canTranscode = server.supportsVideoTranscoding and 1 or 0 + choice.sorts.canRemuxOnly = server.supportsVideoRemuxOnly and 1 or 0 + choice.sorts.directPlay = (choice.isDirectPlayable is True and choice.forceTranscode is not True) and 1 or 0 + choice.sorts.proxyType = choice.media.proxyType and choice.media.proxyType or self.proxyTypes.NORMAL + + return choice + + def canDirectPlay(self, item, choice): + maxResolution = item.settings.getMaxResolution(item.getQualityType(), self.isSupported4k(choice.media, choice.videoStream)) + height = choice.media.getVideoResolution() + if height > maxResolution: + util.LOG("MDE: (DP) Video height is greater than max allowed: {0} > {1}".format(height, maxResolution)) + if height > 1088 and item.settings.getPreference("allow_4k", True): + util.LOG("MDE: (DP) Unsupported 4k media") + return False + + maxBitrate = item.settings.getMaxBitrate(item.getQualityType()) + bitrate = choice.media.bitrate.asInt() + if bitrate > maxBitrate: + util.LOG("MDE: (DP) Video bitrate is greater than the allowed max: {0} > {1}".format(bitrate, maxBitrate)) + return False + + if choice.videoStream is None: + util.ERROR_LOG("MDE: (DP) No video stream") + return True + + if not item.settings.getGlobal("supports1080p60"): + videoFrameRate = choice.videoStream.asInt() + if videoFrameRate > 30 and height >= 1080: + util.LOG("MDE: (DP) Frame rate is not supported for resolution: {0}@{1}".format(height, videoFrameRate)) + return False + + if choice.videoStream.codec == "hevc" and not item.settings.getPreference("allow_hevc", True): + util.LOG("MDE: (DP) Codec is HEVC, which is disabled") + return False + + if choice.videoStream.codec == "av1" and not item.settings.getPreference("allow_av1", False): + util.LOG("MDE: (DP) Codec is AV1, which is disabled") + return False + + return True + + # container = choice.media.get('container') + # videoCodec = choice.videoStream.codec + # if choice.audioStream is None: + # audioCodec = None + # numChannels = 0 + # else: + # audioCodec = choice.audioStream.codec + # numChannels = choice.audioStream.channels.asInt() + + # Formats: https://support.roku.com/hc/en-us/articles/208754908-Roku-Media-Player-Playing-your-personal-videos-music-photos + # All Models: H.264/AVC (MKV, MP4, MOV), + # Roku 4 only: H.265/HEVC (MKV, MP4, MOV); VP9 (.MKV) + + # if True: # container in ("mp4", "mov", "m4v", "mkv"): + # util.LOG("MDE: {0} container looks OK, checking streams".format(container)) + + # isHEVC = videoCodec == "hevc" and item.settings.getPreference("allow_hevc", False) + # isVP9 = videoCodec == "vp9" and container == "mkv" and item.settings.getGlobal("vp9Support") + + # if videoCodec != "h264" and videoCodec != "mpeg4" and not isHEVC and not isVP9: + # util.LOG("MDE: Unsupported video codec: {0}".format(videoCodec)) + # return False + + # # TODO(schuyler): Fix ref frames check. It's more nuanced than this. + # if choice.videoStream.refFrames.asInt() > 8: + # util.LOG("MDE: Too many ref frames: {0}".format(choice.videoStream.refFrames)) + # return False + + # # HEVC supports a bitDepth of 10, otherwise 8 is the limit + # if choice.videoStream.bitDepth.asInt() > (isHEVC and 10 or 8): + # util.LOG("MDE: Bit depth too high: {0}".format(choice.videoStream.bitDepth)) + # return False + + # # We shouldn't have to whitelist particular audio codecs, we can just + # # check to see if the Roku can decode this codec with the number of channels. + # if not item.settings.supportsAudioStream(audioCodec, numChannels): + # util.LOG("MDE: Unsupported audio track: {0} ({1} channels)".format(audioCodec, numChannels)) + # return False + + # # # TODO(schuyler): We've reported this to Roku, they may fix it. If/when + # # # they do, we should move this behind a firmware version check. + # # if container == "mkv" and choice.videoStream.headerStripping.asBool() and audioCodec == "ac3": + # # util.ERROR_LOG("MDE: Header stripping with AC3 audio") + # # return False + + # # Those were our problems, everything else should be OK. + # return True + # else: + # util.LOG("MDE: Unsupported container: {0}".format(container)) + + # return False + + def evaluateSubtitles(self, stream): + if util.INTERFACE.getPreference("burn_subtitles") == "always": + # If the user prefers them burned, always burn + return mediachoice.MediaChoice.SUBTITLES_BURN + # elif stream.codec != "srt": + # # We only support soft subtitles for SRT. Anything else has to use the + # # transcoder, and we defer to it on whether the subs will have to be + # # burned or can be converted to SRT and muxed. + + # return mediachoice.MediaChoice.SUBTITLES_DEFAULT + elif stream.key is None: + # Embedded subs don't have keys and can only be direct played + result = mediachoice.MediaChoice.SUBTITLES_SOFT_DP + else: + # Sidecar subs can be direct played or used alongside a transcode + result = mediachoice.MediaChoice.SUBTITLES_SOFT_ANY + + # # TODO(schuyler) If Roku adds support for non-Latin characters, remove + # # this hackery. To the extent that we continue using this hackery, it + # # seems that the Roku requires UTF-8 subtitles but only supports characters + # # from Windows-1252. This should be the full set of languages that are + # # completely representable in Windows-1252. PMS should specifically be + # # returning ISO 639-2/B language codes. + # # Update: Roku has added support for additional characters, but still only + # # Latin characters. We can now basically support anything from the various + # # ISO-8859 character sets, but nothing non-Latin. + + # if not self.softSubLanguages: + # self.softSubLanguages = frozenset(( + # 'afr', + # 'alb', + # 'baq', + # 'bre', + # 'cat', + # 'cze', + # 'dan', + # 'dut', + # 'eng', + # 'epo', + # 'est', + # 'fao', + # 'fin', + # 'fre', + # 'ger', + # 'gla', + # 'gle', + # 'glg', + # 'hrv', + # 'hun', + # 'ice', + # 'ita', + # 'lat', + # 'lav', + # 'lit', + # 'ltz', + # 'may', + # 'mlt', + # 'nno', + # 'nob', + # 'nor', + # 'oci', + # 'pol', + # 'por', + # 'roh', + # 'rum', + # 'slo', + # 'slv', + # 'spa', + # 'srd', + # 'swa', + # 'swe', + # 'tur', + # 'vie', + # 'wel', + # 'wln' + # )) + + # if not (stream.languageCode or 'eng') in self.softSubLanguages: + # # If the language is unsupported,: we need to force burning + # result = mediachoice.MediaChoice.SUBTITLES_BURN + + return result + + def evaluateMediaMusic(self, item, media): + # Resolve indirects before doing anything else. + if media.isIndirect(): + util.LOG("Resolve indirect media for {0}".format(item)) + media = media.resolveIndirect() + + choice = mediachoice.MediaChoice(media) + if media is None: + return choice + + # Verify the server supports audio transcoding, otherwise force direct play + if not item.getServer().supportsAudioTranscoding: + util.LOG("MDE: force direct play because the server does not support audio transcoding") + choice.isDirectPlayable = True + return choice + + # See if this part has a server decision to transcode and obey it + if choice.part and choice.part.get( + "decision", serverdecision.ServerDecision.DECISION_DIRECT_PLAY + ) != serverdecision.ServerDecision.DECISION_DIRECT_PLAY: + util.WARN_LOG("MDE: Server has decided this cannot direct play") + return choice + + # Verify the codec and container are compatible + codec = media.audioCodec + container = media.get('container') + canPlayCodec = item.settings.supportsAudioStream(codec, media.audioChannels.asInt()) + canPlayContainer = (codec == container) or True # (container in ("mp4", "mka", "mkv")) + + choice.isDirectPlayable = (canPlayCodec and canPlayContainer) + if choice.isDirectPlayable: + # Inspect the audio stream attributes if the codec/container can direct + # play. For now we only need to verify the sample rate. + + if choice.audioStream is not None and choice.audioStream.samplingRate.asInt() >= 192000: + util.LOG("MDE: sampling rate is not compatible") + choice.isDirectPlayable = False + else: + util.LOG("MDE: container or codec is incompatible") + + return choice + + # Simple Quick sort function modeled after roku sdk function + def sort(self, choices, key=None): + if not isinstance(choices, list): + return + + if key is None: + choices.sort() + elif isinstance(key, six.string_types): + choices.sort(key=lambda x: getattr(x.media, key)) + elif hasattr(key, '__call__'): + choices.sort(key=key) + + def higherResIfCapable(self, choice): + if choice.media is not None: + server = choice.media.getServer() + if server.supportsVideoTranscoding and not server.supportsVideoRemuxOnly and (choice.sorts.directPlay == 1 or choice.sorts.videoDS == 1): + return util.validInt(choice.sorts.resolution) + + return 0 + + def cloudIfRemote(self, choice): + if choice.media is not None and choice.media.getServer().isLocalConnection() and choice.media.proxyType != self.proxyTypes.CLOUD: + return 1 + + return 0 + + def isSupported4k(self, media, videoStream): + if videoStream is None or not util.INTERFACE.getPreference("allow_4k", True): + return False + + # # Roku 4 only: H.265/HEVC (MKV, MP4, MOV); VP9 (.MKV) + # if media.get('container') in ("mp4", "mov", "m4v", "mkv"): + # isHEVC = (videoStream.codec == "hevc" and util.INTERFACE.getPreference("allow_hevc")) + # isVP9 = (videoStream.codec == "vp9" and media.get('container') == "mkv" and util.INTERFACE.getGlobal("vp9Support")) + # return (isHEVC or isVP9) + + # return False + + return True diff --git a/script.plexmod/lib/_included_packages/plexnet/myplex.py b/script.plexmod/lib/_included_packages/plexnet/myplex.py new file mode 100644 index 0000000000..94b88e9625 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/myplex.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from . import util +from . import http +from threading import Thread +from xml.etree import ElementTree +import time + +from . import exceptions + +from . import video +from . import audio +from . import photo +from . import plexobjects + +video, audio, photo # Hides warning message + + +class PinLogin(object): + INIT = 'https://plex.tv/pins.xml' + POLL = 'https://plex.tv/pins/{0}.xml' + POLL_INTERVAL = 1 + + def __init__(self, callback=None): + self._callback = callback + self.id = None + self.pin = None + self.authenticationToken = None + self._finished = False + self._abort = False + self._expired = False + self._init() + + def _init(self): + response = http.POST(self.INIT) + if response.status_code != http.codes.created: + codename = http.status_codes.get(response.status_code)[0] + raise exceptions.BadRequest('({0}) {1}'.format(response.status_code, codename)) + data = ElementTree.fromstring(response.text.encode('utf-8')) + self.pin = data.find('code').text + self.id = data.find('id').text + + def _poll(self): + try: + start = time.time() + while not self._abort and time.time() - start < 300: + try: + response = http.GET(self.POLL.format(self.id)) + except Exception as e: + util.ERROR('PinLogin connection error: {0}'.format(e.__class__), err=e) + time.sleep(self.POLL_INTERVAL) + continue + + if response.status_code != http.codes.ok: + self._expired = True + break + try: + data = ElementTree.fromstring(response.text.encode('utf-8')) + except Exception as e: + util.ERROR('PinLogin data error: {0}'.format(e.__class__), err=e) + time.sleep(self.POLL_INTERVAL) + continue + + token = data.find('auth_token').text + if token: + self.authenticationToken = token + break + time.sleep(self.POLL_INTERVAL) + + if self._callback: + self._callback(self.authenticationToken) + finally: + self._finished = True + + def finished(self): + return self._finished + + def expired(self): + return self._expired + + def startTokenPolling(self): + t = Thread(target=self._poll, name='PIN-LOGIN:Token-Poll') + t.start() + return t + + def waitForToken(self): + t = self.startTokenPolling() + t.join() + return self.authenticationToken + + def abort(self): + self._abort = True diff --git a/script.plexmod/lib/_included_packages/plexnet/myplexaccount.py b/script.plexmod/lib/_included_packages/plexnet/myplexaccount.py new file mode 100644 index 0000000000..6eb1d65bb4 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/myplexaccount.py @@ -0,0 +1,323 @@ +from __future__ import absolute_import +import json +import time +import hashlib +from xml.etree import ElementTree + +from . import plexapp +from . import myplexrequest +from . import locks +from . import callback +from . import asyncadapter + +from . import util + +ACCOUNT = None + + +class HomeUser(util.AttributeDict): + pass + + +class MyPlexAccount(object): + def __init__(self): + # Strings + self.ID = None + self.title = None + self.username = None + self.thumb = None + self.email = None + self.authToken = None + self.pin = None + self.thumb = None + + # Booleans + self.isAuthenticated = util.INTERFACE.getPreference('auto_signin', False) + self.isSignedIn = False + self.isOffline = False + self.isExpired = False + self.isPlexPass = False + self.isManaged = False + self.isSecure = False + self.hasQueue = False + + self.isAdmin = False + self.switchUser = False + + self.adminHasPlexPass = False + + self.lastHomeUserUpdate = None + self.homeUsers = [] + + def init(self): + self.loadState() + + def saveState(self): + obj = { + 'ID': self.ID, + 'title': self.title, + 'username': self.username, + 'email': self.email, + 'authToken': self.authToken, + 'pin': self.pin, + 'isPlexPass': self.isPlexPass, + 'isManaged': self.isManaged, + 'isAdmin': self.isAdmin, + 'isSecure': self.isSecure, + 'adminHasPlexPass': self.adminHasPlexPass, + 'thumb': self.thumb + } + + util.INTERFACE.setRegistry("MyPlexAccount", json.dumps(obj), "myplex") + + def loadState(self): + # Look for the new JSON serialization. If it's not there, look for the + # old token and Plex Pass values. + + util.APP.addInitializer("myplex") + + jstring = util.INTERFACE.getRegistry("MyPlexAccount", None, "myplex") + + if jstring: + try: + obj = json.loads(jstring) + except: + util.ERROR() + obj = None + + if obj: + self.ID = obj.get('ID') or self.ID + self.title = obj.get('title') or self.title + self.username = obj.get('username') or self.username + self.email = obj.get('email') or self.email + self.authToken = obj.get('authToken') or self.authToken + self.pin = obj.get('pin') or self.pin + self.isPlexPass = obj.get('isPlexPass') or self.isPlexPass + self.isManaged = obj.get('isManaged') or self.isManaged + self.isAdmin = obj.get('isAdmin') or self.isAdmin + self.isSecure = obj.get('isSecure') or self.isSecure + self.isProtected = bool(obj.get('pin')) + self.adminHasPlexPass = obj.get('adminHasPlexPass') or self.adminHasPlexPass + self.thumb = obj.get('thumb') + + def verifyAccount(self): + if self.authToken: + request = myplexrequest.MyPlexRequest("/users/account") + context = request.createRequestContext("account", callback.Callable(self.onAccountResponse), + timeout=util.LONG_TIMEOUT) + util.APP.startRequest(request, context) + else: + util.APP.clearInitializer("myplex") + + def logState(self): + util.LOG("Authenticated as {0}:{1}".format(self.ID, repr(self.title))) + util.LOG("SignedIn: {0}".format(self.isSignedIn)) + util.LOG("Offline: {0}".format(self.isOffline)) + util.LOG("Authenticated: {0}".format(self.isAuthenticated)) + util.LOG("PlexPass: {0}".format(self.isPlexPass)) + util.LOG("Managed: {0}".format(self.isManaged)) + util.LOG("Protected: {0}".format(self.isProtected)) + util.LOG("Admin: {0}".format(self.isAdmin)) + util.LOG("AdminPlexPass: {0}".format(self.adminHasPlexPass)) + + def onAccountResponse(self, request, response, context): + oldId = self.ID + + if response.isSuccess(): + data = response.getBodyXml() + + # The user is signed in + self.isSignedIn = True + self.isOffline = False + self.ID = data.attrib.get('id') + self.title = data.attrib.get('title') + self.username = data.attrib.get('username') + self.email = data.attrib.get('email') + self.thumb = data.attrib.get('thumb') + self.authToken = data.attrib.get('authenticationToken') + self.isPlexPass = (data.find('subscription') is not None and data.find('subscription').attrib.get('active') == '1') + self.isManaged = data.attrib.get('restricted') == '1' + self.isSecure = data.attrib.get('secure') == '1' + self.hasQueue = bool(data.attrib.get('queueEmail')) + + # PIN + if data.attrib.get('pin'): + self.pin = data.attrib.get('pin') + else: + self.pin = None + self.isProtected = bool(self.pin) + + # update the list of users in the home + self.updateHomeUsers() + + # set admin attribute for the user + self.isAdmin = False + if self.homeUsers: + for user in self.homeUsers: + if self.ID == user.id: + self.isAdmin = str(user.admin) == "1" + break + + if self.isAdmin and self.isPlexPass: + self.adminHasPlexPass = True + + # consider a single, unprotected user authenticated + if not self.isAuthenticated and not self.isProtected and len(self.homeUsers) <= 1: + self.isAuthenticated = True + + self.logState() + + self.saveState() + util.MANAGER.publish() + + if oldId != self.ID or self.switchUser: + util.DEBUG_LOG("User changed, deferring refresh resources (force=False)") + else: + util.DEBUG_LOG("User selected, refreshing resources (force=False)") + plexapp.refreshResources() + + elif response.getStatus() >= 400 and response.getStatus() < 500: + # The user is specifically unauthorized, clear everything + util.WARN_LOG("Sign Out: User is unauthorized") + self.signOut(True) + else: + # Unexpected error, keep using whatever we read from the registry + util.WARN_LOG("Unexpected response from plex.tv ({0}), switching to OFFLINE mode".format(response.getStatus())) + self.logState() + self.isOffline = True + # consider a single, unprotected user authenticated + if not self.isAuthenticated and not self.isProtected: + self.isAuthenticated = True + + util.APP.clearInitializer("myplex") + # Logger().UpdateSyslogHeader() # TODO: ------------------------------------------------------------------------------------------------------IMPLEMENT + + if oldId != self.ID or self.switchUser: + self.switchUser = None + util.APP.trigger("change:user", account=self, reallyChanged=oldId != self.ID) + + util.APP.trigger("account:response") + + def signOut(self, expired=False): + # Strings + self.ID = None + self.title = None + self.username = None + self.email = None + self.authToken = None + self.pin = None + self.lastHomeUserUpdate = None + + # Booleans + self.isSignedIn = False + self.isPlexPass = False + self.adminHasPlexPass = False + self.isManaged = False + self.isSecure = False + self.isExpired = expired + + # Clear the saved resources + util.INTERFACE.clearRegistry("mpaResources", "xml_cache") + + # Remove all saved servers + plexapp.SERVERMANAGER.clearServers() + + # Enable the welcome screen again + util.INTERFACE.setPreference("show_welcome", True) + + util.APP.trigger("change:user", account=self, reallyChanged=True) + + self.saveState() + + def hasPlexPass(self): + return self.isPlexPass or self.adminHasPlexPass + + def validateToken(self, token, switchUser=False): + self.authToken = token + self.switchUser = switchUser + + request = myplexrequest.MyPlexRequest("/users/sign_in.xml") + context = request.createRequestContext("sign_in", callback.Callable(self.onAccountResponse), + timeout=util.LONG_TIMEOUT) + if self.isOffline: + context.timeout = self.isOffline and asyncadapter.AsyncTimeout(1).setConnectTimeout(1) + util.APP.startRequest(request, context, {}) + + def refreshAccount(self): + if not self.authToken: + return + self.validateToken(self.authToken, False) + + def updateHomeUsers(self): + # Ignore request and clear any home users we are not signed in + if not self.isSignedIn: + self.homeUsers = [] + if self.isOffline: + self.homeUsers.append(MyPlexAccount()) + + self.lastHomeUserUpdate = None + return + + # Cache home users for 60 seconds, mainly to stop back to back tests + epoch = time.time() + if not self.lastHomeUserUpdate: + self.lastHomeUserUpdate = epoch + elif self.lastHomeUserUpdate + 60 > epoch: + util.DEBUG_LOG("Skipping home user update (updated {0} seconds ago)".format(epoch - self.lastHomeUserUpdate)) + return + + req = myplexrequest.MyPlexRequest("/api/home/users") + xml = req.getToStringWithTimeout(seconds=util.LONG_TIMEOUT) + data = ElementTree.fromstring(xml) + if data.attrib.get('size') and data.find('User') is not None: + self.homeUsers = [] + for user in data.findall('User'): + homeUser = HomeUser(user.attrib) + homeUser.isAdmin = homeUser.admin == "1" + homeUser.isManaged = homeUser.restricted == "1" + homeUser.isProtected = homeUser.protected == "1" + self.homeUsers.append(homeUser) + + self.lastHomeUserUpdate = epoch + + util.LOG("home users: {0}".format(self.homeUsers)) + + def switchHomeUser(self, userId, pin=''): + if userId == self.ID and self.isAuthenticated: + return True + + # Offline support + if self.isOffline: + hashed = 'NONE' + if pin and self.authToken: + hashed = hashlib.sha256(pin + self.authToken).digest() + + if not self.isProtected or self.isAuthenticated or hashed == (self.pin or ""): + util.DEBUG_LOG("OFFLINE access granted") + self.isAuthenticated = True + self.validateToken(self.authToken, True) + return True + else: + # build path and post to myplex to swith the user + path = '/api/home/users/{0}/switch'.format(userId) + req = myplexrequest.MyPlexRequest(path) + xml = req.postToStringWithTimeout({'pin': pin}, seconds=util.LONG_TIMEOUT) + try: + data = ElementTree.fromstring(xml) + except: + return False + + if data.attrib.get('authenticationToken'): + self.isAuthenticated = True + # validate the token (trigger change:user) on user change or channel startup + if userId != self.ID or not locks.LOCKS.isLocked("idleLock"): + self.validateToken(data.attrib.get('authenticationToken'), True) + return True + + return False + + def isActive(self): + return self.isSignedIn or self.isOffline + + +ACCOUNT = MyPlexAccount() diff --git a/script.plexmod/lib/_included_packages/plexnet/myplexmanager.py b/script.plexmod/lib/_included_packages/plexnet/myplexmanager.py new file mode 100644 index 0000000000..72c2ebb9ce --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/myplexmanager.py @@ -0,0 +1,79 @@ +from __future__ import absolute_import +from xml.etree import ElementTree +import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error + +from . import plexapp +from . import plexconnection +from . import plexserver +from . import myplexrequest +from . import callback +from . import util + + +class MyPlexManager(object): + def publish(self): + util.LOG('MyPlexManager().publish() - NOT IMPLEMENTED') + return # TODO: ----------------------------------------------------------------------------------------------------------------------------- IMPLEMENT? + request = myplexrequest.MyPlexRequest("/devices/" + util.INTERFACE.getGlobal("clientIdentifier")) + context = request.createRequestContext("publish") + + addrs = util.INTERFACE.getGlobal("roDeviceInfo").getIPAddrs() + + for iface in addrs: + request.addParam(six.moves.urllib.parse.quote("Connection[][uri]"), "http://{0):8324".format(addrs[iface])) + + util.APP.startRequest(request, context, "_method=PUT") + + def refreshResources(self, force=False): + util.LOG('MyPlexManager().refreshResources() - Force: {}'.format(force)) + if force: + plexapp.SERVERMANAGER.resetLastTest() + + request = myplexrequest.MyPlexRequest("/pms/resources") + context = request.createRequestContext("resources", callback.Callable(self.onResourcesResponse), + timeout=util.LONG_TIMEOUT) + + if plexapp.ACCOUNT.isSecure: + request.addParam("includeHttps", "1") + + util.APP.startRequest(request, context) + + def onResourcesResponse(self, request, response, context): + servers = [] + + response.parseResponse() + + # Save the last successful response to cache + if response.isSuccess() and response.event: + util.INTERFACE.setRegistry("mpaResources", response.event.text.encode('utf-8'), "xml_cache") + util.DEBUG_LOG("Saved resources response to registry") + # Load the last successful response from cache + elif util.INTERFACE.getRegistry("mpaResources", None, "xml_cache"): + data = ElementTree.fromstring(util.INTERFACE.getRegistry("mpaResources", None, "xml_cache")) + response.parseFakeXMLResponse(data) + util.DEBUG_LOG("Using cached resources") + + if response.container: + for resource in response.container: + util.DEBUG_LOG( + "Parsed resource from plex.tv: type:{0} clientIdentifier:{1} name:{2} product:{3} provides:{4}".format( + resource.type, + resource.clientIdentifier, + resource.name.encode('utf-8'), + resource.product.encode('utf-8'), + resource.provides.encode('utf-8') + ) + ) + + for conn in resource.connections: + util.DEBUG_LOG(' {0}'.format(conn)) + + if 'server' in resource.provides: + server = plexserver.createPlexServerForResource(resource) + util.DEBUG_LOG(' {0}'.format(server)) + servers.append(server) + + plexapp.SERVERMANAGER.updateFromConnectionType(servers, plexconnection.PlexConnection.SOURCE_MYPLEX) + + +MANAGER = MyPlexManager() diff --git a/script.plexmod/lib/_included_packages/plexnet/myplexrequest.py b/script.plexmod/lib/_included_packages/plexnet/myplexrequest.py new file mode 100644 index 0000000000..5f560afe91 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/myplexrequest.py @@ -0,0 +1,13 @@ +# We don't particularly need a class definition here (yet?), it's just a +# PlexRequest where the server is fixed. +from __future__ import absolute_import +from . import plexrequest + + +class MyPlexRequest(plexrequest.PlexServerRequest): + def __init__(self, path): + from . import myplexserver + plexrequest.PlexServerRequest.__init__(self, myplexserver.MyPlexServer(), path) + + # Make sure we're always getting XML + self.addHeader("Accept", "application/xml") diff --git a/script.plexmod/lib/_included_packages/plexnet/myplexserver.py b/script.plexmod/lib/_included_packages/plexnet/myplexserver.py new file mode 100644 index 0000000000..aad8e3f032 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/myplexserver.py @@ -0,0 +1,36 @@ +from __future__ import absolute_import +from . import plexapp +from . import plexconnection +from . import plexserver +from . import plexresource +from . import plexservermanager + + +class MyPlexServer(plexserver.PlexServer): + TYPE = 'MYPLEXSERVER' + + def __init__(self): + plexserver.PlexServer.__init__(self) + self.uuid = 'myplex' + self.name = 'plex.tv' + conn = plexconnection.PlexConnection(plexresource.ResourceConnection.SOURCE_MYPLEX, "https://plex.tv", False, None) + self.connections.append(conn) + self.activeConnection = conn + + def getToken(self): + return plexapp.ACCOUNT.authToken + + def buildUrl(self, path, includeToken=False): + if "://node.plexapp.com" in path: + # Locate the best fit server that supports channels, otherwise we'll + # continue to use the node urls. Service code between the node and + # PMS differs sometimes, so it's a toss up which one is actually + # more accurate. Either way, we try to offload work from the node. + + server = plexservermanager.MANAGER.getChannelServer() + if server: + url = server.swizzleUrl(path, includeToken) + if url: + return url + + return plexserver.PlexServer.buildUrl(self, path, includeToken) diff --git a/script.plexmod/lib/_included_packages/plexnet/netif/__init__.py b/script.plexmod/lib/_included_packages/plexnet/netif/__init__.py new file mode 100644 index 0000000000..03c29ea034 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/netif/__init__.py @@ -0,0 +1,217 @@ +from __future__ import absolute_import +import socket +import struct +import os +from six.moves import range + + +class Interface: + def __init__(self): + self.name = '' + self.ip = '' + self.mask = '' + + @property + def broadcast(self): + if self.name == 'FALLBACK': return '' + if not self.ip or not self.mask: return None + return calcBroadcast(self.ip,self.mask) + + +def getInterfaces(): + if os.name == "nt": + try: + ret = _getInterfacesWin() + if ret: + return ret + except: + raise + + try: + return _getInterfacesWinPS() + except: + pass + + try: + return _getInterfaces() + except: + pass + + try: + return _getInterfacesBSD() + except: + pass + + i = Interface() + i.name = 'FALLBACK' + return [i] + + +def _getInterfaces(): + vals = all_interfaces() + interfaces = [] + for name,ip in vals: + i = Interface() + i.name = name.decode() + i.ip = ip + try: + mask = getSubnetMask(i.name) + i.mask = mask + except: + i.mask = '' + interfaces.append(i) + return interfaces + + +def _getInterfacesBSD(): + #name flags family address netmask + interfaces = [] + from . import getifaddrs + for info in getifaddrs.getifaddrs(): + if info.family == 2: + i = Interface() + i.name = info.name + i.ip = info.address + i.mask = info.netmask + interfaces.append(i) + return interfaces + + +def _getInterfacesWin(): + from . import ipconfig + interfaces = [] + adapters = ipconfig.parse() + for a in adapters: + if not 'IPv4 Address' in a: continue + if not 'Subnet Mask' in a: continue + i = Interface() + i.name = a.get('name','UNKNOWN') + i.ip = a['IPv4 Address'] + i.mask = a['Subnet Mask'] + interfaces.append(i) + return interfaces + + +def _getInterfacesWinPS(): + from . import winpsif + interfaces = [] + + for (name, ip, subnet) in winpsif.getInterfaces(): + i = Interface() + i.name = name + i.ip = ip + i.mask = subnet + interfaces.append(i) + + return interfaces + + +def all_interfaces(): + import sys + import array + import fcntl + + is_64bits = sys.maxsize > 2**32 + struct_size = 40 if is_64bits else 32 + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + max_possible = 8 # initial value + while True: + bytes = max_possible * struct_size + names = array.array('B', b'\0' * bytes) + outbytes = struct.unpack('iL', fcntl.ioctl( + s.fileno(), + 0x8912, # SIOCGIFCONF + struct.pack('iL', bytes, names.buffer_info()[0]) + ))[0] + if outbytes == bytes: + max_possible *= 2 + else: + break + namestr = names.tobytes() + return [(namestr[i:i+16].split(b'\0', 1)[0], + socket.inet_ntoa(namestr[i+20:i+24])) + for i in range(0, outbytes, struct_size)] + +def getSubnetMask(name): + import fcntl + return socket.inet_ntoa(fcntl.ioctl(socket.socket(socket.AF_INET, socket.SOCK_DGRAM), 35099, struct.pack('256s', name))[20:24]) + +def calcIPValue(ipaddr): + """ + Calculates the binary + value of the ip addresse + """ + ipaddr = ipaddr.split('.') + value = 0 + for i in range(len(ipaddr)): + value = value | (int(ipaddr[i]) << ( 8*(3-i) )) + return value + +def calcIPNotation(value): + """ + Calculates the notation + of the ip addresse given its value + """ + notat = [] + for i in range(4): + shift = 255 << ( 8*(3-i) ) + part = value & shift + part = part >> ( 8*(3-i) ) + notat.append(str(part)) + notat = '.'.join(notat) + return notat + +def calcSubnet(cidr): + """ + Calculates the Subnet + based on the CIDR + """ + subn = 4294967295 << (32-cidr) # 4294967295 = all bits set to 1 + subn = subn % 4294967296 # round it back to be 4 bytes + subn = calcIPNotation(subn) + return subn + +def calcCIDR(subnet): + """ + Calculates the CIDR + based on the SUbnet + """ + cidr = 0 + subnet = calcIPValue(subnet) + while subnet != 0: + subnet = subnet << 1 + subnet = subnet % 4294967296 + cidr += 1 + return cidr + +def calcNetpart(ipaddr,subnet): + ipaddr = calcIPValue(ipaddr) + subnet = calcIPValue(subnet) + netpart = ipaddr & subnet + netpart = calcIPNotation(netpart) + return netpart + +def calcMacpart(subnet): + macpart = ~calcIPValue(subnet) + macpart = calcIPNotation(macpart) + return macpart + +def calcBroadcast(ipaddr,subnet): + netpart = calcNetpart(ipaddr,subnet) + macpart = calcMacpart(subnet) + netpart = calcIPValue(netpart) + macpart = calcIPValue(macpart) + broadcast = netpart | macpart + broadcast = calcIPNotation(broadcast) + return broadcast + +def calcDefaultGate(ipaddr,subnet): + defaultgw = calcNetpart(ipaddr,subnet) + defaultgw = calcIPValue(defaultgw) + 1 + defaultgw = calcIPNotation(defaultgw) + return defaultgw + +def calcHostNum(subnet): + macpart = calcMacpart(subnet) + hostnum = calcIPValue(macpart) - 1 + return hostnum \ No newline at end of file diff --git a/script.plexmod/lib/_included_packages/plexnet/netif/getifaddrs.py b/script.plexmod/lib/_included_packages/plexnet/netif/getifaddrs.py new file mode 100644 index 0000000000..16f227bd91 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/netif/getifaddrs.py @@ -0,0 +1,192 @@ +""" +Wrapper for getifaddrs(3). +""" + +from __future__ import absolute_import +from __future__ import print_function +import socket +import sys + +from collections import namedtuple +from ctypes import * +from six.moves import map + +class sockaddr_in(Structure): + _fields_ = [ + ('sin_len', c_uint8), + ('sin_family', c_uint8), + ('sin_port', c_uint16), + ('sin_addr', c_uint8 * 4), + ('sin_zero', c_uint8 * 8) + ] + + def __str__(self): + try: + assert self.sin_len >= sizeof(sockaddr_in) + data = ''.join(map(chr, self.sin_addr)) + return socket.inet_ntop(socket.AF_INET, data) + except: + return '' + +class sockaddr_in6(Structure): + _fields_ = [ + ('sin6_len', c_uint8), + ('sin6_family', c_uint8), + ('sin6_port', c_uint16), + ('sin6_flowinfo', c_uint32), + ('sin6_addr', c_uint8 * 16), + ('sin6_scope_id', c_uint32) + ] + + def __str__(self): + try: + assert self.sin6_len >= sizeof(sockaddr_in6) + data = ''.join(map(chr, self.sin6_addr)) + return socket.inet_ntop(socket.AF_INET6, data) + except: + return '' + +class sockaddr_dl(Structure): + _fields_ = [ + ('sdl_len', c_uint8), + ('sdl_family', c_uint8), + ('sdl_index', c_short), + ('sdl_type', c_uint8), + ('sdl_nlen', c_uint8), + ('sdl_alen', c_uint8), + ('sdl_slen', c_uint8), + ('sdl_data', c_uint8 * 12) + ] + + def __str__(self): + assert self.sdl_len >= sizeof(sockaddr_dl) + addrdata = self.sdl_data[self.sdl_nlen:self.sdl_nlen+self.sdl_alen] + return ':'.join('%02x' % x for x in addrdata) + +class sockaddr_storage(Structure): + _fields_ = [ + ('sa_len', c_uint8), + ('sa_family', c_uint8), + ('sa_data', c_uint8 * 254) + ] + +class sockaddr(Union): + _anonymous_ = ('sa_storage', ) + _fields_ = [ + ('sa_storage', sockaddr_storage), + ('sa_sin', sockaddr_in), + ('sa_sin6', sockaddr_in6), + ('sa_sdl', sockaddr_dl), + ] + + def family(self): + return self.sa_storage.sa_family + + def __str__(self): + family = self.family() + if family == socket.AF_INET: + return str(self.sa_sin) + elif family == socket.AF_INET6: + return str(self.sa_sin6) + elif family == 18: # AF_LINK + return str(self.sa_sdl) + else: + print(family) + raise NotImplementedError("address family %d not supported" % family) + + +class ifaddrs(Structure): + pass + +ifaddrs._fields_ = [ + ('ifa_next', POINTER(ifaddrs)), + ('ifa_name', c_char_p), + ('ifa_flags', c_uint), + ('ifa_addr', POINTER(sockaddr)), + ('ifa_netmask', POINTER(sockaddr)), + ('ifa_dstaddr', POINTER(sockaddr)), + ('ifa_data', c_void_p) +] + +# Define constants for the most useful interface flags (from if.h). +IFF_UP = 0x0001 +IFF_BROADCAST = 0x0002 +IFF_LOOPBACK = 0x0008 +IFF_POINTTOPOINT = 0x0010 +IFF_RUNNING = 0x0040 +if sys.platform == 'darwin' or 'bsd' in sys.platform: + IFF_MULTICAST = 0x8000 +elif sys.platform == 'linux': + IFF_MULTICAST = 0x1000 + +# Load library implementing getifaddrs and freeifaddrs. +if sys.platform == 'darwin': + libc = cdll.LoadLibrary('libc.dylib') +else: + libc = cdll.LoadLibrary('libc.so') + +# Tell ctypes the argument and return types for the getifaddrs and +# freeifaddrs functions so it can do marshalling for us. +libc.getifaddrs.argtypes = [POINTER(POINTER(ifaddrs))] +libc.getifaddrs.restype = c_int +libc.freeifaddrs.argtypes = [POINTER(ifaddrs)] + + +def getifaddrs(): + """ + Get local interface addresses. + + Returns generator of tuples consisting of interface name, interface flags, + address family (e.g. socket.AF_INET, socket.AF_INET6), address, and netmask. + The tuple members can also be accessed via the names 'name', 'flags', + 'family', 'address', and 'netmask', respectively. + """ + # Get address information for each interface. + addrlist = POINTER(ifaddrs)() + if libc.getifaddrs(pointer(addrlist)) < 0: + raise OSError + + X = namedtuple('ifaddrs', 'name flags family address netmask') + + # Iterate through the address information. + ifaddr = addrlist + while ifaddr and ifaddr.contents: + # The following is a hack to workaround a bug in FreeBSD + # (PR kern/152036) and MacOSX wherein the netmask's sockaddr may be + # truncated. Specifically, AF_INET netmasks may have their sin_addr + # member truncated to the minimum number of bytes necessary to + # represent the netmask. For example, a sockaddr_in with the netmask + # 255.255.254.0 may be truncated to 7 bytes (rather than the normal + # 16) such that the sin_addr field only contains 0xff, 0xff, 0xfe. + # All bytes beyond sa_len bytes are assumed to be zero. Here we work + # around this truncation by copying the netmask's sockaddr into a + # zero-filled buffer. + if ifaddr.contents.ifa_netmask: + netmask = sockaddr() + memmove(byref(netmask), ifaddr.contents.ifa_netmask, + ifaddr.contents.ifa_netmask.contents.sa_len) + if netmask.sa_family == socket.AF_INET and netmask.sa_len < sizeof(sockaddr_in): + netmask.sa_len = sizeof(sockaddr_in) + else: + netmask = None + + try: + yield X(ifaddr.contents.ifa_name, + ifaddr.contents.ifa_flags, + ifaddr.contents.ifa_addr.contents.family(), + str(ifaddr.contents.ifa_addr.contents), + str(netmask) if netmask else None) + except NotImplementedError: + # Unsupported address family. + yield X(ifaddr.contents.ifa_name, + ifaddr.contents.ifa_flags, + None, + None, + None) + ifaddr = ifaddr.contents.ifa_next + + # When we are done with the address list, ask libc to free whatever memory + # it allocated for the list. + libc.freeifaddrs(addrlist) + +__all__ = ['getifaddrs'] + [n for n in dir() if n.startswith('IFF_')] \ No newline at end of file diff --git a/script.plexmod/lib/_included_packages/plexnet/netif/ipconfig.py b/script.plexmod/lib/_included_packages/plexnet/netif/ipconfig.py new file mode 100644 index 0000000000..24804348c4 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/netif/ipconfig.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +from __future__ import absolute_import +from __future__ import print_function +import subprocess +import sys + +def parse(data=None): + kwa = {} + if sys.version_info[0] >= 3: + kwa = {"encoding": "latin-1"} + + data = data or subprocess.check_output('ipconfig /all',startupinfo=getStartupInfo(), **kwa) + dlist = [d.rstrip() for d in data.split('\n')] + mode = None + sections = [] + while dlist: + d = dlist.pop(0) + try: + if not d: + continue + elif not d.startswith(' '): + sections.append({'name':d.strip('.: ')}) + elif d.startswith(' '): + if d.endswith(':'): + k = d.strip(':. ') + mode = 'VALUE:' + k + sections[-1][k] = '' + elif ':' in d: + k,v = d.split(':',1) + k = k.strip(':. ') + mode = 'VALUE:' + k + v = v.replace('(Preferred)','') + sections[-1][k] = v.strip() + elif mode and mode.startswith('VALUE:'): + if not d.startswith(' '): + mode = None + dlist.insert(0,d) + continue + k = mode.split(':',1)[-1] + v = d.replace('(Preferred)','') + sections[-1][k] += ',' + v.strip() + except: + print(d) + raise + + return sections[1:] + +def getStartupInfo(): + if hasattr(subprocess,'STARTUPINFO'): #Windows + startupinfo = subprocess.STARTUPINFO() + try: + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW #Suppress terminal window + except: + startupinfo.dwFlags |= 1 + return startupinfo + + return None \ No newline at end of file diff --git a/script.plexmod/lib/_included_packages/plexnet/netif/winpsif.py b/script.plexmod/lib/_included_packages/plexnet/netif/winpsif.py new file mode 100644 index 0000000000..db13eca886 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/netif/winpsif.py @@ -0,0 +1,22 @@ +# coding=utf-8 + +import subprocess +import re +import sys + +PS_RE = re.compile(r'(?mu)^Description\s+: (?P[^\n]+)\nIPAddress\s+: {(?P[0-9.]+),' + r'.+\nIPSubnet\s+: {(?P[0-9.]+),.+\n') + + +def getInterfaces(): + """ + Use powershell to retrieve interfaces; parse using PS_RE, returning tuples of (name, ipaddress, subnet) + """ + kwa = {} + if sys.version_info[0] >= 3: + kwa = {"encoding": "windows-1252"} + + return PS_RE.findall(subprocess.check_output( + 'powershell "Get-WmiObject -Class Win32_NetworkAdapterConfiguration | ' + 'Select-Object Description, IPAddress, IPSubnet | Format-List"', + shell=True, **kwa)) diff --git a/script.plexmod/lib/_included_packages/plexnet/nowplayingmanager.py b/script.plexmod/lib/_included_packages/plexnet/nowplayingmanager.py new file mode 100644 index 0000000000..6d043f24c5 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/nowplayingmanager.py @@ -0,0 +1,215 @@ +# Most of this is ported from Roku code and much of it is currently unused +# TODO: Perhaps remove unnecessary code +from __future__ import absolute_import +import time + +from . import util +from six import moves +import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error +import six.moves.urllib.parse +from . import plexrequest +from . import callback +from . import http + + +class ServerTimeline(util.AttributeDict): + def reset(self): + self.expires = time.time() + 15 + + def isExpired(self): + return time.time() > self.get('expires', 0) + + +class TimelineData(util.AttributeDict): + def __init__(self, timelineType, *args, **kwargs): + util.AttributeDict.__init__(self, *args, **kwargs) + self.type = timelineType + self.state = "stopped" + self.item = None + self.choice = None + self.playQueue = None + + self.controllable = util.AttributeDict() + self.controllableStr = None + + self.attrs = util.AttributeDict() + + # Set default controllable for all content. Other controllable aspects + # will be set based on the players content. + # + self.setControllable("playPause", True) + self.setControllable("stop", True) + + def setControllable(self, name, isControllable): + if isControllable: + self.controllable[name] = "" + else: + if name in self.controllable: + del self.controllable[name] + + self.controllableStr = None + + def updateControllableStr(self): + if not self.controllableStr: + self.controllableStr = "" + prependComma = False + + for name in self.controllable: + if prependComma: + self.controllableStr += ',' + else: + prependComma = True + self.controllableStr += name + + def toXmlAttributes(self, elem): + self.updateControllableStr() + elem.attrib["type"] = self.type + elem.attrib["start"] = self.state + elem.attrib["controllable"] = self.controllableStr + + if self.item: + if self.item.duration: + elem.attrib['duration'] = self.item.duration + if self.item.ratingKey: + elem.attrib['ratingKey'] = self.item.ratingKey + if self.item.key: + elem.attrib['key'] = self.item.key + if self.item.container.address: + elem.attrib['containerKey'] = self.item.container.address + + # Send the audio, video and subtitle choice if it's available + if self.choice: + for stream in ("audioStream", "videoStream", "subtitleStream"): + if self.choice.get(stream) and self.choice[stream].id: + elem.attrib[stream + "ID"] = self.choice[stream].id + + server = self.item.getServer() + if server: + elem.attrib["machineIdentifier"] = server.uuid + + if server.activeConnection: + parts = six.moves.urllib.parse.uslparse(server.activeConnection.address) + elem.attrib["protocol"] = parts.scheme + elem.attrib["address"] = parts.netloc.split(':', 1)[0] + if ':' in parts.netloc: + elem.attrib["port"] = parts.netloc.split(':', 1)[-1] + elif parts.scheme == 'https': + elem.attrib["port"] = '443' + else: + elem.attrib["port"] = '80' + + if self.playQueue: + elem.attrib["playQueueID"] = str(self.playQueue.id) + elem.attrib["playQueueItemID"] = str(self.playQueue.selectedId) + elem.attrib["playQueueVersion"] = str(self.playQueue.version) + + for key, val in self.attrs.items(): + elem.attrib[key] = val + + +class NowPlayingManager(object): + def __init__(self): + # Constants + self.NAVIGATION = "navigation" + self.FULLSCREEN_VIDEO = "fullScreenVideo" + self.FULLSCREEN_MUSIC = "fullScreenMusic" + self.FULLSCREEN_PHOTO = "fullScreenPhoto" + self.TIMELINE_TYPES = ["video", "music", "photo"] + + # Members + self.serverTimelines = util.AttributeDict() + self.subscribers = util.AttributeDict() + self.pollReplies = util.AttributeDict() + self.timelines = util.AttributeDict() + self.location = self.NAVIGATION + + self.textFieldName = None + self.textFieldContent = None + self.textFieldSecure = None + + # Initialization + for timelineType in self.TIMELINE_TYPES: + self.timelines[timelineType] = TimelineData(timelineType) + + def updatePlaybackState(self, timelineType, playerObject, state, time, playQueue=None, duration=0): + timeline = self.timelines[timelineType] + timeline.state = state + timeline.item = playerObject.item + timeline.choice = playerObject.choice + timeline.playQueue = playQueue + timeline.attrs["time"] = str(time) + timeline.duration = duration + + # self.sendTimelineToAll() + + self.sendTimelineToServer(timelineType, timeline, time) + + def sendTimelineToServer(self, timelineType, timeline, time): + if not hasattr(timeline.item, 'getServer') or not timeline.item.getServer(): + return + + serverTimeline = self.getServerTimeline(timelineType) + + # Only send timeline if it's the first, item changes, playstate changes or timer pops + itemsEqual = timeline.item and serverTimeline.item and timeline.item.ratingKey == serverTimeline.item.ratingKey + if itemsEqual and timeline.state == serverTimeline.state and not serverTimeline.isExpired(): + return + + serverTimeline.reset() + serverTimeline.item = timeline.item + serverTimeline.state = timeline.state + + # Ignore sending timelines for multi part media with no duration + obj = timeline.choice + if obj and obj.part and obj.part.duration.asInt() == 0 and obj.media.parts and len(obj.media.parts) > 1: + util.WARN_LOG("Timeline not supported: the current part doesn't have a valid duration") + return + + # It's possible with timers and in player seeking for the time to be greater than the + # duration, which causes a 400, so in that case we'll set the time to the duration. + duration = timeline.item.duration.asInt() or timeline.duration + if time > duration: + time = duration + + params = util.AttributeDict() + params["time"] = time + params["duration"] = duration + params["state"] = timeline.state + params["guid"] = timeline.item.guid + params["ratingKey"] = timeline.item.ratingKey + params["url"] = timeline.item.url + params["key"] = timeline.item.key + params["containerKey"] = timeline.item.container.address + if timeline.playQueue: + params["playQueueItemID"] = timeline.playQueue.selectedId + + path = "/:/timeline" + for paramKey in params: + if params[paramKey]: + path = http.addUrlParam(path, paramKey + "=" + six.moves.urllib.parse.quote(str(params[paramKey]))) + + request = plexrequest.PlexRequest(timeline.item.getServer(), path) + + context = request.createRequestContext("timelineUpdate", callback.Callable(self.onTimelineResponse)) + context.playQueue = timeline.playQueue + util.APP.startRequest(request, context) + + def getServerTimeline(self, timelineType): + if not self.serverTimelines.get(timelineType): + serverTL = ServerTimeline() + serverTL.reset() + + self.serverTimelines[timelineType] = serverTL + + return self.serverTimelines[timelineType] + + def nowPlayingSetControllable(self, timelineType, name, isControllable): + self.timelines[timelineType].setControllable(name, isControllable) + + def onTimelineResponse(self, request, response, context): + context.request.server.trigger("np:timelineResponse", response=response) + + if not context.playQueue or not context.playQueue.refreshOnTimeline: + return + context.playQueue.refreshOnTimeline = False + context.playQueue.refresh(False) diff --git a/script.plexmod/lib/_included_packages/plexnet/photo.py b/script.plexmod/lib/_included_packages/plexnet/photo.py new file mode 100644 index 0000000000..d3a66ca681 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/photo.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from . import media +from . import plexobjects +from . import plexmedia + + +class Photo(media.MediaItem): + TYPE = 'photo' + + def _setData(self, data): + self.art = plexobjects.PlexValue('') + media.MediaItem._setData(self, data) + + if self.isFullObject(): + self.media = plexobjects.PlexMediaItemList(data, plexmedia.PlexMedia, media.Media.TYPE, + initpath=self.initpath, server=self.server, media=self) + + def analyze(self): + """ The primary purpose of media analysis is to gather information about that media + item. All of the media you add to a Library has properties that are useful to + know–whether it's a video file, a music track, or one of your photos. + """ + self.server.query('/%s/analyze' % self.key) + + def markWatched(self): + path = '/:/scrobble?key=%s&identifier=com.plexapp.plugins.library' % self.ratingKey + self.server.query(path) + self.reload() + + def markUnwatched(self): + path = '/:/unscrobble?key=%s&identifier=com.plexapp.plugins.library' % self.ratingKey + self.server.query(path) + self.reload() + + def play(self, client): + client.playMedia(self) + + def refresh(self): + self.server.query('%s/refresh' % self.key, method=self.server.session.put) + + def isPhotoOrDirectoryItem(self): + return True + + +class PhotoDirectory(media.MediaItem): + TYPE = 'photodirectory' + + def all(self): + path = self.key + return plexobjects.listItems(self.server, path) + + def isPhotoOrDirectoryItem(self): + return True + + +@plexobjects.registerLibFactory('photo') +@plexobjects.registerLibFactory('image') +def PhotoFactory(data, initpath=None, server=None, container=None): + if data.tag == 'Photo': + return Photo(data, initpath=initpath, server=server, container=container) + else: + return PhotoDirectory(data, initpath=initpath, server=server, container=container) diff --git a/script.plexmod/lib/_included_packages/plexnet/playlist.py b/script.plexmod/lib/_included_packages/plexnet/playlist.py new file mode 100644 index 0000000000..b06358dd7e --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/playlist.py @@ -0,0 +1,183 @@ +from __future__ import absolute_import +import random + +from . import plexobjects +from . import signalsmixin +from six.moves import range + + +class BasePlaylist(plexobjects.PlexObject, signalsmixin.SignalsMixin): + TYPE = 'baseplaylist' + + isRemote = False + + def __init__(self, *args, **kwargs): + plexobjects.PlexObject.__init__(self, *args, **kwargs) + signalsmixin.SignalsMixin.__init__(self) + self._items = [] + self._shuffle = None + self.pos = 0 + self.startShuffled = False + self.isRepeat = False + self.isRepeatOne = False + + def __getitem__(self, idx): + if self._shuffle: + return self._items[self._shuffle[idx]] + else: + return self._items[idx] + + def __iter__(self): + if self._shuffle: + for i in self._shuffle: + yield self._items[i] + else: + for i in self._items: + yield i + + def __len__(self): + return len(self._items) + + def items(self): + if self._shuffle: + return [i for i in self] + else: + return self._items + + def setRepeat(self, repeat, one=False): + if self.isRepeat == repeat and self.isRepeatOne == one: + return + + self.isRepeat = repeat + self.isRepeatOne = one + + def hasNext(self): + if len(self._items) < 2: + return False + if self.isRepeatOne: + return False + if self.isRepeat: + return True + return self.pos < len(self._items) - 1 + + def hasPrev(self): + if len(self._items) < 2: + return False + if self.isRepeatOne: + return False + if self.isRepeat: + return True + return self.pos > 0 + + def next(self): + if not self.hasNext(): + return False + + if self.isRepeatOne: + return True + + self.pos += 1 + if self.pos >= len(self._items): + self.pos = 0 + + return True + + __next__ = next + + def prev(self): + if not self.hasPrev(): + return False + + if self.isRepeatOne: + return True + + self.pos -= 1 + if self.pos < 0: + self.pos = len(self._items) - 1 + + return True + + def getPosFromItem(self, item): + if item not in self._items: + return -1 + return self._items.index(item) + + def setCurrent(self, pos): + if not isinstance(pos, int): + item = pos + pos = self.getPosFromItem(item) + self._items[pos] = item + + if pos < 0 or pos >= len(self._items): + return False + + self.pos = pos + return True + + def current(self): + return self[self.pos] + + def userCurrent(self): + for item in self._items: + if not item.isWatched or item.viewOffset.asInt(): + return item + else: + return self.current() + + def prevItem(self): + if self.pos < 1: + return None + return self[self.pos - 1] + + def shuffle(self, on=True, first=False): + if on and self._items: + self._shuffle = list(range(len(self._items))) + random.shuffle(self._shuffle) + if not first: + self.pos = self._shuffle.index(self.pos) + else: + if self._shuffle: + self.pos = self._shuffle[self.pos] + if not first: + self._shuffle = None + self.trigger('items.changed') + self.refresh() + + def setShuffle(self, shuffle=None): + if shuffle is None: + shuffle = not self.isShuffled + + self.shuffle(shuffle) + + @property + def isShuffled(self): + return bool(self._shuffle) + + def refresh(self, *args, **kwargs): + self.trigger('change') + + +class LocalPlaylist(BasePlaylist): + TYPE = 'localplaylist' + + def __init__(self, items, server, media_item=None): + BasePlaylist.__init__(self, None, server=server) + self._items = items + self._mediaItem = media_item + + def __getattr__(self, name): + if not self._mediaItem: + return BasePlaylist.__getattr__(self, name) + return getattr(self._mediaItem, name) + + def get(self, name, default=''): + if not self._mediaItem: + return BasePlaylist.get(self, name, default) + + return self._mediaItem.get(name, default) + + @property + def defaultArt(self): + if not self._mediaItem: + return super(LocalPlaylist, self).defaultArt + return self._mediaItem.defaultArt diff --git a/script.plexmod/lib/_included_packages/plexnet/playqueue.py b/script.plexmod/lib/_included_packages/plexnet/playqueue.py new file mode 100644 index 0000000000..a7adc3b0ca --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/playqueue.py @@ -0,0 +1,786 @@ +from __future__ import absolute_import +import re +import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error +import time + +from . import plexapp +from . import plexrequest +from . import callback +from . import plexobjects +from . import util +from . import signalsmixin +from six.moves import range + + +class AudioUsage(object): + def __init__(self, skipsPerHour, playQueueId): + self.HOUR = 3600 + self.skipsPerHour = skipsPerHour + self.playQueueId = playQueueId + self.skips = [] + + def allowSkip(self): + if self.skipsPerHour < 0: + return True + self.updateSkips() + return len(self.skips) < self.skipsPerHour + + def updateSkips(self, reset=False): + if reset or len(self.skips) == 0: + if reset: + self.skips = [] + return + + # Remove old skips if applicable + epoch = util.now() + if self.skips[0] + self.HOUR < epoch: + newSkips = [] + for skip in self.skips: + if skip + self.HOUR > epoch: + newSkips.append(skip) + self.skips = newSkips + self.log("updated skips") + + def registerSkip(self): + self.skips.append(util.now()) + self.updateSkips() + self.log("registered skip") + + def allowSkipMessage(self): + if self.skipsPerHour < 0 or self.allowSkip(): + return None + return "You can skip {0} songs an hour per mix.".format(self.skipsPerHour) + + def log(self, prefix): + util.DEBUG_LOG("AudioUsage {0}: total skips={1}, allowed skips={2}".format(prefix, len(self.skips), self.skipsPerHour)) + + +class UsageFactory(object): + def __init__(self, play_queue): + self.playQueue = play_queue + self.type = play_queue.type + self.usage = play_queue.usage + + @classmethod + def createUsage(cls, playQueue): + obj = cls(playQueue) + + if obj.type: + if obj.type == "audio": + return obj.createAudioUsage() + + util.DEBUG_LOG("Don't know how to usage for " + str(obj.type)) + return None + + def createAudioUsage(self): + skips = self.playQueue.container.stationSkipsPerHour.asInt(-1) + if skips == -1: + return None + + # Create new usage if invalid, or if we start a new PQ, otherwise + # we'll return the existing usage for the PQ. + if not self.usage or self.usage.playQueueId != self.playQueue.id: + self.usage = AudioUsage(skips, self.playQueue.id) + + return self.usage + + +class PlayOptions(util.AttributeDict): + def __init__(self, *args, **kwargs): + util.AttributeDict.__init__(self, *args, **kwargs) + # At the moment, this is really just a glorified struct. But the + # expected fields include key, shuffle, extraPrefixCount, + # and unwatched. We may give this more definition over time. + + # These aren't widely used yet, but half inspired by a PMS discussion... + self.CONTEXT_AUTO = 0 + self.CONTEXT_SELF = 1 + self.CONTEXT_PARENT = 2 + self.CONTEXT_CONTAINER = 3 + + self.context = self.CONTEXT_AUTO + + +def createLocalPlayQueue(item, children, contentType, options): + pass + + +class PlayQueueFactory(object): + def getContentType(self, item): + if item.isMusicOrDirectoryItem(): + return "audio" + elif item.isVideoOrDirectoryItem(): + return "video" + elif item.isPhotoOrDirectoryItem(): + return "photo" + + return None + + def canCreateRemotePlayQueue(self): + if self.item.getServer().isSecondary(): + reason = "Server is secondary" + elif not (self.item.isLibraryItem() or self.item.isGracenoteCollection() or self.item.isLibraryPQ or self.item.isCollection): + reason = "Item is not a library item or gracenote collection" + else: + return True + + util.DEBUG_LOG("Requires local play queue: " + reason) + return False + + def itemRequiresRemotePlayQueue(self): + # TODO(rob): handle entire section? (if we create PQ's of sections) + # return item instanceof PlexSection || item.type == PlexObject.Type.artist; + return self.item.type == "artist" + + +def createPlayQueueForItem(item, children=None, options=None, args=None): + obj = PlayQueueFactory() + + contentType = obj.getContentType(item) + if not contentType: + # TODO(schuyler): We may need to try harder, but I'm not sure yet. For + # example, what if we're shuffling an entire library? + # + # No reason to crash here. We can safely return None and move on. + # We'll stop if we're in dev mode to catch and debug. + # + util.DEBUG_LOG("Don't know how to create play queue for item " + repr(item)) + return None + + obj.item = item + + options = PlayOptions(options or {}) + + if obj.canCreateRemotePlayQueue(): + return createRemotePlayQueue(item, contentType, options, args) + else: + if obj.itemRequiresRemotePlayQueue(): + util.DEBUG_LOG("Can't create remote PQs and item does not support local PQs") + return None + else: + return createLocalPlayQueue(item, children, contentType, options) + + +class PlayQueue(signalsmixin.SignalsMixin): + TYPE = 'playqueue' + + isRemote = True + + def __init__(self, server, contentType, options=None): + signalsmixin.SignalsMixin.__init__(self) + self.id = None + self.selectedId = None + self.version = -1 + self.isShuffled = False + self.isRepeat = False + self.isRepeatOne = False + self.isLocalPlayQueue = False + self.isMixed = None + self.totalSize = 0 + self.windowSize = 0 + self.forcedWindow = False + self.container = None + + # Forced limitations + self.allowShuffle = False + self.allowSeek = True + self.allowRepeat = False + self.allowSkipPrev = False + self.allowSkipNext = False + self.allowAddToQueue = False + + self.refreshOnTimeline = False + + self.server = server + self.type = contentType + self._items = [] + self.options = options or util.AttributeDict() + + self.usage = None + + self.refreshTimer = None + + self.canceled = False + self.responded = False + self.initialized = False + + self.composite = plexobjects.PlexValue('', parent=self) + + # Add a few default options for specific PQ types + if self.type == "audio": + self.options.includeRelated = True + elif self.type == "photo": + self.setRepeat(True) + + def get(self, name): + return getattr(self, name, plexobjects.PlexValue('', parent=self)) + + @property + def defaultArt(self): + return self.current().defaultArt + + def waitForInitialization(self): + start = time.time() + timeout = util.TIMEOUT + util.DEBUG_LOG('Waiting for playQueue to initialize...') + while not self.canceled and not self.initialized: + if not self.responded and time.time() - start > timeout: + util.DEBUG_LOG('PlayQueue timed out wating for initialization') + return self.initialized + time.sleep(0.1) + + if self.initialized: + util.DEBUG_LOG('PlayQueue initialized in {0:.2f} secs: {1}'.format(time.time() - start, self)) + else: + util.DEBUG_LOG('PlayQueue failed to initialize') + + return self.initialized + + def onRefreshTimer(self): + self.refreshTimer = None + self.refresh(True, False) + + def refresh(self, force=True, delay=False, wait=False): + # Ignore refreshing local PQs + if self.isLocal(): + return + + if wait: + self.responded = False + self.initialized = False + # We refresh our play queue if the caller insists or if we only have a + # portion of our play queue loaded. In particular, this means that we don't + # refresh the play queue if we're asked to refresh because a new track is + # being played but we have the entire album loaded already. + + if force or self.isWindowed(): + if delay: + # We occasionally want to refresh the PQ in response to moving to a + # new item and starting playback, but if we refresh immediately: + # we probably end up refreshing before PMS realizes we've moved on. + # There's no great solution, but delaying our refresh by just a few + # seconds makes us much more likely to get an accurate window (and + # accurate selected IDs) from PMS. + + if not self.refreshTimer: + self.refreshTimer = plexapp.createTimer(5000, self.onRefreshTimer) + util.APP.addTimer(self.refreshTimer) + else: + request = plexrequest.PlexRequest(self.server, "/playQueues/" + str(self.id)) + self.addRequestOptions(request) + context = request.createRequestContext("refresh", callback.Callable(self.onResponse)) + util.APP.startRequest(request, context) + + if wait: + return self.waitForInitialization() + + def shuffle(self, shuffle=True): + self.setShuffle(shuffle) + + def setShuffle(self, shuffle=None): + if shuffle is None: + shuffle = not self.isShuffled + + if self.isShuffled == shuffle: + return + + if shuffle: + command = "/shuffle" + else: + command = "/unshuffle" + + # Don't change self.isShuffled, it'll be set in OnResponse if all goes well + + request = plexrequest.PlexRequest(self.server, "/playQueues/" + str(self.id) + command, "PUT") + self.addRequestOptions(request) + context = request.createRequestContext("shuffle", callback.Callable(self.onResponse)) + util.APP.startRequest(request, context) + + def setRepeat(self, repeat, one=False): + if self.isRepeat == repeat and self.isRepeatOne == one: + return + + self.options.repeat = repeat + self.isRepeat = repeat + self.isRepeatOne = one + + def moveItemUp(self, item): + for index in range(1, len(self._items)): + if self._items[index].get("playQueueItemID") == item.get("playQueueItemID"): + if index > 1: + after = self._items[index - 2] + else: + after = None + + self.swapItem(index, -1) + self.moveItem(item, after) + return True + + return False + + def moveItemDown(self, item): + for index in range(len(self._items) - 1): + if self._items[index].get("playQueueItemID") == item.get("playQueueItemID"): + after = self._items[index + 1] + self.swapItem(index) + self.moveItem(item, after) + return True + + return False + + def moveItem(self, item, after): + if after: + query = "?after=" + after.get("playQueueItemID", "-1") + else: + query = "" + + request = plexrequest.PlexRequest(self.server, "/playQueues/" + str(self.id) + "/items/" + item.get("playQueueItemID", "-1") + "/move" + query, "PUT") + self.addRequestOptions(request) + context = request.createRequestContext("move", callback.Callable(self.onResponse)) + util.APP.startRequest(request, context) + + def swapItem(self, index, delta=1): + before = self._items[index] + after = self._items[index + delta] + + self._items[index] = after + self._items[index + delta] = before + + def removeItem(self, item): + request = plexrequest.PlexRequest(self.server, "/playQueues/" + str(self.id) + "/items/" + item.get("playQueueItemID", "-1"), "DELETE") + self.addRequestOptions(request) + context = request.createRequestContext("delete", callback.Callable(self.onResponse)) + util.APP.startRequest(request, context) + + def addItem(self, item, addNext=False, excludeSeedItem=False): + request = plexrequest.PlexRequest(self.server, "/playQueues/" + str(self.id), "PUT") + request.addParam("uri", item.getItemUri()) + request.addParam("next", addNext and "1" or "0") + request.addParam("excludeSeedItem", excludeSeedItem and "1" or "0") + self.addRequestOptions(request) + context = request.createRequestContext("add", callback.Callable(self.onResponse)) + util.APP.startRequest(request, context) + + def onResponse(self, request, response, context): + # Close any loading modal regardless of response status + # Application().closeLoadingModal() + util.DEBUG_LOG('playQueue: Received response') + self.responded = True + if response.parseResponse(): + util.DEBUG_LOG('playQueue: {0} items'.format(len(response.items))) + self.container = response.container + # Handle an empty PQ if we have specified an pqEmptyCallable + if self.options and self.options.pqEmptyCallable: + callable = self.options.pqEmptyCallable + del self.options["pqEmptyCallable"] + if len(response.items) == 0: + callable.call() + return + + self.id = response.container.playQueueID.asInt() + self.isShuffled = response.container.playQueueShuffled.asBool() + self.totalSize = response.container.playQueueTotalCount.asInt() + self.windowSize = len(response.items) + self.version = response.container.playQueueVersion.asInt() + + itemsChanged = False + if len(response.items) == len(self._items): + for i in range(len(self._items)): + if self._items[i] != response.items[i]: + itemsChanged = True + break + else: + itemsChanged = True + + if itemsChanged: + self._items = response.items + + # Process any forced limitations + self.allowSeek = response.container.allowSeek.asBool() + self.allowShuffle = ( + self.totalSize > 1 and response.container.allowShuffle.asBool() and not response.container.playQueueLastAddedItemID + ) + self.allowRepeat = response.container.allowRepeat.asBool() + self.allowSkipPrev = self.totalSize > 1 and response.container.allowSkipPrevious != "0" + self.allowSkipNext = self.totalSize > 1 and response.container.allowSkipNext != "0" + + # Figure out the selected track index and offset. PMS tries to make some + # of this easy, but it might not realize that we've advanced to a new + # track, so we can't blindly trust it. On the other hand, it's possible + # that PMS completely changed the PQ item IDs (e.g. upon shuffling), so + # we might need to use its values. We iterate through the items and try + # to find the item that we believe is selected, only settling for what + # PMS says if we fail. + + playQueueOffset = None + selectedId = None + pmsSelectedId = response.container.playQueueSelectedItemID.asInt() + self.deriveIsMixed() + + # lastItem = None # Not used + for index in range(len(self._items)): + item = self._items[index] + + if not playQueueOffset and item.playQueueItemID.asInt() == pmsSelectedId: + playQueueOffset = response.container.playQueueSelectedItemOffset.asInt() - index + 1 + + # Update the index of everything we've already past, and handle + # wrapping indexes (repeat). + for i in range(index): + pqIndex = playQueueOffset + i + if pqIndex < 1: + pqIndex = pqIndex + self.totalSize + + self._items[i].playQueueIndex = plexobjects.PlexValue(str(pqIndex), parent=self._items[i]) + + if playQueueOffset: + pqIndex = playQueueOffset + index + if pqIndex > self.totalSize: + pqIndex = pqIndex - self.totalSize + + item.playQueueIndex = plexobjects.PlexValue(str(pqIndex), parent=item) + + # If we found the item that we believe is selected: we should + # continue to treat it as selected. + # TODO(schuyler): Should we be checking the metadata ID (rating key) + # instead? I don't think it matters in practice, but it may be + # more correct. + + if not selectedId and item.playQueueItemID.asInt() == self.selectedId: + selectedId = self.selectedId + + if not selectedId: + self.selectedId = pmsSelectedId + + # TODO(schuyler): Set repeat as soon as PMS starts returning it + + # Fix up the container for all our items + response.container.address = "/playQueues/" + str(self.id) + + # Create usage limitations + self.usage = UsageFactory.createUsage(self) + + self.initialized = True + self.trigger("change") + + if itemsChanged: + self.trigger("items.changed") + + def isWindowed(self): + return (not self.isLocal() and (self.totalSize > self.windowSize or self.forcedWindow)) + + def hasNext(self): + if self.isRepeatOne: + return True + + if not self.allowSkipNext and -1 < list(self.items()).index(self.current()) < (len(list(self.items())) - 1): # TODO: Was 'or' - did change cause issues? + return self.isRepeat and not self.isWindowed() + + return True + + def hasPrev(self): + # return self.allowSkipPrev or self.items().index(self.current()) > 0 + return list(self.items()).index(self.current()) > 0 + + def next(self): + if self.isRepeatOne: + return self.current() + + item = self.getNext() + if not item: + return None + + self.selectedId = item.playQueueItemID.asInt() + return item + + __next__ = next + + def prev(self): + if self.isRepeatOne: + return self.current() + + item = self.getPrev() + if not item: + return None + + self.selectedId = item.playQueueItemID.asInt() + return item + + def getPrev(self): + if not self.hasPrev(): + return None + + pos = list(self.items()).index(self.current()) - 1 + return list(self.items())[pos] + + def getNext(self): + if not self.hasNext(): + return None + + pos = list(self.items()).index(self.current()) + 1 + if pos >= len(self.items()): + if not self.isRepeat or self.isWindowed(): + return None + pos = 0 + + return list(self.items())[pos] + + + def setCurrent(self, pos): + if pos < 0 or pos >= len(list(self.items())): + return False + + item = list(self.items())[pos] + self.selectedId = item.playQueueItemID.asInt() + return item + + def setCurrentItem(self, item): + self.selectedId = item.playQueueItemID.asInt() + + def __eq__(self, other): + if not other: + return False + if self.__class__ != other.__class__: + return False + return self.id == other.id and self.type == other.type + + def __ne__(self, other): + return not self.__eq__(other) + + def addRequestOptions(self, request): + boolOpts = ["repeat", "includeRelated"] + for opt in boolOpts: + if self.options.get(opt): + request.addParam(opt, "1") + + intOpts = ["extrasPrefixCount"] + for opt in intOpts: + if self.options.get(opt): + request.addParam(opt, str(self.options.get(opt))) + + includeChapters = self.options.get('includeChapters') is not None and self.options.includeChapters or 1 + request.addParam("includeChapters", str(includeChapters)) + + def __repr__(self): + return ( + str(self.__class__.__name__) + " " + + str(self.type) + " windowSize=" + + str(self.windowSize) + " totalSize=" + + str(self.totalSize) + " selectedId=" + + str(self.selectedId) + " shuffled=" + + str(self.isShuffled) + " repeat=" + + str(self.isRepeat) + " mixed=" + + str(self.isMixed) + " allowShuffle=" + + str(self.allowShuffle) + " version=" + + str(self.version) + " id=" + str(self.id) + ) + + def isLocal(self): + return self.isLocalPlayQueue + + def deriveIsMixed(self): + if self.isMixed is None: + self.isMixed = False + + lastItem = None + for item in self._items: + if not self.isMixed: + if not item.get("parentKey"): + self.isMixed = True + else: + self.isMixed = lastItem and item.get("parentKey") != lastItem.get("parentKey") + + lastItem = item + + def items(self): + return self._items + + def current(self): + for item in self.items(): + if item.playQueueItemID.asInt() == self.selectedId: + return item + + return None + + def prevItem(self): + last = None + for item in self.items(): + if item.playQueueItemID.asInt() == self.selectedId: + return last + last = item + + return None + + +def createRemotePlayQueue(item, contentType, options, args): + util.DEBUG_LOG('Creating remote playQueue request...') + obj = PlayQueue(item.getServer(), contentType, options) + + # The item's URI is made up of the library section UUID, a descriptor of + # the item type (item or directory), and the item's path, URL-encoded. + + uri = "library://" + item.getLibrarySectionUuid() + "/" + itemType = item.isDirectory() and "directory" or "item" + path = None + + if not options.key: + # if item.onDeck and len(item.onDeck) > 0: + # options.key = item.onDeck[0].getAbsolutePath("key") + # el + if not item.isDirectory(): + options.key = item.get("key") + + # If we're asked to play unwatched, ignore the option unless we are unwatched. + options.unwatched = options.unwatched and item.isUnwatched() + + # TODO(schuyler): Until we build postplay, we're not allowed to queue containers for episodes. + if item.type == "episode": + options.context = options.CONTEXT_SELF + elif item.type == "movie": + if not options.extrasPrefixCount and not options.resume: + options.extrasPrefixCount = util.INTERFACE.getPreference("cinema_trailers", 0) + + # How exactly to construct the item URI depends on the metadata type, though + # whenever possible we simply use /library/metadata/:id. + + if item.isLibraryItem() and not item.isLibraryPQ: + path = "/library/metadata/" + item.ratingKey + else: + path = item.getAbsolutePath("key") + + if options.context == options.CONTEXT_SELF: + # If the context is specifically for just this item,: just use the + # item's key and get out. + pass + elif item.type == "playlist": + path = None + uri = item.get("ratingKey") + options.isPlaylist = True + elif item.type == "track": + # TODO(rob): Is there ever a time the container address is wrong? If we + # expect to play a single track,: use options.CONTEXT_SELF. + path = item.container.address or "/library/metadata/" + item.get("parentRatingKey", "") + itemType = "directory" + elif item.isPhotoOrDirectoryItem(): + if item.type == "photoalbum" or item.parentKey: + path = item.getParentPath(item.type == "photoalbum" and "key" or "parentKey") + itemType = "item" + elif item.isDirectory(): + path = item.getAbsolutePath("key") + else: + path = item.container.address + itemType = "directory" + options.key = item.getAbsolutePath("key") + + elif item.type == "episode": + path = "/library/metadata/" + item.get("grandparentRatingKey", "") + itemType = "directory" + options.key = item.getAbsolutePath("key") + # elif item.type == "show": + # path = "/library/metadata/" + item.get("ratingKey", "") + + if path: + if args: + path += util.joinArgs(args) + + util.DEBUG_LOG("playQueue path: " + str(path)) + + if "/search" not in path: + # Convert a few params to the PQ spec + convert = { + 'type': "sourceType", + 'unwatchedLeaves': "unwatched" + } + + for key in convert: + regex = re.compile("(?i)([?&])" + key + "=") + path = regex.sub("\1" + convert[key] + "=", path) + + util.DEBUG_LOG("playQueue path: " + str(path)) + uri = uri + itemType + "/" + six.moves.urllib.parse.quote_plus(path) + + util.DEBUG_LOG("playQueue uri: " + str(uri)) + + # Create the PQ request + request = plexrequest.PlexRequest(obj.server, "/playQueues") + + request.addParam(not options.isPlaylist and "uri" or "playlistID", uri) + request.addParam("type", contentType) + # request.addParam('X-Plex-Client-Identifier', util.INTERFACE.getGlobal('clientIdentifier')) + + # Add options we pass once during PQ creation + if options.shuffle: + request.addParam("shuffle", "1") + options.key = None + else: + request.addParam("shuffle", "0") + + if options.key: + request.addParam("key", options.key) + + # Add options we pass every time querying PQs + obj.addRequestOptions(request) + + util.DEBUG_LOG('Initial playQueue request started...') + context = request.createRequestContext("create", callback.Callable(obj.onResponse)) + util.APP.startRequest(request, context, body='') + + return obj + + +def createPlayQueueForId(id, server=None, contentType=None): + obj = PlayQueue(server, contentType) + obj.id = id + + request = plexrequest.PlexRequest(server, "/playQueues/" + str(id)) + request.addParam("own", "1") + obj.addRequestOptions(request) + context = request.createRequestContext("own", callback.Callable(obj.onResponse)) + util.APP.startRequest(request, context) + + return obj + + +class AudioPlayer(): + pass + + +class VideoPlayer(): + pass + + +class PhotoPlayer(): + pass + + +def addItemToPlayQueue(item, addNext=False): + # See if we have an active play queue for this self.dia type or if we need to + # create one. + + if item.isMusicOrDirectoryItem(): + player = AudioPlayer() + elif item.isVideoOrDirectoryItem(): + player = VideoPlayer() + elif item.isPhotoOrDirectoryItem(): + player = PhotoPlayer() + else: + player = None + + if not player: + util.ERROR_LOG("Don't know how to add item to play queue: " + str(item)) + return None + elif not player.allowAddToQueue(): + util.DEBUG_LOG("Not allowed to add to this player") + return None + + if player.playQueue: + playQueue = player.playQueue + playQueue.addItem(item, addNext) + else: + options = PlayOptions() + options.context = options.CONTEXT_SELF + playQueue = createPlayQueueForItem(item, None, options) + if playQueue: + player.setPlayQueue(playQueue, False) + + return playQueue diff --git a/script.plexmod/lib/_included_packages/plexnet/plexapp.py b/script.plexmod/lib/_included_packages/plexnet/plexapp.py new file mode 100644 index 0000000000..cc7d087b13 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexapp.py @@ -0,0 +1,403 @@ +from __future__ import print_function, absolute_import +import threading +import platform +import uuid +import sys + +from . import callback +from . import signalsmixin +from . import simpleobjects +from . import util +import six + +Res = simpleobjects.Res +SERVERMANAGER = None +ACCOUNT = None +MANAGER = None + +PLATFORM = util.X_PLEX_DEVICE + + +def init(): + global MANAGER, SERVERMANAGER, ACCOUNT + from . import myplexaccount + ACCOUNT = myplexaccount.ACCOUNT + ACCOUNT.init() + from . import plexservermanager + SERVERMANAGER = plexservermanager.MANAGER + from . import myplexmanager + util.MANAGER = MANAGER = myplexmanager.MANAGER + ACCOUNT.verifyAccount() + + +class App(signalsmixin.SignalsMixin): + def __init__(self): + signalsmixin.SignalsMixin.__init__(self) + self.pendingRequests = {} + self.initializers = {} + self.timers = [] + from . import nowplayingmanager + self.nowplayingmanager = nowplayingmanager.NowPlayingManager() + + def addTimer(self, timer): + self.timers.append(timer) + + def startRequest(self, request, context, body=None, contentType=None): + context.request = request + + started = request.startAsync(body=body, contentType=contentType, context=context) + + if started: + requestID = context.request.getIdentity() + self.pendingRequests[requestID] = context + elif context.callback: + context.callback(None, context) + + return started + + def onRequestTimeout(self, context): + requestID = context.request.getIdentity() + + if requestID not in self.pendingRequests: + return + + context.request.cancel() + + util.WARN_LOG("Request to {0} timed out after {1} sec".format(util.cleanToken(context.request.url), context.timeout)) + + if context.callback: + context.callback(None, context) + + def delRequest(self, request): + requestID = request.getIdentity() + if requestID not in self.pendingRequests: + return + + del self.pendingRequests[requestID] + + def addInitializer(self, name): + self.initializers[name] = True + + def clearInitializer(self, name): + if name in self.initializers: + del self.initializers[name] + if self.isInitialized(): + self.onInitialized() + + def isInitialized(self): + return not self.initializers + + def onInitialized(self): + # Wire up a few of our own listeners + # PlexServerManager() + # self.on("change:user", callback.Callable(self.onAccountChange)) + + self.trigger('init') + + def cancelAllTimers(self): + for timer in self.timers: + timer.cancel() + + def preShutdown(self): + from . import http + http.HttpRequest._cancel = True + if self.pendingRequests: + util.DEBUG_LOG('Closing down {0} App() requests...'.format(len(self.pendingRequests))) + for k in list(self.pendingRequests.keys()): + p = self.pendingRequests.get(k) + if p: + p.request.cancel() + + if self.timers: + util.DEBUG_LOG('Canceling App() timers...') + self.cancelAllTimers() + + if SERVERMANAGER.selectedServer: + util.DEBUG_LOG('Closing server...') + SERVERMANAGER.selectedServer.close() + + def shutdown(self): + if self.timers: + util.DEBUG_LOG('Waiting for {0} App() timers: Started'.format(len(self.timers))) + + self.cancelAllTimers() + + for timer in self.timers: + timer.join() + + util.DEBUG_LOG('Waiting for App() timers: Finished') + + +class DeviceInfo(object): + def getCaptionsOption(self, key): + return None + + +class AppInterface(object): + QUALITY_LOCAL = 0 + QUALITY_REMOTE = 1 + QUALITY_ONLINE = 2 + + _globals = {} + + def __init__(self): + self.setQualities() + + def setQualities(self): + # Calculate the max quality based on 4k support + if self._globals.get("supports4k"): + maxQuality = simpleobjects.AttributeDict({ + 'height': 2160, + 'maxHeight': 2160, + 'origHeight': 1080 + }) + maxResolution = self._globals.get("Is4k") and "4k" or "1080p" + else: + maxQuality = simpleobjects.AttributeDict({ + 'height': 1080, + 'maxHeight': 1088 + }) + maxResolution = "1080p" + + self._globals['qualities'] = [ + simpleobjects.AttributeDict({'title': "Original", 'index': 13, 'maxBitrate': 1000000}), + simpleobjects.AttributeDict({'title': "20 Mbps " + maxResolution, 'index': 12, 'maxBitrate': 20000}), + simpleobjects.AttributeDict({'title': "12 Mbps " + maxResolution, 'index': 11, 'maxBitrate': 12000}), + simpleobjects.AttributeDict({'title': "10 Mbps " + maxResolution, 'index': 10, 'maxBitrate': 10000}), + simpleobjects.AttributeDict({'title': "8 Mbps " + maxResolution, 'index': 9, 'maxBitrate': 8000}), + simpleobjects.AttributeDict({'title': "4 Mbps 720p", 'index': 8, 'maxBitrate': 4000, 'maxHeight': 720}), + simpleobjects.AttributeDict({'title': "3 Mbps 720p", 'index': 7, 'maxBitrate': 3000, 'maxHeight': 720}), + simpleobjects.AttributeDict({'title': "2 Mbps 720p", 'index': 6, 'maxBitrate': 2000, 'maxHeight': 720}), + simpleobjects.AttributeDict({'title': "1.5 Mbps 480p", 'index': 5, 'maxBitrate': 1500, 'maxHeight': 480}), + simpleobjects.AttributeDict({'title': "720 Kbps", 'index': 4, 'maxBitrate': 720, 'maxHeight': 360}), + simpleobjects.AttributeDict({'title': "320 Kbps", 'index': 3, 'maxBitrate': 320, 'maxHeight': 360}), + maxQuality + ] + + for quality in self._globals['qualities']: + if quality.index is not None and quality.index >= 9: + quality.update(maxQuality) + + def getPreference(self, pref, default=None): + raise NotImplementedError + + def setPreference(self, pref, value): + raise NotImplementedError + + def clearRegistry(self, reg, sec=None): + raise NotImplementedError + + def getRegistry(self, reg, default=None, sec=None): + raise NotImplementedError + + def setRegistry(self, reg, value, sec=None): + raise NotImplementedError + + def getGlobal(self, glbl, default=None): + raise NotImplementedError + + def getCapabilities(self): + raise NotImplementedError + + def LOG(self, msg): + raise NotImplementedError + + def DEBUG_LOG(self, msg): + self.LOG(msg) + + def WARN_LOG(self, msg): + self.LOG(msg) + + def ERROR_LOG(self, msg): + self.LOG(msg) + + def ERROR(self, msg=None, err=None): + self.LOG(msg) + + def FATAL(self, msg=None): + self.ERROR_LOG('FATAL: {0}'.format(msg)) + + def supportsAudioStream(self, codec, channels): + return False + + def supportsSurroundSound(self): + return False + + def getMaxResolution(self, quality_type, allow4k=False): + return 480 + + def getQualityIndex(self, qualityType): + if qualityType == self.QUALITY_LOCAL: + return self.getPreference("local_quality", 13) + elif qualityType == self.QUALITY_ONLINE: + return self.getPreference("online_quality", 13) + else: + return self.getPreference("remote_quality", 13) + + def settingsGetMaxResolution(self, qualityType, allow4k): + qualityIndex = self.getQualityIndex(qualityType) + + if qualityIndex >= 9: + return allow4k and 2160 or 1088 + elif qualityIndex >= 6: + return 720 + elif qualityIndex >= 5: + return 480 + else: + return 360 + + def getMaxBitrate(self, qualityType): + qualityIndex = self.getQualityIndex(qualityType) + + qualities = self.getGlobal("qualities", []) + for quality in qualities: + if quality.index == qualityIndex: + return util.validInt(quality.maxBitrate) + + return 0 + + +class PlayerSettingsInterface(object): + def __init__(self): + self.prefOverrides = {} + + def __getattr__(self, name): + return getattr(util.INTERFACE, name) + + def setPrefOverride(self, key, val): + self.prefOverrides[key] = val + + def getPrefOverride(self, key, default=None): + return self.prefOverrides.get(key, default) + + def getQualityIndex(self, qualityType): + if qualityType == util.INTERFACE.QUALITY_LOCAL: + return self.getPreference("local_quality", 13) + elif qualityType == util.INTERFACE.QUALITY_ONLINE: + return self.getPreference("online_quality", 13) + else: + return self.getPreference("remote_quality", 13) + + def getPreference(self, key, default=None): + if key in self.prefOverrides: + return self.prefOverrides[key] + else: + return util.INTERFACE.getPreference(key, default) + + def getMaxResolution(self, quality_type, allow4k=False): + qualityIndex = self.getQualityIndex(quality_type) + + if qualityIndex >= 9: + return allow4k and 2160 or 1088 + elif qualityIndex >= 6: + return 720 + elif qualityIndex >= 5: + return 480 + else: + return 360 + + def getMaxBitrate(self, qualityType): + qualityIndex = self.getQualityIndex(qualityType) + + qualities = self.getGlobal("qualities", []) + for quality in qualities: + if quality.index == qualityIndex: + return util.validInt(quality.maxBitrate) + + return 0 + + +class DumbInterface(AppInterface): + _prefs = {} + _regs = { + None: {} + } + _globals = { + 'platform': platform.uname()[0], + 'appVersionStr': '0.0.0a1', + 'clientIdentifier': str(hex(uuid.getnode())), + 'platformVersion': platform.uname()[2], + 'product': 'PlexNet.API', + 'provides': 'player', + 'device': platform.uname()[0], + 'model': 'Unknown', + 'friendlyName': 'PlexNet.API', + 'deviceInfo': DeviceInfo() + } + + def getPreference(self, pref, default=None): + return self._prefs.get(pref, default) + + def setPreference(self, pref, value): + self._prefs[pref] = value + + def getRegistry(self, reg, default=None, sec=None): + section = self._regs.get(sec) + if section: + return section.get(reg, default) + + return default + + def setRegistry(self, reg, value, sec=None): + if sec and sec not in self._regs: + self._regs[sec] = {} + self._regs[sec][reg] = value + + def clearRegistry(self, reg, sec=None): + del self._regs[sec][reg] + + def getGlobal(self, glbl, default=None): + return self._globals.get(glbl, default) + + def getCapabilities(self): + return '' + + def LOG(self, msg): + print('PlexNet.API: {0}'.format(msg)) + + def DEBUG_LOG(self, msg): + self.LOG('DEBUG: {0}'.format(msg)) + + def WARN_LOG(self, msg): + self.LOG('WARNING: {0}'.format(msg)) + + def ERROR_LOG(self, msg): + self.LOG('ERROR: {0}'.format(msg)) + + def ERROR(self, msg=None, err=None): + if err: + self.LOG('ERROR: {0} - {1}'.format(msg, err.message)) + else: + import traceback + traceback.print_exc() + + +def createTimer(timeout, function, repeat=False, *args, **kwargs): + if isinstance(function, six.string_types): + def dummy(*args, **kwargs): + pass + dummy.__name__ = function + function = dummy + timer = util.TIMER(timeout / 1000.0, function, repeat=repeat, *args, **kwargs) + return timer + + +def setUserAgent(agent): + util.USER_AGENT = agent + util.BASE_HEADERS = util.resetBaseHeaders() + + +def setAbortFlagFunction(func): + from . import asyncadapter + asyncadapter.ABORT_FLAG_FUNCTION = func + + +def refreshResources(force=False): + from . import gdm + gdm.DISCOVERY.discover() + util.MANAGER.refreshResources(force) + SERVERMANAGER.refreshManualConnections() + + +util.setApp(App()) +util.setInterface(DumbInterface()) diff --git a/script.plexmod/lib/_included_packages/plexnet/plexconnection.py b/script.plexmod/lib/_included_packages/plexnet/plexconnection.py new file mode 100644 index 0000000000..617a2d1469 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexconnection.py @@ -0,0 +1,284 @@ +from __future__ import absolute_import +import random +import socket + +from . import http +from . import callback +from . import util + +HAS_ICMPLIB = False +try: + from icmplib import ping, resolve, ICMPLibError +except: + pass +else: + HAS_ICMPLIB = True + from urllib.parse import urlparse + from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network + + # local networks + LOCAL_NETWORKS = { + 4: [IPv4Network('10.0.0.0/8'), IPv4Network('192.168.0.0/16'), IPv4Network('127.0.0.0/8')], + 6: [IPv6Network('fd00::/8')] + } + + +class ConnectionSource(int): + def init(self, name): + self.name = name + return self + + def __repr__(self): + return self.name + + +class PlexConnection(object): + # Constants + STATE_UNKNOWN = "unknown" + STATE_UNREACHABLE = "unreachable" + STATE_REACHABLE = "reachable" + STATE_UNAUTHORIZED = "unauthorized" + STATE_INSECURE = "insecure_untested" + + SOURCE_MANUAL = ConnectionSource(1).init('MANUAL') + SOURCE_DISCOVERED = ConnectionSource(2).init('DISCOVERED') + SOURCE_MANUAL_AND_DISCOVERED = ConnectionSource(3).init('MANUAL, DISCOVERED') + SOURCE_MYPLEX = ConnectionSource(4).init('MYPLEX') + SOURCE_MANUAL_AND_MYPLEX = ConnectionSource(5).init('MANUAL, MYPLEX') + SOURCE_DISCOVERED_AND_MYPLEX = ConnectionSource(6).init('DISCOVERED, MYPLEX') + SOURCE_ALL = ConnectionSource(7).init('ALL') + + SCORE_REACHABLE = 4 + SCORE_LOCAL = 2 + SCORE_SECURE = 1 + + SOURCE_BY_VAL = { + 1: SOURCE_MANUAL, + 2: SOURCE_DISCOVERED, + 3: SOURCE_MANUAL_AND_DISCOVERED, + 4: SOURCE_MYPLEX, + 5: SOURCE_MANUAL_AND_MYPLEX, + 6: SOURCE_DISCOVERED_AND_MYPLEX, + 7: SOURCE_ALL + } + + def __init__(self, source, address, isLocal, token, isFallback=False, skipLocalCheck=False): + self.state = self.STATE_UNKNOWN + self.sources = source + self.address = address + self.isLocal = isLocal + self.isSecure = address[:5] == 'https' + self.isFallback = isFallback + self.token = token + self.refreshed = True + self.score = 0 + self.request = None + + self.lastTestedAt = 0 + self.hasPendingRequest = False + + self.isSecureButLocal = False + + if not HAS_ICMPLIB: + util.WARN_LOG("icmplib not found, can't check local connectivity") + + # check whether hostname is on LAN + if HAS_ICMPLIB and util.CHECK_LOCAL and not skipLocalCheck: + self.checkLocal() + + self.getScore(True) + + def __eq__(self, other): + if not other: + return False + if self.__class__ != other.__class__: + return False + return self.address == other.address + + def __ne__(self, other): + return not self.__eq__(other) + + def __str__(self): + return "Connection: {0} local: {1} token: {2} sources: {3} state: {4} score: {5}".format( + self.address, + self.isLocal, + util.hideToken(self.token), + repr(self.sources), + self.state, + self.getScore() + ) + + def __repr__(self): + return self.__str__() + + def ipInLocalNet(self, ip): + key = ":" in ip and 6 or 4 + addr = key == 4 and IPv4Address(ip) or IPv6Address(ip) + for network in LOCAL_NETWORKS[key]: + if addr in network: + return network + return False + + def checkLocal(self): + pUrl = urlparse(self.address) + hostname = pUrl.hostname + try: + ips = resolve(hostname) + except (socket.gaierror, ICMPLibError): + return False + + for ip in ips: + if ip == hostname: + continue + + network = self.ipInLocalNet(ip) + if not network: + continue + + try: + host = ping(ip, count=1, interval=1, timeout=util.LAN_REACHABILITY_TIMEOUT, privileged=False) + except: + continue + + if host.is_alive: + self.isLocal = True + util.LOG("Found IP {0} in local network ({1}) when checking {2}. Ping: {3}ms (max: {4}ms)" + .format(ip, network, self.address, host.max_rtt, int(util.LAN_REACHABILITY_TIMEOUT * 1000))) + + if self.isSecure: + # alert the server that we've found the IP locally, so we can test non-secure connectivity + self.isSecureButLocal = (ip, pUrl.port) + + return False + + def merge(self, other): + # plex.tv trumps all, otherwise assume newer is better + # ROKU: if (other.sources and self.SOURCE_MYPLEX) <> 0 then + if other.sources == self.SOURCE_MYPLEX: + self.token = other.token + else: + self.token = self.token or other.token + + self.address = other.address + self.sources = self.SOURCE_BY_VAL[self.sources | other.sources] + self.isLocal = self.isLocal | other.isLocal + self.isSecure = other.isSecure + self.isFallback = self.isFallback or other.isFallback + self.refreshed = True + + self.getScore(True) + + def testReachability(self, server, allowFallback=False): + # Check if we will allow the connection test. If this is a fallback connection, + # then we will defer it until we "allowFallback" (test insecure connections + # after secure tests have completed and failed). Insecure connections will be + # tested if the policy "always" allows them, or if set to "same_network" and + # the current connection is local and server has (publicAddressMatches=1). + insecurePolicy = util.INTERFACE.getPreference("allow_insecure") + insecureAllowed = insecurePolicy == "always" or (insecurePolicy == "same_network" and + server.sameNetwork and self.isLocal) + + allowConnectionTest = not self.isFallback or (util.LOCAL_OVER_SECURE and insecureAllowed) + if not allowConnectionTest: + if insecureAllowed: + allowConnectionTest = allowFallback + server.hasFallback = not allowConnectionTest + util.LOG( + '{0} for {1}'.format( + allowConnectionTest and "Continuing with insecure connection testing" or "Insecure connection testing is deferred", server + ) + ) + else: + util.LOG("Insecure connections not allowed. Ignore insecure connection test for {0}".format(server)) + self.state = self.STATE_INSECURE + callable = callback.Callable(server.onReachabilityResult, [self], random.randint(0, 256)) + callable.deferCall() + return True + + if allowConnectionTest: + if not self.isSecure and not util.LOCAL_OVER_SECURE and ( + not allowFallback and + server.hasSecureConnections() or + server.activeConnection and + server.activeConnection.state != self.STATE_REACHABLE and + server.activeConnection.isSecure + ): + util.DEBUG_LOG("Invalid insecure connection test in progress") + self.request = http.HttpRequest(self.buildUrl(server, "/")) + context = self.request.createRequestContext("reachability", callback.Callable(self.onReachabilityResponse), + timeout=util.CONN_CHECK_TIMEOUT) + context.server = server + util.addPlexHeaders(self.request, server.getToken()) + self.hasPendingRequest = util.APP.startRequest(self.request, context) + util.DEBUG_LOG("Testing insecure connection test for: {0}".format(server)) + return True + + return False + + def cancelReachability(self): + if self.request: + self.request.ignoreResponse = True + self.request.cancel() + + def onReachabilityResponse(self, request, response, context): + self.hasPendingRequest = False + # It's possible we may have a result pending before we were able + # to cancel it, so we'll just ignore it. + + # if request.ignoreResponse: + # return + + if response.isSuccess(): + data = response.getBodyXml() + if data is not None and context.server.collectDataFromRoot(data): + self.state = self.STATE_REACHABLE + else: + # This is unexpected, but treat it as unreachable + util.ERROR_LOG("Unable to parse root response from {0}".format(context.server)) + self.state = self.STATE_UNREACHABLE + elif response.getStatus() == 401: + self.state = self.STATE_UNAUTHORIZED + else: + self.state = self.STATE_UNREACHABLE + + self.getScore(True) + + context.server.onReachabilityResult(self) + + def buildUrl(self, server, path, includeToken=False): + if '://' in path: + url = path + else: + url = self.address + path + + if includeToken: + # If we have a token, use it. Otherwise see if any other connections + # for this server have one. That will let us use a plex.tv token for + # something like a manually configured connection. + + token = self.token or server.getToken() + + if token: + url = http.addUrlParam(url, "X-Plex-Token=" + token) + + return url + + def simpleBuildUrl(self, server, path): + token = (self.token or server.getToken()) + param = '' + if token: + param = '&X-Plex-Token={0}'.format(token) + + return '{0}{1}{2}'.format(self.address, path, param) + + def getScore(self, recalc=False): + if recalc: + self.score = 0 + if self.state == self.STATE_REACHABLE: + self.score += self.SCORE_REACHABLE + if self.isSecure: + self.score += self.SCORE_SECURE + if self.isLocal: + self.score += self.SCORE_LOCAL + (not self.isSecure and util.LOCAL_OVER_SECURE and 2 or 0) + + return self.score diff --git a/script.plexmod/lib/_included_packages/plexnet/plexlibrary.py b/script.plexmod/lib/_included_packages/plexnet/plexlibrary.py new file mode 100644 index 0000000000..9d93d557c7 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexlibrary.py @@ -0,0 +1,634 @@ +# -*- coding: utf-8 -*- +""" +PlexLibrary +""" +from __future__ import absolute_import +import re +from . import plexobjects +from . import playlist +from . import media +from . import exceptions +from . import util +from . import signalsmixin +from six.moves import map + + +class Library(plexobjects.PlexObject): + def __repr__(self): + return ''.format(self.title1.encode('utf8')) + + def sections(self): + items = [] + + path = '/library/sections' + for elem in self.server.query(path): + stype = elem.attrib['type'] + if stype in SECTION_TYPES: + cls = SECTION_TYPES[stype] + items.append(cls(elem, initpath=path, server=self.server, container=self)) + return items + + def section(self, title=None): + for item in self.sections(): + if item.title == title: + return item + raise exceptions.NotFound('Invalid library section: %s' % title) + + def all(self): + return plexobjects.listItems(self.server, '/library/all') + + def onDeck(self): + return plexobjects.listItems(self.server, '/library/onDeck') + + def recentlyAdded(self): + return plexobjects.listItems(self.server, '/library/recentlyAdded') + + def get(self, title): + return plexobjects.findItem(self.server, '/library/all', title) + + def getByKey(self, key): + return plexobjects.findKey(self.server, key) + + def search(self, title, libtype=None, **kwargs): + """ Searching within a library section is much more powerful. It seems certain attributes on the media + objects can be targeted to filter this search down a bit, but I havent found the documentation for + it. For example: "studio=Comedy%20Central" or "year=1999" "title=Kung Fu" all work. Other items + such as actor= seem to work, but require you already know the id of the actor. + TLDR: This is untested but seems to work. Use library section search when you can. + """ + args = {} + if title: + args['title'] = title + if libtype: + args['type'] = plexobjects.searchType(libtype) + for attr, value in kwargs.items(): + args[attr] = value + query = '/library/all%s' % util.joinArgs(args) + return plexobjects.listItems(self.server, query) + + def cleanBundles(self): + self.server.query('/library/clean/bundles') + + def emptyTrash(self): + for section in self.sections(): + section.emptyTrash() + + def optimize(self): + self.server.query('/library/optimize') + + def refresh(self): + self.server.query('/library/sections/all/refresh') + + def randomArts(self): + return plexobjects.listItems(self.server, '/library/arts?sort=random&type=1%2c2%2c8&X-Plex-Container-Start=0&X-Plex-Container-Size=50') + + +class LibrarySection(plexobjects.PlexObject): + ALLOWED_FILTERS = () + ALLOWED_SORT = () + BOOLEAN_FILTERS = ('unwatched', 'duplicate') + + isLibraryPQ = True + + def __repr__(self): + title = self.title.replace(' ', '.')[0:20] + return '<%s:%s>' % (self.__class__.__name__, title.encode('utf8')) + + @staticmethod + def fromFilter(filter_): + cls = SECTION_IDS.get(filter_.getLibrarySectionType()) + if not cls: + return + section = cls(None, initpath=filter_.initpath, server=filter_.server, container=filter_.container) + section.key = filter_.getLibrarySectionId() + section.title = filter_.reasonTitle + section.type = cls.TYPE + return section + + def reload(self, **kwargs): + """ Reload the data for this object from PlexServer XML. """ + initpath = '/library/sections/{0}'.format(self.key) + key = self.key + try: + data = self.server.query(initpath, params=kwargs) + except Exception as e: + import traceback + traceback.print_exc() + util.ERROR(err=e) + self.initpath = self.key + return + + self._setData(data[0]) + self.initpath = self.key = key + + def isDirectory(self): + return True + + def isLibraryItem(self): + return True + + def getAbsolutePath(self, key): + if key == 'key': + return '/library/sections/{0}/all'.format(self.key) + + return plexobjects.PlexObject.getAbsolutePath(self, key) + + def all(self, start=None, size=None, filter_=None, sort=None, unwatched=False, type_=None): + if self.key.startswith('/'): + path = '{0}/all'.format(self.key) + else: + path = '/library/sections/{0}/all'.format(self.key) + + return self.items(path, start, size, filter_, sort, unwatched, type_, False) + + def folder(self, start=None, size=None, subDir=False): + if self.key.startswith('/'): + path = self.key + else: + path = '/library/sections/{0}'.format(self.key) + + if not subDir: + path = '{0}/folder'.format(path) + + return self.items(path, start, size, None, None, False, None, True) + + def items(self, path, start, size, filter_, sort, unwatched, type_, tag_fallback): + + args = {"includeCollections" : "1"} + + if size is not None: + args['X-Plex-Container-Start'] = start + args['X-Plex-Container-Size'] = size + + if filter_: + args[filter_[0]] = filter_[1] + + if sort: + args['sort'] = '{0}:{1}'.format(*sort) + + if type_: + args['type'] = str(type_) + + if unwatched: + args[self.TYPE == 'movie' and 'unwatched' or 'unwatchedLeaves'] = 1 + + if args: + path += util.joinArgs(args, '?' not in path) + + return plexobjects.listItems(self.server, path, tag_fallback=tag_fallback) + + def jumpList(self, filter_=None, sort=None, unwatched=False, type_=None): + if self.key.startswith('/'): + path = '{0}/firstCharacter'.format(self.key) + else: + path = '/library/sections/{0}/firstCharacter'.format(self.key) + + args = {"includeCollections" : "1"} + + if filter_: + args[filter_[0]] = filter_[1] + + if sort: + args['sort'] = '{0}:{1}'.format(*sort) + + if type_: + args['type'] = str(type_) + + if unwatched: + args[self.TYPE == 'movie' and 'unwatched' or 'unwatchedLeaves'] = 1 + + if args: + path += util.joinArgs(args) + + try: + return plexobjects.listItems(self.server, path, bytag=True) + except exceptions.BadRequest: + util.ERROR('jumpList() request error for path: {0}'.format(repr(path))) + return None + + @property + def onDeck(self): + return plexobjects.listItems(self.server, '/library/sections/%s/onDeck' % self.key) + + def analyze(self): + self.server.query('/library/sections/%s/analyze' % self.key) + + def emptyTrash(self): + self.server.query('/library/sections/%s/emptyTrash' % self.key) + + def refresh(self): + self.server.query('/library/sections/%s/refresh' % self.key) + + def listChoices(self, category, libtype=None, **kwargs): + """ List choices for the specified filter category. kwargs can be any of the same + kwargs in self.search() to help narrow down the choices to only those that + matter in your current context. + """ + if category in kwargs: + raise exceptions.BadRequest('Cannot include kwarg equal to specified category: %s' % category) + args = {} + for subcategory, value in kwargs.items(): + args[category] = self._cleanSearchFilter(subcategory, value) + if libtype is not None: + args['type'] = plexobjects.searchType(libtype) + query = '/library/sections/%s/%s%s' % (self.key, category, util.joinArgs(args)) + + return plexobjects.listItems(self.server, query, bytag=True) + + def search(self, title=None, sort=None, maxresults=999999, libtype=None, **kwargs): + """ Search the library. If there are many results, they will be fetched from the server + in batches of X_PLEX_CONTAINER_SIZE amounts. If you're only looking for the first + results, it would be wise to set the maxresults option to that amount so this functions + doesn't iterate over all results on the server. + title: General string query to search for. + sort: column:dir; column can be any of {addedAt, originallyAvailableAt, lastViewedAt, + titleSort, rating, mediaHeight, duration}. dir can be asc or desc. + maxresults: Only return the specified number of results + libtype: Filter results to a spcifiec libtype {movie, show, episode, artist, album, track} + kwargs: Any of the available filters for the current library section. Partial string + matches allowed. Multiple matches OR together. All inputs will be compared with the + available options and a warning logged if the option does not appear valid. + 'unwatched': Display or hide unwatched content (True, False). [all] + 'duplicate': Display or hide duplicate items (True, False). [movie] + 'actor': List of actors to search ([actor_or_id, ...]). [movie] + 'collection': List of collections to search within ([collection_or_id, ...]). [all] + 'contentRating': List of content ratings to search within ([rating_or_key, ...]). [movie, tv] + 'country': List of countries to search within ([country_or_key, ...]). [movie, music] + 'decade': List of decades to search within ([yyy0, ...]). [movie] + 'director': List of directors to search ([director_or_id, ...]). [movie] + 'genre': List Genres to search within ([genere_or_id, ...]). [all] + 'network': List of TV networks to search within ([resolution_or_key, ...]). [tv] + 'resolution': List of video resolutions to search within ([resolution_or_key, ...]). [movie] + 'studio': List of studios to search within ([studio_or_key, ...]). [music] + 'year': List of years to search within ([yyyy, ...]). [all] + """ + # Cleanup the core arguments + args = {} + for category, value in kwargs.items(): + args[category] = self._cleanSearchFilter(category, value, libtype) + if title is not None: + args['title'] = title + if sort is not None: + args['sort'] = self._cleanSearchSort(sort) + if libtype is not None: + args['type'] = plexobjects.searchType(libtype) + # Iterate over the results + results, subresults = [], '_init' + args['X-Plex-Container-Start'] = 0 + args['X-Plex-Container-Size'] = min(util.X_PLEX_CONTAINER_SIZE, maxresults) + while subresults and maxresults > len(results): + query = '/library/sections/%s/all%s' % (self.key, util.joinArgs(args)) + subresults = plexobjects.listItems(self.server, query) + results += subresults[:maxresults - len(results)] + args['X-Plex-Container-Start'] += args['X-Plex-Container-Size'] + return results + + def _cleanSearchFilter(self, category, value, libtype=None): + # check a few things before we begin + if category not in self.ALLOWED_FILTERS: + raise exceptions.BadRequest('Unknown filter category: %s' % category) + if category in self.BOOLEAN_FILTERS: + return '1' if value else '0' + if not isinstance(value, (list, tuple)): + value = [value] + # convert list of values to list of keys or ids + result = set() + choices = self.listChoices(category, libtype) + lookup = {} + for c in choices: + lookup[c.title.lower()] = c.key + + allowed = set(c.key for c in choices) + for item in value: + item = str(item.id if isinstance(item, media.MediaTag) else item).lower() + # find most logical choice(s) to use in url + if item in allowed: + result.add(item) + continue + if item in lookup: + result.add(lookup[item]) + continue + matches = [k for t, k in lookup.items() if item in t] + if matches: + list(map(result.add, matches)) + continue + # nothing matched; use raw item value + util.LOG('Filter value not listed, using raw item value: {0}'.format(item)) + result.add(item) + return ','.join(result) + + def _cleanSearchSort(self, sort): + sort = '%s:asc' % sort if ':' not in sort else sort + scol, sdir = sort.lower().split(':') + lookup = {} + for s in self.ALLOWED_SORT: + lookup[s.lower()] = s + if scol not in lookup: + raise exceptions.BadRequest('Unknown sort column: %s' % scol) + if sdir not in ('asc', 'desc'): + raise exceptions.BadRequest('Unknown sort dir: %s' % sdir) + return '%s:%s' % (lookup[scol], sdir) + + +class MovieSection(LibrarySection): + ALLOWED_FILTERS = ( + 'unwatched', 'duplicate', 'year', 'decade', 'genre', 'contentRating', 'collection', + 'director', 'actor', 'country', 'studio', 'resolution' + ) + ALLOWED_SORT = ( + 'addedAt', 'originallyAvailableAt', 'lastViewedAt', 'titleSort', 'rating', 'audienceRating', 'userRating', + 'contentRating', 'mediaHeight', 'duration' + ) + TYPE = 'movie' + ID = '1' + + +class ShowSection(LibrarySection): + ALLOWED_FILTERS = ('unwatched', 'year', 'genre', 'contentRating', 'network', 'collection') + ALLOWED_SORT = ('addedAt', 'lastViewedAt', 'originallyAvailableAt', 'titleSort', 'rating', 'audienceRating', + 'userRating', 'contentRating', 'unwatched') + TYPE = 'show' + ID = '2' + + def searchShows(self, **kwargs): + return self.search(libtype='show', **kwargs) + + def searchEpisodes(self, **kwargs): + return self.search(libtype='episode', **kwargs) + + +class MusicSection(LibrarySection): + ALLOWED_FILTERS = ('genre', 'country', 'collection') + ALLOWED_SORT = ('addedAt', 'lastViewedAt', 'viewCount', 'titleSort') + TYPE = 'artist' + ID = '8' + + def searchShows(self, **kwargs): + return self.search(libtype='artist', **kwargs) + + def searchEpisodes(self, **kwargs): + return self.search(libtype='album', **kwargs) + + def searchTracks(self, **kwargs): + return self.search(libtype='track', **kwargs) + + +class PhotoSection(LibrarySection): + ALLOWED_FILTERS = () + ALLOWED_SORT = ('addedAt', 'lastViewedAt', 'viewCount', 'titleSort') + TYPE = 'photo' + ID = 'None' + + def isPhotoOrDirectoryItem(self): + return True + + +@plexobjects.registerLibType +class Collection(media.MediaItem): + TYPE = 'collection' + + def __repr__(self): + title = self.title.replace(' ', '.')[0:20] + return '<{0}:{1}:{2}>'.format(self.__class__.__name__, self.key, title) + + def all(self, *args, **kwargs): + items = plexobjects.listItems(self.server, self.key) + items.totalSize = items.size + return items + + def isMusicOrDirectoryItem(self): + return self.container.viewGroup in ('artist', 'album', 'track') + + def isVideoOrDirectoryItem(self): + return self.container.viewGroup in ('movie', 'show', 'episode') + + def isCollection(self): + return True + + +@plexobjects.registerLibType +class Generic(plexobjects.PlexObject): + TYPE = 'Directory' + + def __repr__(self): + title = self.title.replace(' ', '.')[0:20] + return '<{0}:{1}:{2}>'.format(self.__class__.__name__, self.key, title) + +#@plexobjects.registerLibType +#class Collection(Generic): +# TYPE = 'collection' + +@plexobjects.registerLibType +class Playlist(playlist.BasePlaylist, signalsmixin.SignalsMixin): + TYPE = 'playlist' + + def __init__(self, *args, **kwargs): + playlist.BasePlaylist.__init__(self, *args, **kwargs) + signalsmixin.SignalsMixin.__init__(self) + self._itemsLoaded = False + + def __repr__(self): + title = self.title.replace(' ', '.')[0:20] + return '<{0}:{1}:{2}>'.format(self.__class__.__name__, self.key, title) + + def exists(self): + try: + self.server.query('/playlists/{0}'.format(self.ratingKey)) + return True + except exceptions.BadRequest: + return False + + def isMusicOrDirectoryItem(self): + return self.playlistType == 'audio' + + def isVideoOrDirectoryItem(self): + return self.playlistType == 'video' + + def items(self): + if not self._itemsLoaded: + path = '/playlists/{0}/items'.format(self.ratingKey) + self._items = plexobjects.listItems(self.server, path) + self._itemsLoaded = True + + return playlist.BasePlaylist.items(self) + + def extend(self, start=0, size=0): + if not self._items: + self._items = [None] * self.leafCount.asInt() + + args = {} + + if size is not None: + args['X-Plex-Container-Start'] = start + args['X-Plex-Container-Size'] = size + + path = '/playlists/{0}/items'.format(self.ratingKey) + if args: + path += util.joinArgs(args) if '?' not in path else '&' + util.joinArgs(args).lstrip('?') + + items = plexobjects.listItems(self.server, path) + self._items[start:start + len(items)] = items + + self.trigger('items.added') + + return items + + def unshuffledItems(self): + if not self._itemsLoaded: + list(self.items()) + return self._items + + @property + def defaultThumb(self): + return self.composite + + def buildComposite(self, **kwargs): + if kwargs: + params = '?' + '&'.join('{0}={1}'.format(k, v) for k, v in kwargs.items()) + else: + params = '' + + path = self.composite + params + return self.getServer().buildUrl(path, True) + + +class BaseHub(plexobjects.PlexObject): + def reset(self): + self.set('offset', 0) + self.set('size', len(self.items)) + totalSize = self.items[0].container.totalSize.asInt() + if totalSize: # Hubs from a list of hubs don't have this, so it it's not here this is intital and we can leave as is + self.set( + 'more', + (self.items[0].container.offset.asInt() + self.items[0].container.size.asInt() < totalSize) and '1' or '' + ) + + +class Hub(BaseHub): + TYPE = "Hub" + + def init(self, data): + self.items = [] + + container = plexobjects.PlexContainer(data, self.key, self.server, self.key or '') + + if self.type == 'genre': + self.items = [media.Genre(elem, initpath='/hubs', server=self.server, container=container) for elem in data] + elif self.type == 'director': + self.items = [media.Director(elem, initpath='/hubs', server=self.server, container=container) for elem in data] + elif self.type == 'actor': + self.items = [media.Role(elem, initpath='/hubs', server=self.server, container=container) for elem in data] + else: + for elem in data: + try: + self.items.append(plexobjects.buildItem(self.server, elem, '/hubs', container=container, tag_fallback=True)) + except exceptions.UnknownType: + util.DEBUG_LOG('Unkown hub item type({1}): {0}'.format(elem, elem.attrib.get('type'))) + + def __repr__(self): + return '<{0}:{1}>'.format(self.__class__.__name__, self.hubIdentifier) + + def getCleanHubIdentifier(self): + return re.sub(r'\.\d+$', '', re.sub(r'\.\d+$', '', self.hubIdentifier)) + + def reload(self, **kwargs): + """ Reload the data for this object from PlexServer XML. """ + try: + data = self.server.query(self.key, params=kwargs) + except Exception as e: + import traceback + traceback.print_exc() + util.ERROR(err=e) + self.initpath = self.key + return + + self.initpath = self.key + self._setData(data) + self.init(data) + + def extend(self, start=None, size=None): + path = self.key + + args = {} + + if size is not None: + args['X-Plex-Container-Start'] = start + args['X-Plex-Container-Size'] = size + + if args: + path += util.joinArgs(args) if '?' not in path else '&' + util.joinArgs(args).lstrip('?') + + items = plexobjects.listItems(self.server, path) + self.offset = plexobjects.PlexValue(start) + self.size = plexobjects.PlexValue(len(items)) + self.more = plexobjects.PlexValue('') + if items: + self.more = plexobjects.PlexValue( + (items[0].container.offset.asInt() + items[0].container.size.asInt() < items[0].container.totalSize.asInt()) and '1' or '' + ) + return items + + +class PlaylistHub(BaseHub): + TYPE = "Hub" + type = None + hubIdentifier = None + + def init(self, data): + try: + self.items = self.extend(0, 10) + except exceptions.BadRequest: + util.DEBUG_LOG('AudioPlaylistHub: Bad request: {0}'.format(self)) + self.items = [] + + def getCleanHubIdentifier(self): + return re.sub(r'\.\d+$', '', re.sub(r'\.\d+$', '', self.hubIdentifier)) + + def extend(self, start=None, size=None): + path = '/playlists/all?playlistType={0}'.format(self.type) + + args = {"includeMarkers": 1} + + if size is not None: + args['X-Plex-Container-Start'] = start + args['X-Plex-Container-Size'] = size + else: + start = 0 + + if args: + path += '&' + util.joinArgs(args).lstrip('?') + + items = plexobjects.listItems(self.server, path) + + if not items: + return + + self.set('offset', start) + self.set('size', len(items)) + self.set('more', (items[0].container.offset.asInt() + items[0].container.size.asInt() < items[0].container.totalSize.asInt()) and '1' or '') + return items + + +class AudioPlaylistHub(PlaylistHub): + type = 'audio' + hubIdentifier = 'playlists.audio' + + +class VideoPlaylistHub(PlaylistHub): + type = 'video' + hubIdentifier = 'playlists.video' + + +SECTION_TYPES = { + MovieSection.TYPE: MovieSection, + ShowSection.TYPE: ShowSection, + MusicSection.TYPE: MusicSection, + PhotoSection.TYPE: PhotoSection +} + +SECTION_IDS = { + MovieSection.ID: MovieSection, + ShowSection.ID: ShowSection, + MusicSection.ID: MusicSection, + PhotoSection.ID: PhotoSection +} diff --git a/script.plexmod/lib/_included_packages/plexnet/plexmedia.py b/script.plexmod/lib/_included_packages/plexnet/plexmedia.py new file mode 100644 index 0000000000..bbbc51825b --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexmedia.py @@ -0,0 +1,154 @@ +from __future__ import absolute_import +from . import locks +from . import http +from . import plexobjects +from . import plexpart +from . import plexrequest +from . import util +from six.moves import filter +import six + + +class PlexMedia(plexobjects.PlexObject): + def __init__(self, data, initpath=None, server=None, container=None): + self._data = data.attrib + plexobjects.PlexObject.__init__(self, data, initpath, server) + self.container_ = self.get('container') + self.container = container + self.indirectHeaders = None + self.parts = [] + # If we weren't given any data, this is a synthetic media + if data is not None: + self.parts = [plexpart.PlexPart(elem, initpath=self.initpath, server=self.server, media=self) for elem in data] + + def get(self, key, default=None): + return self._data.get(key, default) + + def hasStreams(self): + return len(self.parts) > 0 and self.parts[0].hasStreams() + + def isIndirect(self): + return self.get('indirect') == '1' + + def isAccessible(self): + return any(p.isAccessible() for p in self.parts) + + def isAvailable(self): + return any(p.isAvailable() for p in self.parts) + + def resolveIndirect(self): + if not self.isIndirect() or locks.LOCKS.isLocked("resolve_indirect"): + return self + + part = self.parts[0] + if part is None: + util.DEBUG("Failed to resolve indirect media: missing valid part") + return None + + postBody = None + postUrl = part.postURL + request = plexrequest.PlexRequest(self.getServer(), part.key, postUrl is not None and "POST" or "GET") + + if postUrl is not None: + util.DEBUG("Fetching content for indirect media POST URL: {0}".format(postUrl)) + # Force setting the certificate to handle following https redirects + postRequest = http.HttpRequest(postUrl, None, True) + postResponse = postRequest.getToStringWithTimeout(30) + if len(postResponse) > 0 and type(postRequest.event) == "roUrlEvent": + util.DEBUG("Retrieved data from postURL, posting to resolve container") + crlf = chr(13) + chr(10) + postBody = "" + for header in postRequest.event.getResponseHeadersArray(): + for name in header: + postBody = postBody + name + ": " + header[name] + crlf + postBody = postBody + crlf + postResponse + else: + util.DEBUG("Failed to resolve indirect media postUrl") + self.Set("indirect", "-1") + return self + + request.addParam("postURL", postUrl) + + response = request.doRequestWithTimeout(30, postBody) + + item = response.items[0] + if item is None or item.mediaItems[0] is None: + util.DEBUG("Failed to resolve indirect media: no media items") + self.indirect = -1 + return self + + media = item.mediaItems[0] + + # Add indirect headers to the media item + media.indirectHeaders = util.AttributeDict() + for header in (item.container.httpHeaders or '').split("&"): + arr = header.split("=") + if len(arr) == 2: + media.indirectHeaders[arr[0]] = arr[1] + + # Reset the fallback media id if applicable + if self.id.asInt() < 0: + media.id = self.id + + return media.resolveIndirect() + + def __str__(self): + extra = [] + attrs = ("videoCodec", "audioCodec", "audioChannels", "protocol", "id") + if self.get('container'): + extra.append("container={0}".format(self.get('container'))) + + for astr in attrs: + if hasattr(self, astr): + attr = getattr(self, astr) + if attr and not attr.NA: + extra.append("{0}={1}".format(astr, attr)) + + return self.versionString(log_safe=True) + " " + ' '.join(extra) + + def versionString(self, log_safe=False): + details = [] + details.append(self.getVideoResolutionString()) + if self.bitrate.asInt() > 0: + details.append(util.bitrateToString(self.bitrate.asInt() * 1000)) + + detailString = ', '.join(details) + return (log_safe and ' * ' or u" \u2022 ").join([_f for _f in [self.title, detailString] if _f]) + + def __eq__(self, other): + if not other: + return False + + if self.__class__ != other.__class__: + return False + + return self.id == other.id + + def __ne__(self, other): + return not self.__eq__(other) + + def __repr__(self): + return self.__str__() + + def getVideoResolution(self): + if self.videoResolution: + standardDefinitionHeight = 480 + if str(util.validInt(list(filter(six.text_type.isdigit, self.videoResolution)))) != self.videoResolution: + return self.height.asInt() > standardDefinitionHeight and self.height.asInt() or standardDefinitionHeight + else: + return self.videoResolution.asInt(standardDefinitionHeight) + + return self.height.asInt() + + def getVideoResolutionString(self): + resNumber = util.validInt(list(filter(six.text_type.isdigit, self.videoResolution))) + if resNumber > 0 and str(resNumber) == self.videoResolution: + return self.videoResolution + "p" + + return self.videoResolution.upper() + + def isSelected(self): + from . import plexapp + return self.selected.asBool() or self.id == util.INTERFACE.getPreference("local_mediaId") + + # TODO(schuyler): getParts diff --git a/script.plexmod/lib/_included_packages/plexnet/plexobjects.py b/script.plexmod/lib/_included_packages/plexnet/plexobjects.py new file mode 100644 index 0000000000..6d5c01f2d4 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexobjects.py @@ -0,0 +1,572 @@ +from __future__ import absolute_import +from datetime import datetime + +from . import exceptions +from . import util +import json +import six +import time + +# Search Types - Plex uses these to filter specific media types when searching. +SEARCHTYPES = { + 'movie': 1, + 'show': 2, + 'season': 3, + 'episode': 4, + 'artist': 8, + 'album': 9, + 'track': 10 +} + +LIBRARY_TYPES = {} + + +def registerLibType(cls): + LIBRARY_TYPES[cls.TYPE] = cls + return cls + + +def registerLibFactory(ftype): + def wrap(func): + LIBRARY_TYPES[ftype] = func + return func + return wrap + + +class PlexValue(six.text_type): + def __new__(cls, value, parent=None): + self = super(PlexValue, cls).__new__(cls, value) + self.parent = parent + self.NA = False + return self + + def __call__(self, default): + return not self.NA and self or PlexValue(default, self.parent) + + def asBool(self): + return self == '1' + + def asInt(self, default=0): + return int(self or default) + + def asFloat(self, default=0): + return float(self or default) + + def asDatetime(self, format_=None): + if not self: + return None + + if self.isdigit(): + dt = datetime.fromtimestamp(int(self)) + else: + # dt = datetime.strptime(self, '%Y-%m-%d') + # Avoid datetime.strptime to avoid + # https://github.com/python/cpython/issues/71587 + try: + dt = datetime.fromtimestamp(time.mktime(time.strptime(self, '%Y-%m-%d'))) + except OverflowError: + # special case for dates before 1970-01-02 (yes, there are shows that old), mktime fails on those + year, month, day = (int(p) for p in str(self).split("-")) + dt = datetime(year=year, month=month, day=day) + + if not format_: + return dt + + return dt.strftime(format_) + + def asURL(self, includeToken=False): + return self.parent.server.buildUrl(self, includeToken) + + def asTranscodedImageURL(self, w, h, **extras): + return self.parent.server.getImageTranscodeURL(self, w, h, **extras) + + +class JEncoder(json.JSONEncoder): + def default(self, o): + try: + return json.JSONEncoder.default(self, o) + except: + return None + + +def asFullObject(func): + def wrap(self, *args, **kwargs): + if not self.isFullObject(): + self.reload() + return func(self, *args, **kwargs) + + return wrap + + +class Checks(object): + def isLibraryItem(self): + return "/library/metadata" in self.get('key', '') or ("/playlists/" in self.get('key', '') and self.get("type", "") == "playlist") + + def isVideoItem(self): + return False + + def isMusicItem(self): + return False + + def isOnlineItem(self): + return self.isChannelItem() or self.isMyPlexItem() or self.isVevoItem() or self.isIvaItem() + + def isMyPlexItem(self): + return self.container.server.TYPE == 'MYPLEXSERVER' or self.container.identifier == 'com.plexapp.plugins.myplex' + + def isChannelItem(self): + identifier = self.getIdentifier() or "com.plexapp.plugins.library" + return not self.isLibraryItem() and not self.isMyPlexItem() and identifier != "com.plexapp.plugins.library" + + def isVevoItem(self): + return 'vevo://' in self.get('guid') + + def isIvaItem(self): + return 'iva://' in self.get('guid') + + def isGracenoteCollection(self): + return False + + def isIPhoto(self): + return (self.title == "iPhoto" or self.container.title == "iPhoto" or (self.mediaType == "Image" or self.mediaType == "Movie")) + + def isDirectory(self): + return self.name == "Directory" or self.name == "Playlist" + + def isPhotoOrDirectoryItem(self): + return self.type == "photoalbum" # or self.isPhotoItem() + + def isMusicOrDirectoryItem(self): + return self.type in ('artist', 'album', 'track') + + def isVideoOrDirectoryItem(self): + return self.type in ('movie', 'show', 'episode') + + def isSettings(self): + return False + + +class PlexObject(Checks): + def __init__(self, data, initpath=None, server=None, container=None): + self.initpath = initpath + self.key = None + self.server = server + self.container = container + self.mediaChoice = None + self.titleSort = PlexValue('') + self.deleted = False + self._reloaded = False + self.data = data + + if data is None: + return + + self._setData(data) + + self.init(data) + + def _setData(self, data): + if data is False: + return + + self.name = data.tag + for k, v in data.attrib.items(): + if k in ("container",): + k = "attrib_%s" % k + + setattr(self, k, PlexValue(v, self)) + + def __getattr__(self, attr): + a = PlexValue('', self) + a.NA = True + + try: + setattr(self, attr, a) + except AttributeError: + util.LOG('Failed to set attribute: {0} ({1})'.format(attr, self.__class__)) + + return a + + def exists(self): + # Used for media items - for others we just return True + return True + + def get(self, attr, default=''): + ret = self.__dict__.get(attr) + return ret is not None and ret or PlexValue(default, self) + + def set(self, attr, value): + setattr(self, attr, PlexValue(six.text_type(value), self)) + + def init(self, data): + pass + + def isFullObject(self): + return self.initpath is None or self.key is None or self.initpath == self.key + + def getAddress(self): + return self.server.activeConnection.address + + @property + def defaultTitle(self): + return self.get('title') + + @property + def defaultThumb(self): + return self.__dict__.get('thumb') and self.thumb or PlexValue('', self) + + @property + def defaultArt(self): + return self.__dict__.get('art') and self.art or PlexValue('', self) + + def refresh(self): + import requests + self.server.query('%s/refresh' % self.key, method=requests.put) + + def reload(self, _soft=False, **kwargs): + """ Reload the data for this object from PlexServer XML. """ + if _soft and self._reloaded: + return self + + kwargs["includeMarkers"] = 1 + + try: + if self.get('ratingKey'): + data = self.server.query('/library/metadata/{0}'.format(self.ratingKey), params=kwargs) + else: + data = self.server.query(self.key, params=kwargs) + self._reloaded = True + except Exception as e: + import traceback + traceback.print_exc() + util.ERROR(err=e) + self.initpath = self.key + return self + + self.initpath = self.key + + try: + self._setData(data[0]) + except (IndexError, TypeError, AttributeError): + util.DEBUG_LOG('No data on reload: {0}'.format(self)) + return self + + return self + + def softReload(self, **kwargs): + return self.reload(_soft=True, **kwargs) + + def getLibrarySectionId(self): + ID = self.get('librarySectionID') + + if not ID: + ID = self.container.get("librarySectionID", '') + + return ID + + def getLibrarySectionTitle(self): + title = self.get('librarySectionTitle') + + if not title: + title = self.container.get("librarySectionTitle", '') + + if not title: + lsid = self.getLibrarySectionId() + if lsid: + data = self.server.query('/library/sections/{0}'.format(lsid)) + title = data.attrib.get('title1') + if title: + self.librarySectionTitle = title + return str(title) + + def getLibrarySectionType(self): + type_ = self.get('librarySectionType') + + if not type_: + type_ = self.container.get("librarySectionType", '') + + if not type_: + lsid = self.getLibrarySectionId() + if lsid: + data = self.server.query('/library/sections/{0}'.format(lsid)) + type_ = data.attrib.get('type') + if type_: + self.librarySectionTitle = type_ + return type_ + + def getLibrarySectionUuid(self): + uuid = self.get("uuid") or self.get("librarySectionUUID") + + if not uuid: + uuid = self.container.get("librarySectionUUID", "") + + return uuid + + def _findLocation(self, data): + elem = data.find('Location') + if elem is not None: + return elem.attrib.get('path') + return None + + def _findPlayer(self, data): + elem = data.find('Player') + if elem is not None: + return PlexObject(elem, server=self.server) + return None + + def _findTranscodeSession(self, data): + elem = data.find('TranscodeSession') + if elem is not None: + from . import media + return media.TranscodeSession(elem, server=self.server) + return None + + def _findBandwidths(self, data): + elem = data.find("Bandwidths") + if elem is not None: + from . import media + return PlexItemList(elem, media.Bandwidth, media.Bandwidth.TYPE, server=self.server) + return [] + + def _findUser(self, data): + elem = data.find('User') + if elem is not None: + return PlexObject(elem, self.initpath) + return None + + def _findSession(self, data): + elem = data.find('Session') + if elem is not None: + return PlexObject(elem, self.initpath, server=self.server) + return None + + def getAbsolutePath(self, attr): + path = getattr(self, attr, None) + if path is None: + return None + else: + return self.container._getAbsolutePath(path) + + def _getAbsolutePath(self, path): + if path.startswith('/'): + return path + elif "://" in path: + return path + else: + return self.getAddress() + "/" + path + + def getParentPath(self, key): + # Some containers have /children on its key while others (such as playlists) use /items + path = self.getAbsolutePath(key) + if path is None: + return "" + + for suffix in ("/children", "/items"): + path = path.replace(suffix, "") + + return path + + def getServer(self): + return self.server + + def getTranscodeServer(self, localServerRequired=False, transcodeType=None): + server = self.server + + # If the server is myPlex, try to use a different PMS for transcoding + from . import myplexserver + from . import plexapp + if server == myplexserver.MyPlexServer: + fallbackServer = plexapp.SERVERMANAGER.getChannelServer() + + if fallbackServer: + server = fallbackServer + elif localServerRequired: + return None + + return server + + @classmethod + def deSerialize(cls, jstring): + from . import plexserver + obj = json.loads(jstring) + server = plexserver.PlexServer.deSerialize(obj['server']) + server.identifier = None + ad = util.AttributeDict() + ad.attrib = obj['obj'] + ad.find = lambda x: None + po = buildItem(server, ad, ad.initpath, container=server) + + return po + + def serialize(self, full=False): + import json + odict = {} + if full: + for k, v in self.__dict__.items(): + if k not in ('server', 'container', 'media', 'initpath', '_data') and v: + odict[k] = v + else: + odict['key'] = self.key + odict['type'] = self.type + + odict['initpath'] = '/none' + obj = {'obj': odict, 'server': self.server.serialize(full=full)} + + return json.dumps(obj, cls=JEncoder) + + +class PlexContainer(PlexObject): + def __init__(self, data, initpath=None, server=None, address=None): + PlexObject.__init__(self, data, initpath, server) + self.setAddress(address) + + def setAddress(self, address): + if address != "/" and address.endswith("/"): + self.address = address[:-1] + else: + self.address = address + + # TODO(schuyler): Do we need to make sure that we only hang onto the path here and not a full URL? + if not self.address.startswith("/") and "node.plexapp.com" not in self.address: + util.FATAL("Container address is not an expected path: {0}".format(address)) + + def getAbsolutePath(self, path): + if path.startswith('/'): + return path + elif "://" in path: + return path + else: + return self.address + "/" + path + + +class PlexServerContainer(PlexContainer): + def __init__(self, data, initpath=None, server=None, address=None): + PlexContainer.__init__(self, data, initpath, server, address) + from . import plexserver + self.resources = [plexserver.PlexServer(elem) for elem in data] + + def __getitem__(self, idx): + return self.resources[idx] + + def __iter__(self): + for i in self.resources: + yield i + + def __len__(self): + return len(self.resources) + + +class PlexItemList(object): + def __init__(self, data, item_cls, tag, server=None, container=None): + self._data = data + self._itemClass = item_cls + self._itemTag = tag + self._server = server + self._container = container + self._items = None + + def __iter__(self): + for i in self.items: + yield i + + def __getitem__(self, idx): + return self.items[idx] + + @property + def items(self): + if self._items is None: + if self._data is not None: + if self._server: + self._items = [self._itemClass(elem, server=self._server, container=self._container) for elem in self._data if elem.tag == self._itemTag] + else: + self._items = [self._itemClass(elem) for elem in self._data if elem.tag == self._itemTag] + else: + self._items = [] + + return self._items + + def __call__(self, *args): + return self.items + + def __len__(self): + return len(self.items) + + def append(self, item): + self.items.append(item) + + +class PlexMediaItemList(PlexItemList): + def __init__(self, data, item_cls, tag, initpath=None, server=None, media=None): + PlexItemList.__init__(self, data, item_cls, tag, server) + self._initpath = initpath + self._media = media + self._items = None + + @property + def items(self): + if self._items is None: + if self._data is not None: + self._items = [self._itemClass(elem, self._initpath, self._server, self._media) for elem in self._data if elem.tag == self._itemTag] + else: + self._items = [] + + return self._items + + +def findItem(server, path, title): + for elem in server.query(path): + if elem.attrib.get('title').lower() == title.lower(): + return buildItem(server, elem, path) + raise exceptions.NotFound('Unable to find item: {0}'.format(title)) + + +def buildItem(server, elem, initpath, bytag=False, container=None, tag_fallback=False): + libtype = elem.tag if bytag else elem.attrib.get('type') + if not libtype and tag_fallback: + libtype = elem.tag + + if libtype in LIBRARY_TYPES: + cls = LIBRARY_TYPES[libtype] + return cls(elem, initpath=initpath, server=server, container=container) + raise exceptions.UnknownType('Unknown library type: {0}'.format(libtype)) + + +class ItemContainer(list): + def __getattr__(self, attr): + return getattr(self.container, attr) + + def init(self, container): + self.container = container + return self + + +def listItems(server, path, libtype=None, watched=None, bytag=False, data=None, container=None, offset=None, + limit=None, tag_fallback=False, **kwargs): + data = data if data is not None else server.query(path, offset=offset, limit=limit, **kwargs) + container = container or PlexContainer(data, path, server, path) + items = ItemContainer().init(container) + + if data: + for elem in data: + if libtype and elem.attrib.get('type') != libtype: + continue + if watched is True and elem.attrib.get('viewCount', 0) == 0: + continue + if watched is False and elem.attrib.get('viewCount', 0) >= 1: + continue + try: + items.append(buildItem(server, elem, path, bytag, container, tag_fallback)) + except exceptions.UnknownType: + pass + + return items + + +def searchType(libtype): + searchtypesstrs = [str(k) for k in SEARCHTYPES.keys()] + if libtype in SEARCHTYPES + searchtypesstrs: + return libtype + stype = SEARCHTYPES.get(libtype.lower()) + if not stype: + raise exceptions.NotFound('Unknown libtype: %s' % libtype) + return stype diff --git a/script.plexmod/lib/_included_packages/plexnet/plexpart.py b/script.plexmod/lib/_included_packages/plexnet/plexpart.py new file mode 100644 index 0000000000..7fd0c138cd --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexpart.py @@ -0,0 +1,178 @@ +from __future__ import absolute_import +from . import plexobjects +from . import plexstream +from . import plexrequest +from . import util + + +class PlexPart(plexobjects.PlexObject): + def reload(self): + self.initpath = self.key + + def __init__(self, data, initpath=None, server=None, media=None): + plexobjects.PlexObject.__init__(self, data, initpath, server) + self.container_ = self.container + self.container = media + self.streams = [] + + # If we weren't given any data, this is a synthetic part + if data is not None: + self.streams = [plexstream.PlexStream(e, initpath=self.initpath, server=self.server) for e in data if e.tag == 'Stream'] + if self.indexes: + indexKeys = self.indexes('').split(",") + self.indexes = util.AttributeDict() + for indexKey in indexKeys: + self.indexes[indexKey] = True + + def getAddress(self): + address = self.key + + if address != "": + # TODO(schuyler): Do we need to add a token? Or will it be taken care of via header else:where? + address = self.container.getAbsolutePath(address) + + return address + + def isAccessible(self): + # If we haven't fetched accessibility info, assume it's accessible. + return self.accessible.asBool() if self.accessible else True + + def isAvailable(self): + # If we haven't fetched availability info, assume it's available + return not self.exists or self.exists.asBool() + + def getStreamsOfType(self, streamType): + streams = [] + + foundSelected = False + + for stream in self.streams: + if stream.streamType.asInt() == streamType: + streams.append(stream) + + if stream.isSelected(): + foundSelected = True + + # If this is subtitles, add the none option + if streamType == plexstream.PlexStream.TYPE_SUBTITLE: + none = plexstream.NoneStream() + streams.insert(0, none) + none.setSelected(not foundSelected) + + return streams + + # def getSelectedStreamStringOfType(self, streamType): + # default = None + # availableStreams = 0 + # for stream in self.streams: + # if stream.streamType.asInt() == streamType: + # availableStreams = availableStreams + 1 + # if stream.isSelected() or (default is None and streamType != stream.TYPE_SUBTITLE): + # default = stream + + # if default is not None: + # availableStreams = availableStreams - 1 + # title = default.getTitle() + # suffix = "More" + # else: + # title = "None" + # suffix = "Available" + + # if availableStreams > 0 and streamType != stream.TYPE_VIDEO: + # # Indicate available streams to choose from, excluding video + # # streams until the server supports multiple videos streams. + + # return u"{0} : {1} {2}".format(title, availableStreams, suffix) + # else: + # return title + + def getSelectedStreamOfType(self, streamType): + # Video streams, in particular, may not be selected. Pretend like the + # first one was selected. + + default = None + + for stream in self.streams: + if stream.streamType.asInt() == streamType: + if stream.isSelected(): + return stream + elif default is None and streamType != stream.TYPE_SUBTITLE: + default = stream + + return default + + def setSelectedStream(self, streamType, streamId, _async): + if streamType == plexstream.PlexStream.TYPE_AUDIO: + typeString = "audio" + elif streamType == plexstream.PlexStream.TYPE_SUBTITLE: + typeString = "subtitle" + elif streamType == plexstream.PlexStream.TYPE_VIDEO: + typeString = "video" + else: + return None + + path = "/library/parts/{0}?{1}StreamID={2}".format(self.id(''), typeString, streamId) + + if self.getServer().supportsFeature("allPartsStreamSelection"): + path = path + "&allParts=1" + + request = plexrequest.PlexRequest(self.getServer(), path, "PUT") + + if _async: + context = request.createRequestContext("ignored") + from . import plexapp + util.APP.startRequest(request, context, "") + else: + request.postToStringWithTimeout() + + matching = plexstream.NoneStream() + + # Update any affected streams + for stream in self.streams: + if stream.streamType.asInt() == streamType: + if stream.id == streamId: + stream.setSelected(True) + matching = stream + elif stream.isSelected(): + stream.setSelected(False) + + return matching + + def isIndexed(self): + return bool(self.indexes) + + def getIndexUrl(self, indexKey): + path = self.getIndexPath(indexKey) + if path is not None: + return self.container.server.buildUrl(path + "?interval=10000", True) + else: + return None + + def getIndexPath(self, indexKey, interval=None): + if self.indexes is not None and indexKey in self.indexes: + return "/library/parts/{0}/indexes/{1}".format(self.id, indexKey) + else: + return None + + def hasStreams(self): + return bool(self.streams) + + def __str__(self): + return "PlexPart {0} {1}".format(self.id("NaN"), self.key) + + def __eq__(self, other): + if other is None: + return False + + if self.__class__ != other.__class__: + return False + + return self.id == other.id + + def __ne__(self, other): + return not self.__eq__(other) + + def __repr__(self): + return self.__str__() + + # TODO(schuyler): getStreams, getIndexThumbUrl diff --git a/script.plexmod/lib/_included_packages/plexnet/plexplayer.py b/script.plexmod/lib/_included_packages/plexnet/plexplayer.py new file mode 100644 index 0000000000..e90a010251 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexplayer.py @@ -0,0 +1,934 @@ +from __future__ import absolute_import +import re +from . import util +from . import captions +from . import http +from . import plexrequest +from . import mediadecisionengine +from . import serverdecision +from lib.util import CACHE_SIZE, advancedSettings, KODI_VERSION_MAJOR + +from six.moves import range + +DecisionFailure = serverdecision.DecisionFailure + + +class PlexPlayer(object): + DECISION_ENDPOINT = "/video/:/transcode/universal/decision" + + def __init__(self, item, seekValue=0, forceUpdate=False): + self.decision = None + self.seekValue = seekValue + self.metadata = None + self.init(item, forceUpdate) + + def init(self, item, forceUpdate=False): + self.item = item + self.choice = mediadecisionengine.MediaDecisionEngine().chooseMedia(item, forceUpdate=forceUpdate) + if self.choice: + self.media = self.choice.media + + def terminate(self, code, reason): + util.LOG('TERMINATE PLAYER: ({0}, {1})'.format(code, reason)) + # TODO: Handle this? ---------------------------------------------------------------------------------------------------------- TODO + + @property + def audioChannels(self): + """ + Parse Kodi channel setting into channel count + """ + channelDef = self.item.settings.getGlobal("audioChannels", "2.0") + major, minor = channelDef.split(".") if "." in channelDef else (channelDef, 0) + return int(major) + int(minor) + + def rebuild(self, item, decision=None): + # item.settings = self.item.settings + oldChoice = self.choice + self.init(item, True) + util.LOG("Replacing '{0}' with '{1}' and rebuilding.".format(oldChoice, self.choice)) + self.build() + self.decision = decision + + def build(self, forceTranscode=False): + if self.item.settings.getPreference("playback_directplay", True): + directPlayPref = self.item.settings.getPreference("playback_directplay_force", False) and 'forced' or 'allow' + else: + directPlayPref = 'disabled' + + if forceTranscode or directPlayPref == "disabled" or self.choice.hasBurnedInSubtitles is True: + directPlay = False + else: + directPlay = directPlayPref == "forced" and True or None + + return self._build(directPlay, self.item.settings.getPreference("playback_remux", True)) + + def _build(self, directPlay=None, directStream=True, currentPartIndex=None): + isForced = directPlay is not None + if isForced: + util.LOG(directPlay and "Forced Direct Play" or "Forced Transcode; allowDirectStream={0}".format(directStream)) + + directPlay = False if directPlay is False else self.choice.isDirectPlayable + + server = self.item.getServer() + + # A lot of our content metadata is independent of the direct play decision. + # Add that first. + + obj = util.AttributeDict() + obj.duration = self.media.duration.asInt() + + videoRes = self.media.getVideoResolution() + obj.fullHD = videoRes >= 1080 + obj.streamQualities = (videoRes >= 480 and self.item.settings.getGlobal("IsHD")) and ["HD"] or ["SD"] + + frameRate = self.media.videoFrameRate or "24p" + if frameRate == "24p": + obj.frameRate = 24 + elif frameRate == "NTSC": + obj.frameRate = 30 + + # Add soft subtitle info + if self.choice.subtitleDecision == self.choice.SUBTITLES_SOFT_ANY: + obj.subtitleUrl = server.buildUrl(self.choice.subtitleStream.getSubtitlePath(), True) + elif self.choice.subtitleDecision == self.choice.SUBTITLES_SOFT_DP: + obj.subtitleConfig = {'TrackName': "mkv/" + str(self.choice.subtitleStream.index.asInt() + 1)} + + # Create one content metadata object for each part and store them as a + # linked list. We probably want a doubly linked list, except that it + # becomes a circular reference nuisance, so we make the current item the + # base object and singly link in each direction from there. + + baseObj = obj + prevObj = None + startOffset = 0 + + startPartIndex = currentPartIndex or 0 + for partIndex in range(startPartIndex, len(self.media.parts)): + isCurrentPart = (currentPartIndex is not None and partIndex == currentPartIndex) + partObj = util.AttributeDict() + partObj.update(baseObj) + + partObj.live = False + partObj.partIndex = partIndex + partObj.startOffset = startOffset + + part = self.media.parts[partIndex] + + partObj.partDuration = part.duration.asInt() + partObj.path = str(part.file) + partObj.size = part.size and int(part.size) or '' + + if part.isIndexed(): + partObj.sdBifPath = part.getIndexPath("sd") + partObj.hdBifPath = part.getIndexPath("hd") + + # We have to evaluate every part before playback. Normally we'd expect + # all parts to be identical, but in reality they can be different. + + if partIndex > 0 and (not isForced and directPlay or not isCurrentPart): + choice = mediadecisionengine.MediaDecisionEngine().evaluateMediaVideo(self.item, self.media, partIndex) + canDirectPlay = (choice.isDirectPlayable is True) + else: + canDirectPlay = directPlay + + if canDirectPlay: + partObj = self.buildDirectPlay(partObj, partIndex) + else: + transcodeServer = self.item.getTranscodeServer(True, "video") + if transcodeServer is None: + return None + partObj = self.buildTranscode(transcodeServer, partObj, partIndex, directStream, isCurrentPart) + + # Set up our linked list references. If we couldn't build an actual + # object: fail fast. Otherwise, see if we're at our start offset + # yet in order to decide if we need to link forwards or backwards. + # We also need to account for parts missing a duration, by verifying + # the prevObj is None or if the startOffset has incremented. + + if partObj is None: + obj = None + break + elif prevObj is None or (startOffset > 0 and int(self.seekValue / 1000) >= startOffset): + obj = partObj + partObj.prevObj = prevObj + elif prevObj is not None: + prevObj.nextPart = partObj + + startOffset = startOffset + int(part.duration.asInt() / 1000) + + prevObj = partObj + + # Only set PlayStart for the initial part, and adjust for the part's offset + if obj is not None: + if obj.live: + # Start the stream at the end. Per Roku, this can be achieved using + # a number higher than the duration. Using the current time should + # ensure it's definitely high enough. + + obj.playStart = util.now() + 1800 + else: + obj.playStart = int(self.seekValue / 1000) - obj.startOffset + + self.metadata = obj + + util.LOG("Constructed video item for playback: {0}".format(dict(obj))) + + return self.metadata + + @property + def startOffset(self): + return self.metadata and self.metadata.startOffset or 0 + + def offsetIsValid(self, offset_seconds): + return self.metadata.startOffset <= offset_seconds < self.metadata.startOffset + (self.metadata.partDuration / 1000) + + def isLiveHls(url=None, headers=None): + # Check to see if this is a live HLS playlist to fix two issues. One is a + # Roku workaround since it doesn't obey the absence of EXT-X-ENDLIST to + # start playback at the END of the playlist. The second is for us to know + # if it's live to modify the functionality and player UI. + + # if IsString(url): + # request = createHttpRequest(url, "GET", true) + # AddRequestHeaders(request.request, headers) + # response = request.GetToStringWithTimeout(10) + + # ' Inspect one of the media playlist streams if this is a master playlist. + # if response.instr("EXT-X-STREAM-INF") > -1 then + # Info("Identify live HLS: inspecting the master playlist") + # mediaUrl = CreateObject("roRegex", "(^https?://.*$)", "m").Match(response)[1] + # if mediaUrl <> invalid then + # request = createHttpRequest(mediaUrl, "GET", true) + # AddRequestHeaders(request.request, headers) + # response = request.GetToStringWithTimeout(10) + # end if + # end if + + # isLiveHls = (response.Trim().Len() > 0 and response.instr("EXT-X-ENDLIST") = -1 and response.instr("EXT-X-STREAM-INF") = -1) + # Info("Identify live HLS: live=" + isLiveHls.toStr()) + # return isLiveHls + + return False + + def getServerDecision(self): + directPlay = not (self.metadata and self.metadata.isTranscoded) + decisionPath = self.getDecisionPath(directPlay) + newDecision = None + + if decisionPath: + server = self.metadata.transcodeServer or self.item.getServer() + request = plexrequest.PlexRequest(server, decisionPath) + response = request.getWithTimeout(10) + + if response.isSuccess() and response.container: + decision = serverdecision.ServerDecision(self, response, self) + + if decision.isSuccess(): + util.LOG("MDE: Server was happy with client's original decision. {0}".format(decision)) + return self + elif decision.isDecision(True): + util.WARN_LOG("MDE: Server was unhappy with client's original decision. {0}".format(decision)) + return decision.getDecision() + else: + util.LOG("MDE: Server was unbiased about the decision. {0}".format(decision)) + + # Check if the server has provided a new media item to use it. If + # there is no item, then we'll continue along as if there was no + # decision made. + newDecision = decision.getDecision(False) + else: + util.WARN_LOG("MDE: Server failed to provide a decision") + else: + util.WARN_LOG("MDE: Server or item does not support decisions") + + return newDecision or self + + def getDecisionPath(self, directPlay=False): + if not self.item or not self.metadata: + return None + + decisionPath = self.metadata.decisionPath + if not decisionPath: + server = self.metadata.transcodeServer or self.item.getServer() + decisionPath = self.buildTranscode(server, util.AttributeDict(), self.metadata.partIndex, True, False).decisionPath + + # Modify the decision params based on the transcode url + if decisionPath: + if directPlay: + decisionPath = decisionPath.replace("directPlay=0", "directPlay=1") + + # Clear all subtitle parameters and add the a valid subtitle type based + # on the video player. This will let the server decide if it can supply + # sidecar subs, burn or embed w/ an optional transcode. + for key in ("subtitles", "advancedSubtitles"): + decisionPath = re.sub('([?&]{0}=)\w+'.format(key), '', decisionPath) + subType = 'sidecar' # AppSettings().getBoolPreference("custom_video_player"), "embedded", "sidecar") + decisionPath = http.addUrlParam(decisionPath, "subtitles=" + subType) + + # Global variables for all decisions + # Kodi default is 20971520 (20MB) + decisionPath = http.addUrlParam(decisionPath, + "mediaBufferSize={}".format(str(CACHE_SIZE * 1024))) + decisionPath = http.addUrlParam(decisionPath, "hasMDE=1") + + if not advancedSettings.oldprofile: + decisionPath = http.addUrlParam(decisionPath, 'X-Plex-Client-Profile-Name=Generic') + else: + decisionPath = http.addUrlParam(decisionPath, 'X-Plex-Client-Profile-Name=Chrome') + + return decisionPath + + def getTranscodeReason(self): + # Combine the server and local MDE decisions + obj = [] + if self.decision: + obj.append(self.decision.getDecisionText()) + if self.item: + obj.append(self.item.transcodeReason) + reason = ' '.join(obj) + if not reason: + return None + + return reason + + def buildTranscodeHls(self, obj): + util.DEBUG_LOG('buildTranscodeHls()') + obj.streamFormat = "hls" + obj.streamBitrates = [0] + obj.switchingStrategy = "no-adaptation" + obj.transcodeEndpoint = "/video/:/transcode/universal/start.m3u8" + + builder = http.HttpRequest(obj.transcodeServer.buildUrl(obj.transcodeEndpoint, True)) + builder.extras = [] + builder.addParam("protocol", "hls") + + # TODO: This should be Generic, but will need to re-evaluate the augmentations with that change + if not advancedSettings.oldprofile: + builder.addParam("X-Plex-Client-Profile-Name", "Generic") + else: + builder.addParam("X-Plex-Client-Profile-Name", "Chrome") + + if self.choice.subtitleDecision == self.choice.SUBTITLES_SOFT_ANY: + builder.addParam("skipSubtitles", "1") + else: # elif self.choice.hasBurnedInSubtitles is True: # Must burn transcoded because we can't set offset + captionSize = captions.CAPTIONS.getBurnedSize() + if captionSize is not None: + builder.addParam("subtitleSize", captionSize) + + # Augment the server's profile for things that depend on the Roku's configuration. + if self.item.settings.supportsAudioStream("ac3", 6): + builder.extras.append("append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=hls&audioCodec=ac3)") + if not advancedSettings.oldprofile: + builder.extras.append("add-direct-play-profile(type=videoProfile&container=mkv&videoCodec=*&audioCodec=ac3)") + else: + builder.extras.append( + "add-direct-play-profile(type=videoProfile&container=matroska&videoCodec=*&audioCodec=ac3)") + + return builder + + def buildTranscodeMkv(self, obj, directStream=True): + util.DEBUG_LOG('buildTranscodeMkv()') + obj.streamFormat = "mkv" + obj.streamBitrates = [0] + obj.transcodeEndpoint = "/video/:/transcode/universal/start.mkv" + + builder = http.HttpRequest(obj.transcodeServer.buildUrl(obj.transcodeEndpoint, True)) + builder.extras = [] + builder.addParam("protocol", "http") + builder.addParam("copyts", "1") + if not advancedSettings.oldprofile: + builder.addParam("X-Plex-Client-Profile-Name", "Generic") + else: + builder.addParam("X-Plex-Client-Profile-Name", "Chrome") + + obj.subtitleUrl = None + + clampToOrig = self.item.settings.getPreference("audio_clamp_to_orig", True) + useKodiAudio = self.item.settings.getPreference("audio_channels_kodi", False) + AC3Cond = self.item.settings.getPreference("audio_force_ac3_cond", 'never') + dtsIsAC3 = self.item.settings.getPreference("audio_ac3dts", True) + hasAudioChoice = self.choice.audioStream is not None + forceAC3 = AC3Cond != 'never' + + ach = None + if AC3Cond in ('2', '5'): + ach = int(AC3Cond) + + # fixme: still necessary? + if self.choice.subtitleDecision == self.choice.SUBTITLES_BURN: + builder.addParam("subtitles", "burn") + captionSize = captions.CAPTIONS.getBurnedSize() + if captionSize is not None: + builder.addParam("subtitleSize", captionSize) + + else: + # TODO(rob): can we safely assume the id will also be 3 (one based index). + # If not, we will have to get tricky and select the subtitle stream after + # video playback starts via roCaptionRenderer: GetSubtitleTracks() and + # ChangeSubtitleTrack() + + obj.subtitleConfig = {'TrackName': "mkv/3" if hasAudioChoice else "mkv/2"} + + # Allow text conversion of subtitles if we only burn image formats + #if self.item.settings.getPreference("burn_subtitles") == "image": + if not self.item.settings.getPreference("burn_ssa", True): + builder.addParam("advancedSubtitles", "text") + + builder.addParam("subtitles", "auto") + + if not forceAC3: + if directStream: + audioCodecs = "eac3,ac3,dca,aac,mp3,mp2,pcm,flac,alac,wmav2,wmapro,wmavoice,opus,vorbis,truehd" + else: + audioCodecs = "mp3,ac3,dca,aac,opus" + else: + if dtsIsAC3: + audioCodecs = "ac3,dca" + else: + audioCodecs = "ac3" + + subtitleCodecs = "srt,ssa,ass,mov_text,tx3g,ttxt,text,pgs,vobsub,smi,subrip,eia_608_embedded," \ + "eia_708_embedded,dvb_subtitle" + (",webvtt" if KODI_VERSION_MAJOR > 19 else '') + + + util.LOG('MDE-prep: enabling codecs: {}'.format(audioCodecs)) + + # Allow virtually anything in Kodi playback. + + # DP might not do anything here + # builder.extras.append( + # "add-direct-play-profile(type=videoProfile&videoCodec=" + # "h264,mpeg1video,mpeg2video,mpeg4,msmpeg4v2,msmpeg4v3,vc1,wmv3&container=*&" + # "audioCodec="+audioCodecs+"&protocol=http)") + + builder.extras.append( + "add-transcode-target(type=videoProfile&videoCodec=" + "h264,mpeg1video,mpeg2video,mpeg4,msmpeg4v2,msmpeg4v3,vc1,wmv3&container=mkv&" + "audioCodec={}&subtitleCodec={}&protocol=http&context=streaming)".format(audioCodecs, subtitleCodecs)) + + # builder.extras.append( + # "append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=http&audioCodec=" + + # audioCodecs + ")") + + # if self.item.settings.supportsSurroundSound(): + # if self.choice.audioStream is not None: + # numChannels = self.choice.audioStream.channels.asInt(8) + # else: + # numChannels = 8 + # + # for codec in ("ac3", "eac3", "dca"): + # if self.item.settings.supportsAudioStream(codec, numChannels): + # builder.extras.append("append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=http&audioCodec=" + codec + ")") + # builder.extras.append("add-direct-play-profile(type=videoProfile&videoCodec=*&container=mkv&audioCodec=" + codec + ")") + # if codec == "dca": + # builder.extras.append( + # "add-limitation(scope=videoAudioCodec&scopeName=dca&type=upperBound&name=audio.channels&value=8&isRequired=false)" + # ) + # + # for codec in ("ac3", "eac3", "dca"): + # builder.extras.append("append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=http&audioCodec=" + codec + ")") + # builder.extras.append("add-direct-play-profile(type=videoProfile&videoCodec=*&container=mkv&audioCodec=" + codec + ")") + + util.LOG('MDE-prep: settings: clampOrig: {}, kodiAudio: {}, forceAC3: {}, dtsIsAC3: {}' + .format(clampToOrig, useKodiAudio, forceAC3, dtsIsAC3)) + + # limit audio channels to original stream's audio channel amount + numChannels = self.choice.audioStream.channels.asInt(8) if hasAudioChoice and \ + self.choice.audioStream.channels else 8 + + # limit OPUS to 334kbit + if numChannels == 8: + # 7.1 + opusBitrate = 334 + elif numChannels >= 6: + # 5.1 + opusBitrate = 256 + else: + # 2 + opusBitrate = 128 + + # limit max audio channels to audio stream or kodi (whichever is lower) + maxAudioChannels = numChannels if not useKodiAudio else min(numChannels, self.audioChannels) + + # if we've got a channel limit for AC3/DTS, apply it + maxAudioChannels = maxAudioChannels if not ach else min(maxAudioChannels, ach) + + if forceAC3 and hasAudioChoice: + # limit max audio channels to the above or 6 for AC3 (whichever is lower) + if self.choice.audioStream.codec != "dca": + maxAudioChannels = min(6, maxAudioChannels) + else: + # allow DTS 6.1 ES + maxAudioChannels = min(7, maxAudioChannels) + + streamWasAC3 = hasAudioChoice and self.choice.audioStream.codec == "ac3" + + if not forceAC3 and hasAudioChoice: + # limit audio bitrate to the same bitrate as the current stream's codec + if clampToOrig and self.choice.audioStream.bitrate: + util.LOG('MDE-prep: limiting {} to {} kbit'.format(self.choice.audioStream.codec.upper(), + self.choice.audioStream.bitrate)) + builder.extras.append( + "add-limitation(scope=videoAudioCodec&scopeName={}&" + "type=upperBound&name=audio.bitrate&value={})".format( + self.choice.audioStream.codec, + self.choice.audioStream.bitrate + ) + ) + + # limit OPUS bitrate + if hasAudioChoice and self.choice.audioStream.codec != "opus": + util.LOG('MDE-prep: limiting OPUS bitrate to {} kbit'.format(opusBitrate)) + builder.extras.append( + "add-limitation(scope=videoAudioCodec&scopeName=opus&type=upperBound&name=audio.bitrate&" + "value={}&isRequired=false)".format(opusBitrate) + ) + + # limit AC3 + if not streamWasAC3 or forceAC3: + util.LOG('MDE-prep: limiting AC3 to 640 kbit') + builder.extras.append( + "add-limitation(scope=videoAudioCodec&scopeName=ac3&type=upperBound&name=audio.bitrate&value=640)" + ) + + util.LOG('MDE-prep: limiting audio channels to {}'.format(maxAudioChannels)) + builder.extras.append( + "add-limitation(scope=videoAudioCodec&scopeName=*&type=upperBound&" + "name=audio.channels&value={})".format(maxAudioChannels) + ) + + # AAC sample rate cannot be less than 22050hz (HLS is capable). + if self.choice.audioStream is not None and self.choice.audioStream.samplingRate.asInt(22050) < 22050: + builder.extras.append( + "add-limitation(scope=videoAudioCodec&scopeName=aac&type=lowerBound&" + "name=audio.samplingRate&value=22050&isRequired=false)") + + # HEVC + if self.item.settings.getPreference("allow_hevc", True): + builder.extras.append( + "append-transcode-target-codec(type=videoProfile&context=streaming&container=mkv&" + "protocol=http&videoCodec=hevc)") + # builder.extras.append( + # "add-direct-play-profile(type=videoProfile&videoCodec=hevc&container=*&audioCodec=*)") + + # VP9 + if self.item.settings.getGlobal("vp9Support"): + builder.extras.append( + "append-transcode-target-codec(type=videoProfile&context=streaming&container=mkv&" + "protocol=http&videoCodec=vp9)") + # builder.extras.append( + # "add-direct-play-profile(type=videoProfile&videoCodec=vp9&container=*&audioCodec=*)") + + # AV1 + if self.item.settings.getPreference("allow_av1", False): + builder.extras.append( + "append-transcode-target-codec(type=videoProfile&context=streaming&container=mkv&" + "protocol=http&videoCodec=av1)") + # builder.extras.append( + # "add-direct-play-profile(type=videoProfile&videoCodec=av1&container=*&audioCodec=*)") + + return builder + + def buildTranscodeMkvLegacy(self, obj, directStream=True): + util.DEBUG_LOG('buildTranscodeMkvLegacy()') + obj.streamFormat = "mkv" + obj.streamBitrates = [0] + obj.transcodeEndpoint = "/video/:/transcode/universal/start.mkv" + + builder = http.HttpRequest(obj.transcodeServer.buildUrl(obj.transcodeEndpoint, True)) + builder.extras = [] + builder.addParam("protocol", "http") + builder.addParam("copyts", "1") + builder.addParam("X-Plex-Client-Profile-Name", "Generic") + + obj.subtitleUrl = None + + # fixme: still necessary? + if True: # if self.choice.subtitleDecision == self.choice.SUBTITLES_BURN: # Must burn transcoded because we can't set offset + builder.addParam("subtitles", "burn") + captionSize = captions.CAPTIONS.getBurnedSize() + if captionSize is not None: + builder.addParam("subtitleSize", captionSize) + + else: + # TODO(rob): can we safely assume the id will also be 3 (one based index). + # If not, we will have to get tricky and select the subtitle stream after + # video playback starts via roCaptionRenderer: GetSubtitleTracks() and + # ChangeSubtitleTrack() + + obj.subtitleConfig = {'TrackName': "mkv/3"} + + # Allow text conversion of subtitles if we only burn image formats + if self.item.settings.getPreference("burn_subtitles") == "image": + builder.addParam("advancedSubtitles", "text") + + builder.addParam("subtitles", "auto") + + if directStream: + audioCodecs = "eac3,ac3,dca,aac,mp3,mp2,pcm,flac,alac,wmav2,wmapro,wmavoice,opus,vorbis,truehd" + else: + audioCodecs = "mp3,ac3,aac,opus" + + # Allow virtually anything in Kodi playback. + + # DP might not do anything here + # builder.extras.append( + # "add-direct-play-profile(type=videoProfile&videoCodec=" + # "h264,mpeg1video,mpeg2video,mpeg4,msmpeg4v2,msmpeg4v3,vc1,wmv3&container=*&" + # "audioCodec="+audioCodecs+"&protocol=http)") + + builder.extras.append( + "add-transcode-target(type=videoProfile&videoCodec=" + "h264,mpeg1video,mpeg2video,mpeg4,msmpeg4v2,msmpeg4v3,vc1,wmv3&container=mkv&" + "audioCodec="+audioCodecs+"&protocol=http&context=streaming)") + + # builder.extras.append( + # "append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=http&audioCodec=" + + # audioCodecs + ")") + + # if self.item.settings.supportsSurroundSound(): + # if self.choice.audioStream is not None: + # numChannels = self.choice.audioStream.channels.asInt(8) + # else: + # numChannels = 8 + # + # for codec in ("ac3", "eac3", "dca"): + # if self.item.settings.supportsAudioStream(codec, numChannels): + # builder.extras.append("append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=http&audioCodec=" + codec + ")") + # builder.extras.append("add-direct-play-profile(type=videoProfile&videoCodec=*&container=mkv&audioCodec=" + codec + ")") + # if codec == "dca": + # builder.extras.append( + # "add-limitation(scope=videoAudioCodec&scopeName=dca&type=upperBound&name=audio.channels&value=8&isRequired=false)" + # ) + # + # for codec in ("ac3", "eac3", "dca"): + # builder.extras.append("append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=http&audioCodec=" + codec + ")") + # builder.extras.append("add-direct-play-profile(type=videoProfile&videoCodec=*&container=mkv&audioCodec=" + codec + ")") + + # limit OPUS to 334kbit + numChannels = self.choice.audioStream.channels.asInt(8) if self.choice.audioStream else 8 + + if numChannels == 8: + # 7.1 + opusBitrate = 334 + elif numChannels >= 6: + # 5.1 + opusBitrate = 256 + else: + # 2 + opusBitrate = 128 + + builder.extras.append( + "add-limitation(scope=videoAudioCodec&scopeName=opus&type=upperBound&name=audio.bitrate&" + "value={}&isRequired=false)".format(opusBitrate) + ) + + # limit AC3 + builder.extras.append( + "add-limitation(scope=videoAudioCodec&scopeName=ac3&type=upperBound&name=audio.bitrate&value=640)" + ) + + # limit audio to Kodi audio channels + builder.extras.append( + "add-limitation(scope=videoAudioCodec&scopeName=*&type=upperBound&" + "name=audio.channels&value={})".format(self.audioChannels) + ) + + # AAC sample rate cannot be less than 22050hz (HLS is capable). + if self.choice.audioStream is not None and self.choice.audioStream.samplingRate.asInt(22050) < 22050: + builder.extras.append( + "add-limitation(scope=videoAudioCodec&scopeName=aac&type=lowerBound&" + "name=audio.samplingRate&value=22050&isRequired=false)") + + # HEVC + if self.item.settings.getPreference("allow_hevc", True): + builder.extras.append( + "append-transcode-target-codec(type=videoProfile&context=streaming&container=mkv&" + "protocol=http&videoCodec=hevc)") + # builder.extras.append( + # "add-direct-play-profile(type=videoProfile&videoCodec=hevc&container=*&audioCodec=*)") + + # VP9 + if self.item.settings.getGlobal("vp9Support"): + builder.extras.append( + "append-transcode-target-codec(type=videoProfile&context=streaming&container=mkv&" + "protocol=http&videoCodec=vp9)") + # builder.extras.append( + # "add-direct-play-profile(type=videoProfile&videoCodec=vp9&container=*&audioCodec=*)") + + # AV1 + if self.item.settings.getPreference("allow_av1", False): + builder.extras.append( + "append-transcode-target-codec(type=videoProfile&context=streaming&container=mkv&" + "protocol=http&videoCodec=av1)") + # builder.extras.append( + # "add-direct-play-profile(type=videoProfile&videoCodec=av1&container=*&audioCodec=*)") + + return builder + + def buildDirectPlay(self, obj, partIndex): + util.DEBUG_LOG('buildDirectPlay()') + part = self.media.parts[partIndex] + + server = self.item.getServer() + + # Check if we should include our token or not for this request + obj.isRequestToServer = server.isRequestToServer(server.buildUrl(part.getAbsolutePath("key"))) + obj.streamUrls = [server.buildUrl(part.getAbsolutePath("key"), obj.isRequestToServer)] + obj.token = obj.isRequestToServer and server.getToken() or None + if self.media.protocol == "hls": + obj.streamFormat = "hls" + obj.switchingStrategy = "full-adaptation" + obj.live = self.isLiveHLS(obj.streamUrls[0], self.media.indirectHeaders) + else: + obj.streamFormat = self.media.get('container', 'mp4') + if obj.streamFormat == "mov" or obj.streamFormat == "m4v": + obj.streamFormat = "mp4" + + obj.streamBitrates = [self.media.bitrate.asInt()] + obj.isTranscoded = False + + if self.choice.audioStream is not None: + obj.audioLanguageSelected = self.choice.audioStream.languageCode + + return obj + + def hasMoreParts(self): + return (self.metadata is not None and self.metadata.nextPart is not None) + + def getNextPartOffset(self): + return self.metadata.nextPart.startOffset * 1000 + + def goToNextPart(self): + oldPart = self.metadata + if oldPart is None: + return + + newPart = oldPart.nextPart + if newPart is None: + return + + newPart.prevPart = oldPart + oldPart.nextPart = None + self.metadata = newPart + + util.LOG("Next part set for playback: {0}".format(self.metadata)) + + def getBifUrl(self, offset=0): + server = self.item.getServer() + startOffset = 0 + for part in self.media.parts: + duration = part.duration.asInt() + if startOffset <= offset < startOffset + duration: + bifUrl = part.getIndexPath("hd") or part.getIndexPath("sd") + if bifUrl is not None: + url = server.buildUrl('{0}/{1}'.format(bifUrl, offset - startOffset), True) + return url + + startOffset += duration + + return None + + def buildTranscode(self, server, obj, partIndex, directStream, isCurrentPart): + util.DEBUG_LOG('buildTranscode()') + obj.transcodeServer = server + obj.isTranscoded = True + + # if server.supportsFeature("mkvTranscode") and self.item.settings.getPreference("transcode_format", 'mkv') != "hls": + if server.supportsFeature("mkvTranscode"): + if not advancedSettings.oldprofile: + builder = self.buildTranscodeMkv(obj, directStream=directStream) + else: + builder = self.buildTranscodeMkvLegacy(obj, directStream=directStream) + else: + builder = self.buildTranscodeHls(obj) + + if self.item.getServer().TYPE == 'MYPLEXSERVER': + path = server.swizzleUrl(self.item.getAbsolutePath("key")) + else: + path = self.item.getAbsolutePath("key") + + builder.addParam("path", path) + + part = self.media.parts[partIndex] + seekOffset = int(self.seekValue / 1000) + startOffset = obj.get("startOffset", 0) + + # Disabled for HLS due to a Roku bug plexinc/roku-client-issues#776 + if True: # obj.streamFormat == "mkv": + # Trust our seekOffset for this part if it's the current part (now playing) or + # the seekOffset is within the time frame. We have to trust the current part + # as we may have to rebuild the transcode when seeking, and not all parts + # have a valid duration. + + if isCurrentPart or len(self.media.parts) <= 1 or ( + seekOffset >= startOffset and seekOffset <= startOffset + int(part.duration.asInt() / 1000) + ): + startOffset = seekOffset - startOffset + + # Avoid a perfect storm of PMS and Roku quirks. If we pass an offset to + # the transcoder,: it'll start transcoding from that point. But if + # we try to start a few seconds into the video, the Roku seems to want + # to grab the first segment. The first segment doesn't exist, so PMS + # returns a 404 (but only if the offset is <= 12s, otherwise it returns + # a blank segment). If the Roku gets a 404 for the first segment,: + # it'll fail. So, if we're going to start playing from less than 12 + # seconds, don't bother telling the transcoder. It's not worth the + # potential failure, let it transcode from the start so that the first + # segment will always exist. + + # TODO: Probably can remove this (Rick) + if startOffset <= 12: + startOffset = 0 + else: + startOffset = 0 + + builder.addParam("offset", str(startOffset)) + + builder.addParam("session", self.item.settings.getGlobal("clientIdentifier")) + builder.addParam("directStream", directStream and "1" or "0") + builder.addParam("directPlay", "0") + + qualityIndex = self.item.settings.getQualityIndex(self.item.getQualityType(server)) + builder.addParam("videoQuality", self.item.settings.getGlobal("transcodeVideoQualities")[qualityIndex]) + builder.addParam("videoResolution", str(self.item.settings.getGlobal("transcodeVideoResolutions")[qualityIndex])) + builder.addParam("maxVideoBitrate", self.item.settings.getGlobal("transcodeVideoBitrates")[qualityIndex]) + + if self.media.mediaIndex is not None: + builder.addParam("mediaIndex", str(self.media.mediaIndex)) + + builder.addParam("partIndex", str(partIndex)) + + # Augment the server's profile for things that depend on the Roku's configuration. + if self.item.settings.getPreference("h264_level", "auto") != "auto": + builder.extras.append( + "add-limitation(scope=videoCodec&scopeName=h264&type=upperBound&name=video.level&value={0}&isRequired=true)".format( + self.item.settings.getPreference("h264_level") + ) + ) + + if not self.item.settings.getGlobal("supports1080p60") and self.item.settings.getGlobal("transcodeVideoResolutions")[qualityIndex][0] >= 1920: + builder.extras.append("add-limitation(scope=videoCodec&scopeName=h264&type=upperBound&name=video.frameRate&value=30&isRequired=false)") + + if builder.extras: + builder.addParam("X-Plex-Client-Profile-Extra", '+'.join(builder.extras)) + + if server.isLocalConnection(): + builder.addParam("location", "lan") + + obj.streamUrls = [builder.getUrl()] + + # Build the decision path now that we have build our stream url, and only if the server supports it. + if server.supportsFeature("streamingBrain"): + decisionPath = builder.getRelativeUrl().replace(obj.transcodeEndpoint, self.DECISION_ENDPOINT) + if decisionPath.startswith(self.DECISION_ENDPOINT): + obj.decisionPath = decisionPath + + return obj + + +class PlexAudioPlayer(object): + def __init__(self, item): + self.containerFormats = { + 'aac': "es.aac-adts" + } + + self.item = item + self.choice = mediadecisionengine.MediaDecisionEngine().chooseMedia(item) + if self.choice: + self.media = self.choice.media + self.lyrics = None # createLyrics(item, self.media) + + def build(self, directPlay=None): + directPlay = directPlay or self.choice.isDirectPlayable + + obj = util.AttributeDict() + + # TODO(schuyler): Do we want/need to add anything generic here? Title? Duration? + + if directPlay: + obj = self.buildDirectPlay(obj) + else: + obj = self.buildTranscode(obj) + + self.metadata = obj + + util.LOG("Constructed audio item for playback: {0}".format(dict(obj))) + + return self.metadata + + def buildTranscode(self, obj): + transcodeServer = self.item.getTranscodeServer(True, "audio") + if not transcodeServer: + return None + + obj.streamFormat = "mp3" + obj.isTranscoded = True + obj.transcodeServer = transcodeServer + obj.transcodeEndpoint = "/music/:/transcode/universal/start.m3u8" + + builder = http.HttpRequest(transcodeServer.buildUrl(obj.transcodeEndpoint, True)) + # builder.addParam("protocol", "http") + builder.addParam("path", self.item.getAbsolutePath("key")) + builder.addParam("session", self.item.getGlobal("clientIdentifier")) + builder.addParam("directPlay", "0") + builder.addParam("directStream", "0") + + obj.url = builder.getUrl() + + return obj + + def buildDirectPlay(self, obj): + if self.choice.part: + obj.url = self.item.getServer().buildUrl(self.choice.part.getAbsolutePath("key"), True) + + # Set and override the stream format if applicable + obj.streamFormat = self.choice.media.get('container', 'mp3') + if self.containerFormats.get(obj.streamFormat): + obj.streamFormat = self.containerFormats[obj.streamFormat] + + # If we're direct playing a FLAC, bitrate can be required, and supposedly + # this is the only way to do it. plexinc/roku-client#48 + # + bitrate = self.choice.media.bitrate.asInt() + if bitrate > 0: + obj.streams = [{'url': obj.url, 'bitrate': bitrate}] + + return obj + + # We may as well fallback to transcoding if we could not direct play + return self.buildTranscode(obj) + + def getLyrics(self): + return self.lyrics + + def hasLyrics(self): + return False + return self.lyrics.isAvailable() + + +class PlexPhotoPlayer(object): + def __init__(self, item): + self.item = item + self.choice = item + self.media = item.media()[0] + self.metadata = None + + def build(self, item=None): + item = item or self.item + media = item.media()[0] + if media.parts and media.parts[0]: + obj = util.AttributeDict() + + part = media.parts[0] + path = part.key or part.thumb + server = item.getServer() + + obj.url = server.buildUrl(path, True) + obj.enableBlur = server.supportsPhotoTranscoding + + util.DEBUG_LOG("Constructed photo item for playback: {0}".format(dict(obj))) + + self.metadata = obj + + return self.metadata diff --git a/script.plexmod/lib/_included_packages/plexnet/plexrequest.py b/script.plexmod/lib/_included_packages/plexnet/plexrequest.py new file mode 100644 index 0000000000..764ae1d587 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexrequest.py @@ -0,0 +1,46 @@ +from __future__ import absolute_import +from xml.etree import ElementTree + +from . import plexserver +from . import plexresult +from . import http +from . import util + + +class PlexRequest(http.HttpRequest): + def __init__(self, server, path, method=None): + server = server or plexserver.dummyPlexServer() + + http.HttpRequest.__init__(self, server.buildUrl(path, includeToken=True), method) + + self.server = server + self.path = path + + util.addPlexHeaders(self, server.getToken()) + + def onResponse(self, event, context): + if context.get('completionCallback'): + result = plexresult.PlexResult(self.server, self.path) + result.setResponse(event) + context['completionCallback'](self, result, context) + + def doRequestWithTimeout(self, timeout=10, postBody=None): + # non async request/response + if postBody: + data = ElementTree.fromstring(self.postToStringWithTimeout(postBody, timeout)) + else: + data = ElementTree.fromstring(self.getToStringWithTimeout(timeout)) + + response = plexresult.PlexResult(self.server, self.path) + response.setResponse(self.event) + response.parseFakeXMLResponse(data) + + return response + + +class PlexServerRequest(PlexRequest): + def onResponse(self, event, context): + if context.get('completionCallback'): + result = plexresult.PlexServerResult(self.server, self.path) + result.setResponse(event) + context['completionCallback'](self, result, context) diff --git a/script.plexmod/lib/_included_packages/plexnet/plexresource.py b/script.plexmod/lib/_included_packages/plexnet/plexresource.py new file mode 100644 index 0000000000..11dd75f950 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexresource.py @@ -0,0 +1,231 @@ +from __future__ import absolute_import +from xml.etree import ElementTree + +from . import http +from . import exceptions +from . import plexobjects +from . import plexconnection +from . import util + +RESOURCES = 'https://plex.tv/api/resources?includeHttps=1' + + +class PlexResource(object): + def __init__(self, data): + self.connection = None + self.connections = [] + self.accessToken = None + self.sourceType = None + + if data is None: + return + + self.accessToken = data.attrib.get('accessToken') + self.httpsRequired = data.attrib.get('httpsRequired') == '1' + self.type = data.attrib.get('type') + self.clientIdentifier = data.attrib.get('clientIdentifier') + self.product = data.attrib.get('product') + self.provides = data.attrib.get('provides') + self.serverClass = data.attrib.get('serverClass') + self.sourceType = data.attrib.get('sourceType') + self.uuid = self.clientIdentifier + + hasSecureConn = False + + for conn in data.findall('Connection'): + if conn.attrib.get('protocol') == "https": + hasSecureConn = True + break + + addLocalConsFound = [] + for conn in data.findall('Connection'): + connection = plexconnection.PlexConnection( + plexconnection.PlexConnection.SOURCE_MYPLEX, + conn.attrib.get('uri'), + conn.attrib.get('local') == '1', + self.accessToken, + hasSecureConn and conn.attrib.get('protocol') != "https" + ) + + # Keep the secure connection on top + if connection.isSecure and not util.LOCAL_OVER_SECURE: + self.connections.insert(0, connection) + elif not connection.isSecure and util.LOCAL_OVER_SECURE: + self.connections.insert(0, connection) + else: + self.connections.append(connection) + + if connection.isSecureButLocal: + addLocalConsFound.append((connection.isSecureButLocal, connection.address)) + + # If the connection is one of our plex.direct secure connections, add + # the nonsecure variant as well, unless https is required. + # + if self.httpsRequired and conn.attrib.get('protocol') == "https" and conn.attrib.get('address') not in conn.attrib.get('uri'): + self.connections.append( + plexconnection.PlexConnection( + plexconnection.PlexConnection.SOURCE_MYPLEX, + "http://{0}:{1}".format(conn.attrib.get('address'), conn.attrib.get('port')), + conn.attrib.get('local') == '1', + self.accessToken, + True + ) + ) + + # add discovered local cons if necessary + for ipPort, origAddress in addLocalConsFound: + ip, port = ipPort + address = "http://" + ip + ":" + str(port) + for conn in self.connections: + if conn.address == address: + continue + + util.DEBUG_LOG( + "Secure connection {0} has a locally reachable IP, add it to the checklist".format(origAddress)) + lcon = plexconnection.PlexConnection( + plexconnection.PlexConnection.SOURCE_DISCOVERED, + "http://" + ip + ":" + str(port), + True, + self.accessToken, + not util.LOCAL_OVER_SECURE, + skipLocalCheck=True + ) + if util.LOCAL_OVER_SECURE: + self.connections.insert(0, lcon) + else: + self.connections.append(lcon) + + def __repr__(self): + return '<{0}:{1}>'.format(self.__class__.__name__, self.name.encode('utf8')) + + +class ResourceConnection(plexobjects.PlexObject): + # Constants + STATE_UNKNOWN = "unknown" + STATE_UNREACHABLE = "unreachable" + STATE_REACHABLE = "reachable" + STATE_UNAUTHORIZED = "unauthorized" + STATE_INSECURE = "insecure_untested" + + SOURCE_MANUAL = 1 + SOURCE_DISCOVERED = 2 + SOURCE_MYPLEX = 4 + + SCORE_REACHABLE = 4 + SCORE_LOCAL = 2 + SCORE_SECURE = 1 + + def init(self, data): + self.secure = True + self.reachable = False + self.data = None + + def __repr__(self): + return '<{0}:{1}>'.format(self.__class__.__name__, self.uri.encode('utf8')) + + @property + def http_uri(self): + return 'http://{0}:{1}'.format(self.address, self.port) + + @property + def URL(self): + if self.secure: + return self.uri + else: + return self.http_url + + def connect(self): + util.LOG('Connecting: {0}'.format(util.cleanToken(self.URL))) + try: + self.data = self.query('/') + self.reachable = True + return True + except Exception as err: + util.ERROR(util.cleanToken(self.URL), err) + + util.LOG('Connecting: Secure failed, trying insecure...') + self.secure = False + + try: + self.data = self.query('/') + self.reachable = True + return True + except Exception as err: + util.ERROR(util.cleanToken(self.URL), err) + + return False + + def headers(self, token=None): + headers = util.BASE_HEADERS.copy() + if token: + headers['X-Plex-Token'] = token + return headers + + def query(self, path, method=None, token=None, **kwargs): + method = method or http.requests.get + url = self.getURL(path) + util.LOG('{0} {1}'.format(method.__name__.upper(), url)) + response = method(url, headers=self.headers(token), timeout=util.TIMEOUT, **kwargs) + if response.status_code not in (200, 201): + codename = http.status_codes.get(response.status_code)[0] + raise exceptions.BadRequest('({0}) {1}'.format(response.status_code, codename)) + data = response.text.encode('utf8') + + return ElementTree.fromstring(data) if data else None + + def getURL(self, path, token=None): + if token: + delim = '&' if '?' in path else '?' + return '{base}{path}{delim}X-Plex-Token={token}'.format(base=self.URL, path=path, delim=delim, token=util.hideToken(token)) + return '{0}{1}'.format(self.URL, path) + + +class PlexResourceList(plexobjects.PlexItemList): + def __init__(self, data, initpath=None, server=None): + self._data = data + self.initpath = initpath + self._server = server + self._items = None + + @property + def items(self): + if self._items is None: + if self._data is not None: + self._items = [PlexResource(elem, initpath=self.initpath, server=self._server) for elem in self._data] + else: + self._items = [] + + return self._items + + +def fetchResources(token): + headers = util.BASE_HEADERS.copy() + headers['X-Plex-Token'] = token + util.LOG('GET {0}?X-Plex-Token={1}'.format(RESOURCES, util.hideToken(token))) + response = http.GET(RESOURCES) + data = ElementTree.fromstring(response.text.encode('utf8')) + from . import plexserver + return [plexserver.PlexServer(elem) for elem in data] + + +def findResource(resources, search, port=32400): + """ Searches server.name """ + search = search.lower() + util.LOG('Looking for server: {0}'.format(search)) + for server in resources: + if search == server.name.lower(): + util.LOG('Server found: {0}'.format(server)) + return server + util.LOG('Unable to find server: {0}'.format(search)) + raise exceptions.NotFound('Unable to find server: {0}'.format(search)) + + +def findResourceByID(resources, ID): + """ Searches server.clientIdentifier """ + util.LOG('Looking for server by ID: {0}'.format(ID)) + for server in resources: + if ID == server.clientIdentifier: + util.LOG('Server found by ID: {0}'.format(server)) + return server + util.LOG('Unable to find server by ID: {0}'.format(ID)) + raise exceptions.NotFound('Unable to find server by ID: {0}'.format(ID)) diff --git a/script.plexmod/lib/_included_packages/plexnet/plexresult.py b/script.plexmod/lib/_included_packages/plexnet/plexresult.py new file mode 100644 index 0000000000..7d65d4f4b0 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexresult.py @@ -0,0 +1,102 @@ +from __future__ import absolute_import +from . import http +from . import plexobjects + + +class PlexResult(http.HttpResponse): + def __init__(self, server, address): + self.server = server + self.address = address + self.container = None + self.parsed = None + self.items = [] + + def setResponse(self, event): + self.event = event + + def parseResponse(self): + if self.parsed: + return self.parsed + + self.parsed = False + + if self.isSuccess(): + data = self.getBodyXml() + if data is not None: + self.container = plexobjects.PlexContainer(data, initpath=self.address, server=self.server, address=self.address) + + for node in data: + self.addItem(self.container, node) + + self.parsed = True + + return self.parsed + + def parseFakeXMLResponse(self, data): + if self.parsed: + return self.parsed + + self.parsed = False + + if data is not None: + self.container = plexobjects.PlexContainer(data, initpath=self.address, server=self.server, address=self.address) + + for node in data: + self.addItem(self.container, node) + + self.parsed = True + + return self.parsed + + def addItem(self, container, node): + if node.attrib.get('type') in ('track', 'movie', 'episode', 'photo') and node.tag != 'PlayQueue': + item = plexobjects.buildItem(self.server, node, self.address, container=self.container) + else: + item = plexobjects.PlexObject(node, server=self.container.server, container=self.container) + + # TODO(rob): handle channel settings. We should be able to utilize + # the settings component with some modifications. + if not item.isSettings(): + self.items.append(item) + else: + # Decrement the size and total size if applicable + if self.container.get("size"): + self.container.size = plexobjects.PlexValue(str(self.container.size.asInt() - 1)) + if self.container.get("totalSize"): + self.container.totalSize = plexobjects.PlexValue(str(self.container.totalSize.asInt() - 1)) + + +class PlexServerResult(PlexResult): + def parseResponse(self): + if self.parsed: + return self.parsed + + self.parsed = False + + if self.isSuccess(): + data = self.getBodyXml() + if data is not None: + self.container = plexobjects.PlexServerContainer(data, initpath=self.address, server=self.server, address=self.address) + + for node in data: + self.addItem(self.container, node) + + self.parsed = True + + return self.parsed + + def parseFakeXMLResponse(self, data): + if self.parsed: + return self.parsed + + self.parsed = False + + if data is not None: + self.container = plexobjects.PlexServerContainer(data, initpath=self.address, server=self.server, address=self.address) + + for node in data: + self.addItem(self.container, node) + + self.parsed = True + + return self.parsed diff --git a/script.plexmod/lib/_included_packages/plexnet/plexserver.py b/script.plexmod/lib/_included_packages/plexnet/plexserver.py new file mode 100644 index 0000000000..9bb4b6cd59 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexserver.py @@ -0,0 +1,700 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +import time +import re +import json +import urllib3.exceptions + +from . import http +from . import util +from . import exceptions +from . import compat +from . import verlib + +from xml.etree import ElementTree +from . import signalsmixin +from . import plexobjects +from . import plexresource +from . import plexlibrary +from . import asyncadapter +from six.moves import range +# from plexapi.client import Client +# from plexapi.playqueue import PlayQueue + + +TOTAL_QUERIES = 0 +DEFAULT_BASEURI = 'http://localhost:32400' + + +class PlexServer(plexresource.PlexResource, signalsmixin.SignalsMixin): + TYPE = 'PLEXSERVER' + + def __init__(self, data=None): + signalsmixin.SignalsMixin.__init__(self) + plexresource.PlexResource.__init__(self, data) + self.accessToken = None + self.multiuser = False + self.isSupported = None + self.hasFallback = False + self.supportsAudioTranscoding = False + self.supportsVideoTranscoding = False + self.supportsPhotoTranscoding = False + self.supportsVideoRemuxOnly = False + self.supportsScrobble = True + self.allowsMediaDeletion = False + self.allowChannelAccess = False + self.activeConnection = None + self.serverClass = None + + self.pendingReachabilityRequests = 0 + self.pendingSecureRequests = 0 + + self.features = {} + self.librariesByUuid = {} + + self.server = self + self.session = http.Session() + + self.owner = None + self.owned = False + self.synced = False + self.sameNetwork = False + self.uuid = None + self.name = None + self.platform = None + self.versionNorm = None + self.rawVersion = None + self.transcodeSupport = False + + if data is None: + return + + self.owner = data.attrib.get('sourceTitle') + self.owned = data.attrib.get('owned') == '1' + self.synced = data.attrib.get('synced') == '1' + self.sameNetwork = data.attrib.get('publicAddressMatches') == '1' + self.uuid = data.attrib.get('clientIdentifier') + self.name = data.attrib.get('name') + self.platform = data.attrib.get('platform') + self.rawVersion = data.attrib.get('productVersion') + self.versionNorm = util.normalizedVersion(self.rawVersion) + self.transcodeSupport = data.attrib.get('transcodeSupport') == '1' + + def __eq__(self, other): + if not other: + return False + if self.__class__ != other.__class__: + + return False + return self.uuid == other.uuid and self.owner == other.owner + + def __ne__(self, other): + return not self.__eq__(other) + + def __str__(self): + return ""\ + .format(repr(self.name), self.owned, self.uuid, self.versionNorm, self.activeConnection) + + def __repr__(self): + return self.__str__() + + def close(self): + self.session.cancel() + + def get(self, attr, default=None): + return default + + @property + def isSecure(self): + if self.activeConnection: + return self.activeConnection.isSecure + + @property + def isLocal(self): + if self.activeConnection: + return self.activeConnection.isLocal + + def getObject(self, key): + data = self.query(key) + return plexobjects.buildItem(self, data[0], key, container=self) + + def hubs(self, section=None, count=None, search_query=None): + hubs = [] + + params = {"includeMarkers": 1} + if search_query: + q = '/hubs/search' + params['query'] = search_query.lower() + if section: + params['sectionId'] = section + + if count is not None: + params['limit'] = count + else: + q = '/hubs' + if section: + if section == 'playlists': + audio = plexlibrary.AudioPlaylistHub(False, server=self.server) + video = plexlibrary.VideoPlaylistHub(False, server=self.server) + if audio.items: + hubs.append(audio) + if video.items: + hubs.append(video) + return hubs + else: + q = '/hubs/sections/%s' % section + + if count is not None: + params['count'] = count + + data = self.query(q, params=params) + container = plexobjects.PlexContainer(data, initpath=q, server=self, address=q) + + for elem in data: + hubs.append(plexlibrary.Hub(elem, server=self, container=container)) + return hubs + + def playlists(self, start=0, size=10, hub=None): + try: + return plexobjects.listItems(self, '/playlists/all') + except exceptions.BadRequest: + return None + + @property + def library(self): + if self.platform == 'cloudsync': + return plexlibrary.Library(None, server=self) + else: + return plexlibrary.Library(self.query('/library/'), server=self) + + @property + def sessions(self): + if self.owned: + return plexobjects.listItems(self, '/status/sessions') + raise exceptions.ServerNotOwned + + def findVideoSession(self, client_id, rating_key): + for item in self.sessions: + if item.session and item.session.id == client_id and item.ratingKey == rating_key: + return item + + def buildUrl(self, path, includeToken=False): + if self.activeConnection: + return self.activeConnection.buildUrl(self, path, includeToken) + else: + util.WARN_LOG("Server connection is None, returning an empty url") + return "" + + def query(self, path, method=None, **kwargs): + method = method or self.session.get + + limit = kwargs.pop("limit", None) + params = kwargs.pop("params", None) + if params: + if limit is None: + limit = params.get("limit", None) + path += util.joinArgs(params, '?' not in path) + + offset = kwargs.pop("offset", None) + if kwargs: + path += util.joinArgs(kwargs, '?' not in path) + kwargs.clear() + + url = self.buildUrl(path, includeToken=True) + + # If URL is empty, try refresh resources and return empty set for now + if not url: + util.WARN_LOG("Empty server url, returning None and refreshing resources") + util.MANAGER.refreshResources(True) + return None + + # add offset/limit + offset = offset or 0 + + if limit is not None: + url = http.addUrlParam(url, "X-Plex-Container-Start=%s" % offset) + url = http.addUrlParam(url, "X-Plex-Container-Size=%s" % limit) + + util.LOG('{0} {1}'.format(method.__name__.upper(), re.sub('X-Plex-Token=[^&]+', 'X-Plex-Token=****', url))) + try: + response = method(url, **kwargs) + if response.status_code not in (200, 201): + codename = http.status_codes.get(response.status_code, ['Unknown'])[0] + raise exceptions.BadRequest('({0}) {1}'.format(response.status_code, codename)) + data = response.text.encode('utf8') + except asyncadapter.TimeoutException: + util.ERROR() + util.MANAGER.refreshResources(True) + return None + except (http.requests.ConnectionError, urllib3.exceptions.ProtocolError): + util.ERROR() + return None + except asyncadapter.CanceledException: + return None + + return ElementTree.fromstring(data) if data else None + + def getImageTranscodeURL(self, path, width, height, **extraOpts): + if not path: + return '' + + eOpts = {"minSize": 1, "upscale": 1} + eOpts.update(extraOpts) + + params = ("&width=%s&height=%s" % (width, height)) + ''.join(["&%s=%s" % (key, eOpts[key]) for key in eOpts]) + + if "://" in path: + imageUrl = self.convertUrlToLoopBack(path) + else: + imageUrl = "http://127.0.0.1:" + self.getLocalServerPort() + path + + path = "/photo/:/transcode?url=" + compat.quote_plus(imageUrl) + params + + # Try to use a better server to transcode for synced servers + if self.synced: + from . import plexservermanager + selectedServer = plexservermanager.MANAGER.getTranscodeServer("photo") + if selectedServer: + return selectedServer.buildUrl(path, True) + + if self.activeConnection: + return self.activeConnection.simpleBuildUrl(self, path) + else: + util.WARN_LOG("Server connection is None, returning an empty url") + return "" + + def isReachable(self, onlySupported=True): + if onlySupported and not self.isSupported: + return False + + return self.activeConnection and self.activeConnection.state == plexresource.ResourceConnection.STATE_REACHABLE + + def isLocalConnection(self): + return self.activeConnection and (self.sameNetwork or self.activeConnection.isLocal) + + def isRequestToServer(self, url): + if not self.activeConnection: + return False + + if ':' in self.activeConnection.address[8:]: + schemeAndHost = self.activeConnection.address.rsplit(':', 1)[0] + else: + schemeAndHost = self.activeConnection.address + + return url.startswith(schemeAndHost) + + def getToken(self): + # It's dangerous to use for each here, because it may reset the index + # on self.connections when something else was in the middle of an iteration. + + for i in range(len(self.connections)): + try: + conn = self.connections[i] + except IndexError: + continue + if conn.token: + return conn.token + + return None + + def getLocalServerPort(self): + # TODO(schuyler): The correct thing to do here is to iterate over local + # connections and pull out the port. For now, we're always returning 32400. + + return '32400' + + def collectDataFromRoot(self, data): + # Make sure we're processing data for our server, and not some other + # server that happened to be at the same IP. + if self.uuid != data.attrib.get('machineIdentifier'): + util.LOG("Got a reachability response, but from a different server") + return False + + self.serverClass = data.attrib.get('serverClass') + self.supportsAudioTranscoding = data.attrib.get('transcoderAudio') == '1' + self.supportsVideoTranscoding = data.attrib.get('transcoderVideo') == '1' or data.attrib.get('transcoderVideoQualities') + self.supportsVideoRemuxOnly = data.attrib.get('transcoderVideoRemuxOnly') == '1' + self.supportsPhotoTranscoding = data.attrib.get('transcoderPhoto') == '1' or ( + not data.attrib.get('transcoderPhoto') and not self.synced and not self.isSecondary() + ) + self.allowChannelAccess = data.attrib.get('allowChannelAccess') == '1' or ( + not data.attrib.get('allowChannelAccess') and self.owned and not self.synced and not self.isSecondary() + ) + self.supportsScrobble = not self.isSecondary() or self.synced + self.allowsMediaDeletion = not self.synced and self.owned and data.attrib.get('allowMediaDeletion') == '1' + self.multiuser = data.attrib.get('multiuser') == '1' + self.name = data.attrib.get('friendlyName') or self.name + self.platform = data.attrib.get('platform') + + # TODO(schuyler): Process transcoder qualities + + self.rawVersion = data.attrib.get('version') + if self.rawVersion: + self.versionNorm = util.normalizedVersion(self.rawVersion) + + features = { + 'mkvTranscode': '0.9.11.11', + 'themeTranscode': '0.9.14.0', + 'allPartsStreamSelection': '0.9.12.5', + 'claimServer': '0.9.14.2', + 'streamingBrain': '1.2.0' + } + + for f, v in features.items(): + if util.normalizedVersion(v) <= self.versionNorm: + self.features[f] = True + + appMinVer = util.INTERFACE.getGlobal('minServerVersionArr', '0.0.0.0') + self.isSupported = self.isSecondary() or util.normalizedVersion(appMinVer) <= self.versionNorm + + util.DEBUG_LOG("Server information updated from reachability check: {0}".format(self)) + + return True + + def updateReachability(self, force=True, allowFallback=False): + if not force and self.activeConnection and self.activeConnection.state != plexresource.ResourceConnection.STATE_UNKNOWN: + return + + util.LOG('Updating reachability for {0}: conns={1}, allowFallback={2}'.format(repr(self.name), len(self.connections), allowFallback)) + + epoch = time.time() + retrySeconds = 60 + minSeconds = 10 + for i in range(len(self.connections)): + conn = self.connections[i] + diff = epoch - (conn.lastTestedAt or 0) + if conn.hasPendingRequest: + util.DEBUG_LOG("Skip reachability test for {0} (has pending request)".format(conn)) + elif (diff < minSeconds or (not self.isSecondary() and self.isReachable() and diff < retrySeconds)) and \ + not conn.state == "unauthorized": + util.DEBUG_LOG("Skip reachability test for {0} (checked {1} secs ago)".format(conn, diff)) + elif conn.testReachability(self, allowFallback): + self.pendingReachabilityRequests += 1 + if conn.isSecure: + self.pendingSecureRequests += 1 + + if self.pendingReachabilityRequests == 1: + self.trigger("started:reachability") + + if self.pendingReachabilityRequests <= 0: + self.trigger("completed:reachability") + + def cancelReachability(self): + for i in range(len(self.connections)): + conn = self.connections[i] + conn.cancelReachability() + + def onReachabilityResult(self, connection): + connection.lastTestedAt = time.time() + connection.hasPendingRequest = None + self.pendingReachabilityRequests -= 1 + if connection.isSecure: + self.pendingSecureRequests -= 1 + + util.DEBUG_LOG("Reachability result for {0}: {1} is {2}".format(repr(self.name), connection.address, connection.state)) + + # Noneate active connection if the state is unreachable + if self.activeConnection and self.activeConnection.state != plexresource.ResourceConnection.STATE_REACHABLE: + self.activeConnection = None + + # Pick a best connection. If we already had an active connection and + # it's still reachable, stick with it. (replace with local if + # available) + best = self.activeConnection + for i in range(len(self.connections) - 1, -1, -1): + try: + conn = self.connections[i] + except IndexError: + continue + + util.DEBUG_LOG("Connection score: {0}, {1}".format(conn.address, conn.getScore(True))) + + if not best or conn.getScore() > best.getScore(): + best = conn + + if best and best.state == best.STATE_REACHABLE: + if (best.isSecure or util.LOCAL_OVER_SECURE) or self.pendingSecureRequests <= 0: + util.DEBUG_LOG("Using connection for {0} for now: {1}".format(repr(self.name), best.address)) + self.activeConnection = best + else: + util.DEBUG_LOG("Found a good connection for {0}, but holding out for better".format(repr(self.name))) + + if self.pendingReachabilityRequests <= 0: + # Retest the server with fallback enabled. hasFallback will only + # be True if there are available insecure connections and fallback + # is allowed. + + if self.hasFallback: + self.updateReachability(False, True) + else: + self.trigger("completed:reachability") + + util.LOG("Active connection for {0} is {1}".format(repr(self.name), self.activeConnection)) + + from . import plexservermanager + plexservermanager.MANAGER.updateReachabilityResult(self, bool(self.activeConnection)) + + def markAsRefreshing(self): + for i in range(len(self.connections)): + conn = self.connections[i] + conn.refreshed = False + + def markUpdateFinished(self, source): + # Any connections for the given source which haven't been refreshed should + # be removed. Since removing from a list is hard, we'll make a new list. + toKeep = [] + hasSecureConn = False + + for i in range(len(self.connections)): + try: + conn = self.connections[i] + except IndexError: + util.DEBUG_LOG("Connection lost during iteration") + continue + if not conn.refreshed: + conn.sources = conn.sources & (~source) + + # If we lost our plex.tv connection, don't remember the token. + if source == conn.SOURCE_MYPLEX: + conn.token = None + + if conn.sources: + if conn.address[:5] == "https": + hasSecureConn = True + toKeep.append(conn) + else: + util.DEBUG_LOG("Removed connection {0} for {1} after updating connections for {2}".format(conn, repr(self.name), source)) + if conn == self.activeConnection: + util.DEBUG_LOG("Active connection lost") + self.activeConnection = None + + # Update fallback flag if our connections have changed + if len(toKeep) != len(self.connections): + for conn in toKeep: + conn.isFallback = hasSecureConn and conn.address[:5] != "https" and not util.LOCAL_OVER_SECURE + + self.connections = toKeep + + return len(self.connections) > 0 + + def merge(self, other): + # Wherever this other server came from, assume its information is better + # except for manual connections. + + if other.sourceType != plexresource.ResourceConnection.SOURCE_MANUAL: + self.name = other.name + self.versionNorm = other.versionNorm + self.sameNetwork = other.sameNetwork + + if other.sourceType == plexresource.ResourceConnection.SOURCE_MANUAL and util.LOCAL_OVER_SECURE: + self.sameNetwork = other.sameNetwork + + # Merge connections + for otherConn in other.connections: + merged = False + for i in range(len(self.connections)): + myConn = self.connections[i] + if myConn == otherConn: + myConn.merge(otherConn) + merged = True + break + + if not merged: + self.connections.append(otherConn) + + # If the other server has a token, then it came from plex.tv, which + # means that its ownership information is better than ours. But if + # it was discovered, then it may incorrectly claim to be owned, so + # we stick with whatever we already had. + + if other.getToken(): + self.owned = other.owned + self.owner = other.owner + + def supportsFeature(self, feature): + return feature in self.features + + def getVersion(self): + if not self.versionNorm: + return '' + + return str(self.versionNorm) + + def convertUrlToLoopBack(self, url): + # If the URL starts with our server URL, replace it with 127.0.0.1:32400. + if self.isRequestToServer(url): + url = 'http://127.0.0.1:32400/' + url.split('://', 1)[-1].split('/', 1)[-1] + return url + + def resetLastTest(self): + for i in range(len(self.connections)): + conn = self.connections[i] + conn.lastTestedAt = None + + def isSecondary(self): + return self.serverClass == "secondary" + + def getLibrarySectionByUuid(self, uuid=None): + if not uuid: + return None + return self.librariesByUuid[uuid] + + def setLibrarySectionByUuid(self, uuid, library): + self.librariesByUuid[uuid] = library + + def hasInsecureConnections(self): + if util.INTERFACE.getPreference('allow_insecure') == 'always': + return False + + # True if we have any insecure connections we have disallowed + for i in range(len(self.connections)): + conn = self.connections[i] + if not conn.isSecure and conn.state == conn.STATE_INSECURE: + return True + + return False + + def hasSecureConnections(self): + for i in range(len(self.connections)): + conn = self.connections[i] + if conn.isSecure: + return True + + return False + + def getLibrarySectionPrefs(self, uuid): + # TODO: Make sure I did this right - ruuk + librarySection = self.getLibrarySectionByUuid(uuid) + + if librarySection and librarySection.key: + # Query and store the prefs only when asked for. We could just return the + # items, but it'll be more useful to store the pref ids in an associative + # array for ease of selecting the pref we need. + + if not librarySection.sectionPrefs: + path = "/library/sections/{0}/prefs".format(librarySection.key) + data = self.query(path) + if data: + librarySection.sectionPrefs = {} + for elem in data: + item = plexobjects.buildItem(self, elem, path) + if item.id: + librarySection.sectionPrefs[item.id] = item + + return librarySection.sectionPrefs + + return None + + def swizzleUrl(self, url, includeToken=False): + m = re.search(r"^\w+://.+?(/.+)", url) + newUrl = m and m.group(1) or None + return self.buildUrl(newUrl or url, includeToken) + + def hasHubs(self): + return self.platform != 'cloudsync' + + @property + def address(self): + return self.activeConnection.address + + @classmethod + def deSerialize(cls, jstring): + try: + serverObj = json.loads(jstring) + except: + util.ERROR() + util.ERROR_LOG("Failed to deserialize PlexServer JSON") + return + + from . import plexconnection + + server = createPlexServerForName(serverObj['uuid'], serverObj['name']) + server.owned = bool(serverObj.get('owned')) + server.sameNetwork = serverObj.get('sameNetwork') + + hasSecureConn = False + for i in range(len(serverObj.get('connections', []))): + conn = serverObj['connections'][i] + if conn['address'][:5] == "https": + hasSecureConn = True + break + + for i in range(len(serverObj.get('connections', []))): + conn = serverObj['connections'][i] + isFallback = hasSecureConn and conn['address'][:5] != "https" and not util.LOCAL_OVER_SECURE + sources = plexconnection.PlexConnection.SOURCE_BY_VAL[conn['sources']] + connection = plexconnection.PlexConnection(sources, conn['address'], conn['isLocal'], conn['token'], isFallback) + + # Keep the secure connection on top + if connection.isSecure and not util.LOCAL_OVER_SECURE: + server.connections.insert(0, connection) + elif not connection.isSecure and util.LOCAL_OVER_SECURE: + server.connections.insert(0, connection) + else: + server.connections.append(connection) + + if conn.get('active'): + server.activeConnection = connection + + return server + + def serialize(self, full=False): + serverObj = { + 'name': self.name, + 'uuid': self.uuid, + 'owned': self.owned, + 'connections': [] + } + + if full: + for conn in self.connections: + serverObj['connections'].append({ + 'sources': conn.sources, + 'address': conn.address, + 'isLocal': conn.isLocal, + 'isSecure': conn.isSecure, + 'token': conn.token + }) + if conn == self.activeConnection: + serverObj['connections'][-1]['active'] = True + else: + serverObj['connections'] = [{ + 'sources': self.activeConnection.sources, + 'address': self.activeConnection.address, + 'isLocal': self.activeConnection.isLocal, + 'isSecure': self.activeConnection.isSecure, + 'token': self.activeConnection.token or self.getToken(), + 'active': True + }] + + return json.dumps(serverObj) + + +def dummyPlexServer(): + return createPlexServer() + + +def createPlexServer(): + return PlexServer() + + +def createPlexServerForConnection(conn): + obj = createPlexServer() + obj.connections.append(conn) + obj.activeConnection = conn + return obj + + +def createPlexServerForName(uuid, name): + obj = createPlexServer() + obj.uuid = uuid + obj.name = name + return obj + + +def createPlexServerForResource(resource): + # resource.__class__ = PlexServer + # resource.server = resource + # resource.session = http.Session() + return resource diff --git a/script.plexmod/lib/_included_packages/plexnet/plexservermanager.py b/script.plexmod/lib/_included_packages/plexnet/plexservermanager.py new file mode 100644 index 0000000000..4738a55ce7 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexservermanager.py @@ -0,0 +1,651 @@ +from __future__ import absolute_import +import json + +from . import http +from . import plexconnection +from . import plexresource +from . import plexserver +from . import signalsmixin +from . import callback +from . import plexapp +from . import gdm +from . import util +from six.moves import range + + +class SearchContext(dict): + def __getattr__(self, attr): + return self.get(attr) + + def __setattr__(self, attr, value): + self[attr] = value + + +class PlexServerManager(signalsmixin.SignalsMixin): + def __init__(self): + signalsmixin.SignalsMixin.__init__(self) + # obj.Append(ListenersMixin()) + self.serversByUuid = {} + self.selectedServer = None + self.transcodeServer = None + self.channelServer = None + self.deferReachabilityTimer = None + + self.startSelectedServerSearch() + self.loadState() + + plexapp.util.APP.on("change:user", callback.Callable(self.onAccountChange)) + plexapp.util.APP.on("change:allow_insecure", callback.Callable(self.onSecurityChange)) + plexapp.util.APP.on("change:manual_connections", callback.Callable(self.onManualConnectionChange)) + + def getSelectedServer(self): + return self.selectedServer + + def setSelectedServer(self, server, force=False): + # Don't do anything if the server is already selected. + if self.selectedServer and self.selectedServer == server: + return False + + if server: + # Don't select servers that don't have connections. + if not server.activeConnection: + return False + + # Don't select servers that are not supported + if not server.isSupported: + return False + + if not self.selectedServer or force: + util.LOG("Setting selected server to {0}".format(server)) + self.selectedServer = server + + # Update our saved state. + self.saveState(setPreferred=True) + + # Notify anyone who might care. + util.APP.trigger("change:selectedServer", server=server) + + return True + + return False + + def getServer(self, uuid=None): + if uuid is None: + return None + elif uuid == "myplex": + from . import myplexserver + return myplexserver.MyPlexServer() + else: + return self.serversByUuid[uuid] + + def getServers(self): + servers = [] + for uuid in list(self.serversByUuid.keys()): + if uuid != "myplex": + servers.append(self.serversByUuid[uuid]) + + return servers + + def hasPendingRequests(self): + for server in self.getServers(): + if server.pendingReachabilityRequests: + return True + + return False + + def removeServer(self, server): + del self.serversByUuid[server.uuid] + + self.trigger('remove:server') + + if server == self.selectedServer: + util.LOG("The selected server went away") + self.setSelectedServer(None, force=True) + + if server == self.transcodeServer: + util.LOG("The selected transcode server went away") + self.transcodeServer = None + + if server == self.channelServer: + util.LOG("The selected channel server went away") + self.channelServer = None + + def updateFromConnectionType(self, servers, source): + self.markDevicesAsRefreshing() + + for server in servers: + self.mergeServer(server) + + if self.searchContext and source in self.searchContext.waitingForResources: + #self.searchContext.waitingForResources = False + self.searchContext.waitingForResources.remove(source) + + if not self.searchContext.waitingForResources: + self.deviceRefreshComplete(source) + self.updateReachability(True, True) + self.saveState() + + def updateFromDiscovery(self, server): + merged = self.mergeServer(server) + + if not merged.activeConnection: + merged.updateReachability(False, True) + else: + # self.notifyAboutDevice(merged, True) + pass + + def markDevicesAsRefreshing(self): + for uuid in list(self.serversByUuid.keys()): + self.serversByUuid[uuid].markAsRefreshing() + + def mergeServer(self, server): + if server.uuid in self.serversByUuid: + existing = self.serversByUuid[server.uuid] + existing.merge(server) + util.DEBUG_LOG("Merged {0}".format(repr(server.name))) + return existing + else: + self.serversByUuid[server.uuid] = server + util.DEBUG_LOG("Added new server {0}".format(repr(server.name))) + self.trigger("new:server", server=server) + return server + + def deviceRefreshComplete(self, source): + toRemove = [] + for uuid in list(self.serversByUuid.keys()): + if not self.serversByUuid[uuid].markUpdateFinished(source): + toRemove.append(uuid) + + for uuid in toRemove: + if uuid not in self.serversByUuid: + util.DEBUG_LOG("Server {} lost - removing".format(uuid)) + continue + + server = self.serversByUuid[uuid] + + util.DEBUG_LOG("Server {0} has no more connections - removing".format(repr(server.name))) + # self.notifyAboutDevice(server, False) + self.removeServer(server) + + def updateReachability(self, force=False, preferSearch=False, defer=False): + # We don't need to test any servers unless we are signed in and authenticated. + if not plexapp.ACCOUNT.isAuthenticated and plexapp.ACCOUNT.isActive(): + util.LOG("Ignore testing server reachability until we're authenticated") + return + + # To improve reachability performance and app startup, we'll try to test the + # preferred server first, and defer the connection tests for a few seconds. + + hasPreferredServer = bool(self.searchContext.preferredServer) + preferredServerExists = hasPreferredServer and self.searchContext.preferredServer in self.serversByUuid + + if preferSearch and hasPreferredServer and preferredServerExists: + # Update the preferred server immediately if requested and exits + util.LOG("Updating reachability for preferred server: force={0}".format(force)) + self.serversByUuid[self.searchContext.preferredServer].updateReachability(force) + self.deferUpdateReachability() + elif defer: + self.deferUpdateReachability() + elif hasPreferredServer and not preferredServerExists and gdm.DISCOVERY.isActive(): + # Defer the update if requested or if GDM discovery is enabled and + # active while the preferred server doesn't exist. + + util.LOG("Defer update reachability until GDM has finished to help locate the preferred server") + self.deferUpdateReachability(True, False) + else: + if self.deferReachabilityTimer: + self.deferReachabilityTimer.cancel() + self.deferReachabilityTimer = None + + util.LOG("Updating reachability for all devices: force={0}".format(force)) + for uuid in list(self.serversByUuid.keys()): + self.serversByUuid[uuid].updateReachability(force) + + def cancelReachability(self): + if self.deferReachabilityTimer: + self.deferReachabilityTimer.cancel() + self.deferReachabilityTimer = None + + for uuid in list(self.serversByUuid.keys()): + self.serversByUuid[uuid].cancelReachability() + + def updateReachabilityResult(self, server, reachable=False): + searching = not self.selectedServer and self.searchContext + + if reachable: + # If we're in the middle of a search for our selected server, see if + # this is a candidate. + self.trigger('reachable:server', server=server) + if searching: + # If this is what we were hoping for, select it + if server.uuid == self.searchContext.preferredServer: + self.setSelectedServer(server, True) + elif server.synced: + self.searchContext.fallbackServer = server + elif self.compareServers(self.searchContext.bestServer, server) < 0: + self.searchContext.bestServer = server + else: + # If this is what we were hoping for, see if there are any more pending + # requests to hope for. + + if searching and server.uuid == self.searchContext.preferredServer and server.pendingReachabilityRequests <= 0: + self.searchContext.preferredServer = None + + if server == self.selectedServer: + util.LOG("Selected server is not reachable") + self.setSelectedServer(None, True) + + if server == self.transcodeServer: + util.LOG("The selected transcode server is not reachable") + self.transcodeServer = None + + if server == self.channelServer: + util.LOG("The selected channel server is not reachable") + self.channelServer = None + + # See if we should settle for the best we've found so far. + self.checkSelectedServerSearch() + + def checkSelectedServerSearch(self, skip_preferred=False, skip_owned=False): + if self.selectedServer: + return self.selectedServer + elif self.searchContext: + # If we're still waiting on the resources response then there's no + # reason to settle, so don't even iterate over our servers. + + if self.searchContext.waitingForResources: + util.DEBUG_LOG("Still waiting for plex.tv resources") + return + + waitingForPreferred = False + waitingForOwned = False + waitingForAnything = False + waitingToTestAll = bool(self.deferReachabilityTimer) + + if skip_preferred: + self.searchContext.preferredServer = None + if self.deferReachabilityTimer: + self.deferReachabilityTimer.cancel() + self.deferReachabilityTimer = None + + if not skip_owned: + # Iterate over all our servers and see if we're waiting on any results + servers = self.getServers() + pendingCount = 0 + for server in servers: + if server.pendingReachabilityRequests > 0: + pendingCount += server.pendingReachabilityRequests + if server.uuid == self.searchContext.preferredServer: + waitingForPreferred = True + elif server.owned: + waitingForOwned = True + else: + waitingForAnything = True + + pendingString = "{0} pending reachability tests".format(pendingCount) + + if waitingForPreferred: + util.LOG("Still waiting for preferred server: " + pendingString) + elif waitingToTestAll: + util.LOG("Preferred server not reachable, testing all servers now") + self.updateReachability(True, False, False) + elif waitingForOwned and (not self.searchContext.bestServer or not self.searchContext.bestServer.owned): + util.LOG("Still waiting for an owned server: " + pendingString) + elif waitingForAnything and not self.searchContext.bestServer: + util.LOG("Still waiting for any server: {0}".format(pendingString)) + else: + # No hope for anything better, let's select what we found + util.LOG("Settling for the best server we found") + self.setSelectedServer(self.searchContext.bestServer or self.searchContext.fallbackServer, True) + return self.selectedServer + + def compareServers(self, first, second): + if not first or not first.isSupported: + return second and -1 or 0 + elif not second: + return 1 + elif first.owned != second.owned: + return first.owned and 1 or -1 + elif first.isLocalConnection() != second.isLocalConnection(): + return first.isLocalConnection() and 1 or -1 + else: + return 0 + + def loadState(self): + jstring = util.INTERFACE.getRegistry("PlexServerManager") + if not jstring: + return + + try: + obj = json.loads(jstring) + except: + util.ERROR() + obj = None + + if not obj: + util.ERROR_LOG("Failed to parse PlexServerManager JSON") + return + + for serverObj in obj['servers']: + server = plexserver.createPlexServerForName(serverObj['uuid'], serverObj['name']) + server.owned = bool(serverObj.get('owned')) + server.sameNetwork = serverObj.get('sameNetwork') + + hasSecureConn = False + for i in range(len(serverObj.get('connections', []))): + conn = serverObj['connections'][i] + if conn['address'][:5] == "https": + hasSecureConn = True + break + + for i in range(len(serverObj.get('connections', []))): + conn = serverObj['connections'][i] + isFallback = hasSecureConn and conn['address'][:5] != "https" and not util.LOCAL_OVER_SECURE + sources = plexconnection.PlexConnection.SOURCE_BY_VAL[conn['sources']] + connection = plexconnection.PlexConnection(sources, conn['address'], conn['isLocal'], conn['token'], isFallback) + + # Keep the secure connection on top + if connection.isSecure and not util.LOCAL_OVER_SECURE: + server.connections.insert(0, connection) + elif not connection.isSecure and util.LOCAL_OVER_SECURE: + server.connections.insert(0, connection) + else: + server.connections.append(connection) + + self.serversByUuid[server.uuid] = server + + util.LOG("Loaded {0} servers from registry".format(len(obj['servers']))) + self.updateReachability(False, True) + + def saveState(self, setPreferred=False): + # Serialize our important information to JSON and save it to the registry. + # We'll always update server info upon connecting, so we don't need much + # info here. We do have to use roArray instead of roList, because Brightscript. + + obj = {} + + servers = self.getServers() + obj['servers'] = [] + + for server in servers: + # Don't save secondary servers. They should be discovered through GDM or myPlex. + if not server.isSecondary(): + serverObj = { + 'name': server.name, + 'uuid': server.uuid, + 'owned': server.owned, + 'sameNetwork': server.sameNetwork, + 'connections': [] + } + + for i in range(len(server.connections)): + conn = server.connections[i] + serverObj['connections'].append({ + 'sources': conn.sources, + 'address': conn.address, + 'isLocal': conn.isLocal, + 'isSecure': conn.isSecure, + 'token': conn.token + }) + + obj['servers'].append(serverObj) + + if self.selectedServer and not self.selectedServer.synced and not self.selectedServer.isSecondary() \ + and setPreferred: + util.INTERFACE.setPreference("lastServerId.{}".format(plexapp.ACCOUNT.ID), self.selectedServer.uuid) + + util.INTERFACE.setRegistry("PlexServerManager", json.dumps(obj)) + + def clearState(self): + util.INTERFACE.setRegistry("PlexServerManager", '') + + def isValidForTranscoding(self, server): + return server and server.activeConnection and server.owned and not server.synced and not server.isSecondary() + + def getChannelServer(self): + if not self.channelServer or not self.channelServer.isReachable(): + self.channelServer = None + + # Attempt to find a server that supports channels and transcoding + for s in self.getServers(): + if s.supportsVideoTranscoding and s.allowChannelAccess and s.isReachable() and self.compareServers(self.channelServer, s) < 0: + self.channelServer = s + + # Fallback to any server that supports channels + if not self.channelServer: + for s in self.getServers(): + if s.allowChannelAccess and s.isReachable() and self.compareServers(self.channelServer, s) < 0: + self.channelServer = s + + if self.channelServer: + util.LOG("Setting channel server to {0}".format(self.channelServer)) + + return self.channelServer + + def getTranscodeServer(self, transcodeType=None): + if not self.selectedServer: + return None + + transcodeMap = { + 'audio': "supportsAudioTranscoding", + 'video': "supportsVideoTranscoding", + 'photo': "supportsPhotoTranscoding" + } + transcodeSupport = transcodeMap[transcodeType] + + # Try to use a better transcoding server for synced or secondary servers + if self.selectedServer.synced or self.selectedServer.isSecondary(): + if self.transcodeServer and self.transcodeServer.isReachable(): + return self.transcodeServer + + self.transcodeServer = None + for server in self.getServers(): + if not server.synced and server.isReachable() and self.compareServers(self.transcodeServer, server) < 0: + if not transcodeSupport or server.transcodeSupport: + self.transcodeServer = server + + if self.transcodeServer: + transcodeTypeString = transcodeType or '' + util.LOG("Found a better {0} transcode server than {1}, using: {2}".format(transcodeTypeString, self.selectedserver, self.transcodeServer)) + return self.transcodeServer + + return self.selectedServer + + def startSelectedServerSearch(self, reset=False, ID=None): + if reset: + self.selectedServer = None + self.transcodeServer = None + self.channelServer = None + + ID = ID is not None and ID or plexapp.ACCOUNT.ID + pServ = util.INTERFACE.getPreference("lastServerId.{}".format(ID), '') + util.DEBUG_LOG("Preferred server for {0} is: {1}".format(ID, pServ)) + # Keep track of some information during our search + + waitFor = [] + if plexapp.ACCOUNT.isSignedIn: + waitFor.append(plexresource.ResourceConnection.SOURCE_MYPLEX) + + if util.LOCAL_OVER_SECURE and self.getManualConnections(): + waitFor.append(plexresource.ResourceConnection.SOURCE_MANUAL) + + self.searchContext = SearchContext({ + 'bestServer': None, + 'preferredServer': pServ, + 'waitingForResources': waitFor + }) + + util.LOG("Starting selected server search, hoping for {0}".format(self.searchContext.preferredServer)) + if util.LOCAL_OVER_SECURE: + util.WARN_LOG("Preferring local server connections over secure ones!") + + def onAccountChange(self, account, reallyChanged=False): + # Clear any AudioPlayer data before invalidating the active server + if reallyChanged: + # AudioPlayer().Cleanup() + # PhotoPlayer().Cleanup() + + util.DEBUG_LOG("Account really changed, clearing all servers") + + # Clear selected and transcode servers on user change + self.selectedServer = None + self.transcodeServer = None + self.channelServer = None + self.cancelReachability() + + if account.isSignedIn: + # If the user didn't really change, such as selecting the previous user + # on the lock screen, then we don't need to clear anything. We can + # avoid a costly round of reachability checks. + + if not reallyChanged: + return + + # A request to refresh resources has already been kicked off. We need + # to clear out any connections for the previous user and then start + # our selected server search. + + self.updateFromConnectionType([], plexresource.ResourceConnection.SOURCE_MYPLEX) + self.updateFromConnectionType([], plexresource.ResourceConnection.SOURCE_DISCOVERED) + self.updateFromConnectionType([], plexresource.ResourceConnection.SOURCE_MANUAL) + + self.startSelectedServerSearch(True, ID=account.ID) + + if reallyChanged: + util.DEBUG_LOG("User really changed, refreshing resources now") + plexapp.refreshResources() + else: + # Clear servers/connections from plex.tv + self.updateFromConnectionType([], plexresource.ResourceConnection.SOURCE_MYPLEX) + + def deferUpdateReachability(self, addTimer=True, logInfo=True): + if addTimer and not self.deferReachabilityTimer: + self.deferReachabilityTimer = plexapp.createTimer(1000, callback.Callable(self.onDeferUpdateReachabilityTimer), repeat=True) + util.APP.addTimer(self.deferReachabilityTimer) + else: + if self.deferReachabilityTimer: + self.deferReachabilityTimer.reset() + + if self.deferReachabilityTimer and logInfo: + util.LOG('Defer update reachability for all devices a few seconds: GDMactive={0}'.format(gdm.DISCOVERY.isActive())) + + def onDeferUpdateReachabilityTimer(self): + if not self.selectedServer and self.searchContext: + for server in self.getServers(): + if server.pendingReachabilityRequests > 0 and server.uuid == self.searchContext.preferredServer: + util.DEBUG_LOG( + 'Still waiting on {0} responses from preferred server: {1}'.format( + server.pendingReachabilityRequests, self.searchContext.preferredServer + ) + ) + return + + if self.deferReachabilityTimer: + self.deferReachabilityTimer.cancel() + self.deferReachabilityTimer = None + self.updateReachability(True, False, False) + + def resetLastTest(self): + for uuid in list(self.serversByUuid.keys()): + self.serversByUuid[uuid].resetLastTest() + + def clearServers(self): + self.cancelReachability() + self.serversByUuid = {} + self.saveState() + + def onSecurityChange(self, value=None): + # If the security policy changes, then we will need to allow all + # connections to be retested by resetting the last test. We can + # simply call `self.resetLastTest()` to allow all connection to be + # tested when the server dropdown is enable, but we may as well + # test all the connections immediately. + + plexapp.refreshResources(True) + + def onManualConnectionChange(self, value=None): + # Clear all manual connections on change. We will keep the selected + # server around temporarily if it's a manual connection regardless + # if it's been removed. + + # Remember the current server in case it's removed + server = self.getSelectedServer() + activeConn = [] + if server and server.activeConnection: + activeConn.append(server.activeConnection) + + # Clear all manual connections + self.updateFromConnectionType([], plexresource.ResourceConnection.SOURCE_MANUAL) + + # Reused the previous selected server if our manual connection has gone away + if not self.getSelectedServer() and activeConn.sources == plexresource.ResourceConnection.SOURCE_MANUAL: + server.activeConnection = activeConn + server.connections.append(activeConn) + self.setSelectedServer(server, True) + + def refreshManualConnections(self): + manualConnections = self.getManualConnections() + if not manualConnections: + util.DEBUG_LOG("No manual connections.") + return + + util.LOG("Refreshing {0} manual connections".format(len(manualConnections))) + + for conn in manualConnections: + # Default to http, as the server will need to be signed in for https to work, + # so the client should too. We'd also have to allow hostname entry, instead of + # IP address for the cert to validate. + + proto = "http" + port = conn.port or "32400" + serverAddress = "{0}://{1}:{2}".format(proto, conn.connection, port) + + request = http.HttpRequest(serverAddress + "/identity") + context = request.createRequestContext("manual_connections", callback.Callable(self.onManualConnectionsResponse)) + context.serverAddress = serverAddress + context.address = conn.connection + context.proto = proto + context.port = port + util.APP.startRequest(request, context) + + def onManualConnectionsResponse(self, request, response, context): + if not response.isSuccess(): + return + + data = response.getBodyXml() + if data is not None: + serverAddress = context.serverAddress + util.DEBUG_LOG("Received manual connection response for {0}".format(serverAddress)) + + machineID = data.attrib.get('machineIdentifier') + name = context.address + if not name or not machineID: + return + + # TODO(rob): Do we NOT want to consider manual connections local? + conn = plexconnection.PlexConnection(plexresource.ResourceConnection.SOURCE_MANUAL, serverAddress, True, None) + server = plexserver.createPlexServerForConnection(conn) + server.uuid = machineID + server.name = name + server.sourceType = plexresource.ResourceConnection.SOURCE_MANUAL + self.updateFromConnectionType([server], plexresource.ResourceConnection.SOURCE_MANUAL) + + def getManualConnections(self): + manualConnections = [] + + jstring = util.INTERFACE.getPreference('manual_connections') + if jstring: + connections = json.loads(jstring) + if isinstance(connections, list): + for conn in connections: + conn = util.AttributeDict(conn) + if conn.connection: + manualConnections.append(conn) + + return manualConnections + +# TODO(schuyler): Notifications +# TODO(schuyler): Transcode (and primary) server selection + + +MANAGER = PlexServerManager() diff --git a/script.plexmod/lib/_included_packages/plexnet/plexstream.py b/script.plexmod/lib/_included_packages/plexnet/plexstream.py new file mode 100644 index 0000000000..33b5352f60 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/plexstream.py @@ -0,0 +1,195 @@ +from __future__ import absolute_import +from . import plexobjects +from . import util + + +class PlexStream(plexobjects.PlexObject): + # Constants + TYPE_UNKNOWN = 0 + TYPE_VIDEO = 1 + TYPE_AUDIO = 2 + TYPE_SUBTITLE = 3 + TYPE_LYRICS = 4 + + streamTypeNames = ( + "Unknown", "VideoStream", "AudioStream", "SubtitleStream", "LyricsStream" + ) + + # We have limited font support, so make a very modest effort at using + # English names for common unsupported languages. + + SAFE_LANGUAGE_NAMES = { + 'ara': "Arabic", + 'arm': "Armenian", + 'bel': "Belarusian", + 'ben': "Bengali", + 'bul': "Bulgarian", + 'chi': "Chinese", + 'cze': "Czech", + 'gre': "Greek", + 'heb': "Hebrew", + 'hin': "Hindi", + 'jpn': "Japanese", + 'kor': "Korean", + 'rus': "Russian", + 'srp': "Serbian", + 'tha': "Thai", + 'ukr': "Ukrainian", + 'yid': "Yiddish" + } + + def reload(self): + pass + + def getTitle(self, translate_func=util.dummyTranslate): + streamType = self.streamType.asInt() + + if streamType == self.TYPE_SUBTITLE \ + and util.INTERFACE.getPreference('subtitle_use_extended_title', True) \ + and self.extendedDisplayTitle: + return self.extendedDisplayTitle + + title = self.getLanguageName(translate_func) + + if streamType == self.TYPE_VIDEO: + title = self.getCodec() or translate_func("Unknown") + elif streamType == self.TYPE_AUDIO: + codec = self.getCodec() + channels = self.getChannels(translate_func) + + if codec != "" and channels != "": + title += u" ({0} {1})".format(codec, channels) + elif codec != "" or channels != "": + title += u" ({0}{1})".format(codec, channels) + elif streamType == self.TYPE_SUBTITLE: + extras = [] + + codec = self.getCodec() + if codec: + extras.append(codec) + + if self.sdh: + title += " {}".format(translate_func("SDH")) + + if not self.key: + extras.append(translate_func("Embedded")) + + if self.forced.asBool(): + extras.append(translate_func("Forced")) + + if len(extras) > 0: + title += u" ({0})".format('/'.join(extras)) + elif streamType == self.TYPE_LYRICS: + title = translate_func("Lyrics") + if self.format: + title += u" ({0})".format(self.format) + + return title + + def getCodec(self): + codec = (self.codec or '').lower() + + if codec in ('dca', 'dca-ma', 'dts-hd', 'dts-es', 'dts-hra'): + codec = "DTS" + else: + codec = codec.upper() + + return codec + + def getChannels(self, translate_func=util.dummyTranslate): + channels = self.channels.asInt() + + if channels == 1: + return translate_func("Mono") + elif channels == 2: + return translate_func("Stereo") + elif channels > 0: + return "{0}.1".format(channels - 1) + else: + return "" + + def getLanguageName(self, translate_func=util.dummyTranslate): + code = self.languageCode + + if not code: + return translate_func("Unknown") + + return self.SAFE_LANGUAGE_NAMES.get(code) or self.language or "Unknown" + + def getSubtitlePath(self): + query = "?encoding=utf-8" + + if self.codec == "smi": + query += "&format=srt" + + return self.key + query + + def getSubtitleServerPath(self): + if not self.key: + return None + + return self.getServer().buildUrl(self.getSubtitlePath(), True) + + @property + def embedded(self): + return not bool(self.getSubtitleServerPath()) + + def isSelected(self): + return self.selected.asBool() + + def setSelected(self, selected): + self.selected = plexobjects.PlexValue(selected and '1' or '0') + + @property + def sdh(self): + return self.hearingImpaired or "SDH" in self.title or "SDH" in self.displayTitle \ + or "SDH" in self.extendedDisplayTitle + + @property + def videoCodecRendering(self): + render = "sdr" + + if self.colorTrc == "smpte2084": + if self.DOVIProfile == "8" and self.DOVIBLCompatID == "1": + render = "dv/hdr10" + elif self.DOVIProfile: + render = "dv" + else: + render = "hdr" + elif self.colorTrc == "arib-std-b67": + render = "hlg" + + return render.upper() + + def __str__(self): + return self.getTitle() + + def __repr__(self): + return '<{}: {}>'.format(self.streamTypeNames[self.streamType.asInt()], str(self)) + + def __eq__(self, other): + if not other: + return False + + if self.__class__ != other.__class__: + return False + + for attr in ("streamType", "language", "codec", "channels", "index", "key"): + if getattr(self, attr) != getattr(other, attr): + return False + return True + + +# Synthetic subtitle stream for 'none' + +class NoneStream(PlexStream): + def __init__(self, *args, **kwargs): + PlexStream.__init__(self, None, *args, **kwargs) + self.id = plexobjects.PlexValue("0") + self.streamType = plexobjects.PlexValue(str(self.TYPE_SUBTITLE)) + + def getTitle(self, translate_func=util.dummyTranslate): + return translate_func("None") + + +NONE_STREAM = NoneStream() diff --git a/script.plexmod/lib/_included_packages/plexnet/serverdecision.py b/script.plexmod/lib/_included_packages/plexnet/serverdecision.py new file mode 100644 index 0000000000..e1a5344c62 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/serverdecision.py @@ -0,0 +1,102 @@ +from __future__ import absolute_import +from . import mediachoice +from . import util + + +class DecisionFailure(Exception): + def __init__(self, code, reason): + self.code = code + self.reason = reason + + +class ServerDecision(object): + DECISION_DIRECT_PLAY = "directplay" + DECISION_COPY = "copy" + DECISION_TRANSCODE = "transcode" + DIRECT_PLAY_OK = 1000 + TRANSCODE_OK = 1001 + + def __init__(self, original, response, player): + self.original = original + self.response = response + self.player = player + self.item = None + + self.init() + + def init(self): + self.isSupported = self.response.server.supportsFeature("streamingBrain") + for item in self.response.items: + if item and item.media: + self.item = item + self.original.transcodeDecision = mediachoice.MediaChoice(self.item.media[0]) + + # Decision codes and text + self.decisionsCodes = {} + self.decisionsTexts = {} + for key in ["directPlayDecision", "generalDecision", "mdeDecision", "transcodeDecision", "termination"]: + self.decisionsCodes[key] = self.response.container.get(key + "Code", "-1").asInt() + self.decisionsTexts[key] = self.response.container.get(key + "Text") + + util.DEBUG_LOG("Decision codes: {0}".format(self.decisionsCodes)) + + def __str__(self): + if self.isSupported: + obj = [] + for v in self.decisionsTexts.values(): + if v: + obj.append(v) + return ' '.join(obj) + else: + return "Server version does not support decisions." + + def __repr__(self): + return self.__str__() + + def getDecision(self, requireDecision=True): + if not self.item: + # Return no decision. The player will either continue with the original + # or terminate if a valid decision was required. + + if requireDecision: + # Terminate the player by default if there was no decision returned. + code = self.decisionsCodes["generalDecision"] + reason = ' '.join([self.decisionsTexts["transcodeDecision"], self.decisionsTexts["generalDecision"]]) + raise DecisionFailure(code, reason) + + return None + + # Rebuild the original item with the new item. + util.WARN_LOG("Server requested new playback decision: {0}".format(self)) + self.original.rebuild(self.item, self) + return self.original + + def isSuccess(self): + code = self.decisionsCodes["mdeDecision"] + return not self.isSupported or 1000 <= code < 2000 + + def isDecision(self, requireItem=False): + # Server has provided a valid decision if there was a valid decision code + # or if the response returned zero items (could not play). + return self.isSupported and (self.decisionsCodes["mdeDecision"] > -1 or requireItem and not self.item) + + def isTimelineDecision(self): + return self.isSupported and self.item + + def isTermination(self): + return self.isSupported and self.decisionsCodes["termination"] > -1 + + def directPlayOK(self): + return self.decisionsCodes["mdeDecision"] == 1000 + + def getTermination(self): + return { + 'code': str(self.decisionsCodes["termination"]), + 'text': self.decisionsTexts["termination"] or "Unknown" # TODO: Translate Unknown + } + + def getDecisionText(self): + for key in ["mdeDecision", "directPlayDecision", "generalDecision", "transcodeDecision"]: + if self.decisionsTexts.get(key): + return self.decisionsTexts[key] + return None diff --git a/script.plexmod/lib/_included_packages/plexnet/signalslot/__init__.py b/script.plexmod/lib/_included_packages/plexnet/signalslot/__init__.py new file mode 100644 index 0000000000..b9c234ff34 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/signalslot/__init__.py @@ -0,0 +1,11 @@ +from __future__ import absolute_import +try: + from .signal import Signal + from .slot import Slot + from .exceptions import * +except ImportError: # pragma: no cover + # Possible we are running from setup.py, in which case we're after + # the __version__ string only. + pass + +__version__ = '0.1.1' diff --git a/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/__init__.py b/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/__init__.py b/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/__init__.py new file mode 100644 index 0000000000..280e6a2ad4 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/__init__.py @@ -0,0 +1 @@ +from .task import Task diff --git a/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/task.py b/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/task.py new file mode 100644 index 0000000000..b6c81c1d25 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/task.py @@ -0,0 +1,76 @@ +from __future__ import absolute_import +import sys +import eventlet +import contexter +import six + + +class Task(object): + @classmethod + def get_or_create(cls, signal, kwargs=None, logger=None): + if not hasattr(cls, '_registry'): + cls._registry = [] + + task = cls(signal, kwargs, logger=logger) + + if task not in cls._registry: + cls._registry.append(task) + + return cls._registry[cls._registry.index(task)] + + def __init__(self, signal, kwargs=None, logger=None): + self.signal = signal + self.kwargs = kwargs or {} + self.logger = logger + self.failures = 0 + self.task_semaphore = eventlet.semaphore.BoundedSemaphore(1) + + def __call__(self, semaphores=None): + semaphores = semaphores or [] + + with contexter.Contexter(self.task_semaphore, *semaphores): + result = self._do() + + if result: + self.failures = 0 + else: + self.failures += 1 + + return result + + def _do(self): + try: + self._emit() + except Exception: + self._exception(*sys.exc_info()) + return False + else: + self._completed() + return True + finally: + self._clean() + + def _clean(self): + pass + + def _completed(self): + if self.logger: + self.logger.info('[%s] Completed' % self) + + def _exception(self, e_type, e_value, e_traceback): + if self.logger: + self.logger.exception('[%s] Raised exception: %s' % ( + self, e_value)) + else: + six.reraise(e_type, e_value, e_traceback) + + def _emit(self): + if self.logger: + self.logger.info('[%s] Running' % self) + self.signal.emit(**self.kwargs) + + def __eq__(self, other): + return (self.signal == other.signal and self.kwargs == other.kwargs) + + def __str__(self): + return '%s: %s' % (self.signal.__class__.__name__, self.kwargs) diff --git a/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/test.py b/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/test.py new file mode 100644 index 0000000000..c356408723 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/signalslot/contrib/task/test.py @@ -0,0 +1,185 @@ +from __future__ import absolute_import +import pytest +import mock +import logging +import eventlet +import time +from signalslot import Signal +from signalslot.contrib.task import Task + +eventlet.monkey_patch(time=True) + + +class TestTask(object): + def setup_method(self, method): + self.signal = mock.Mock() + + def get_task_mock(self, *methods, **kwargs): + if kwargs.get('logger'): + log = logging.getLogger('TestTask') + else: + log = None + task_mock = Task(self.signal, logger=log) + + for method in methods: + setattr(task_mock, method, mock.Mock()) + + return task_mock + + def test_eq(self): + x = Task(self.signal, dict(some_kwarg='foo'), + logger=logging.getLogger('TaskX')) + y = Task(self.signal, dict(some_kwarg='foo'), + logger=logging.getLogger('TaskY')) + + assert x == y + + def test_not_eq(self): + x = Task(self.signal, dict(some_kwarg='foo', + logger=logging.getLogger('TaskX'))) + y = Task(self.signal, dict(some_kwarg='bar', + logger=logging.getLogger('TaskY'))) + + assert x != y + + def test_unicode(self): + t = Task(self.signal, dict(some_kwarg='foo'), + logger=logging.getLogger('TaskT')) + + assert str(t) == "Mock: {'some_kwarg': 'foo'}" + + def test_get_or_create_gets(self): + x = Task.get_or_create(self.signal, dict(some_kwarg='foo'), + logger=logging.getLogger('TaskX')) + y = Task.get_or_create(self.signal, dict(some_kwarg='foo'), + logger=logging.getLogger('TaskY')) + + assert x is y + + def test_get_or_create_creates(self): + x = Task.get_or_create(self.signal, dict(some_kwarg='foo'), + logger=logging.getLogger('TaskX')) + y = Task.get_or_create(self.signal, dict(some_kwarg='bar'), + logger=logging.getLogger('TaskY')) + + assert x is not y + + def test_get_or_create_without_kwargs(self): + t = Task.get_or_create(self.signal) + + assert t.kwargs == {} + + def test_get_or_create_uses_cls(self): + class Foo(Task): + pass + + assert isinstance(Foo.get_or_create(self.signal), Foo) + + def test_do_emit(self): + task_mock = self.get_task_mock('_clean', '_exception', '_completed') + + task_mock._do() + + self.signal.emit.assert_called_once_with() + + def test_do_emit_nolog(self): + task_mock = self.get_task_mock( + '_clean', '_exception', '_completed', logging=True) + + task_mock._do() + + self.signal.emit.assert_called_once_with() + + def test_do_emit_no_log(self): + task_mock = self.get_task_mock('_clean', '_exception', '_completed') + + task_mock._do() + + self.signal.emit.assert_called_once_with() + + def test_do_complete(self): + task_mock = self.get_task_mock('_clean', '_exception', '_completed') + + task_mock._do() + + task_mock._exception.assert_not_called() + task_mock._completed.assert_called_once_with() + task_mock._clean.assert_called_once_with() + + def test_do_success(self): + task_mock = self.get_task_mock() + assert task_mock._do() is True + + def test_do_failure_nolog(self): + # Our dummy exception + class DummyError(Exception): + pass + + task_mock = self.get_task_mock('_emit') + task_mock._emit.side_effect = DummyError() + + # This will throw an exception at us, be ready to catch it. + try: + task_mock._do() + assert False + except DummyError: + pass + + def test_do_failure_withlog(self): + task_mock = self.get_task_mock('_emit', logger=True) + task_mock._emit.side_effect = Exception() + assert task_mock._do() is False + + def test_do_exception(self): + task_mock = self.get_task_mock( + '_clean', '_exception', '_completed', '_emit') + + task_mock._emit.side_effect = Exception() + + task_mock._do() + + task_mock._exception.assert_called_once_with( + Exception, task_mock._emit.side_effect, mock.ANY) + + task_mock._completed.assert_not_called() + task_mock._clean.assert_called_once_with() + + @mock.patch('signalslot.signal.inspect') + def test_semaphore(self, inspect): + slot = mock.Mock() + slot.side_effect = lambda **k: time.sleep(.3) + + signal = Signal('tost') + signal.connect(slot) + + x = Task.get_or_create(signal, dict(some_kwarg='foo'), + logger=logging.getLogger('TaskX')) + y = Task.get_or_create(signal, dict(some_kwarg='foo'), + logger=logging.getLogger('TaskY')) + + eventlet.spawn(x) + time.sleep(.1) + eventlet.spawn(y) + time.sleep(.1) + + assert slot.call_count == 1 + time.sleep(.4) + assert slot.call_count == 2 + + def test_call_context(self): + task_mock = self.get_task_mock('_clean', '_exception', '_completed', + '_emit') + + task_mock._emit.side_effect = Exception() + + assert task_mock.failures == 0 + task_mock() + assert task_mock.failures == 1 + + def test_call_success(self): + task_mock = self.get_task_mock('_clean', '_exception', '_completed', + '_emit') + + assert task_mock.failures == 0 + task_mock() + assert task_mock.failures == 0 diff --git a/script.plexmod/lib/_included_packages/plexnet/signalslot/exceptions.py b/script.plexmod/lib/_included_packages/plexnet/signalslot/exceptions.py new file mode 100644 index 0000000000..272b1b3477 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/signalslot/exceptions.py @@ -0,0 +1,28 @@ +class SignalSlotException(Exception): + """Base class for all exceptions of this module.""" + pass + + +class SlotMustAcceptKeywords(SignalSlotException): + """ + Raised when connecting a slot that does not accept ``**kwargs`` in its + signature. + """ + def __init__(self, signal, slot): + m = 'Cannot connect %s to %s because it does not accept **kwargs' % ( + slot, signal) + + super(SlotMustAcceptKeywords, self).__init__(m) + + +# Not yet being used. +class QueueCantQueueNonSignalInstance(SignalSlotException): # pragma: no cover + """ + Raised when trying to queue something else than a + :py:class:`~signalslot.signal.Signal` instance. + """ + def __init__(self, queue, arg): + m = 'Cannot queue %s to %s because it is not a Signal instance' % ( + arg, queue) + + super(QueueCantQueueNonSignalInstance, self).__init__(m) diff --git a/script.plexmod/lib/_included_packages/plexnet/signalslot/signal.py b/script.plexmod/lib/_included_packages/plexnet/signalslot/signal.py new file mode 100644 index 0000000000..435461ee02 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/signalslot/signal.py @@ -0,0 +1,176 @@ +""" +Module defining the Signal class. +""" + +from __future__ import absolute_import +import inspect +import threading + +from . import exceptions + + +class DummyLock(object): + """ + Class that implements a no-op instead of a re-entrant lock. + """ + + def __enter__(self): + pass + + def __exit__(self, exc_type=None, exc_value=None, traceback=None): + pass + + +class BaseSlot(object): + """ + Slot abstract class for type resolution purposes. + """ + pass + + +class Signal(object): + """ + Define a signal by instanciating a :py:class:`Signal` object, ie.: + + >>> conf_pre_load = Signal() + + Optionaly, you can declare a list of argument names for this signal, ie.: + + >>> conf_pre_load = Signal(args=['conf']) + + Any callable can be connected to a Signal, it **must** accept keywords + (``**kwargs``), ie.: + + >>> def yourmodule_conf(conf, **kwargs): + ... conf['yourmodule_option'] = 'foo' + ... + + Connect your function to the signal using :py:meth:`connect`: + + >>> conf_pre_load.connect(yourmodule_conf) + + Emit the signal to call all connected callbacks using + :py:meth:`emit`: + + >>> conf = {} + >>> conf_pre_load.emit(conf=conf) + >>> conf + {'yourmodule_option': 'foo'} + + Note that you may disconnect a callback from a signal if it is already + connected: + + >>> conf_pre_load.is_connected(yourmodule_conf) + True + >>> conf_pre_load.disconnect(yourmodule_conf) + >>> conf_pre_load.is_connected(yourmodule_conf) + False + """ + def __init__(self, args=None, name=None, threadsafe=False): + self._slots = [] + self._slots_lk = threading.RLock() if threadsafe else DummyLock() + self.args = args or [] + self.name = name + + @property + def slots(self): + """ + Return a list of slots for this signal. + """ + with self._slots_lk: + # Do a slot clean-up + slots = [] + for s in self._slots: + if isinstance(s, BaseSlot) and (not s.is_alive): + continue + slots.append(s) + self._slots = slots + return list(slots) + + def connect(self, slot): + """ + Connect a callback ``slot`` to this signal. + """ + if not isinstance(slot, BaseSlot): + if getattr(inspect, "getfullargspec", False): + try: + if inspect.getfullargspec(slot).varkw is None: + raise exceptions.SlotMustAcceptKeywords(self, slot) + except TypeError: + if inspect.getfullargspec(slot.__call__).varkw is None: + raise exceptions.SlotMustAcceptKeywords(self, slot) + else: + try: + if inspect.getargspec(slot).keywords is None: + raise exceptions.SlotMustAcceptKeywords(self, slot) + except TypeError: + if inspect.getargspec(slot.__call__).keywords is None: + raise exceptions.SlotMustAcceptKeywords(self, slot) + + with self._slots_lk: + if not self.is_connected(slot): + self._slots.append(slot) + + def is_connected(self, slot): + """ + Check if a callback ``slot`` is connected to this signal. + """ + with self._slots_lk: + return slot in self._slots + + def disconnect(self, slot): + """ + Disconnect a slot from a signal if it is connected else do nothing. + """ + with self._slots_lk: + if self.is_connected(slot): + self._slots.pop(self._slots.index(slot)) + + def emit(self, **kwargs): + """ + Emit this signal which will execute every connected callback ``slot``, + passing keyword arguments. + + If a slot returns anything other than None, then :py:meth:`emit` will + return that value preventing any other slot from being called. + + >>> need_something = Signal() + >>> def get_something(**kwargs): + ... return 'got something' + ... + >>> def make_something(**kwargs): + ... print('I will not be called') + ... + >>> need_something.connect(get_something) + >>> need_something.connect(make_something) + >>> need_something.emit() + 'got something' + """ + for slot in reversed(self.slots): + result = slot(**kwargs) + + if result is not None: + return result + + def __eq__(self, other): + """ + Return True if other has the same slots connected. + + >>> a = Signal() + >>> b = Signal() + >>> a == b + True + >>> def slot(**kwargs): + ... pass + ... + >>> a.connect(slot) + >>> a == b + False + >>> b.connect(slot) + >>> a == b + True + """ + return self.slots == other.slots + + def __repr__(self): + return '' % (self.name or 'NO_NAME') diff --git a/script.plexmod/lib/_included_packages/plexnet/signalslot/slot.py b/script.plexmod/lib/_included_packages/plexnet/signalslot/slot.py new file mode 100644 index 0000000000..18363e7967 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/signalslot/slot.py @@ -0,0 +1,74 @@ +""" +Module defining the Slot class. +""" + +from __future__ import absolute_import +import types +import weakref +import sys + +from .signal import BaseSlot + +# We cannot test a branch for Python >= 3.4 in Python < 3.4. +if sys.version_info < (3, 4): # pragma: no cover + from weakrefmethod import WeakMethod +else: # pragma: no cover + from weakref import WeakMethod + + +class Slot(BaseSlot): + """ + A slot is a callable object that manages a connection to a signal. + If weak is true or the slot is a subclass of weakref.ref, the slot + is automatically de-referenced to the called function. + """ + def __init__(self, slot, weak=False): + self._weak = weak or isinstance(slot, weakref.ref) + if weak and not isinstance(slot, weakref.ref): + if isinstance(slot, types.MethodType): + slot = WeakMethod(slot) + else: + slot = weakref.ref(slot) + self._slot = slot + + @property + def is_alive(self): + """ + Return True if this slot is "alive". + """ + return (not self._weak) or (self._slot() is not None) + + @property + def func(self): + """ + Return the function that is called by this slot. + """ + if self._weak: + return self._slot() + else: + return self._slot + + def __call__(self, **kwargs): + """ + Execute this slot. + """ + func = self.func + if func is not None: + return func(**kwargs) + + def __eq__(self, other): + """ + Compare this slot to another. + """ + if isinstance(other, BaseSlot): + return self.func == other.func + else: + return self.func == other + + def __repr__(self): + fn = self.func + if fn is None: + fn = 'dead' + else: + fn = repr(fn) + return '' % fn diff --git a/script.plexmod/lib/_included_packages/plexnet/signalslot/tests.py b/script.plexmod/lib/_included_packages/plexnet/signalslot/tests.py new file mode 100644 index 0000000000..87ff3dce83 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/signalslot/tests.py @@ -0,0 +1,206 @@ +from __future__ import absolute_import +import pytest +import mock + +from signalslot import Signal, SlotMustAcceptKeywords, Slot + + +@mock.patch('signalslot.signal.inspect') +class TestSignal(object): + def setup_method(self, method): + self.signal_a = Signal(threadsafe=True) + self.signal_b = Signal(args=['foo']) + + self.slot_a = mock.Mock(spec=lambda **kwargs: None) + self.slot_a.return_value = None + self.slot_b = mock.Mock(spec=lambda **kwargs: None) + self.slot_b.return_value = None + + def test_is_connected(self, inspect): + self.signal_a.connect(self.slot_a) + + assert self.signal_a.is_connected(self.slot_a) + assert not self.signal_a.is_connected(self.slot_b) + assert not self.signal_b.is_connected(self.slot_a) + assert not self.signal_b.is_connected(self.slot_b) + + def test_emit_one_slot(self, inspect): + self.signal_a.connect(self.slot_a) + + self.signal_a.emit() + + self.slot_a.assert_called_once_with() + assert self.slot_b.call_count == 0 + + def test_emit_two_slots(self, inspect): + self.signal_a.connect(self.slot_a) + self.signal_a.connect(self.slot_b) + + self.signal_a.emit() + + self.slot_a.assert_called_once_with() + self.slot_b.assert_called_once_with() + + def test_emit_one_slot_with_arguments(self, inspect): + self.signal_b.connect(self.slot_a) + + self.signal_b.emit(foo='bar') + + self.slot_a.assert_called_once_with(foo='bar') + assert self.slot_b.call_count == 0 + + def test_emit_two_slots_with_arguments(self, inspect): + self.signal_b.connect(self.slot_a) + self.signal_b.connect(self.slot_b) + + self.signal_b.emit(foo='bar') + + self.slot_a.assert_called_once_with(foo='bar') + self.slot_b.assert_called_once_with(foo='bar') + + def test_reconnect_does_not_duplicate(self, inspect): + self.signal_a.connect(self.slot_a) + self.signal_a.connect(self.slot_a) + self.signal_a.emit() + + self.slot_a.assert_called_once_with() + + def test_disconnect_does_not_fail_on_not_connected_slot(self, inspect): + self.signal_a.disconnect(self.slot_b) + + +def test_anonymous_signal_has_nice_repr(): + signal = Signal() + assert repr(signal) == '' + + +def test_named_signal_has_a_nice_repr(): + signal = Signal(name='update_stuff') + assert repr(signal) == '' + + +class TestSignalConnect(object): + def setup_method(self, method): + self.signal = Signal() + + def test_connect_with_kwargs(self): + def cb(**kwargs): + pass + + self.signal.connect(cb) + + def test_connect_without_kwargs(self): + def cb(): + pass + + with pytest.raises(SlotMustAcceptKeywords): + self.signal.connect(cb) + + +class MyTestError(Exception): + pass + + +class TestException(object): + def setup_method(self, method): + self.signal = Signal(threadsafe=False) + self.seen_exception = False + + def failing_slot(**args): + raise MyTestError('die!') + + self.signal.connect(failing_slot) + + def test_emit_exception(self): + try: + self.signal.emit() + except MyTestError: + self.seen_exception = True + + assert self.seen_exception + + +class TestStrongSlot(object): + def setup_method(self, method): + self.called = False + + def slot(**kwargs): + self.called = True + + self.slot = Slot(slot) + + def test_alive(self): + assert self.slot.is_alive + + def test_call(self): + self.slot(testing=1234) + assert self.called + + +class TestWeakFuncSlot(object): + def setup_method(self, method): + self.called = False + + def slot(**kwargs): + self.called = True + + self.slot = Slot(slot, weak=True) + self.slot_ref = slot + + def test_alive(self): + assert self.slot.is_alive + assert repr(self.slot) == '' % repr(self.slot_ref) + + def test_call(self): + self.slot(testing=1234) + assert self.called + + def test_gc(self): + self.slot_ref = None + assert not self.slot.is_alive + assert repr(self.slot) == '' + self.slot(testing=1234) + + +class TestWeakMethodSlot(object): + def setup_method(self, method): + + class MyObject(object): + + def __init__(self): + self.called = False + + def slot(self, **kwargs): + self.called = True + + self.obj_ref = MyObject() + self.slot = Slot(self.obj_ref.slot, weak=True) + self.signal = Signal() + self.signal.connect(self.slot) + + def test_alive(self): + assert self.slot.is_alive + + def test_call(self): + self.signal.emit(testing=1234) + assert self.obj_ref.called + + def test_gc(self): + self.obj_ref = None + assert not self.slot.is_alive + self.signal.emit(testing=1234) + + +class TestSlotEq(object): + def setup_method(self, method): + self.slot_a = Slot(self.slot, weak=False) + self.slot_b = Slot(self.slot, weak=True) + + def slot(self, **kwargs): + pass + + def test_eq_other(self): + assert self.slot_a == self.slot_b + + def test_eq_func(self): + assert self.slot_a == self.slot diff --git a/script.plexmod/lib/_included_packages/plexnet/signalsmixin.py b/script.plexmod/lib/_included_packages/plexnet/signalsmixin.py new file mode 100644 index 0000000000..2efe9d6e63 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/signalsmixin.py @@ -0,0 +1,41 @@ +from __future__ import absolute_import +from . import signalslot + + +class SignalsMixin(object): + def __init__(self): + self._signals = {} + + def on(self, signalName, callback): + if signalName not in self._signals: + self._signals[signalName] = signalslot.Signal(threadsafe=True) + + signal = self._signals[signalName] + + signal.connect(callback) + + def off(self, signalName, callback): + if not self._signals: + return + + if not signalName: + if not callback: + self._signals = {} + else: + for name in self._signals: + self.off(name, callback) + else: + if not callback: + if signalName in self._signals: + del self._signals[signalName] + else: + self._signals[signalName].disconnect(callback) + + def trigger(self, signalName, **kwargs): + if not self._signals: + return + + if signalName not in self._signals: + return + + self._signals[signalName].emit(**kwargs) diff --git a/script.plexmod/lib/_included_packages/plexnet/simpleobjects.py b/script.plexmod/lib/_included_packages/plexnet/simpleobjects.py new file mode 100644 index 0000000000..16b7b8a784 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/simpleobjects.py @@ -0,0 +1,21 @@ +class Res(tuple): + def __str__(self): + return '{0}x{1}'.format(*self[:2]) + + @classmethod + def fromString(cls, res_string): + try: + return cls([int(n) for n in res_string.split('x')]) + except: + return None + + +class AttributeDict(dict): + def __getattr__(self, attr): + return self.get(attr) + + def __setattr__(self, attr, value): + self[attr] = value + + def __repr__(self): + return '<{0}:{1}:{2}>'.format(self.__class__.__name__, self.id, self.get('title', 'None').encode('utf8')) diff --git a/script.plexmod/lib/_included_packages/plexnet/threadutils.py b/script.plexmod/lib/_included_packages/plexnet/threadutils.py new file mode 100644 index 0000000000..fda46b4de7 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/threadutils.py @@ -0,0 +1,94 @@ +# import inspect +# import ctypes +from __future__ import absolute_import +import threading +# import time + + +# def _async_raise(tid, exctype): +# '''Raises an exception in the threads with id tid''' +# if not inspect.isclass(exctype): +# raise TypeError("Only types can be raised (not instances)") + +# try: +# res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), ctypes.py_object(exctype)) +# except AttributeError: +# # To catch: undefined symbol: PyThreadState_SetAsyncExc +# return + +# if res == 0: +# raise ValueError("invalid thread id") +# elif res != 1: +# # "if it returns a number greater than one, you're in trouble, +# # and you should call it again with exc=NULL to revert the effect" +# ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), 0) +# raise SystemError("PyThreadState_SetAsyncExc failed") + + +# class KillThreadException(Exception): +# pass + + +class KillableThread(threading.Thread): + pass + '''A thread class that supports raising exception in the thread from + another thread. + ''' + # def _get_my_tid(self): + # """determines this (self's) thread id + + # CAREFUL : this function is executed in the context of the caller + # thread, to get the identity of the thread represented by this + # instance. + # """ + # if not self.is_alive(): + # raise threading.ThreadError("the thread is not active") + + # return self.ident + + # def _raiseExc(self, exctype): + # """Raises the given exception type in the context of this thread. + + # If the thread is busy in a system call (time.sleep(), + # socket.accept(), ...), the exception is simply ignored. + + # If you are sure that your exception should terminate the thread, + # one way to ensure that it works is: + + # t = ThreadWithExc( ... ) + # ... + # t.raiseExc( SomeException ) + # while t.is_alive(): + # time.sleep( 0.1 ) + # t.raiseExc( SomeException ) + + # If the exception is to be caught by the thread, you need a way to + # check that your thread has caught it. + + # CAREFUL : this function is executed in the context of the + # caller thread, to raise an excpetion in the context of the + # thread represented by this instance. + # """ + # _async_raise(self._get_my_tid(), exctype) + + def kill(self, force_and_wait=False): + pass + # try: + # self._raiseExc(KillThreadException) + + # if force_and_wait: + # time.sleep(0.1) + # while self.is_alive(): + # self._raiseExc(KillThreadException) + # time.sleep(0.1) + # except threading.ThreadError: + # pass + + # def onKilled(self): + # pass + + # def run(self): + # try: + # self._Thread__target(*self._Thread__args, **self._Thread__kwargs) + # except KillThreadException: + # self.onKilled() diff --git a/script.plexmod/lib/_included_packages/plexnet/util.py b/script.plexmod/lib/_included_packages/plexnet/util.py new file mode 100644 index 0000000000..031b36d49b --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/util.py @@ -0,0 +1,311 @@ +from __future__ import absolute_import +from . import simpleobjects +import re +import sys +import time +import platform +import uuid +import threading +import six +from kodi_six import xbmcaddon + +from . import verlib +from . import compat + +if six.PY2: + Event = threading._Event +else: + Event = threading.Event + +BASE_HEADERS = '' + +# to maintain py2 compatibility, duplicate ADDON from lib.util to avoid circular import +ADDON = xbmcaddon.Addon() + + +def resetBaseHeaders(): + return { + 'X-Plex-Platform': X_PLEX_PLATFORM, + 'X-Plex-Platform-Version': X_PLEX_PLATFORM_VERSION, + 'X-Plex-Provides': X_PLEX_PROVIDES, + 'X-Plex-Product': "PM4K", + 'X-Plex-Version': ADDON.getAddonInfo('version'), + 'X-Plex-Device': X_PLEX_DEVICE, + 'X-Plex-Client-Identifier': X_PLEX_IDENTIFIER, + 'Accept-Encoding': 'gzip,deflate', + 'Accept-Language': ACCEPT_LANGUAGE, + 'User-Agent': '{0}/{1}'.format("PM4K", ADDON.getAddonInfo('version')) + } + + +# Core Settings +PROJECT = 'PlexNet' # name provided to plex server +VERSION = '0.0.0a1' # version of this api +TIMEOUT = 10 # request timeout +LONG_TIMEOUT = 20 # s +CONN_CHECK_TIMEOUT = 2.5 # s +LAN_REACHABILITY_TIMEOUT = 10 # ms +CHECK_LOCAL = False +LOCAL_OVER_SECURE = False +X_PLEX_CONTAINER_SIZE = 50 # max results to return in a single search page + +ACCEPT_LANGUAGE = 'en-US,en' + +# Plex Header Configuation +X_PLEX_PROVIDES = 'player,controller' # one or more of [player, controller, server] +X_PLEX_PLATFORM = platform.uname()[0] # Platform name, eg iOS, MacOSX, Android, LG, etc +X_PLEX_PLATFORM_VERSION = platform.uname()[2] # Operating system version, eg 4.3.1, 10.6.7, 3.2 +X_PLEX_PRODUCT = PROJECT # Plex application name, eg Laika, Plex Media Server, Media Link +X_PLEX_VERSION = VERSION # Plex application version number +USER_AGENT = '{0}/{1}'.format(PROJECT, VERSION) + +INTERFACE = None +TIMER = None +APP = None +MANAGER = None + +try: + _platform = platform.system() +except: + try: + _platform = platform.platform(terse=True) + except: + _platform = sys.platform + +X_PLEX_DEVICE = _platform # Device name and model number, eg iPhone3,2, Motorola XOOM, LG5200TV +X_PLEX_IDENTIFIER = str(hex(uuid.getnode())) # UUID, serial number, or other number unique per device + +BASE_HEADERS = resetBaseHeaders() + +QUALITY_LOCAL = 0 +QUALITY_REMOTE = 1 +QUALITY_ONLINE = 2 + +Res = simpleobjects.Res +AttributeDict = simpleobjects.AttributeDict + + +def setInterface(interface): + global INTERFACE + INTERFACE = interface + + +def setTimer(timer): + global TIMER + TIMER = timer + + +def setApp(app): + global APP + APP = app + + +def LOG(msg): + INTERFACE.LOG(msg) + + +def DEBUG_LOG(msg): + INTERFACE.DEBUG_LOG(msg) + + +def ERROR_LOG(msg): + INTERFACE.ERROR_LOG(msg) + + +def WARN_LOG(msg): + INTERFACE.WARN_LOG(msg) + + +def ERROR(msg=None, err=None): + INTERFACE.ERROR(msg, err) + + +def FATAL(msg=None): + INTERFACE.FATAL(msg) + + +def TEST(msg): + INTERFACE.LOG(' ---TEST: {0}'.format(msg)) + + +def userAgent(): + return INTERFACE.getGlobal("userAgent") + + +def dummyTranslate(string): + return string + + +def hideToken(token): + # return 'X' * len(token) + if not token: + return token + return '****' + token[-4:] + + +def cleanToken(url): + return re.sub('X-Plex-Token=[^&]+', 'X-Plex-Token=****', url) + + +def now(local=False): + if local: + return time.time() + else: + return time.mktime(time.gmtime()) + + +def joinArgs(args, includeQuestion=True): + if not args: + return '' + + arglist = [] + for key in sorted(args, key=lambda x: x.lower()): + value = str(args[key]) + arglist.append('{0}={1}'.format(key, compat.quote(value))) + + return '{0}{1}'.format(includeQuestion and '?' or '&', '&'.join(arglist)) + + +def addPlexHeaders(transferObj, token=None): + headers = {"X-Plex-Platform": INTERFACE.getGlobal("platform"), + "X-Plex-Version": INTERFACE.getGlobal("appVersionStr"), + "X-Plex-Client-Identifier": INTERFACE.getGlobal("clientIdentifier"), + "X-Plex-Platform-Version": INTERFACE.getGlobal("platformVersion", "unknown"), + "X-Plex-Product": INTERFACE.getGlobal("product"), + "X-Plex-Provides": not INTERFACE.getPreference("remotecontrol", False) and 'player' or '', + "X-Plex-Device": INTERFACE.getGlobal("device"), + "X-Plex-Model": INTERFACE.getGlobal("model"), + "X-Plex-Device-Name": INTERFACE.getGlobal("friendlyName"), + } + + transferObj.session.headers.update(headers) + + # Adding the X-Plex-Client-Capabilities header causes node.plexapp.com to 500 + if not type(transferObj) == "roUrlTransfer" or 'node.plexapp.com' not in transferObj.getUrl(): + transferObj.addHeader("X-Plex-Client-Capabilities", INTERFACE.getCapabilities()) + + addAccountHeaders(transferObj, token) + + +def addAccountHeaders(transferObj, token=None): + if token: + transferObj.addHeader("X-Plex-Token", token) + + # TODO(schuyler): Add username? + + +def validInt(int_str): + try: + return int(int_str) + except: + return 0 + + +def bitrateToString(bits): + if not bits: + return '' + + speed = bits / 1000000.0 + if speed < 1: + speed = int(round(bits / 1000.0)) + return '{0} Kbps'.format(speed) + else: + return '{0:.1f} Mbps'.format(speed) + + +def normalizedVersion(ver): + try: + modv = '.'.join(ver.split('.')[:4]).split('-', 1)[0] # Clean the version i.e. Turn 1.2.3.4-asdf8-ads7f into 1.2.3.4 + return verlib.NormalizedVersion(verlib.suggest_normalized_version(modv)) + except: + if ver: + ERROR() + return verlib.NormalizedVersion(verlib.suggest_normalized_version('0.0.0')) + + +class CompatEvent(Event): + def wait(self, timeout): + Event.wait(self, timeout) + return self.isSet() + + +class Timer(object): + def __init__(self, timeout, function, repeat=False, name=None, fname=None, *args, **kwargs): + self.function = function + self.timeout = timeout + self.repeat = repeat + self.args = args + self.kwargs = kwargs + self._reset = False + self.name = name or 'TIMER:{0}'.format(self.function) + self.fname = fname or repr(self.function) + self.event = CompatEvent() + self.start() + + def start(self): + self.event.clear() + self.thread = threading.Thread(target=self.run, name=self.name, *self.args, **self.kwargs) + self.thread.start() + + def run(self): + DEBUG_LOG('Timer {0}: {1}'.format(self.fname, self._reset and 'RESET'or 'STARTED')) + try: + while not self.event.isSet() and not self.shouldAbort(): + while not self.event.wait(self.timeout) and not self.shouldAbort(): + if self._reset: + return + + self.function(*self.args, **self.kwargs) + if not self.repeat: + return + finally: + if not self._reset: + if self in APP.timers: + APP.timers.remove(self) + + DEBUG_LOG('Timer {0}: FINISHED'.format(self.fname)) + + self._reset = False + + def cancel(self): + self.event.set() + + def reset(self): + self._reset = True + self.cancel() + if self.thread and self.thread.is_alive(): + self.thread.join() + self.start() + + def is_alive(self): + return self.thread and self.thread.is_alive() + + def shouldAbort(self): + return False + + def join(self): + if self.thread.is_alive(): + self.thread.join() + + def isExpired(self): + return self.event.isSet() + + +class RepeatingCounterTimer(Timer): + def __init__(self, timeout, function, repeat=True, *args, **kwargs): + self.ticks = 0 + self._function = function + super(RepeatingCounterTimer, self).__init__(timeout, self.count, repeat=repeat, + name='TIMER:{0}'.format(function), + fname=repr(function), *args, **kwargs) + + def count(self): + self.ticks += 1 + self._function(*self.args, **self.kwargs) + + def reset(self): + super(RepeatingCounterTimer, self).reset() + self.ticks = 0 + + +TIMER = Timer diff --git a/script.plexmod/lib/_included_packages/plexnet/verlib.py b/script.plexmod/lib/_included_packages/plexnet/verlib.py new file mode 100644 index 0000000000..a068890310 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/verlib.py @@ -0,0 +1,329 @@ +""" +"Rational" version definition and parsing for DistutilsVersionFight +discussion at PyCon 2009. +""" +from __future__ import absolute_import +import re + + +class IrrationalVersionError(Exception): + """This is an irrational version.""" + pass + + +class HugeMajorVersionNumError(IrrationalVersionError): + """An irrational version because the major version number is huge + (often because a year or date was used). + + See `error_on_huge_major_num` option in `NormalizedVersion` for details. + This guard can be disabled by setting that option False. + """ + pass + +# A marker used in the second and third parts of the `parts` tuple, for +# versions that don't have those segments, to sort properly. An example +# of versions in sort order ('highest' last): +# 1.0b1 ((1,0), ('b',1), ('f',)) +# 1.0.dev345 ((1,0), ('f',), ('dev', 345)) +# 1.0 ((1,0), ('f',), ('f',)) +# 1.0.post256.dev345 ((1,0), ('f',), ('f', 'post', 256, 'dev', 345)) +# 1.0.post345 ((1,0), ('f',), ('f', 'post', 345, 'f')) +# ^ ^ ^ +# 'b' < 'f' ---------------------/ | | +# | | +# 'dev' < 'f' < 'post' -------------------/ | +# | +# 'dev' < 'f' ----------------------------------------------/ +# Other letters would do, but 'f' for 'final' is kind of nice. +FINAL_MARKER = ('f',) + +VERSION_RE = re.compile(r''' + ^ + (?P\d+\.\d+) # minimum 'N.N' + (?P(?:\.\d+)*) # any number of extra '.N' segments + (?: + (?P[abc]|rc) # 'a'=alpha, 'b'=beta, 'c'=release candidate + # 'rc'= alias for release candidate + (?P\d+(?:\.\d+)*) + )? + (?P(\.post(?P\d+))?(\.dev(?P\d+))?)? + $''', re.VERBOSE) + + +class NormalizedVersion(object): + """A rational version. + + Good: + 1.2 # equivalent to "1.2.0" + 1.2.0 + 1.2a1 + 1.2.3a2 + 1.2.3b1 + 1.2.3c1 + 1.2.3.4 + TODO: fill this out + + Bad: + 1 # mininum two numbers + 1.2a # release level must have a release serial + 1.2.3b + """ + + def __init__(self, s, error_on_huge_major_num=True): + """Create a NormalizedVersion instance from a version string. + + @param s {str} The version string. + @param error_on_huge_major_num {bool} Whether to consider an + apparent use of a year or full date as the major version number + an error. Default True. One of the observed patterns on PyPI before + the introduction of `NormalizedVersion` was version numbers like this: + 2009.01.03 + 20040603 + 2005.01 + This guard is here to strongly encourage the package author to + use an alternate version, because a release deployed into PyPI + and, e.g. downstream Linux package managers, will forever remove + the possibility of using a version number like "1.0" (i.e. + where the major number is less than that huge major number). + """ + self._parse(s, error_on_huge_major_num) + + @classmethod + def from_parts(cls, version, prerelease=FINAL_MARKER, + devpost=FINAL_MARKER): + return cls(cls.parts_to_str((version, prerelease, devpost))) + + def _parse(self, s, error_on_huge_major_num=True): + """Parses a string version into parts.""" + match = VERSION_RE.search(s) + if not match: + raise IrrationalVersionError(s) + + groups = match.groupdict() + parts = [] + + # main version + block = self._parse_numdots(groups['version'], s, False, 2) + extraversion = groups.get('extraversion') + if extraversion not in ('', None): + block += self._parse_numdots(extraversion[1:], s) + parts.append(tuple(block)) + + # prerelease + prerel = groups.get('prerel') + if prerel is not None: + block = [prerel] + block += self._parse_numdots(groups.get('prerelversion'), s, + pad_zeros_length=1) + parts.append(tuple(block)) + else: + parts.append(FINAL_MARKER) + + # postdev + if groups.get('postdev'): + post = groups.get('post') + dev = groups.get('dev') + postdev = [] + if post is not None: + postdev.extend([FINAL_MARKER[0], 'post', int(post)]) + if dev is None: + postdev.append(FINAL_MARKER[0]) + if dev is not None: + postdev.extend(['dev', int(dev)]) + parts.append(tuple(postdev)) + else: + parts.append(FINAL_MARKER) + self.parts = tuple(parts) + if error_on_huge_major_num and self.parts[0][0] > 1980: + raise HugeMajorVersionNumError("huge major version number, %r, " + "which might cause future problems: %r" % (self.parts[0][0], s)) + + def _parse_numdots(self, s, full_ver_str, drop_trailing_zeros=True, + pad_zeros_length=0): + """Parse 'N.N.N' sequences, return a list of ints. + + @param s {str} 'N.N.N..." sequence to be parsed + @param full_ver_str {str} The full version string from which this + comes. Used for error strings. + @param drop_trailing_zeros {bool} Whether to drop trailing zeros + from the returned list. Default True. + @param pad_zeros_length {int} The length to which to pad the + returned list with zeros, if necessary. Default 0. + """ + nums = [] + for n in s.split("."): + if len(n) > 1 and n[0] == '0': + raise IrrationalVersionError("cannot have leading zero in " + "version number segment: '%s' in %r" % (n, full_ver_str)) + nums.append(int(n)) + if drop_trailing_zeros: + while nums and nums[-1] == 0: + nums.pop() + while len(nums) < pad_zeros_length: + nums.append(0) + return nums + + def __str__(self): + return self.parts_to_str(self.parts) + + @classmethod + def parts_to_str(cls, parts): + """Transforms a version expressed in tuple into its string + representation.""" + # XXX This doesn't check for invalid tuples + main, prerel, postdev = parts + s = '.'.join(str(v) for v in main) + if prerel is not FINAL_MARKER: + s += prerel[0] + s += '.'.join(str(v) for v in prerel[1:]) + if postdev and postdev is not FINAL_MARKER: + if postdev[0] == 'f': + postdev = postdev[1:] + i = 0 + while i < len(postdev): + if i % 2 == 0: + s += '.' + s += str(postdev[i]) + i += 1 + return s + + def __repr__(self): + return "%s('%s')" % (self.__class__.__name__, self) + + def _cannot_compare(self, other): + raise TypeError("cannot compare %s and %s" + % (type(self).__name__, type(other).__name__)) + + def __eq__(self, other): + if not isinstance(other, NormalizedVersion): + self._cannot_compare(other) + return self.parts == other.parts + + def __lt__(self, other): + if not isinstance(other, NormalizedVersion): + self._cannot_compare(other) + return self.parts < other.parts + + def __ne__(self, other): + return not self.__eq__(other) + + def __gt__(self, other): + return not (self.__lt__(other) or self.__eq__(other)) + + def __le__(self, other): + return self.__eq__(other) or self.__lt__(other) + + def __ge__(self, other): + return self.__eq__(other) or self.__gt__(other) + + +def suggest_normalized_version(s): + """Suggest a normalized version close to the given version string. + + If you have a version string that isn't rational (i.e. NormalizedVersion + doesn't like it) then you might be able to get an equivalent (or close) + rational version from this function. + + This does a number of simple normalizations to the given string, based + on observation of versions currently in use on PyPI. Given a dump of + those version during PyCon 2009, 4287 of them: + - 2312 (53.93%) match NormalizedVersion without change + - with the automatic suggestion + - 3474 (81.04%) match when using this suggestion method + + @param s {str} An irrational version string. + @returns A rational version string, or None, if couldn't determine one. + """ + try: + NormalizedVersion(s) + return s # already rational + except IrrationalVersionError: + pass + + rs = s.lower() + + # part of this could use maketrans + for orig, repl in (('-alpha', 'a'), ('-beta', 'b'), ('alpha', 'a'), + ('beta', 'b'), ('rc', 'c'), ('-final', ''), + ('-pre', 'c'), + ('-release', ''), ('.release', ''), ('-stable', ''), + ('+', '.'), ('_', '.'), (' ', ''), ('.final', ''), + ('final', '')): + rs = rs.replace(orig, repl) + + # if something ends with dev or pre, we add a 0 + rs = re.sub(r"pre$", r"pre0", rs) + rs = re.sub(r"dev$", r"dev0", rs) + + # if we have something like "b-2" or "a.2" at the end of the + # version, that is pobably beta, alpha, etc + # let's remove the dash or dot + rs = re.sub(r"([abc|rc])[\-\.](\d+)$", r"\1\2", rs) + + # 1.0-dev-r371 -> 1.0.dev371 + # 0.1-dev-r79 -> 0.1.dev79 + rs = re.sub(r"[\-\.](dev)[\-\.]?r?(\d+)$", r".\1\2", rs) + + # Clean: 2.0.a.3, 2.0.b1, 0.9.0~c1 + rs = re.sub(r"[.~]?([abc])\.?", r"\1", rs) + + # Clean: v0.3, v1.0 + if rs.startswith('v'): + rs = rs[1:] + + # Clean leading '0's on numbers. + # TODO: unintended side-effect on, e.g., "2003.05.09" + # PyPI stats: 77 (~2%) better + rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs) + + # Clean a/b/c with no version. E.g. "1.0a" -> "1.0a0". Setuptools infers + # zero. + # PyPI stats: 245 (7.56%) better + rs = re.sub(r"(\d+[abc])$", r"\g<1>0", rs) + + # the 'dev-rNNN' tag is a dev tag + rs = re.sub(r"\.?(dev-r|dev\.r)\.?(\d+)$", r".dev\2", rs) + + # clean the - when used as a pre delimiter + rs = re.sub(r"-(a|b|c)(\d+)$", r"\1\2", rs) + + # a terminal "dev" or "devel" can be changed into ".dev0" + rs = re.sub(r"[\.\-](dev|devel)$", r".dev0", rs) + + # a terminal "dev" can be changed into ".dev0" + rs = re.sub(r"(?![\.\-])dev$", r".dev0", rs) + + # a terminal "final" or "stable" can be removed + rs = re.sub(r"(final|stable)$", "", rs) + + # The 'r' and the '-' tags are post release tags + # 0.4a1.r10 -> 0.4a1.post10 + # 0.9.33-17222 -> 0.9.3.post17222 + # 0.9.33-r17222 -> 0.9.3.post17222 + rs = re.sub(r"\.?(r|-|-r)\.?(\d+)$", r".post\2", rs) + + # Clean 'r' instead of 'dev' usage: + # 0.9.33+r17222 -> 0.9.3.dev17222 + # 1.0dev123 -> 1.0.dev123 + # 1.0.git123 -> 1.0.dev123 + # 1.0.bzr123 -> 1.0.dev123 + # 0.1a0dev.123 -> 0.1a0.dev123 + # PyPI stats: ~150 (~4%) better + rs = re.sub(r"\.?(dev|git|bzr)\.?(\d+)$", r".dev\2", rs) + + # Clean '.pre' (normalized from '-pre' above) instead of 'c' usage: + # 0.2.pre1 -> 0.2c1 + # 0.2-c1 -> 0.2c1 + # 1.0preview123 -> 1.0c123 + # PyPI stats: ~21 (0.62%) better + rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs) + + # Tcl/Tk uses "px" for their post release markers + rs = re.sub(r"p(\d+)$", r".post\1", rs) + + try: + NormalizedVersion(rs) + return rs # already rational + except IrrationalVersionError: + pass + return None diff --git a/script.plexmod/lib/_included_packages/plexnet/video.py b/script.plexmod/lib/_included_packages/plexnet/video.py new file mode 100644 index 0000000000..8adae39f73 --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/video.py @@ -0,0 +1,782 @@ +from __future__ import absolute_import +from functools import wraps + +from . import plexobjects +from . import media +from . import plexmedia +from . import plexstream +from . import exceptions +from . import compat +from . import plexlibrary +from . import util +from . import mediachoice + + +class PlexVideoItemList(plexobjects.PlexItemList): + def __init__(self, data, initpath=None, server=None, container=None): + self._data = data + self._initpath = initpath + self._server = server + self._container = container + self._items = None + + @property + def items(self): + if self._items is None: + if self._data is not None: + self._items = [plexobjects.buildItem(self._server, elem, self._initpath, container=self._container) for elem in self._data] + else: + self._items = [] + + return self._items + + +def forceMediaChoice(method): + @wraps(method) + def _impl(self, *method_args, **method_kwargs): + # set mediaChoice if we don't have any yet, or the one we have is incomplete and the new one isn't + media = method_kwargs.get("media", self.media()[0]) + partIndex = method_kwargs.get("partIndex", 0) + if not self.mediaChoice or (not self.mediaChoice.media.hasStreams() and media.hasStreams()): + self.setMediaChoice(media=media, partIndex=partIndex) + return method(self, *method_args, **method_kwargs) + return _impl + + +class Video(media.MediaItem): + TYPE = None + manually_selected_sub_stream = False + current_subtitle_is_embedded = False + _current_subtitle_idx = None + + def __init__(self, *args, **kwargs): + self._settings = None + media.MediaItem.__init__(self, *args, **kwargs) + + def __eq__(self, other): + return other and self.ratingKey == other.ratingKey + + def __ne__(self, other): + return not self.__eq__(other) + + @property + def settings(self): + if not self._settings: + from . import plexapp + self._settings = plexapp.PlayerSettingsInterface() + + return self._settings + + @settings.setter + def settings(self, value): + self._settings = value + + # overridden by Movie/Episode + @property + def subtitleStreams(self): + return [] + + @property + def videoStreams(self): + return [] + + @property + def audioStreams(self): + return [] + + def selectedVideoStream(self, fallback=False): + if self.videoStreams: + for stream in self.videoStreams: + if stream.isSelected(): + return stream + if fallback: + return self.videoStreams[0] + return None + + def selectedAudioStream(self, fallback=False): + if self.audioStreams: + for stream in self.audioStreams: + if stream.isSelected(): + return stream + if fallback: + return self.audioStreams[0] + return None + + def selectedSubtitleStream(self, forced_subtitles_override=False, fallback=False): + if self._current_subtitle_idx: + try: + return self.subtitleStreams[self._current_subtitle_idx] + except IndexError: + pass + + if self.subtitleStreams: + for stream in self.subtitleStreams: + if stream.isSelected(): + if forced_subtitles_override and \ + stream.forced.asBool() and self.manually_selected_sub_stream != stream.id: + # try finding a non-forced variant of this stream + possible_alt = None + for alt_stream in self.subtitleStreams: + if alt_stream.language == stream.language and alt_stream != stream \ + and not alt_stream.forced.asBool(): + if possible_alt and not possible_alt.key and alt_stream.key: + possible_alt = alt_stream + break + if not possible_alt: + possible_alt = alt_stream + if possible_alt: + util.DEBUG_LOG("Selecting stream %s instead of %s" % + (possible_alt, stream)) + stream.setSelected(False) + possible_alt.setSelected(True) + self.current_subtitle_is_embedded = possible_alt.embedded + if self._current_subtitle_idx != possible_alt.typeIndex: + self._current_subtitle_idx = possible_alt.typeIndex + return possible_alt + + if self._current_subtitle_idx != stream.typeIndex: + self._current_subtitle_idx = stream.typeIndex + self.current_subtitle_is_embedded = stream.embedded + return stream + if fallback: + stream = self.subtitleStreams[0] + if self._current_subtitle_idx != stream.typeIndex: + self._current_subtitle_idx = stream.typeIndex + return stream + return None + + def setMediaChoice(self, media=None, partIndex=0): + media = media or self.media()[0] + self.mediaChoice = mediachoice.MediaChoice(media, partIndex=partIndex) + + @forceMediaChoice + def selectStream(self, stream, _async=True): + self.mediaChoice.part.setSelectedStream(stream.streamType.asInt(), stream.id, _async) + # Update any affected streams + if stream.streamType.asInt() == plexstream.PlexStream.TYPE_AUDIO: + for audioStream in self.audioStreams: + if audioStream.id == stream.id: + audioStream.setSelected(True) + elif audioStream.isSelected(): + audioStream.setSelected(False) + elif stream.streamType.asInt() == plexstream.PlexStream.TYPE_SUBTITLE: + self._current_subtitle_idx = None + self.current_subtitle_is_embedded = False + for subtitleStream in self.subtitleStreams: + if subtitleStream.id == stream.id: + subtitleStream.setSelected(True) + self.current_subtitle_is_embedded = subtitleStream.embedded + self._current_subtitle_idx = subtitleStream.typeIndex + elif subtitleStream.isSelected(): + subtitleStream.setSelected(False) + + @forceMediaChoice + def cycleSubtitles(self, forward=True): + amount = len(self.subtitleStreams) + if not amount: + return False + cur = self.selectedSubtitleStream() + if not cur: + # use fallback + stream = self.selectedSubtitleStream(fallback=True) + else: + # set next if we're not at the end of the list + if forward: + if cur.typeIndex < len(self.subtitleStreams) - 1: + stream = self.subtitleStreams[cur.typeIndex+1] + else: + stream = self.subtitleStreams[0] + else: + if cur.typeIndex > 0: + stream = self.subtitleStreams[cur.typeIndex - 1] + else: + stream = self.subtitleStreams[-1] + + util.DEBUG_LOG("Selecting subtitle stream: {} (was: {})".format(stream, cur)) + self.selectStream(stream) + return stream + + @forceMediaChoice + def disableSubtitles(self): + self.selectStream(plexstream.NONE_STREAM) + + @property + def hasSubtitle(self): + return bool(self.selectedSubtitleStream()) + + @property + def hasSubtitles(self): + return bool(self.subtitleStreams) + + def isVideoItem(self): + return True + + @forceMediaChoice + def _findStreams(self, streamtype, withMC=True): + idx = 0 + streams = [] + source = [self.mediaChoice.media] if withMC else self.media() + for media_ in source: + parts = [self.mediaChoice.part] if withMC else media_.parts + for part in parts: + for stream in part.streams: + if stream.streamType.asInt() == streamtype: + stream.typeIndex = idx + streams.append(stream) + idx += 1 + return streams + + def analyze(self): + """ The primary purpose of media analysis is to gather information about that media + item. All of the media you add to a Library has properties that are useful to + know - whether it's a video file, a music track, or one of your photos. + """ + self.server.query('/%s/analyze' % self.key) + + def markWatched(self, **kwargs): + path = '/:/scrobble?key=%s&identifier=com.plexapp.plugins.library' % self.ratingKey + self.server.query(path) + self.reload(**kwargs) + + def markUnwatched(self, **kwargs): + path = '/:/unscrobble?key=%s&identifier=com.plexapp.plugins.library' % self.ratingKey + self.server.query(path) + self.reload(**kwargs) + + # def play(self, client): + # client.playMedia(self) + + def refresh(self): + self.server.query('%s/refresh' % self.key, method=self.server.session.put) + + def _getStreamURL(self, **params): + if self.TYPE not in ('movie', 'episode', 'track'): + raise exceptions.Unsupported('Fetching stream URL for %s is unsupported.' % self.TYPE) + mvb = params.get('maxVideoBitrate') + vr = params.get('videoResolution') + + # import plexapp + + params = { + 'path': self.key, + 'offset': params.get('offset', 0), + 'copyts': params.get('copyts', 1), + 'protocol': params.get('protocol', 'hls'), + 'mediaIndex': params.get('mediaIndex', 0), + 'directStream': '1', + 'directPlay': '0', + 'X-Plex-Platform': params.get('platform', ''), + # 'X-Plex-Platform': params.get('platform', util.INTERFACE.getGlobal('platform')), + 'maxVideoBitrate': max(mvb, 64) if mvb else None, + 'videoResolution': '{0}x{1}'.format(*vr) if vr else None + } + + final = {} + + for k, v in params.items(): + if v is not None: # remove None values + final[k] = v + + streamtype = 'audio' if self.TYPE in ('track', 'album') else 'video' + server = self.getTranscodeServer(True, self.TYPE) + + return server.buildUrl('/{0}/:/transcode/universal/start.m3u8?{1}'.format(streamtype, compat.urlencode(final)), includeToken=True) + # path = "/video/:/transcode/universal/" + command + "?session=" + AppSettings().GetGlobal("clientIdentifier") + + @forceMediaChoice + def resolutionString(self): + res = self.mediaChoice.media.videoResolution + if not res: + return '' + + if res.isdigit(): + return '{0}p'.format(self.mediaChoice.media.videoResolution) + else: + return res.upper() + + @forceMediaChoice + def audioCodecString(self): + codec = (self.mediaChoice.media.audioCodec or '').lower() + + if codec in ('dca', 'dca-ma', 'dts-hd', 'dts-es', 'dts-hra'): + codec = "DTS" + else: + codec = codec.upper() + + return codec + + @forceMediaChoice + def videoCodecString(self): + return (self.mediaChoice.media.videoCodec or '').upper() + + @property + @forceMediaChoice + def videoCodecRendering(self): + stream = self.mediaChoice.videoStream + + if not stream: + return '' + + return stream.videoCodecRendering + + @forceMediaChoice + def audioChannelsString(self, translate_func=util.dummyTranslate): + channels = self.mediaChoice.media.audioChannels.asInt() + + if channels == 1: + return translate_func("Mono") + elif channels == 2: + return translate_func("Stereo") + elif channels > 0: + return "{0}.1".format(channels - 1) + else: + return "" + + @property + def remainingTime(self): + if not self.viewOffset.asInt(): + return + return (self.duration.asInt() - self.viewOffset.asInt()) // 1000 + + @property + def remainingTimeString(self): + if not self.remainingTime: + return '' + seconds = self.remainingTime + hours = seconds // 3600 + minutes = (seconds - hours * 3600) // 60 + return (hours and "{}h ".format(hours) or '') + (minutes and "{}m".format(minutes) or "0m") + + def available(self): + return any(v.isAccessible() for v in self.media()) + + +class RelatedMixin(object): + _relatedCount = None + + @property + def relatedCount(self): + if self._relatedCount is None: + related = self.getRelated(0, 0) + if related is not None: + self._relatedCount = related.totalSize + else: + self._relatedCount = 0 + + return self._relatedCount + + @property + def related(self): + return self.getRelated(0, 8) + + def getRelated(self, offset=None, limit=None, _max=36): + path = '/library/metadata/%s/similar' % self.ratingKey + try: + return plexobjects.listItems(self.server, path, offset=offset, limit=limit, params={"count": _max}) + except exceptions.BadRequest: + util.DEBUG_LOG("Invalid related items response returned for %s" % self) + return None + + +class SectionOnDeckMixin(object): + _sectionOnDeckCount = None + + def sectionOnDeck(self, offset=None, limit=None): + query = '/library/sections/{0}/onDeck'.format(self.getLibrarySectionId()) + return plexobjects.listItems(self.server, query, offset=offset, limit=limit) + + @property + def sectionOnDeckCount(self): + if self._sectionOnDeckCount is None: + self._sectionOnDeckCount = self.sectionOnDeck(0, 0).totalSize + + return self._sectionOnDeckCount + + +class PlayableVideo(Video, RelatedMixin): + TYPE = None + _videoStreams = None + _audioStreams = None + _subtitleStreams = None + _current_subtitle_idx = None + + def _setData(self, data): + Video._setData(self, data) + if self.isFullObject(): + self.extras = PlexVideoItemList(data.find('Extras'), initpath=self.initpath, server=self.server, container=self) + self.chapters = plexobjects.PlexItemList(data, media.Chapter, media.Chapter.TYPE, server=self.server) + + self.resetStreams() + + def setMediaChoice(self, *args, **kwargs): + """ + Reset cached streams after setting a mediaChoice + """ + super(PlayableVideo, self).setMediaChoice(*args, **kwargs) + self.resetStreams() + + def resetStreams(self): + self._videoStreams = None + self._audioStreams = None + self._subtitleStreams = None + + def reload(self, *args, **kwargs): + if not kwargs.get('_soft'): + if self.get('viewCount'): + del self.viewCount + if self.get('viewOffset'): + del self.viewOffset + + fromMediaChoice = kwargs.get("fromMediaChoice", False) + + # capture current IDs + mediaID = None + partID = None + streamIDs = None + reSelect = False + if fromMediaChoice and self.mediaChoice: + reSelect = True + mediaID = self.mediaChoice.media.id + partID = self.mediaChoice.part.id + streamIDs = [] + if self.mediaChoice.media.hasStreams(): + subtitleStream = self.selectedSubtitleStream(fallback=False) + streamIDs = [self.selectedVideoStream(fallback=True).id, + self.selectedAudioStream(fallback=True).id] + if subtitleStream: + streamIDs.append(subtitleStream.id) + + Video.reload(self, *args, **kwargs) + + # re-select selected IDs + if reSelect: + selMedia = None + selPartIndex = 0 + for media in self.media: + if media.id == mediaID: + selMedia = media + media.set('selected', '1') + for index, part in enumerate(media.parts): + if part.id == partID: + selPartIndex = index + for stream in part.streams: + if stream.id in streamIDs: + stream.setSelected(True) + self.mediaChoice = mediachoice.MediaChoice(selMedia, partIndex=selPartIndex) + + return self + + def postPlay(self, **params): + query = '/hubs/metadata/{0}/postplay'.format(self.ratingKey) + data = self.server.query(query, params=params) + container = plexobjects.PlexContainer(data, initpath=query, server=self.server, address=query) + + hubs = {} + + for elem in data: + hub = plexlibrary.Hub(elem, server=self.server, container=container) + hubs[hub.hubIdentifier] = hub + return hubs + + +@plexobjects.registerLibType +class Movie(PlayableVideo): + TYPE = 'movie' + + def _setData(self, data): + PlayableVideo._setData(self, data) + if self.isFullObject(): + self.collections = plexobjects.PlexItemList(data, media.Collection, media.Collection.TYPE, + server=self.server) + self.countries = plexobjects.PlexItemList(data, media.Country, media.Country.TYPE, server=self.server) + self.directors = plexobjects.PlexItemList(data, media.Director, media.Director.TYPE, server=self.server) + self.genres = plexobjects.PlexItemList(data, media.Genre, media.Genre.TYPE, server=self.server) + self.media = plexobjects.PlexMediaItemList(data, plexmedia.PlexMedia, media.Media.TYPE, + initpath=self.initpath, server=self.server, media=self) + self.producers = plexobjects.PlexItemList(data, media.Producer, media.Producer.TYPE, server=self.server) + self.roles = plexobjects.PlexItemList(data, media.Role, media.Role.TYPE, server=self.server, + container=self.container) + self.reviews = plexobjects.PlexItemList(data, media.Review, media.Review.TYPE, server=self.server, + container=self.container) + self.writers = plexobjects.PlexItemList(data, media.Writer, media.Writer.TYPE, server=self.server) + #self.related = plexobjects.PlexItemList(data.find('Related'), plexlibrary.Hub, plexlibrary.Hub.TYPE, server=self.server, container=self) + else: + if data.find(media.Media.TYPE) is not None: + self.media = plexobjects.PlexMediaItemList(data, plexmedia.PlexMedia, media.Media.TYPE, initpath=self.initpath, server=self.server, media=self) + + self.markers = plexobjects.PlexItemList(data, media.Marker, media.Marker.TYPE, server=self.server) + + # data for active sessions + self.sessionKey = plexobjects.PlexValue(data.attrib.get('sessionKey', ''), self) + self.user = self._findUser(data) + self.player = self._findPlayer(data) + self.session = self._findSession(data) + self.transcodeSession = self._findTranscodeSession(data) + + @property + def defaultTitle(self): + title = self.title or '' + if self.editionTitle: + title = title + " \u2022 " + self.editionTitle + return title + + @property + def maxHeight(self): + height = 0 + for m in self.media: + if m.height.asInt() > height: + height = m.height.asInt() + return height + + @property + def videoStreams(self): + if self._videoStreams is None: + self._videoStreams = self._findStreams(plexstream.PlexStream.TYPE_VIDEO) + return self._videoStreams + + @property + def audioStreams(self): + if self._audioStreams is None: + self._audioStreams = self._findStreams(plexstream.PlexStream.TYPE_AUDIO) + return self._audioStreams + + @property + def subtitleStreams(self): + if self._subtitleStreams is None: + self._subtitleStreams = self._findStreams(plexstream.PlexStream.TYPE_SUBTITLE) + return self._subtitleStreams + + @property + def actors(self): + return self.roles + + @property + def isWatched(self): + return self.get('viewCount').asInt() > 0 or self.get('viewOffset').asInt() > 0 + + def getStreamURL(self, **params): + return self._getStreamURL(**params) + + +@plexobjects.registerLibType +class Show(Video, RelatedMixin, SectionOnDeckMixin): + TYPE = 'show' + + def _setData(self, data): + Video._setData(self, data) + if self.isFullObject(): + self.genres = plexobjects.PlexItemList(data, media.Genre, media.Genre.TYPE, server=self.server) + self.roles = plexobjects.PlexItemList(data, media.Role, media.Role.TYPE, server=self.server, container=self.container) + #self.related = plexobjects.PlexItemList(data.find('Related'), plexlibrary.Hub, plexlibrary.Hub.TYPE, server=self.server, container=self) + self.extras = PlexVideoItemList(data.find('Extras'), initpath=self.initpath, server=self.server, container=self) + + @property + def unViewedLeafCount(self): + return self.leafCount.asInt() - self.viewedLeafCount.asInt() + + @property + def isWatched(self): + return self.viewedLeafCount == self.leafCount + + @property + def playbackSettings(self): + return util.INTERFACE.playbackManager(self) + + def seasons(self): + path = self.key + return plexobjects.listItems(self.server, path, Season.TYPE) + + def season(self, title): + path = self.key + return plexobjects.findItem(self.server, path, title) + + def episodes(self, watched=None, offset=None, limit=None): + leavesKey = '/library/metadata/%s/allLeaves' % self.ratingKey + return plexobjects.listItems(self.server, leavesKey, watched=watched, offset=offset, limit=limit) + + def episode(self, title): + path = '/library/metadata/%s/allLeaves' % self.ratingKey + return plexobjects.findItem(self.server, path, title) + + def all(self): + return self.episodes() + + def watched(self): + return self.episodes(watched=True) + + def unwatched(self): + return self.episodes(watched=False) + + def refresh(self): + self.server.query('/library/metadata/%s/refresh' % self.ratingKey) + + +@plexobjects.registerLibType +class Season(Video): + TYPE = 'season' + + def _setData(self, data): + Video._setData(self, data) + if self.isFullObject(): + self.extras = PlexVideoItemList(data.find('Extras'), initpath=self.initpath, server=self.server, container=self) + + @property + def defaultTitle(self): + return self.parentTitle or self.title + + @property + def unViewedLeafCount(self): + return self.leafCount.asInt() - self.viewedLeafCount.asInt() + + @property + def isWatched(self): + return self.viewedLeafCount == self.leafCount + + def episodes(self, watched=None, offset=None, limit=None): + path = self.key + return plexobjects.listItems(self.server, path, watched=watched, offset=offset, limit=limit) + + def episode(self, title): + path = self.key + return plexobjects.findItem(self.server, path, title) + + def all(self): + return self.episodes() + + def show(self): + return plexobjects.listItems(self.server, self.parentKey)[0] + + def watched(self): + return self.episodes(watched=True) + + def unwatched(self): + return self.episodes(watched=False) + + +@plexobjects.registerLibType +class Episode(PlayableVideo, SectionOnDeckMixin): + TYPE = 'episode' + + def init(self, data): + self._show = None + self._season = None + + def _setData(self, data): + PlayableVideo._setData(self, data) + if self.isFullObject(): + self.directors = plexobjects.PlexItemList(data, media.Director, media.Director.TYPE, server=self.server) + self.media = plexobjects.PlexMediaItemList(data, plexmedia.PlexMedia, media.Media.TYPE, initpath=self.initpath, server=self.server, media=self) + self.writers = plexobjects.PlexItemList(data, media.Writer, media.Writer.TYPE, server=self.server) + else: + if data.find(media.Media.TYPE) is not None: + self.media = plexobjects.PlexMediaItemList(data, plexmedia.PlexMedia, media.Media.TYPE, initpath=self.initpath, server=self.server, media=self) + + self.markers = plexobjects.PlexItemList(data, media.Marker, media.Marker.TYPE, server=self.server) + + # data for active sessions + self.sessionKey = plexobjects.PlexValue(data.attrib.get('sessionKey', ''), self) + self.user = self._findUser(data) + self.player = self._findPlayer(data) + self.session = self._findSession(data) + self.transcodeSession = self._findTranscodeSession(data) + + @property + def defaultTitle(self): + return self.grandparentTitle or self.parentTitle or self.title + + @property + def defaultThumb(self): + return self.grandparentThumb or self.parentThumb or self.thumb + + @property + def videoStreams(self): + if self._videoStreams is None: + self._videoStreams = self._findStreams(plexstream.PlexStream.TYPE_VIDEO) + return self._videoStreams + + @property + def audioStreams(self): + if self._audioStreams is None: + self._audioStreams = self._findStreams(plexstream.PlexStream.TYPE_AUDIO) + return self._audioStreams + + @property + def subtitleStreams(self): + if self._subtitleStreams is None: + self._subtitleStreams = self._findStreams(plexstream.PlexStream.TYPE_SUBTITLE) + return self._subtitleStreams + + @property + def isWatched(self): + return self.get('viewCount').asInt() > 0 or self.get('viewOffset').asInt() > 0 + + @property + def playbackSettings(self): + return self.show().playbackSettings + + def getStreamURL(self, **params): + return self._getStreamURL(**params) + + def season(self): + skipParent = self.get('skipParent').asBool() + key = self.parentKey if not skipParent else self.grandparentKey + if not self._season: + items = plexobjects.listItems(self.server, key) + + if items: + self._season = items[0] + return self._season + + def show(self): + if not self._show: + self._show = plexobjects.listItems(self.server, self.grandparentKey)[0] + return self._show + + @property + def genres(self): + return self.show().genres + + @property + def roles(self): + return self.show().roles + + def getRelated(self, offset=None, limit=None, _max=36): + return self.show().getRelated(offset=offset, limit=limit, _max=_max) + + +@plexobjects.registerLibType +class Clip(PlayableVideo): + TYPE = 'clip' + + def _setData(self, data): + PlayableVideo._setData(self, data) + if self.isFullObject(): + self.media = plexobjects.PlexMediaItemList(data, plexmedia.PlexMedia, media.Media.TYPE, initpath=self.initpath, server=self.server, media=self) + else: + if data.find(media.Media.TYPE) is not None: + self.media = plexobjects.PlexMediaItemList(data, plexmedia.PlexMedia, media.Media.TYPE, initpath=self.initpath, server=self.server, media=self) + + @property + def isWatched(self): + return self.get('viewCount').asInt() > 0 or self.get('viewOffset').asInt() > 0 + + def getStreamURL(self, **params): + return self._getStreamURL(**params) + + @property + def videoStreams(self): + if self._videoStreams is None: + self._videoStreams = self._findStreams(plexstream.PlexStream.TYPE_VIDEO) + return self._videoStreams + + @property + def audioStreams(self): + if self._audioStreams is None: + self._audioStreams = self._findStreams(plexstream.PlexStream.TYPE_AUDIO) + return self._audioStreams + + @property + def subtitleStreams(self): + if self._subtitleStreams is None: + self._subtitleStreams = self._findStreams(plexstream.PlexStream.TYPE_SUBTITLE) + return self._subtitleStreams diff --git a/script.plexmod/lib/_included_packages/plexnet/videosession.py b/script.plexmod/lib/_included_packages/plexnet/videosession.py new file mode 100644 index 0000000000..933dac0edc --- /dev/null +++ b/script.plexmod/lib/_included_packages/plexnet/videosession.py @@ -0,0 +1,416 @@ +# coding=utf-8 +import six +from collections import OrderedDict +from plexnet import plexapp + + +class MediaDetails: + """ + Gathers attributes from a MediaContainer + """ + details = None + attribute_map = { + "container": "part.attrib_container", + "partDecision": "part.decision", + "videoResolution": "media.videoResolution", + "videoBitrate": "video_stream.bitrate", + "videoCodec": "video_stream.codec", + "videoStreamDecision": "video_stream.decision", + "transcodeVideoDecision": "transcode_session.videoDecision", + "transcodeHWEncoding": "transcode_session.transcodeHwEncoding", + "audioCodec": "audio_stream.codec", + "audioBitrate": "audio_stream.bitrate", + "audioChannels": "audio_stream.channels", + "audioStreamDecision": "audio_stream.decision", + "subtitleCodec": "subtitle_stream.codec", + "subtitleStreamDecision": "subtitle_stream.decision", + "subtitleLocation": "subtitle_stream.location", + "subtitleBurn": "subtitle_stream.burn", + } + + def __init__(self, *args, **kwargs): + self.details = self.findMediaDetails(*args, **kwargs) + + def attributesFromInstance(self, map, reference_data): + # gather attribute values + final_data = {} + for attribute, dataPath in six.iteritems(map): + objName, attribName = dataPath.split(".") + if objName in reference_data: + obj = reference_data[objName] + final_data[attribute] = getattr(obj, attribName, None) or None + return final_data + + def findMediaDetails(self, mediaContainer, mediaChoice, transcodeSession=None): + """ + + """ + reference_data = { + "media": None, + "part": None, + "video_stream": None, + "audio_stream": None, + "subtitle_stream": None, + "transcode_session": transcodeSession or mediaContainer.transcodeSession + } + + # We can't use mediaChoice here directly, because it doesn't necessarily hold the newest data (in case of + # an actual MediaContainer from the Session endpoint that data is king) + # Instead find the media/part/streams which were selected and are held in MediaChoice inside the current + # mediaContainer + for media in mediaContainer.media: + if media.id == mediaChoice.media.id: + reference_data["media"] = media + + for part in media.parts: + if part.id == mediaChoice.part.id: + reference_data["part"] = part + + for stream in part.streams: + if mediaChoice.videoStream != None and stream.id == mediaChoice.videoStream.id: + reference_data["video_stream"] = stream + elif mediaChoice.audioStream != None and stream.id == mediaChoice.audioStream.id: + reference_data["audio_stream"] = stream + elif mediaChoice.subtitleStream != None and stream.id == mediaChoice.subtitleStream.id: + reference_data["subtitle_stream"] = stream + + final_data = { + "hasVideoStream": bool(reference_data["video_stream"]), + "hasAudioStream": bool(reference_data["audio_stream"]), + "hasSubtitleStream": bool(reference_data["subtitle_stream"]), + } + final_data.update(self.attributesFromInstance(self.attribute_map, reference_data)) + + del reference_data + + return final_data + + def __getattr__(self, item): + if self.details and item in self.details: + return self.details[item] + raise AttributeError("%r object has no attribute %r" % (self.__class__, item)) + + +class MediaDetailsIncomplete(MediaDetails): + """ + Gathers attributes from a TranscodeSession + """ + + incompleteAttribMap = { + "container": "transcode_session.attrib_container", + "videoCodec": "transcode_session.videoCodec", + "videoStreamDecision": "transcode_session.videoDecision", + "transcodeVideoDecision": "transcode_session.videoDecision", + "audioCodec": "transcode_session.audioCodec", + "audioChannels": "transcode_session.audioChannels", + "audioStreamDecision": "transcode_session.audioDecision", + "subtitleStreamDecision": "transcode_session.subtitleDecision", + } + + def findMediaDetails(self, mediaContainer, mediaChoice, incompleteSessionData=None): + transcodeSession = mediaContainer._findTranscodeSession(incompleteSessionData) + + # get base data from original mediaChoice media instance + data = MediaDetails.findMediaDetails(self, mediaContainer, mediaChoice, transcodeSession=transcodeSession) + + decision = "directplay" + bandwidths = mediaContainer._findBandwidths(incompleteSessionData) + + if transcodeSession: + decision = "transcode" + + data.update(self.attributesFromInstance(self.incompleteAttribMap, {"transcode_session": transcodeSession})) + + # fill remaining data + + for bw in bandwidths: + if bw.resolution: + data["videoResolution"] = bw.resolution + break + + if data["hasVideoStream"]: + # sadly we don't know the final bitrate for the video/audio streams with incomplete data + data["videoBitrate"] = "?" + + if data["hasAudioStream"]: + data["audioBitrate"] = "?" + + if data["hasSubtitleStream"]: + if data["subtitleStreamDecision"] == "burn": + data["subtitleBurn"] = True + data["subtitleCodec"] = "burn" + + data["partDecision"] = decision + + return data + + +class MediaDetailsHolder: + """ + Holds information about the currently selected MediaContainer (self.original) and the currently playing + MediaContainer (self.session) + """ + session = None + original = None + + def __init__(self, originalMedia, sessionMedia, mediaChoice, incompleteSessionData=None): + if incompleteSessionData: + self.session = MediaDetailsIncomplete(originalMedia, mediaChoice, + incompleteSessionData=incompleteSessionData) + else: + self.session = MediaDetails(sessionMedia, mediaChoice) + self.original = MediaDetails(originalMedia, mediaChoice) + + +ATTRIBUTE_TYPES = OrderedDict() + + +def registerAttributeType(cls): + ATTRIBUTE_TYPES[cls.name] = cls + return cls + + +def normRes(res): + try: + int(res) + except: + pass + else: + res += "p" + return res + + +class DPAttribute: + """ + An attribute reference to source.attr + """ + def __init__(self, attr, source="details.original"): + self.attr = attr + self.attrWithPath = "%s.%s" % (source, attr) if source else attr + + def __call__(self, *args, **kwargs): + return self.value(*args, **kwargs) + + def resolve(self, instance_or_value, obj): + """ + Resolve attribute to value based on the given type. + Returns value or Attribute.value() + + :param instance_or_value: Attribute instance or value + :param obj: VideoSessionInfo instance + :return: + """ + return instance_or_value.value(obj) if isinstance(instance_or_value, DPAttribute) else instance_or_value + + def value(self, obj): + """ + Returns value of the given path based on obj + + :param obj: VideoSessionInfo instance + :return: + """ + o = obj + for p in self.attrWithPath.split("."): + o = getattr(o, p, None) + + return o + + +class DPAttributeOriginal(DPAttribute): + pass + + +class DPAttributeSession(DPAttribute): + def __init__(self, attr): + DPAttribute.__init__(self, attr, source="details.session") + + +class DPAttributesDiffer(DPAttribute): + def __init__(self, attr, formatTrue=u"%(val1)s->%(val2)s", formatFalse=u"%(val1)s", + valueFormatter=lambda i, v1, v2: [v1, v2]): + DPAttribute.__init__(self, attr) + self.formatTrue = formatTrue + self.formatFalse = formatFalse + self.valueFormatter = valueFormatter + + def value(self, obj): + """ + Returns formatted value if values differ, otherwise the original value based on attr + + :param obj: VideoSessionInfo instance + :return: + """ + val1 = getattr(obj.details.original, self.attr, None) + val2 = getattr(obj.details.session, self.attr, None) + formatted_val1, formatted_val2 = self.valueFormatter(obj, val1, val2) + + if formatted_val2 and formatted_val1 != formatted_val2: + return self.formatTrue % {"val1": formatted_val1, "val2": formatted_val2} + if not formatted_val1: + return "" + return (self.formatFalse % {"val1": formatted_val1, "val2": formatted_val2}) if self.formatFalse else formatted_val1 + + +class DPAttributeExists(DPAttribute): + def __init__(self, attr, source="details.session", returnValue=None): + DPAttribute.__init__(self, attr, source=source) + self.returnValue = returnValue + + def value(self, obj): + """ + Returns returnValue, which may also be an Attribute instance, in case attr exists on obj + + :param obj: VideoSessionInfo instance + :return: + """ + result = DPAttribute.value(self, obj) + if self.returnValue and result: + return self.resolve(self.returnValue, obj) + + return result + + +class DPAttributeEqualsValue(DPAttribute): + def __init__(self, attr, compareTo, retVal, source="details.session"): + DPAttribute.__init__(self, attr, source=source) + self.compareTo = compareTo + self.retVal = retVal + + def value(self, obj): + """ + Returns retVal, which may also be an Attribute, if attr's value equals compareTo's value. compareTo may also + be an Attribute. + + :param obj: VideoSessionInfo instance + :return: + """ + result = DPAttribute.value(self, obj) + if result == self.resolve(self.compareTo, obj): + return self.resolve(self.retVal, obj) + + +class ComputedPPIValue: + """ + Holds the final computed attribute data for display + """ + name = None + data = None + displayCondition = None + dataPoints = [] + + @property + def label(self): + return self.name + + @property + def value(self): + return ", ".join([x for x in self.data if x not in (None, "")]) + + def __str__(self): + return "%s: %s" % (self.label, self.value) + + def __repr__(self): + return str(self) + + +@registerAttributeType +class ModePPI(ComputedPPIValue): + name = "Mode" + dataPoints = [ + DPAttributeSession("partDecision"), + DPAttributeExists("local", source="session.player", returnValue="local") + ] + + +@registerAttributeType +class ContainerPPI(ComputedPPIValue): + name = "Container" + dataPoints = [ + DPAttributesDiffer("container"), + ] + + +@registerAttributeType +class VideoPPI(ComputedPPIValue): + name = "Video" + displayCondition = DPAttributeExists("hasVideoStream", source="details.original") + dataPoints = [ + DPAttributesDiffer("videoCodec"), + DPAttributesDiffer("videoResolution", valueFormatter=lambda i, v1, v2: [normRes(v1), normRes(v2)]), + DPAttributesDiffer("videoBitrate", formatTrue=u"%(val1)s->%(val2)skbit", formatFalse=u"%(val1)skbit"), + lambda i: [ + (i.details.session.videoStreamDecision + " HW") + if i.details.session.transcodeVideoDecision == "transcode" and i.details.session.transcodeHWEncoding + else i.details.session.videoStreamDecision + ] + ] + + +@registerAttributeType +class AudioPPI(ComputedPPIValue): + name = "Audio" + displayCondition = DPAttributeExists("hasAudioStream", source="details.original") + dataPoints = [ + DPAttributesDiffer("audioCodec"), + DPAttributesDiffer("audioBitrate", formatTrue=u"%(val1)s->%(val2)skbit", formatFalse=u"%(val1)skbit"), + DPAttributesDiffer("audioChannels", formatTrue=u"%(val1)s->%(val2)sch", formatFalse=u"%(val1)sch"), + DPAttributeExists("audioStreamDecision") + ] + + +@registerAttributeType +class SubtitlesPPI(ComputedPPIValue): + name = "Subtitles" + displayCondition = DPAttributeExists("hasSubtitleStream", source="details.original") + dataPoints = [ + DPAttributesDiffer("subtitleCodec", valueFormatter=lambda i, v1, v2: [v1, + "burn" if i.details.session.subtitleBurn else v2]), + DPAttributeEqualsValue("subtitleStreamDecision", "burn", DPAttribute("subtitleStreamDecision")), + DPAttributeExists("subtitleLocation") + ] + + +@registerAttributeType +class UserPPI(ComputedPPIValue): + name = "User" + dataPoints = [ + lambda i: [u"%s @ %s" % (plexapp.ACCOUNT.title or plexapp.ACCOUNT.username or ' ', i.mediaItem.server.name)] + ] + + +class SessionAttributes(OrderedDict): + """ + Computes all the PPI instances' values + """ + def __init__(self, ref, *args, **kwargs): + self.ref = ref + OrderedDict.__init__(self, *args, **kwargs) + + for name, cls in six.iteritems(ATTRIBUTE_TYPES): + self[name] = instance = cls() + instance.data = [] + if not instance.displayCondition or instance.displayCondition(self.ref): + for dp in instance.dataPoints: + try: + # dataPoint may be a lambda or a DataPoint instance + result = dp(self.ref) + + # result may be list or value + if result is not None: + if isinstance(result, list): + instance.data += result + else: + instance.data.append(result) + except: + pass + + +class VideoSessionInfo: + def __init__(self, sessionMediaContainer, mediaContainer, incompleteSessionData=False): + self.mediaItem = mediaContainer + self.session = sessionMediaContainer + self.details = MediaDetailsHolder(self.mediaItem, self.session, mediaContainer.mediaChoice, + incompleteSessionData=incompleteSessionData) + + self.attributes = SessionAttributes(self) + diff --git a/script.plexmod/lib/backgroundthread.py b/script.plexmod/lib/backgroundthread.py new file mode 100644 index 0000000000..7b69cd09d8 --- /dev/null +++ b/script.plexmod/lib/backgroundthread.py @@ -0,0 +1,255 @@ +from __future__ import absolute_import +import six.moves.queue +import heapq +from kodi_six import xbmc +from . import util +from plexnet import threadutils +from six.moves import range + + +class Tasks(list): + def add(self, task): + for t in self: + if not t.isValid(): + self.remove(t) + + if isinstance(task, list): + self += task + else: + self.append(task) + + def cancel(self): + while self: + self.pop().cancel() + + def kill(self): + self.cancel() + BGThreader.kill() + + +class Task: + def __init__(self, priority=None): + self._priority = priority + self._canceled = False + self.finished = False + + def __cmp__(self, other): + return self._priority - other._priority + + def __le__(self, other): + return self._priority < other._priority + + def __gt__(self, other): + return self._priority > other._priority + + def start(self): + BGThreader.addTask(self) + + def _run(self): + self.run() + self.finished = True + + def run(self): + pass + + def cancel(self): + self._canceled = True + + def isCanceled(self): + return self._canceled or util.MONITOR.abortRequested() + + def isValid(self): + return not self.finished and not self._canceled + + +class MutablePriorityQueue(six.moves.queue.PriorityQueue): + def _get(self, heappop=heapq.heappop): + self.queue.sort() + return heappop(self.queue) + + def lowest(self): + """Return the lowest priority item in the queue (not reliable!).""" + self.mutex.acquire() + try: + lowest = self.queue and min(self.queue) or None + except: + lowest = None + util.ERROR() + finally: + self.mutex.release() + return lowest + + +class BackgroundWorker: + def __init__(self, queue, name=None): + self._queue = queue + self.name = name + self._thread = None + self._abort = False + self._task = None + + def _runTask(self, task): + if task._canceled: + return + try: + task._run() + except: + util.ERROR() + + def abort(self): + self._abort = True + return self + + def aborted(self): + return self._abort or util.MONITOR.abortRequested() + + def start(self): + if self._thread and self._thread.is_alive(): + return + + self._thread = threadutils.KillableThread(target=self._queueLoop, name='BACKGROUND-WORKER({0})'.format(self.name)) + self._thread.start() + + def _queueLoop(self): + if self._queue.empty(): + return + + util.DEBUG_LOG('BGThreader: ({0}): Active'.format(self.name)) + try: + while not self.aborted(): + self._task = self._queue.get_nowait() + self._runTask(self._task) + self._queue.task_done() + self._task = None + except six.moves.queue.Empty: + util.DEBUG_LOG('BGThreader ({0}): Idle'.format(self.name)) + + def shutdown(self): + self.abort() + + if self._task: + self._task.cancel() + + if self._thread and self._thread.is_alive(): + util.DEBUG_LOG('BGThreader: thread ({0}): Waiting...'.format(self.name)) + self._thread.join() + util.DEBUG_LOG('BGThreader: thread ({0}): Done'.format(self.name)) + + def working(self): + return self._thread and self._thread.is_alive() + + def kill(self): + if self._thread and self._thread.is_alive(): + util.DEBUG_LOG('BGThreader: thread ({0}): Waiting...'.format(self.name)) + self._thread.join() + util.DEBUG_LOG('BGThreader: thread ({0}): Done'.format(self.name)) + + +class BackgroundThreader: + def __init__(self, name=None, worker_count=3): + self.name = name + self._queue = MutablePriorityQueue() + self._abort = False + self._priority = -1 + self.workers = [BackgroundWorker(self._queue, 'queue.{0}:worker.{1}'.format(self.name, x)) for x in range(worker_count)] + + def _nextPriority(self): + self._priority += 1 + return self._priority + + def abort(self): + self._abort = True + for w in self.workers: + w.abort() + return self + + def aborted(self): + return self._abort or util.MONITOR.abortRequested() + + def shutdown(self): + self.abort() + + for w in self.workers: + w.shutdown() + + def addTask(self, task): + task._priority = self._nextPriority() + self._queue.put(task) + self.startWorkers() + + def addTasks(self, tasks): + for t in tasks: + t._priority = self._nextPriority() + self._queue.put(t) + + self.startWorkers() + + def addTasksToFront(self, tasks): + lowest = self.getLowestPrority() + if lowest is None: + return self.addTasks(tasks) + + p = lowest - len(tasks) + for t in tasks: + t._priority = p + self._queue.put(t) + p += 1 + + self.startWorkers() + + def startWorkers(self): + for w in self.workers: + w.start() + + def working(self): + return not self._queue.empty() or self.hasTask() + + def hasTask(self): + return any([w.working() for w in self.workers]) + + def getLowestPrority(self): + lowest = self._queue.lowest() + if not lowest: + return None + + return lowest._priority + + def moveToFront(self, qitem): + lowest = self.getLowestPrority() + if lowest is None: + return + + qitem._priority = lowest - 1 + + def kill(self): + for w in self.workers: + w.kill() + + +class ThreaderManager: + def __init__(self): + self.index = 0 + self.abandoned = [] + self.threader = BackgroundThreader(str(self.index)) + + def __getattr__(self, name): + return getattr(self.threader, name) + + def reset(self): + if self.threader._queue.empty() and not self.threader.hasTask(): + return + + self.index += 1 + self.abandoned.append(self.threader.abort()) + self.threader = BackgroundThreader(str(self.index)) + + def shutdown(self): + self.threader.shutdown() + for a in self.abandoned: + a.shutdown() + + def kill(self): + self.threader.kill() + + +BGThreader = ThreaderManager() diff --git a/script.plexmod/lib/colors.py b/script.plexmod/lib/colors.py new file mode 100644 index 0000000000..92d8d49df7 --- /dev/null +++ b/script.plexmod/lib/colors.py @@ -0,0 +1,79 @@ +# Constants +Background = 'FF111111' +BackgroundDark = 'FF0A0A0A' + +# OverlayVeryDark = GetAlpha(FF000000, 90), +# OverlayDark = GetAlpha(FF000000, 70), +# OverlayMed = GetAlpha(FF000000, 50), +# OverlayLht = GetAlpha(FF000000, 35), + +Border = 'FF1F1F1F' +Empty = 'FF1F1F1F' +Card = 'FF1F1F1F' +Button = 'FF1F1F1F' +ButtonDark = 'FF171717' +ButtonLht = 'FF555555' +ButtonMed = 'FF2D2D2D' +Indicator = 'FF999999' +Text = 'FFFFFFFF' +Subtitle = 'FF999999' + +# These are dependent on the regions background color +# TextLht = GetAlpha(FFFFFFFF, 90), +# TextMed = GetAlpha(FFFFFFFF, 75), +# TextDim = GetAlpha(FFFFFFFF, 50), +# TextDis = GetAlpha(FFFFFFFF, 30), +# TextDimDis = GetAlpha(FFFFFFFF, 10), + +Transparent = '00000000' +Black = 'FF000000' +Blue = 'FF0033CC' +Red = 'FFC23529' +RedAlt = 'FFD9534F' +Green = 'FF5CB85C' +Orange = 'FFCC7B19' +OrangeLight = 'FFF9BE03' + +# Component specific +# SettingsBg = 'FF2C2C2C' +# ScrollbarBg = GetAlpha(FFFFFFFF, 10), +# ScrollbarFgFocus = GetAlpha('Orange' 70), +# ScrollbarFg = GetAlpha(FFFFFFFF, 25), +# IndicatorBorder = 'FF000000' +# Separator = 'FF000000' +# Modal = GetAlpha(FF000000, 85), +# Focus = Orange, +# FocusToggle = OrangeLight, + +# ListFocusBg = GetAlpha(FF000000, 40), +# TrackActionsBg = GetAlpha(FF000000, 30), +# ListBg = GetAlpha(FFFFFFFF, 10), +# ListBgNoBlur = GetAlpha(FF666666, 40), +# ListImageBorder = 'FF595959' + +SearchBg = 'FF2D2D2D' +SearchButton = 'FF282828' +SearchButtonDark = 'FF1F1F1F' +SearchButtonLight = 'FF555555' + +InputBg = 'FF000000' +InputButton = 'FF282828' +InputButtonDark = 'FF1F1F1F' +InputButtonLight = 'FF555555' + + +class _noAlpha: + def __getattr__(self, name): + return globals()[name][2:] + +noAlpha = _noAlpha() + + +# def getAlpha(color, percent): +# if isinstance(color, basestring): +# color = COLORS[color] + +# if isinstance(color, int): +# util.ERROR_LOG(str(color) + " is not found in object") + +# return color and int((percent / 100 * 255) - 256) diff --git a/script.plexmod/lib/compat.py b/script.plexmod/lib/compat.py new file mode 100644 index 0000000000..d7558a7cb0 --- /dev/null +++ b/script.plexmod/lib/compat.py @@ -0,0 +1,21 @@ +from __future__ import absolute_import +import time +import datetime + +try: + datetime.datetime.strptime('0', '%H') +except TypeError: + # Fix for datetime issues with XBMC/Kodi + class new_datetime(datetime.datetime): + @classmethod + def strptime(cls, dstring, dformat): + return datetime.datetime(*(time.strptime(dstring, dformat)[0:6])) + + datetime.datetime = new_datetime + + +def timedelta_total_seconds(td): + try: + return td.total_seconds() + except: + return ((float(td.seconds) + float(td.days) * 24 * 3600) * 10**6) / 10**6 diff --git a/script.plexmod/lib/distro.py b/script.plexmod/lib/distro.py new file mode 100644 index 0000000000..89e1868047 --- /dev/null +++ b/script.plexmod/lib/distro.py @@ -0,0 +1,1399 @@ +#!/usr/bin/env python +# Copyright 2015,2016,2017 Nir Cohen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +The ``distro`` package (``distro`` stands for Linux Distribution) provides +information about the Linux distribution it runs on, such as a reliable +machine-readable distro ID, or version information. + +It is the recommended replacement for Python's original +:py:func:`platform.linux_distribution` function, but it provides much more +functionality. An alternative implementation became necessary because Python +3.5 deprecated this function, and Python 3.8 removed it altogether. Its +predecessor function :py:func:`platform.dist` was already deprecated since +Python 2.6 and removed in Python 3.8. Still, there are many cases in which +access to OS distribution information is needed. See `Python issue 1322 +`_ for more information. +""" + +import argparse +import json +import logging +import os +import re +import shlex +import subprocess +import sys +import warnings +from typing import ( + Any, + Callable, + Dict, + Iterable, + Optional, + Sequence, + TextIO, + Tuple, + Type, +) + +try: + from typing import TypedDict +except ImportError: + # Python 3.7 + TypedDict = dict + +__version__ = "1.8.0" + + +class VersionDict(TypedDict): + major: str + minor: str + build_number: str + + +class InfoDict(TypedDict): + id: str + version: str + version_parts: VersionDict + like: str + codename: str + + +_UNIXCONFDIR = os.environ.get("UNIXCONFDIR", "/etc") +_UNIXUSRLIBDIR = os.environ.get("UNIXUSRLIBDIR", "/usr/lib") +_OS_RELEASE_BASENAME = "os-release" + +#: Translation table for normalizing the "ID" attribute defined in os-release +#: files, for use by the :func:`distro.id` method. +#: +#: * Key: Value as defined in the os-release file, translated to lower case, +#: with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_OS_ID = { + "ol": "oracle", # Oracle Linux + "opensuse-leap": "opensuse", # Newer versions of OpenSuSE report as opensuse-leap +} + +#: Translation table for normalizing the "Distributor ID" attribute returned by +#: the lsb_release command, for use by the :func:`distro.id` method. +#: +#: * Key: Value as returned by the lsb_release command, translated to lower +#: case, with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_LSB_ID = { + "enterpriseenterpriseas": "oracle", # Oracle Enterprise Linux 4 + "enterpriseenterpriseserver": "oracle", # Oracle Linux 5 + "redhatenterpriseworkstation": "rhel", # RHEL 6, 7 Workstation + "redhatenterpriseserver": "rhel", # RHEL 6, 7 Server + "redhatenterprisecomputenode": "rhel", # RHEL 6 ComputeNode +} + +#: Translation table for normalizing the distro ID derived from the file name +#: of distro release files, for use by the :func:`distro.id` method. +#: +#: * Key: Value as derived from the file name of a distro release file, +#: translated to lower case, with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_DISTRO_ID = { + "redhat": "rhel", # RHEL 6.x, 7.x +} + +# Pattern for content of distro release file (reversed) +_DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile( + r"(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)" +) + +# Pattern for base file name of distro release file +_DISTRO_RELEASE_BASENAME_PATTERN = re.compile(r"(\w+)[-_](release|version)$") + +# Base file names to be looked up for if _UNIXCONFDIR is not readable. +_DISTRO_RELEASE_BASENAMES = [ + "SuSE-release", + "arch-release", + "base-release", + "centos-release", + "fedora-release", + "gentoo-release", + "mageia-release", + "mandrake-release", + "mandriva-release", + "mandrivalinux-release", + "manjaro-release", + "oracle-release", + "redhat-release", + "rocky-release", + "sl-release", + "slackware-version", +] + +# Base file names to be ignored when searching for distro release file +_DISTRO_RELEASE_IGNORE_BASENAMES = ( + "debian_version", + "lsb-release", + "oem-release", + _OS_RELEASE_BASENAME, + "system-release", + "plesk-release", + "iredmail-release", +) + + +def linux_distribution(full_distribution_name: bool = True) -> Tuple[str, str, str]: + """ + .. deprecated:: 1.6.0 + + :func:`distro.linux_distribution()` is deprecated. It should only be + used as a compatibility shim with Python's + :py:func:`platform.linux_distribution()`. Please use :func:`distro.id`, + :func:`distro.version` and :func:`distro.name` instead. + + Return information about the current OS distribution as a tuple + ``(id_name, version, codename)`` with items as follows: + + * ``id_name``: If *full_distribution_name* is false, the result of + :func:`distro.id`. Otherwise, the result of :func:`distro.name`. + + * ``version``: The result of :func:`distro.version`. + + * ``codename``: The extra item (usually in parentheses) after the + os-release version number, or the result of :func:`distro.codename`. + + The interface of this function is compatible with the original + :py:func:`platform.linux_distribution` function, supporting a subset of + its parameters. + + The data it returns may not exactly be the same, because it uses more data + sources than the original function, and that may lead to different data if + the OS distribution is not consistent across multiple data sources it + provides (there are indeed such distributions ...). + + Another reason for differences is the fact that the :func:`distro.id` + method normalizes the distro ID string to a reliable machine-readable value + for a number of popular OS distributions. + """ + warnings.warn( + "distro.linux_distribution() is deprecated. It should only be used as a " + "compatibility shim with Python's platform.linux_distribution(). Please use " + "distro.id(), distro.version() and distro.name() instead.", + DeprecationWarning, + stacklevel=2, + ) + return _distro.linux_distribution(full_distribution_name) + + +def id() -> str: + """ + Return the distro ID of the current distribution, as a + machine-readable string. + + For a number of OS distributions, the returned distro ID value is + *reliable*, in the sense that it is documented and that it does not change + across releases of the distribution. + + This package maintains the following reliable distro ID values: + + ============== ========================================= + Distro ID Distribution + ============== ========================================= + "ubuntu" Ubuntu + "debian" Debian + "rhel" RedHat Enterprise Linux + "centos" CentOS + "fedora" Fedora + "sles" SUSE Linux Enterprise Server + "opensuse" openSUSE + "amzn" Amazon Linux + "arch" Arch Linux + "buildroot" Buildroot + "cloudlinux" CloudLinux OS + "exherbo" Exherbo Linux + "gentoo" GenToo Linux + "ibm_powerkvm" IBM PowerKVM + "kvmibm" KVM for IBM z Systems + "linuxmint" Linux Mint + "mageia" Mageia + "mandriva" Mandriva Linux + "parallels" Parallels + "pidora" Pidora + "raspbian" Raspbian + "oracle" Oracle Linux (and Oracle Enterprise Linux) + "scientific" Scientific Linux + "slackware" Slackware + "xenserver" XenServer + "openbsd" OpenBSD + "netbsd" NetBSD + "freebsd" FreeBSD + "midnightbsd" MidnightBSD + "rocky" Rocky Linux + "aix" AIX + "guix" Guix System + ============== ========================================= + + If you have a need to get distros for reliable IDs added into this set, + or if you find that the :func:`distro.id` function returns a different + distro ID for one of the listed distros, please create an issue in the + `distro issue tracker`_. + + **Lookup hierarchy and transformations:** + + First, the ID is obtained from the following sources, in the specified + order. The first available and non-empty value is used: + + * the value of the "ID" attribute of the os-release file, + + * the value of the "Distributor ID" attribute returned by the lsb_release + command, + + * the first part of the file name of the distro release file, + + The so determined ID value then passes the following transformations, + before it is returned by this method: + + * it is translated to lower case, + + * blanks (which should not be there anyway) are translated to underscores, + + * a normalization of the ID is performed, based upon + `normalization tables`_. The purpose of this normalization is to ensure + that the ID is as reliable as possible, even across incompatible changes + in the OS distributions. A common reason for an incompatible change is + the addition of an os-release file, or the addition of the lsb_release + command, with ID values that differ from what was previously determined + from the distro release file name. + """ + return _distro.id() + + +def name(pretty: bool = False) -> str: + """ + Return the name of the current OS distribution, as a human-readable + string. + + If *pretty* is false, the name is returned without version or codename. + (e.g. "CentOS Linux") + + If *pretty* is true, the version and codename are appended. + (e.g. "CentOS Linux 7.1.1503 (Core)") + + **Lookup hierarchy:** + + The name is obtained from the following sources, in the specified order. + The first available and non-empty value is used: + + * If *pretty* is false: + + - the value of the "NAME" attribute of the os-release file, + + - the value of the "Distributor ID" attribute returned by the lsb_release + command, + + - the value of the "" field of the distro release file. + + * If *pretty* is true: + + - the value of the "PRETTY_NAME" attribute of the os-release file, + + - the value of the "Description" attribute returned by the lsb_release + command, + + - the value of the "" field of the distro release file, appended + with the value of the pretty version ("" and "" + fields) of the distro release file, if available. + """ + return _distro.name(pretty) + + +def version(pretty: bool = False, best: bool = False) -> str: + """ + Return the version of the current OS distribution, as a human-readable + string. + + If *pretty* is false, the version is returned without codename (e.g. + "7.0"). + + If *pretty* is true, the codename in parenthesis is appended, if the + codename is non-empty (e.g. "7.0 (Maipo)"). + + Some distributions provide version numbers with different precisions in + the different sources of distribution information. Examining the different + sources in a fixed priority order does not always yield the most precise + version (e.g. for Debian 8.2, or CentOS 7.1). + + Some other distributions may not provide this kind of information. In these + cases, an empty string would be returned. This behavior can be observed + with rolling releases distributions (e.g. Arch Linux). + + The *best* parameter can be used to control the approach for the returned + version: + + If *best* is false, the first non-empty version number in priority order of + the examined sources is returned. + + If *best* is true, the most precise version number out of all examined + sources is returned. + + **Lookup hierarchy:** + + In all cases, the version number is obtained from the following sources. + If *best* is false, this order represents the priority order: + + * the value of the "VERSION_ID" attribute of the os-release file, + * the value of the "Release" attribute returned by the lsb_release + command, + * the version number parsed from the "" field of the first line + of the distro release file, + * the version number parsed from the "PRETTY_NAME" attribute of the + os-release file, if it follows the format of the distro release files. + * the version number parsed from the "Description" attribute returned by + the lsb_release command, if it follows the format of the distro release + files. + """ + return _distro.version(pretty, best) + + +def version_parts(best: bool = False) -> Tuple[str, str, str]: + """ + Return the version of the current OS distribution as a tuple + ``(major, minor, build_number)`` with items as follows: + + * ``major``: The result of :func:`distro.major_version`. + + * ``minor``: The result of :func:`distro.minor_version`. + + * ``build_number``: The result of :func:`distro.build_number`. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.version_parts(best) + + +def major_version(best: bool = False) -> str: + """ + Return the major version of the current OS distribution, as a string, + if provided. + Otherwise, the empty string is returned. The major version is the first + part of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.major_version(best) + + +def minor_version(best: bool = False) -> str: + """ + Return the minor version of the current OS distribution, as a string, + if provided. + Otherwise, the empty string is returned. The minor version is the second + part of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.minor_version(best) + + +def build_number(best: bool = False) -> str: + """ + Return the build number of the current OS distribution, as a string, + if provided. + Otherwise, the empty string is returned. The build number is the third part + of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.build_number(best) + + +def like() -> str: + """ + Return a space-separated list of distro IDs of distributions that are + closely related to the current OS distribution in regards to packaging + and programming interfaces, for example distributions the current + distribution is a derivative from. + + **Lookup hierarchy:** + + This information item is only provided by the os-release file. + For details, see the description of the "ID_LIKE" attribute in the + `os-release man page + `_. + """ + return _distro.like() + + +def codename() -> str: + """ + Return the codename for the release of the current OS distribution, + as a string. + + If the distribution does not have a codename, an empty string is returned. + + Note that the returned codename is not always really a codename. For + example, openSUSE returns "x86_64". This function does not handle such + cases in any special way and just returns the string it finds, if any. + + **Lookup hierarchy:** + + * the codename within the "VERSION" attribute of the os-release file, if + provided, + + * the value of the "Codename" attribute returned by the lsb_release + command, + + * the value of the "" field of the distro release file. + """ + return _distro.codename() + + +def info(pretty: bool = False, best: bool = False) -> InfoDict: + """ + Return certain machine-readable information items about the current OS + distribution in a dictionary, as shown in the following example: + + .. sourcecode:: python + + { + 'id': 'rhel', + 'version': '7.0', + 'version_parts': { + 'major': '7', + 'minor': '0', + 'build_number': '' + }, + 'like': 'fedora', + 'codename': 'Maipo' + } + + The dictionary structure and keys are always the same, regardless of which + information items are available in the underlying data sources. The values + for the various keys are as follows: + + * ``id``: The result of :func:`distro.id`. + + * ``version``: The result of :func:`distro.version`. + + * ``version_parts -> major``: The result of :func:`distro.major_version`. + + * ``version_parts -> minor``: The result of :func:`distro.minor_version`. + + * ``version_parts -> build_number``: The result of + :func:`distro.build_number`. + + * ``like``: The result of :func:`distro.like`. + + * ``codename``: The result of :func:`distro.codename`. + + For a description of the *pretty* and *best* parameters, see the + :func:`distro.version` method. + """ + return _distro.info(pretty, best) + + +def os_release_info() -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information items + from the os-release file data source of the current OS distribution. + + See `os-release file`_ for details about these information items. + """ + return _distro.os_release_info() + + +def lsb_release_info() -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information items + from the lsb_release command data source of the current OS distribution. + + See `lsb_release command output`_ for details about these information + items. + """ + return _distro.lsb_release_info() + + +def distro_release_info() -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information items + from the distro release file data source of the current OS distribution. + + See `distro release file`_ for details about these information items. + """ + return _distro.distro_release_info() + + +def uname_info() -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information items + from the distro release file data source of the current OS distribution. + """ + return _distro.uname_info() + + +def os_release_attr(attribute: str) -> str: + """ + Return a single named information item from the os-release file data source + of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `os-release file`_ for details about these information items. + """ + return _distro.os_release_attr(attribute) + + +def lsb_release_attr(attribute: str) -> str: + """ + Return a single named information item from the lsb_release command output + data source of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `lsb_release command output`_ for details about these information + items. + """ + return _distro.lsb_release_attr(attribute) + + +def distro_release_attr(attribute: str) -> str: + """ + Return a single named information item from the distro release file + data source of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `distro release file`_ for details about these information items. + """ + return _distro.distro_release_attr(attribute) + + +def uname_attr(attribute: str) -> str: + """ + Return a single named information item from the distro release file + data source of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + """ + return _distro.uname_attr(attribute) + + +try: + from functools import cached_property +except ImportError: + # Python < 3.8 + class cached_property: # type: ignore + """A version of @property which caches the value. On access, it calls the + underlying function and sets the value in `__dict__` so future accesses + will not re-call the property. + """ + + def __init__(self, f: Callable[[Any], Any]) -> None: + self._fname = f.__name__ + self._f = f + + def __get__(self, obj: Any, owner: Type[Any]) -> Any: + assert obj is not None, f"call {self._fname} on an instance" + ret = obj.__dict__[self._fname] = self._f(obj) + return ret + + +class LinuxDistribution: + """ + Provides information about a OS distribution. + + This package creates a private module-global instance of this class with + default initialization arguments, that is used by the + `consolidated accessor functions`_ and `single source accessor functions`_. + By using default initialization arguments, that module-global instance + returns data about the current OS distribution (i.e. the distro this + package runs on). + + Normally, it is not necessary to create additional instances of this class. + However, in situations where control is needed over the exact data sources + that are used, instances of this class can be created with a specific + distro release file, or a specific os-release file, or without invoking the + lsb_release command. + """ + + def __init__( + self, + include_lsb: Optional[bool] = None, + os_release_file: str = "", + distro_release_file: str = "", + include_uname: Optional[bool] = None, + root_dir: Optional[str] = None, + include_oslevel: Optional[bool] = None, + ) -> None: + """ + The initialization method of this class gathers information from the + available data sources, and stores that in private instance attributes. + Subsequent access to the information items uses these private instance + attributes, so that the data sources are read only once. + + Parameters: + + * ``include_lsb`` (bool): Controls whether the + `lsb_release command output`_ is included as a data source. + + If the lsb_release command is not available in the program execution + path, the data source for the lsb_release command will be empty. + + * ``os_release_file`` (string): The path name of the + `os-release file`_ that is to be used as a data source. + + An empty string (the default) will cause the default path name to + be used (see `os-release file`_ for details). + + If the specified or defaulted os-release file does not exist, the + data source for the os-release file will be empty. + + * ``distro_release_file`` (string): The path name of the + `distro release file`_ that is to be used as a data source. + + An empty string (the default) will cause a default search algorithm + to be used (see `distro release file`_ for details). + + If the specified distro release file does not exist, or if no default + distro release file can be found, the data source for the distro + release file will be empty. + + * ``include_uname`` (bool): Controls whether uname command output is + included as a data source. If the uname command is not available in + the program execution path the data source for the uname command will + be empty. + + * ``root_dir`` (string): The absolute path to the root directory to use + to find distro-related information files. Note that ``include_*`` + parameters must not be enabled in combination with ``root_dir``. + + * ``include_oslevel`` (bool): Controls whether (AIX) oslevel command + output is included as a data source. If the oslevel command is not + available in the program execution path the data source will be + empty. + + Public instance attributes: + + * ``os_release_file`` (string): The path name of the + `os-release file`_ that is actually used as a data source. The + empty string if no distro release file is used as a data source. + + * ``distro_release_file`` (string): The path name of the + `distro release file`_ that is actually used as a data source. The + empty string if no distro release file is used as a data source. + + * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter. + This controls whether the lsb information will be loaded. + + * ``include_uname`` (bool): The result of the ``include_uname`` + parameter. This controls whether the uname information will + be loaded. + + * ``include_oslevel`` (bool): The result of the ``include_oslevel`` + parameter. This controls whether (AIX) oslevel information will be + loaded. + + * ``root_dir`` (string): The result of the ``root_dir`` parameter. + The absolute path to the root directory to use to find distro-related + information files. + + Raises: + + * :py:exc:`ValueError`: Initialization parameters combination is not + supported. + + * :py:exc:`OSError`: Some I/O issue with an os-release file or distro + release file. + + * :py:exc:`UnicodeError`: A data source has unexpected characters or + uses an unexpected encoding. + """ + self.root_dir = root_dir + self.etc_dir = os.path.join(root_dir, "etc") if root_dir else _UNIXCONFDIR + self.usr_lib_dir = ( + os.path.join(root_dir, "usr/lib") if root_dir else _UNIXUSRLIBDIR + ) + + if os_release_file: + self.os_release_file = os_release_file + else: + etc_dir_os_release_file = os.path.join(self.etc_dir, _OS_RELEASE_BASENAME) + usr_lib_os_release_file = os.path.join( + self.usr_lib_dir, _OS_RELEASE_BASENAME + ) + + # NOTE: The idea is to respect order **and** have it set + # at all times for API backwards compatibility. + if os.path.isfile(etc_dir_os_release_file) or not os.path.isfile( + usr_lib_os_release_file + ): + self.os_release_file = etc_dir_os_release_file + else: + self.os_release_file = usr_lib_os_release_file + + self.distro_release_file = distro_release_file or "" # updated later + + is_root_dir_defined = root_dir is not None + if is_root_dir_defined and (include_lsb or include_uname or include_oslevel): + raise ValueError( + "Including subprocess data sources from specific root_dir is disallowed" + " to prevent false information" + ) + self.include_lsb = ( + include_lsb if include_lsb is not None else not is_root_dir_defined + ) + self.include_uname = ( + include_uname if include_uname is not None else not is_root_dir_defined + ) + self.include_oslevel = ( + include_oslevel if include_oslevel is not None else not is_root_dir_defined + ) + + def __repr__(self) -> str: + """Return repr of all info""" + return ( + "LinuxDistribution(" + "os_release_file={self.os_release_file!r}, " + "distro_release_file={self.distro_release_file!r}, " + "include_lsb={self.include_lsb!r}, " + "include_uname={self.include_uname!r}, " + "include_oslevel={self.include_oslevel!r}, " + "root_dir={self.root_dir!r}, " + "_os_release_info={self._os_release_info!r}, " + "_lsb_release_info={self._lsb_release_info!r}, " + "_distro_release_info={self._distro_release_info!r}, " + "_uname_info={self._uname_info!r}, " + "_oslevel_info={self._oslevel_info!r})".format(self=self) + ) + + def linux_distribution( + self, full_distribution_name: bool = True + ) -> Tuple[str, str, str]: + """ + Return information about the OS distribution that is compatible + with Python's :func:`platform.linux_distribution`, supporting a subset + of its parameters. + + For details, see :func:`distro.linux_distribution`. + """ + return ( + self.name() if full_distribution_name else self.id(), + self.version(), + self._os_release_info.get("release_codename") or self.codename(), + ) + + def id(self) -> str: + """Return the distro ID of the OS distribution, as a string. + + For details, see :func:`distro.id`. + """ + + def normalize(distro_id: str, table: Dict[str, str]) -> str: + distro_id = distro_id.lower().replace(" ", "_") + return table.get(distro_id, distro_id) + + distro_id = self.os_release_attr("id") + if distro_id: + return normalize(distro_id, NORMALIZED_OS_ID) + + distro_id = self.lsb_release_attr("distributor_id") + if distro_id: + return normalize(distro_id, NORMALIZED_LSB_ID) + + distro_id = self.distro_release_attr("id") + if distro_id: + return normalize(distro_id, NORMALIZED_DISTRO_ID) + + distro_id = self.uname_attr("id") + if distro_id: + return normalize(distro_id, NORMALIZED_DISTRO_ID) + + return "" + + def name(self, pretty: bool = False) -> str: + """ + Return the name of the OS distribution, as a string. + + For details, see :func:`distro.name`. + """ + name = ( + self.os_release_attr("name") + or self.lsb_release_attr("distributor_id") + or self.distro_release_attr("name") + or self.uname_attr("name") + ) + if pretty: + name = self.os_release_attr("pretty_name") or self.lsb_release_attr( + "description" + ) + if not name: + name = self.distro_release_attr("name") or self.uname_attr("name") + version = self.version(pretty=True) + if version: + name = f"{name} {version}" + return name or "" + + def version(self, pretty: bool = False, best: bool = False) -> str: + """ + Return the version of the OS distribution, as a string. + + For details, see :func:`distro.version`. + """ + versions = [ + self.os_release_attr("version_id"), + self.lsb_release_attr("release"), + self.distro_release_attr("version_id"), + self._parse_distro_release_content(self.os_release_attr("pretty_name")).get( + "version_id", "" + ), + self._parse_distro_release_content( + self.lsb_release_attr("description") + ).get("version_id", ""), + self.uname_attr("release"), + ] + if self.uname_attr("id").startswith("aix"): + # On AIX platforms, prefer oslevel command output. + versions.insert(0, self.oslevel_info()) + elif self.id() == "debian" or "debian" in self.like().split(): + # On Debian-like, add debian_version file content to candidates list. + versions.append(self._debian_version) + version = "" + if best: + # This algorithm uses the last version in priority order that has + # the best precision. If the versions are not in conflict, that + # does not matter; otherwise, using the last one instead of the + # first one might be considered a surprise. + for v in versions: + if v.count(".") > version.count(".") or version == "": + version = v + else: + for v in versions: + if v != "": + version = v + break + if pretty and version and self.codename(): + version = f"{version} ({self.codename()})" + return version + + def version_parts(self, best: bool = False) -> Tuple[str, str, str]: + """ + Return the version of the OS distribution, as a tuple of version + numbers. + + For details, see :func:`distro.version_parts`. + """ + version_str = self.version(best=best) + if version_str: + version_regex = re.compile(r"(\d+)\.?(\d+)?\.?(\d+)?") + matches = version_regex.match(version_str) + if matches: + major, minor, build_number = matches.groups() + return major, minor or "", build_number or "" + return "", "", "" + + def major_version(self, best: bool = False) -> str: + """ + Return the major version number of the current distribution. + + For details, see :func:`distro.major_version`. + """ + return self.version_parts(best)[0] + + def minor_version(self, best: bool = False) -> str: + """ + Return the minor version number of the current distribution. + + For details, see :func:`distro.minor_version`. + """ + return self.version_parts(best)[1] + + def build_number(self, best: bool = False) -> str: + """ + Return the build number of the current distribution. + + For details, see :func:`distro.build_number`. + """ + return self.version_parts(best)[2] + + def like(self) -> str: + """ + Return the IDs of distributions that are like the OS distribution. + + For details, see :func:`distro.like`. + """ + return self.os_release_attr("id_like") or "" + + def codename(self) -> str: + """ + Return the codename of the OS distribution. + + For details, see :func:`distro.codename`. + """ + try: + # Handle os_release specially since distros might purposefully set + # this to empty string to have no codename + return self._os_release_info["codename"] + except KeyError: + return ( + self.lsb_release_attr("codename") + or self.distro_release_attr("codename") + or "" + ) + + def info(self, pretty: bool = False, best: bool = False) -> InfoDict: + """ + Return certain machine-readable information about the OS + distribution. + + For details, see :func:`distro.info`. + """ + return dict( + id=self.id(), + version=self.version(pretty, best), + version_parts=dict( + major=self.major_version(best), + minor=self.minor_version(best), + build_number=self.build_number(best), + ), + like=self.like(), + codename=self.codename(), + ) + + def os_release_info(self) -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information + items from the os-release file data source of the OS distribution. + + For details, see :func:`distro.os_release_info`. + """ + return self._os_release_info + + def lsb_release_info(self) -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information + items from the lsb_release command data source of the OS + distribution. + + For details, see :func:`distro.lsb_release_info`. + """ + return self._lsb_release_info + + def distro_release_info(self) -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information + items from the distro release file data source of the OS + distribution. + + For details, see :func:`distro.distro_release_info`. + """ + return self._distro_release_info + + def uname_info(self) -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information + items from the uname command data source of the OS distribution. + + For details, see :func:`distro.uname_info`. + """ + return self._uname_info + + def oslevel_info(self) -> str: + """ + Return AIX' oslevel command output. + """ + return self._oslevel_info + + def os_release_attr(self, attribute: str) -> str: + """ + Return a single named information item from the os-release file data + source of the OS distribution. + + For details, see :func:`distro.os_release_attr`. + """ + return self._os_release_info.get(attribute, "") + + def lsb_release_attr(self, attribute: str) -> str: + """ + Return a single named information item from the lsb_release command + output data source of the OS distribution. + + For details, see :func:`distro.lsb_release_attr`. + """ + return self._lsb_release_info.get(attribute, "") + + def distro_release_attr(self, attribute: str) -> str: + """ + Return a single named information item from the distro release file + data source of the OS distribution. + + For details, see :func:`distro.distro_release_attr`. + """ + return self._distro_release_info.get(attribute, "") + + def uname_attr(self, attribute: str) -> str: + """ + Return a single named information item from the uname command + output data source of the OS distribution. + + For details, see :func:`distro.uname_attr`. + """ + return self._uname_info.get(attribute, "") + + @cached_property + def _os_release_info(self) -> Dict[str, str]: + """ + Get the information items from the specified os-release file. + + Returns: + A dictionary containing all information items. + """ + if os.path.isfile(self.os_release_file): + with open(self.os_release_file, encoding="utf-8") as release_file: + return self._parse_os_release_content(release_file) + return {} + + @staticmethod + def _parse_os_release_content(lines: TextIO) -> Dict[str, str]: + """ + Parse the lines of an os-release file. + + Parameters: + + * lines: Iterable through the lines in the os-release file. + Each line must be a unicode string or a UTF-8 encoded byte + string. + + Returns: + A dictionary containing all information items. + """ + props = {} + lexer = shlex.shlex(lines, posix=True) + lexer.whitespace_split = True + + tokens = list(lexer) + for token in tokens: + # At this point, all shell-like parsing has been done (i.e. + # comments processed, quotes and backslash escape sequences + # processed, multi-line values assembled, trailing newlines + # stripped, etc.), so the tokens are now either: + # * variable assignments: var=value + # * commands or their arguments (not allowed in os-release) + # Ignore any tokens that are not variable assignments + if "=" in token: + k, v = token.split("=", 1) + props[k.lower()] = v + + if "version" in props: + # extract release codename (if any) from version attribute + match = re.search(r"\((\D+)\)|,\s*(\D+)", props["version"]) + if match: + release_codename = match.group(1) or match.group(2) + props["codename"] = props["release_codename"] = release_codename + + if "version_codename" in props: + # os-release added a version_codename field. Use that in + # preference to anything else Note that some distros purposefully + # do not have code names. They should be setting + # version_codename="" + props["codename"] = props["version_codename"] + elif "ubuntu_codename" in props: + # Same as above but a non-standard field name used on older Ubuntus + props["codename"] = props["ubuntu_codename"] + + return props + + @cached_property + def _lsb_release_info(self) -> Dict[str, str]: + """ + Get the information items from the lsb_release command output. + + Returns: + A dictionary containing all information items. + """ + if not self.include_lsb: + return {} + try: + cmd = ("lsb_release", "-a") + stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL) + # Command not found or lsb_release returned error + except (OSError, subprocess.CalledProcessError): + return {} + content = self._to_str(stdout).splitlines() + return self._parse_lsb_release_content(content) + + @staticmethod + def _parse_lsb_release_content(lines: Iterable[str]) -> Dict[str, str]: + """ + Parse the output of the lsb_release command. + + Parameters: + + * lines: Iterable through the lines of the lsb_release output. + Each line must be a unicode string or a UTF-8 encoded byte + string. + + Returns: + A dictionary containing all information items. + """ + props = {} + for line in lines: + kv = line.strip("\n").split(":", 1) + if len(kv) != 2: + # Ignore lines without colon. + continue + k, v = kv + props.update({k.replace(" ", "_").lower(): v.strip()}) + return props + + @cached_property + def _uname_info(self) -> Dict[str, str]: + if not self.include_uname: + return {} + try: + cmd = ("uname", "-rs") + stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL) + except OSError: + return {} + content = self._to_str(stdout).splitlines() + return self._parse_uname_content(content) + + @cached_property + def _oslevel_info(self) -> str: + if not self.include_oslevel: + return "" + try: + stdout = subprocess.check_output("oslevel", stderr=subprocess.DEVNULL) + except (OSError, subprocess.CalledProcessError): + return "" + return self._to_str(stdout).strip() + + @cached_property + def _debian_version(self) -> str: + try: + with open( + os.path.join(self.etc_dir, "debian_version"), encoding="ascii" + ) as fp: + return fp.readline().rstrip() + except FileNotFoundError: + return "" + + @staticmethod + def _parse_uname_content(lines: Sequence[str]) -> Dict[str, str]: + if not lines: + return {} + props = {} + match = re.search(r"^([^\s]+)\s+([\d\.]+)", lines[0].strip()) + if match: + name, version = match.groups() + + # This is to prevent the Linux kernel version from + # appearing as the 'best' version on otherwise + # identifiable distributions. + if name == "Linux": + return {} + props["id"] = name.lower() + props["name"] = name + props["release"] = version + return props + + @staticmethod + def _to_str(bytestring: bytes) -> str: + encoding = sys.getfilesystemencoding() + return bytestring.decode(encoding) + + @cached_property + def _distro_release_info(self) -> Dict[str, str]: + """ + Get the information items from the specified distro release file. + + Returns: + A dictionary containing all information items. + """ + if self.distro_release_file: + # If it was specified, we use it and parse what we can, even if + # its file name or content does not match the expected pattern. + distro_info = self._parse_distro_release_file(self.distro_release_file) + basename = os.path.basename(self.distro_release_file) + # The file name pattern for user-specified distro release files + # is somewhat more tolerant (compared to when searching for the + # file), because we want to use what was specified as best as + # possible. + match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) + else: + try: + basenames = [ + basename + for basename in os.listdir(self.etc_dir) + if basename not in _DISTRO_RELEASE_IGNORE_BASENAMES + and os.path.isfile(os.path.join(self.etc_dir, basename)) + ] + # We sort for repeatability in cases where there are multiple + # distro specific files; e.g. CentOS, Oracle, Enterprise all + # containing `redhat-release` on top of their own. + basenames.sort() + except OSError: + # This may occur when /etc is not readable but we can't be + # sure about the *-release files. Check common entries of + # /etc for information. If they turn out to not be there the + # error is handled in `_parse_distro_release_file()`. + basenames = _DISTRO_RELEASE_BASENAMES + for basename in basenames: + match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) + if match is None: + continue + filepath = os.path.join(self.etc_dir, basename) + distro_info = self._parse_distro_release_file(filepath) + # The name is always present if the pattern matches. + if "name" not in distro_info: + continue + self.distro_release_file = filepath + break + else: # the loop didn't "break": no candidate. + return {} + + if match is not None: + distro_info["id"] = match.group(1) + + # CloudLinux < 7: manually enrich info with proper id. + if "cloudlinux" in distro_info.get("name", "").lower(): + distro_info["id"] = "cloudlinux" + + return distro_info + + def _parse_distro_release_file(self, filepath: str) -> Dict[str, str]: + """ + Parse a distro release file. + + Parameters: + + * filepath: Path name of the distro release file. + + Returns: + A dictionary containing all information items. + """ + try: + with open(filepath, encoding="utf-8") as fp: + # Only parse the first line. For instance, on SLES there + # are multiple lines. We don't want them... + return self._parse_distro_release_content(fp.readline()) + except OSError: + # Ignore not being able to read a specific, seemingly version + # related file. + # See https://github.com/python-distro/distro/issues/162 + return {} + + @staticmethod + def _parse_distro_release_content(line: str) -> Dict[str, str]: + """ + Parse a line from a distro release file. + + Parameters: + * line: Line from the distro release file. Must be a unicode string + or a UTF-8 encoded byte string. + + Returns: + A dictionary containing all information items. + """ + matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(line.strip()[::-1]) + distro_info = {} + if matches: + # regexp ensures non-None + distro_info["name"] = matches.group(3)[::-1] + if matches.group(2): + distro_info["version_id"] = matches.group(2)[::-1] + if matches.group(1): + distro_info["codename"] = matches.group(1)[::-1] + elif line: + distro_info["name"] = line.strip() + return distro_info + + +_distro = LinuxDistribution() + + +def main() -> None: + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + logger.addHandler(logging.StreamHandler(sys.stdout)) + + parser = argparse.ArgumentParser(description="OS distro info tool") + parser.add_argument( + "--json", "-j", help="Output in machine readable format", action="store_true" + ) + + parser.add_argument( + "--root-dir", + "-r", + type=str, + dest="root_dir", + help="Path to the root filesystem directory (defaults to /)", + ) + + args = parser.parse_args() + + if args.root_dir: + dist = LinuxDistribution( + include_lsb=False, + include_uname=False, + include_oslevel=False, + root_dir=args.root_dir, + ) + else: + dist = _distro + + if args.json: + logger.info(json.dumps(dist.info(), indent=4, sort_keys=True)) + else: + logger.info("Name: %s", dist.name(pretty=True)) + distribution_version = dist.version(pretty=True) + logger.info("Version: %s", distribution_version) + distribution_codename = dist.codename() + logger.info("Codename: %s", distribution_codename) + + +if __name__ == "__main__": + main() diff --git a/script.plexmod/lib/exceptions.py b/script.plexmod/lib/exceptions.py new file mode 100644 index 0000000000..847eb90fcf --- /dev/null +++ b/script.plexmod/lib/exceptions.py @@ -0,0 +1,4 @@ +# coding=utf-8 + +class NoDataException(Exception): + pass diff --git a/script.plexmod/lib/image.py b/script.plexmod/lib/image.py new file mode 100644 index 0000000000..09d778a3fa --- /dev/null +++ b/script.plexmod/lib/image.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import +import os +from lib import util + +CACHE_PATH = os.path.join(util.PROFILE, 'avatars') + +if not os.path.exists(CACHE_PATH): + os.makedirs(CACHE_PATH) + + +def getImage(url, ID): + return url, '' diff --git a/script.plexmod/lib/kodijsonrpc.py b/script.plexmod/lib/kodijsonrpc.py new file mode 100644 index 0000000000..86fdec219d --- /dev/null +++ b/script.plexmod/lib/kodijsonrpc.py @@ -0,0 +1,106 @@ +from __future__ import absolute_import +from kodi_six import xbmc +import json + + +class JSONRPCMethod: + + class Exception(Exception): + pass + + def __init__(self): + self.family = None + + def __getattr__(self, method): + def handler(**kwargs): + command = { + 'jsonrpc': '2.0', + 'id': 1, + 'method': '{0}.{1}'.format(self.family, method) + } + + if kwargs: + command['params'] = kwargs + + # xbmc.log(json.dumps(command)) + ret = json.loads(xbmc.executeJSONRPC(json.dumps(command))) + + if ret: + if 'error' in ret: + raise self.Exception(ret['error']) + else: + return ret['result'] + else: + return None + + return handler + + def __call__(self, family): + self.family = family + return self + + +class KodiJSONRPC: + def __init__(self): + self.methodHandler = JSONRPCMethod() + + def __getattr__(self, family): + return self.methodHandler(family) + + +rpc = KodiJSONRPC() + + +class BuiltInMethod: + + class Exception(Exception): + pass + + def __init__(self): + self.module = None + + def __getattr__(self, method): + def handler(*args, **kwargs): + args = [str(a).replace(',', r'\,') for a in args] + for k, v in kwargs.items(): + args.append('{0}={v}'.format(k, str(v).replace(',', r'\,'))) + + if args: + command = '{0}.{1}({2})'.format(self.module, method, ','.join(args)) + else: + command = '{0}.{1}'.format(self.module, method) + + xbmc.log(command, xbmc.LOGINFO) + + xbmc.executebuiltin(command) + + return handler + + def __call__(self, *args, **kwargs): + args = [str(a).replace(',', r'\,') for a in args] + for k, v in kwargs.items(): + args.append('{0}={v}'.format(k, str(v).replace(',', r'\,'))) + + if args: + command = '{0}({1})'.format(self.module, ','.join(args)) + else: + command = '{0}'.format(self.module) + + xbmc.log(command, xbmc.LOGINFO) + + xbmc.executebuiltin(command) + + def initModule(self, module): + self.module = module + return self + + +class KodiBuiltin: + def __init__(self): + self.methodHandler = BuiltInMethod() + + def __getattr__(self, module): + return self.methodHandler.initModule(module) + + +builtin = KodiBuiltin() diff --git a/script.plexmod/lib/main.py b/script.plexmod/lib/main.py new file mode 100644 index 0000000000..bd7b5cf4e9 --- /dev/null +++ b/script.plexmod/lib/main.py @@ -0,0 +1,178 @@ +from __future__ import absolute_import +from kodi_six import xbmc + +if xbmc.getInfoLabel('Window(10000).Property(script.plex.running)') == "1": + xbmc.executebuiltin('NotifyAll({0},{1},{2})'.format('script.plexmod', 'RESTORE', '{}')) + raise SystemExit + +import gc +import atexit +import threading +import six + +from . import plex + +from plexnet import plexapp +from plexnet import threadutils +from .windows import background, userselect, home, windowutils +from . import player +from . import backgroundthread +from . import util + +BACKGROUND = None + + +if six.PY2: + _Timer = threading._Timer +else: + _Timer = threading.Timer + + +def waitForThreads(): + util.DEBUG_LOG('Main: Checking for any remaining threads') + while len(threading.enumerate()) > 1: + for t in threading.enumerate(): + if t != threading.currentThread(): + if t.is_alive(): + util.DEBUG_LOG('Main: Waiting on: {0}...'.format(t.name)) + if isinstance(t, _Timer): + t.cancel() + + try: + t.join() + except: + util.ERROR() + + +@atexit.register +def realExit(): + xbmc.log('Main: script.plex: REALLY FINISHED', xbmc.LOGINFO) + + +def signout(): + util.setSetting('auth.token', '') + util.DEBUG_LOG('Main: Signing out...') + plexapp.ACCOUNT.signOut() + + +def main(): + global BACKGROUND + try: + with util.Cron(0.1): + BACKGROUND = background.BackgroundWindow.create(function=_main) + + tries = 0 + while not BACKGROUND.isOpen and not util.MONITOR.waitForAbort(2) and tries < 60: + if tries == 0: + util.LOG("Couldn't start main loop, other dialog open? Retrying for 120s.") + BACKGROUND.show() + tries += 1 + + if BACKGROUND.isOpen: + util.setGlobalProperty('running', '1') + BACKGROUND.modal() + del BACKGROUND + else: + util.LOG("Couldn't start main loop, exiting.") + finally: + try: + util.setGlobalProperty('running', '') + util.setGlobalProperty('stop_running', '') + except: + pass + + +def _main(): + util.DEBUG_LOG('[ STARTED: {0} -------------------------------------------------------------------- ]'.format(util.ADDON.getAddonInfo('version'))) + util.DEBUG_LOG('USER-AGENT: {0}'.format(plex.defaultUserAgent())) + background.setSplash() + + try: + while not util.MONITOR.abortRequested() and not util.getGlobalProperty('stop_running'): + if plex.init(): + background.setSplash(False) + fromSwitch = False + while not util.MONITOR.abortRequested() and not util.getGlobalProperty('stop_running'): + if ( + not plexapp.ACCOUNT.isOffline and not + plexapp.ACCOUNT.isAuthenticated and + (len(plexapp.ACCOUNT.homeUsers) > 1 or plexapp.ACCOUNT.isProtected) + + ): + result = userselect.start() + if not result: + return + elif result == 'signout': + signout() + break + elif result == 'signin': + break + elif result == 'cancel' and fromSwitch: + util.DEBUG_LOG('Main: User selection canceled, reusing previous user') + plexapp.ACCOUNT.isAuthenticated = True + + if not fromSwitch: + util.DEBUG_LOG('Main: User selected') + + try: + selectedServer = plexapp.SERVERMANAGER.selectedServer + + if not selectedServer: + background.setBusy() + util.DEBUG_LOG('Main: Waiting for selected server...') + try: + for timeout, skip_preferred, skip_owned in ((10, False, False), (10, True, True)): + plex.CallbackEvent(plexapp.util.APP, 'change:selectedServer', timeout=timeout).wait() + + selectedServer = plexapp.SERVERMANAGER.checkSelectedServerSearch(skip_preferred=skip_preferred, skip_owned=skip_owned) + if selectedServer: + break + else: + util.DEBUG_LOG('Main: Finished waiting for selected server...') + finally: + background.setBusy(False) + + util.DEBUG_LOG('Main: STARTING WITH SERVER: {0}'.format(selectedServer)) + + windowutils.HOME = home.HomeWindow.open() + util.CRON.cancelReceiver(windowutils.HOME) + + if not windowutils.HOME.closeOption: + return + + closeOption = windowutils.HOME.closeOption + + windowutils.shutdownHome() + + if closeOption == 'signout': + signout() + break + elif closeOption == 'switch': + plexapp.ACCOUNT.isAuthenticated = False + fromSwitch = True + finally: + windowutils.shutdownHome() + BACKGROUND.activate() + gc.collect(2) + + else: + break + except: + util.ERROR() + finally: + util.DEBUG_LOG('Main: SHUTTING DOWN...') + background.setShutdown() + player.shutdown() + plexapp.util.APP.preShutdown() + util.CRON.stop() + backgroundthread.BGThreader.shutdown() + plexapp.util.APP.shutdown() + waitForThreads() + background.setBusy(False) + background.setSplash(False) + background.killMonitor() + + util.DEBUG_LOG('FINISHED') + util.shutdown() + + gc.collect(2) diff --git a/script.plexmod/lib/metadata.py b/script.plexmod/lib/metadata.py new file mode 100644 index 0000000000..ffa33ff7b1 --- /dev/null +++ b/script.plexmod/lib/metadata.py @@ -0,0 +1,34 @@ +from __future__ import absolute_import +from plexnet import media +from .util import T + + +EXTRA_MAP = { + media.METADATA_RELATED_TRAILER: T(32201, 'Trailer'), + media.METADATA_RELATED_DELETED_SCENE: T(32202, 'Deleted Scene'), + media.METADATA_RELATED_INTERVIEW: T(32203, 'Interview'), + media.METADATA_RELATED_MUSIC_VIDEO: T(32204, 'Music Video'), + media.METADATA_RELATED_BEHIND_THE_SCENES: T(32205, 'Behind the Scenes'), + media.METADATA_RELATED_SCENE_OR_SAMPLE: T(32206, 'Scene/Sample'), + media.METADATA_RELATED_LIVE_MUSIC_VIDEO: T(32207, 'Live Music Video'), + media.METADATA_RELATED_LYRIC_MUSIC_VIDEO: T(32208, 'Lyric Music Video'), + media.METADATA_RELATED_CONCERT: T(32209, 'Concert'), + media.METADATA_RELATED_FEATURETTE: T(32210, 'Featurette'), + media.METADATA_RELATED_SHORT: T(32211, 'Short'), + media.METADATA_RELATED_OTHER: T(32212, 'Other') +} + + +API_TRANSLATION_MAP = { + 'Unknown': T(32441), + 'Embedded': T(32442), + 'Forced': T(32443), + 'Lyrics': T(32444), + 'Mono': T(32445), + 'Stereo': T(32446), + 'None': T(32447) +} + + +def apiTranslate(string): + return API_TRANSLATION_MAP.get(string) or string diff --git a/script.plexmod/lib/playback_utils.py b/script.plexmod/lib/playback_utils.py new file mode 100644 index 0000000000..57c0edb25d --- /dev/null +++ b/script.plexmod/lib/playback_utils.py @@ -0,0 +1,201 @@ +# coding=utf-8 +import json +import os +from collections import namedtuple, OrderedDict + +from kodi_six import xbmc, xbmcaddon, xbmcvfs +from plexnet import plexapp + +from lib import util + + + +ADDON = xbmcaddon.Addon() + + +ATTR_MAP = { + "b": "binge_mode", + "i": "auto_skip_intro", + "c": "auto_skip_credits", + "e": "show_intro_skip_early" +} + +# I know dicts are ordered in py3, but we want to be compatible with py2. +TRANS_MAP = OrderedDict(( + ("binge_mode", 33618), + ("auto_skip_intro", 32522), + ("auto_skip_credits", 32526), + ("show_intro_skip_early", 33505) +)) + +ATTR_MAP_REV = dict((v, k) for k, v in ATTR_MAP.items()) + + +PlaybackSettings = namedtuple("PlaybackSettings", list(v for v in ATTR_MAP.values())) + + +class PlaybackManager(object): + """ + Manages the playback settings for individual shows; falls back to the global default if no specifics set + """ + version = 1 + _data = None + _currentServerUUID = None + _currentUserID = None + + transMap = TRANS_MAP + + dataPath = os.path.join(util.translatePath(ADDON.getAddonInfo("profile")), "playback_settings.json") + + # this could be a property, but w/e + glob = None + + def __init__(self): + self.reset() + # bind settings change signals + for v in ATTR_MAP.values(): + plexapp.util.APP.on('change:{}'.format(v), lambda **kwargs: self.setGlob(**kwargs)) + + plexapp.util.APP.on('change:selectedServer', lambda **kwargs: self.setServerUUID(**kwargs)) + plexapp.util.APP.on("change:user", lambda **kwargs: self.setUserID(**kwargs)) + plexapp.util.APP.on('init', lambda **kwargs: self.setUserID(**kwargs)) + + def __call__(self, obj, key=None, value=None, kv_dict=None): + # shouldn't happen + if not self._currentServerUUID or not self._currentUserID: + util.DEBUG_LOG("APP.PlaybackManager, something's wrong: ServerUUID: %s, UserID: %s" % ( + self._currentServerUUID, self._currentUserID)) + return + + csid = self._currentServerUUID + cuid = self._currentUserID + + # set + if (key is not None and value is not None) or kv_dict is not None: + # prepare value dict + if csid not in self._data: + self._data[csid] = {} + + if cuid not in self._data[csid]: + self._data[csid][cuid] = {} + + ukv = {key: value} if not kv_dict else kv_dict + + if obj.ratingKey not in self._data[csid][cuid]: + self._data[csid][cuid][obj.ratingKey] = {} + + for k, v in ukv.items(): + # don't write globals into the storage + if v != getattr(self.glob, k): + self._data[csid][cuid][obj.ratingKey][ATTR_MAP_REV[k]] = v + else: + # new val set to global default, delete specific val + if ATTR_MAP_REV[k] in self._data[csid][cuid][obj.ratingKey]: + del self._data[csid][cuid][obj.ratingKey][ATTR_MAP_REV[k]] + + # empty specific settings? clean up + if not self._data[csid][cuid][obj.ratingKey]: + del self._data[csid][cuid][obj.ratingKey] + + self.save() + return self.glob._replace(**ukv) + + if not obj.ratingKey: + return self.glob + + # get + data = self._data.get(csid, {}).get(cuid, {}).get(obj.ratingKey, None) + if data: + return self.glob._replace(**dict((ATTR_MAP[k], v) for k, v in data.items())) + return self.glob + + def reset(self): + self._data = self.load() + if plexapp.SERVERMANAGER and plexapp.SERVERMANAGER.selectedServer: + self.setServerUUID() + + if plexapp.ACCOUNT: + self.setUserID() + self.setGlob() + + def setGlob(self, skey=None, value=None, **kwargs): + if skey is not None and value is not None: + self.glob = self.glob._replace(**{skey: value}) + else: + self.glob = PlaybackSettings(**dict((k, util.getUserSetting(k, False)) for k in ATTR_MAP.values())) + + def setServerUUID(self, server=None): + if not server and not plexapp.SERVERMANAGER.selectedServer: + return + self._currentServerUUID = (server if server is not None else plexapp.SERVERMANAGER.selectedServer).uuid + + def setUserID(self, account=None, reallyChanged=False): + if not account and not plexapp.ACCOUNT: + return + self._currentUserID = (account if account is not None and reallyChanged else plexapp.ACCOUNT).ID + self.setGlob() + + def load(self): + # new load method, v1 + if os.path.isfile(self.dataPath): + try: + f = xbmcvfs.File(self.dataPath) + obj = json.loads(f.read()) + f.close() + + version = obj["version"] + data = obj["data"] + except: + util.ERROR("Couldn't load playback_settings.json") + return {} + + if version < self.version: + migratedAny = False + for v in range(version + 1, self.version + 1): + migFunc = "migrateV{}".format(v) + if hasattr(self, migFunc): + migResult, data = getattr(self, migFunc)(data) + if migResult: + util.DEBUG_LOG("Migrated playback_settings.json to format v{}".format(v)) + migratedAny = True + if migratedAny: + self.save(data=data) + + return data + + else: + # migrate legacy data + jstring = plexapp.util.INTERFACE.getRegistry("BingeModeSettings") + if not jstring: + # fallback + jstring = plexapp.util.INTERFACE.getRegistry("AutoSkipSettings") + if not jstring: + return {} + + try: + util.DEBUG_LOG("Loading old BingeModeSettings") + obj = json.loads(jstring) + migData = {} + # migrate old BM settings into new format + for serverID, userIDs in obj.items(): + migData[serverID] = {} + for userID, ratingKeys in userIDs.items(): + migData[serverID][userID] = {} + for ratingKey, value in ratingKeys.items(): + migData[serverID][userID][ratingKey] = {"b": value} + + # plexapp.util.INTERFACE.clearRegistry("BingeModeSettings") + self.save(data=migData) + return migData + except: + util.DEBUG_LOG("Couldn't parse old BingeModeSettings") + return {} + + def save(self, data=None): + try: + f = xbmcvfs.File(self.dataPath, "w") + f.write(json.dumps({"version": self.version, "data": data or self._data})) + f.close() + except: + util.ERROR("Couldn't write playback_settings.json") + return diff --git a/script.plexmod/lib/player.py b/script.plexmod/lib/player.py new file mode 100644 index 0000000000..7fed192d45 --- /dev/null +++ b/script.plexmod/lib/player.py @@ -0,0 +1,1480 @@ +from __future__ import absolute_import +import base64 +import threading +import six +import re +import os + +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import backgroundthread +from . import kodijsonrpc +from . import colors +from .windows import seekdialog +from . import util +from plexnet import plexplayer +from plexnet import plexapp +from plexnet import signalsmixin +from plexnet import util as plexnetUtil +from six.moves import range + +FIVE_MINUTES_MILLIS = 300000 + + +class BasePlayerHandler(object): + def __init__(self, player, session_id=None): + self.player = player + self.media = None + self.baseOffset = 0 + self.timelineType = None + self.lastTimelineState = None + self.ignoreTimelines = False + self.queuingNext = False + self.playQueue = None + self.sessionID = session_id + + def onAVChange(self): + pass + + def onAVStarted(self): + pass + + def onPrePlayStarted(self): + pass + + def onPlayBackStarted(self): + pass + + def onPlayBackPaused(self): + pass + + def onPlayBackResumed(self): + pass + + def onPlayBackStopped(self): + pass + + def onPlayBackEnded(self): + pass + + def onPlayBackSeek(self, stime, offset): + pass + + def onPlayBackFailed(self): + pass + + def onVideoWindowOpened(self): + pass + + def onVideoWindowClosed(self): + pass + + def onVideoOSD(self): + pass + + def onSeekOSD(self): + pass + + def onMonitorInit(self): + pass + + def tick(self): + pass + + def close(self): + pass + + def setSubtitles(self, *args, **kwargs): + pass + + def getIntroOffset(self, offset=None, setSkipped=False): + pass + + def setup(self, duration, meta, offset, bif_url, **kwargs): + pass + + @property + def trueTime(self): + return self.baseOffset + self.player.currentTime + + def getCurrentItem(self): + if self.player.playerObject: + return self.player.playerObject.item + return None + + def shouldSendTimeline(self, item): + return item.ratingKey and item.getServer() + + def currentDuration(self): + if self.player.playerObject and self.player.isPlaying(): + try: + return int(self.player.getTotalTime() * 1000) + except RuntimeError: + pass + + return 0 + + def updateNowPlaying(self, force=False, refreshQueue=False, state=None, time=None): + util.DEBUG_LOG("UpdateNowPlaying: force: {0} refreshQueue: {1} state: {2}".format(force, refreshQueue, state)) + if self.ignoreTimelines: + util.DEBUG_LOG("UpdateNowPlaying: ignoring timeline as requested") + return + + item = self.getCurrentItem() + if not item: + return + + if not self.shouldSendTimeline(item): + return + + state = state or self.player.playState + # Avoid duplicates + if state == self.lastTimelineState and not force: + return + + self.lastTimelineState = state + # self.timelineTimer.reset() + + time = time or int(self.trueTime * 1000) + + # self.trigger("progress", [m, item, time]) + + if refreshQueue and self.playQueue: + self.playQueue.refreshOnTimeline = True + + plexapp.util.APP.nowplayingmanager.updatePlaybackState( + self.timelineType, self.player.playerObject, state, time, self.playQueue, duration=self.currentDuration() + ) + + def getVolume(self): + return util.rpc.Application.GetProperties(properties=["volume"])["volume"] + + +class SeekPlayerHandler(BasePlayerHandler): + NO_SEEK = 0 + SEEK_IN_PROGRESS = 2 + SEEK_PLAYLIST = 3 + SEEK_REWIND = 4 + SEEK_POST_PLAY = 5 + + MODE_ABSOLUTE = 0 + MODE_RELATIVE = 1 + + def __init__(self, player, session_id=None): + BasePlayerHandler.__init__(self, player, session_id) + self.dialog = None + self.playlist = None + self.playQueue = None + self.timelineType = 'video' + self.ended = False + self.bifURL = '' + self.title = '' + self.title2 = '' + self.seekOnStart = 0 + self.chapters = None + self.stoppedInBingeMode = False + self.inBingeMode = False + self.prePlayWitnessed = False + self.queuingNext = False + self.reset() + + def reset(self): + self.duration = 0 + self.offset = 0 + self.baseOffset = 0 + self.seeking = self.NO_SEEK + self.seekOnStart = 0 + self.mode = self.MODE_RELATIVE + self.ended = False + self.stoppedInBingeMode = False + self.prePlayWitnessed = False + self.queuingNext = False + + def setup(self, duration, meta, offset, bif_url, title='', title2='', seeking=NO_SEEK, chapters=None): + self.ended = False + self.baseOffset = offset / 1000.0 + self.seeking = seeking + self.duration = duration + self.bifURL = bif_url + self.title = title + self.title2 = title2 + self.chapters = chapters or [] + self.playedThreshold = plexapp.util.INTERFACE.getPlayedThresholdValue() + self.ignoreTimelines = False + self.queuingNext = False + self.stoppedInBingeMode = False + self.inBingeMode = False + self.prePlayWitnessed = False + self.getDialog(setup=True) + self.dialog.setup(self.duration, meta, int(self.baseOffset * 1000), self.bifURL, self.title, self.title2, + chapters=self.chapters, keepMarkerDef=seeking == self.SEEK_IN_PROGRESS) + + def getDialog(self, setup=False): + if not self.dialog: + self.dialog = seekdialog.SeekDialog.create(show=False, handler=self) + + return self.dialog + + @property + def isTranscoded(self): + return self.mode == self.MODE_RELATIVE + + @property + def isDirectPlay(self): + return self.mode == self.MODE_ABSOLUTE + + @property + def trueTime(self): + if self.isTranscoded: + return self.baseOffset + self.player.currentTime + else: + if self.seekOnStart: + return self.player.playerObject.startOffset + (self.seekOnStart / 1000) + else: + return self.player.currentTime + self.player.playerObject.startOffset + + def shouldShowPostPlay(self): + if self.playlist and self.playlist.TYPE == 'playlist': + return False + + if self.inBingeMode and not self.stoppedInBingeMode: + return False + + if (not util.advancedSettings.postplayAlways and self.player.video.duration.asInt() <= FIVE_MINUTES_MILLIS)\ + or util.advancedSettings.postplayTimeout <= 0: + return False + + return True + + def showPostPlay(self): + if not self.shouldShowPostPlay(): + util.DEBUG_LOG("SeekHandler: Not showing post-play") + return + util.DEBUG_LOG("SeekHandler: Showing post-play") + + self.seeking = self.SEEK_POST_PLAY + self.hideOSD(delete=True) + + self.player.trigger('post.play', video=self.player.video, playlist=self.playlist, handler=self, + stoppedInBingeMode=self.stoppedInBingeMode) + + self.stoppedInBingeMode = False + + return True + + def getIntroOffset(self, offset=None, setSkipped=False): + return self.getDialog().displayMarkers(onlyReturnIntroMD=True, offset=offset, setSkipped=setSkipped) + + def next(self, on_end=False): + if self.playlist and next(self.playlist): + self.seeking = self.SEEK_PLAYLIST + + if on_end: + if self.showPostPlay(): + return True + + if not self.playlist or self.stoppedInBingeMode: + return False + + xbmc.sleep(500) + + self.player.playVideoPlaylist(self.playlist, handler=self, resume=self.player.resume) + + return True + + def prev(self): + if not self.playlist or not self.playlist.prev(): + return False + + self.seeking = self.SEEK_PLAYLIST + xbmc.sleep(500) + self.player.playVideoPlaylist(self.playlist, handler=self, resume=self.player.resume) + + return True + + def playAt(self, pos): + if not self.playlist or not self.playlist.setCurrent(pos): + return False + + self.seeking = self.SEEK_PLAYLIST + self.player.playVideoPlaylist(self.playlist, handler=self, resume=self.player.resume) + + return True + + def onSeekAborted(self): + if self.seeking: + self.seeking = self.NO_SEEK + self.player.control('play') + + def showOSD(self, from_seek=False): + self.updateOffset() + if self.dialog: + self.dialog.update(self.offset, from_seek) + self.dialog.showOSD() + + def hideOSD(self, delete=False): + util.CRON.forceTick() + if self.dialog: + self.dialog.hideOSD(closing=delete) + if delete: + d = self.dialog + self.dialog = None + d.doClose() + del d + util.garbageCollect() + + def seek(self, offset, settings_changed=False, seeking=SEEK_IN_PROGRESS): + util.DEBUG_LOG( + "SeekHandler: offset={0}, settings_changed={1}, seeking={2}, state={3}".format(offset, + settings_changed, + seeking, + self.player.playState)) + if offset is None: + return + + self.offset = offset + + if self.isDirectPlay and not settings_changed: + util.DEBUG_LOG('New absolute player offset: {0}'.format(self.offset)) + + if self.player.playerObject.offsetIsValid(offset / 1000): + if self.seekAbsolute(offset): + return + + self.updateNowPlaying(state=self.player.STATE_PAUSED) # To for update after seek + + self.seeking = self.SEEK_IN_PROGRESS + + if self.player.playState == self.player.STATE_PAUSED: + self.player.pauseAfterPlaybackStarted = True + + util.DEBUG_LOG('New player offset: {0}, state: {1}'.format(self.offset, self.player.playState)) + self.player._playVideo(offset, seeking=self.seeking, force_update=settings_changed) + + def fastforward(self): + xbmc.executebuiltin('PlayerControl(forward)') + + def rewind(self): + if self.isDirectPlay: + xbmc.executebuiltin('PlayerControl(rewind)') + else: + self.seek(max(self.trueTime - 30, 0) * 1000, seeking=self.SEEK_REWIND) + + def seekAbsolute(self, seek=None): + self.seekOnStart = seek or (self.seekOnStart if self.seekOnStart else None) + if self.seekOnStart is not None: + seekSeconds = self.seekOnStart / 1000.0 + try: + if seekSeconds >= self.player.getTotalTime(): + util.DEBUG_LOG("SeekAbsolute: Bad offset: {0}".format(seekSeconds)) + return False + except RuntimeError: # Not playing a file + util.DEBUG_LOG("SeekAbsolute: runtime error") + return False + self.updateNowPlaying(state=self.player.STATE_PAUSED) # To for update after seek + + util.DEBUG_LOG("SeekAbsolute: Seeking to {0}".format(self.seekOnStart)) + self.player.seekTime(self.seekOnStart / 1000.0) + return True + + def onAVChange(self): + util.DEBUG_LOG('SeekHandler: onAVChange') + if self.dialog: + self.dialog.onAVChange() + + def onAVStarted(self): + util.DEBUG_LOG('SeekHandler: onAVStarted') + + if self.dialog: + self.dialog.onAVStarted() + + # check if embedded subtitle was set correctly + if self.isDirectPlay and self.player.video and self.player.video.current_subtitle_is_embedded: + try: + playerID = kodijsonrpc.rpc.Player.GetActivePlayers()[0]["playerid"] + currIdx = kodijsonrpc.rpc.Player.GetProperties(playerid=playerID, properties=['currentsubtitle'])[ + 'currentsubtitle']['index'] + if currIdx != self.player.video._current_subtitle_idx: + util.LOG("Embedded Subtitle index was incorrect ({}), setting to: {}". + format(currIdx, self.player.video._current_subtitle_idx)) + self.dialog.setSubtitles() + else: + util.DEBUG_LOG("Embedded subtitle was correctly set in Kodi") + except: + util.ERROR("Exception when trying to check for embedded subtitles") + + def onPrePlayStarted(self): + util.DEBUG_LOG('SeekHandler: onPrePlayStarted, DP: {}'.format(self.isDirectPlay)) + self.prePlayWitnessed = True + if self.isDirectPlay: + self.setSubtitles(do_sleep=False) + + def onPlayBackStarted(self): + util.DEBUG_LOG('SeekHandler: onPlayBackStarted, DP: {}'.format(self.isDirectPlay)) + self.updateNowPlaying(force=True, refreshQueue=True) + + if self.dialog: + self.dialog.onPlayBackStarted() + + #if not self.prePlayWitnessed and self.isDirectPlay: + if self.isDirectPlay: + self.setSubtitles(do_sleep=False) + + def onPlayBackResumed(self): + self.updateNowPlaying() + if self.dialog: + self.dialog.onPlayBackResumed() + + util.CRON.forceTick() + # self.hideOSD() + + def onPlayBackStopped(self): + util.DEBUG_LOG('SeekHandler: onPlayBackStopped - ' + 'Seeking={0}, QueueingNext={1}, BingeMode={2}'.format(self.seeking, self.queuingNext, + self.inBingeMode)) + + if self.dialog: + self.dialog.onPlayBackStopped() + + if self.queuingNext and self.inBingeMode: + if self.next(on_end=False): + return + + if self.seeking not in (self.SEEK_IN_PROGRESS, self.SEEK_REWIND): + self.updateNowPlaying() + + # show post play if possible, if an item has been watched (90% by Plex standards) + if self.seeking != self.SEEK_PLAYLIST and self.duration: + playedFac = self.trueTime * 1000 / float(self.duration) + util.DEBUG_LOG("Player - played-threshold: {}/{}".format(playedFac, self.playedThreshold)) + if playedFac >= self.playedThreshold and self.next(on_end=True): + return + + if self.seeking not in (self.SEEK_IN_PROGRESS, self.SEEK_PLAYLIST): + self.hideOSD(delete=True) + self.sessionEnded() + + def onPlayBackEnded(self): + util.DEBUG_LOG('SeekHandler: onPlayBackEnded - Seeking={0}'.format(self.seeking)) + + if self.dialog: + self.dialog.onPlayBackEnded() + + if self.player.playerObject.hasMoreParts(): + self.updateNowPlaying(state=self.player.STATE_PAUSED) # To for update after seek + self.seeking = self.SEEK_IN_PROGRESS + self.player._playVideo(self.player.playerObject.getNextPartOffset(), seeking=self.seeking) + return + + self.updateNowPlaying() + + if self.queuingNext: + util.DEBUG_LOG('SeekHandler: onPlayBackEnded - event ignored') + return + + if self.inBingeMode: + self.stoppedInBingeMode = False + + if self.playlist and self.playlist.hasNext(): + self.queuingNext = True + if self.next(on_end=True): + return + else: + self.queuingNext = False + + if not self.ended: + if self.seeking != self.SEEK_PLAYLIST: + self.hideOSD() + + if self.seeking not in (self.SEEK_IN_PROGRESS, self.SEEK_PLAYLIST): + self.sessionEnded() + + def onPlayBackPaused(self): + self.updateNowPlaying() + if self.dialog: + self.dialog.onPlayBackPaused() + + def onPlayBackSeek(self, stime, offset): + util.DEBUG_LOG('SeekHandler: onPlayBackSeek - {0}, {1}, {2}'.format(stime, offset, self.seekOnStart)) + if self.dialog: + self.dialog.onPlayBackSeek(stime, offset) + + if self.seekOnStart: + seeked = False + if self.dialog: + seeked = self.dialog.tick(stime) + + if seeked: + util.DEBUG_LOG("OnPlayBackSeek: Seeked on start to: {0}".format(stime)) + self.seekOnStart = 0 + return + + self.updateOffset() + # self.showOSD(from_seek=True) + + def setSubtitles(self, do_sleep=True, honor_forced_subtitles_override=True): + if not self.player.video: + util.LOG("Warning: SetSubtitles: no player.video object available") + return + + subs = self.player.video.selectedSubtitleStream( + forced_subtitles_override=honor_forced_subtitles_override and util.getSetting("forced_subtitles_override", + False)) + if subs: + if do_sleep: + xbmc.sleep(100) + + path = subs.getSubtitleServerPath() + if self.isDirectPlay: + self.player.showSubtitles(False) + if path: + util.DEBUG_LOG('Setting subtitle path: {0} ({1})'.format(path, subs)) + self.player.setSubtitles(path) + self.player.showSubtitles(True) + + else: + # u_til.TEST(subs.__dict__) + # u_til.TEST(self.player.video.mediaChoice.__dict__) + util.DEBUG_LOG('Enabling embedded subtitles at: {0} ({1})'.format(subs.typeIndex, subs)) + self.player.setSubtitleStream(subs.typeIndex) + self.player.showSubtitles(True) + + else: + self.player.showSubtitles(False) + + def setAudioTrack(self): + if self.isDirectPlay: + track = self.player.video.selectedAudioStream() + if track: + # only try finding the current audio stream when the BG music isn't playing and wasn't the last + # thing played, because currentaudiostream doesn't populate for audio-only items; in that case, + # always select the proper audio stream + if not self.player.lastPlayWasBGM: + try: + playerID = kodijsonrpc.rpc.Player.GetActivePlayers()[0]["playerid"] + currIdx = kodijsonrpc.rpc.Player.GetProperties(playerid=playerID, properties=['currentaudiostream'])['currentaudiostream']['index'] + if currIdx == track.typeIndex: + util.DEBUG_LOG('Audio track is correct index: {0}'.format(track.typeIndex)) + return + except: + util.ERROR() + + self.player.lastPlayWasBGM = False + + xbmc.sleep(100) + util.DEBUG_LOG('Switching audio track - index: {0}'.format(track.typeIndex)) + self.player.setAudioStream(track.typeIndex) + + def updateOffset(self): + try: + self.offset = int(self.player.getTime() * 1000) + except RuntimeError: + pass + + def initPlayback(self): + self.seeking = self.NO_SEEK + + #self.setSubtitles() + if self.isTranscoded and self.player.getAvailableSubtitleStreams(): + util.DEBUG_LOG('Enabling first subtitle stream, as we\'re in DirectStream') + self.player.showSubtitles(True) + self.setAudioTrack() + + if self.isDirectPlay: + self.seekAbsolute() + + def onPlayBackFailed(self): + if self.ended: + return False + + if self.dialog: + self.dialog.onPlayBackFailed() + + util.DEBUG_LOG('SeekHandler: onPlayBackFailed - Seeking={0}'.format(self.seeking)) + if self.seeking not in (self.SEEK_IN_PROGRESS, self.SEEK_PLAYLIST): + self.sessionEnded() + + if self.seeking == self.SEEK_IN_PROGRESS: + return False + else: + self.seeking = self.NO_SEEK + + return True + + # def onSeekOSD(self): + # self.dialog.activate() + + def onVideoWindowOpened(self): + util.DEBUG_LOG('SeekHandler: onVideoWindowOpened - Seeking={0}'.format(self.seeking)) + self.getDialog().show() + + self.initPlayback() + + def onVideoWindowClosed(self): + self.hideOSD() + util.DEBUG_LOG('SeekHandler: onVideoWindowClosed - Seeking={0}'.format(self.seeking)) + if not self.seeking: + if self.player.isPlaying(): + self.player.stop() + if not self.playlist or not self.playlist.hasNext(): + if not self.shouldShowPostPlay(): + self.sessionEnded() + + def onVideoOSD(self): + # xbmc.executebuiltin('Dialog.Close(seekbar,true)') # Doesn't work :) + self.showOSD() + + def tick(self): + if self.seeking != self.SEEK_IN_PROGRESS: + self.updateNowPlaying(force=True) + + if self.dialog: + self.dialog.tick() + + def close(self): + self.hideOSD(delete=True) + + def sessionEnded(self): + if self.ended: + return + self.ended = True + util.DEBUG_LOG('Player: Video session ended') + self.player.trigger('session.ended', session_id=self.sessionID) + self.hideOSD(delete=True) + + __next__ = next + + +class AudioPlayerHandler(BasePlayerHandler): + def __init__(self, player): + BasePlayerHandler.__init__(self, player) + self.timelineType = 'music' + util.setGlobalProperty('track.ID', '') + self.extractTrackInfo() + + def extractTrackInfo(self): + if not self.player.isPlayingAudio(): + return + + plexID = None + for x in range(10): # Wait a sec (if necessary) for this to become available + try: + item = kodijsonrpc.rpc.Player.GetItem(playerid=0, properties=['comment'])['item'] + plexID = item['comment'] + except: + util.ERROR() + + if plexID: + break + xbmc.sleep(100) + + if not plexID: + return + + if not plexID.startswith('PLEX-'): + return + + util.DEBUG_LOG('Extracting track info from comment') + try: + data = plexID.split(':', 1)[-1] + from plexnet import plexobjects + track = plexobjects.PlexObject.deSerialize(base64.urlsafe_b64decode(data.encode('utf-8'))) + track.softReload() + self.media = track + pobj = plexplayer.PlexAudioPlayer(track) + self.player.playerObject = pobj + self.updatePlayQueueTrack(track) + util.setGlobalProperty('track.ID', track.ratingKey) # This is used in the skins to match a listitem + except: + util.ERROR() + + def setPlayQueue(self, pq): + self.playQueue = pq + pq.on('items.changed', self.playQueueCallback) + + def playQueueCallback(self, **kwargs): + plist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC) + # plist.clear() + try: + citem = kodijsonrpc.rpc.Player.GetItem(playerid=0, properties=['comment'])['item'] + plexID = citem['comment'].split(':', 1)[0] + except: + util.ERROR() + return + + current = plist.getposition() + size = plist.size() + + # Remove everything but the current track + for x in range(size - 1, current, -1): # First everything with a greater position + kodijsonrpc.rpc.Playlist.Remove(playlistid=xbmc.PLAYLIST_MUSIC, position=x) + for x in range(current): # Then anything with a lesser position + kodijsonrpc.rpc.Playlist.Remove(playlistid=xbmc.PLAYLIST_MUSIC, position=0) + + swap = None + for idx, track in enumerate(self.playQueue.items()): + tid = 'PLEX-{0}'.format(track.ratingKey) + if tid == plexID: + # Save the position of the current track in the pq + swap = idx + + url, li = self.player.createTrackListItem(track, index=idx + 1) + + plist.add(url, li) + + plist[0].setInfo('music', { + 'playcount': swap + 1, + }) + + # Now swap the track to the correct position. This seems to be the only way to update the kodi playlist position to the current track's new position + if swap is not None: + kodijsonrpc.rpc.Playlist.Swap(playlistid=xbmc.PLAYLIST_MUSIC, position1=0, position2=swap + 1) + kodijsonrpc.rpc.Playlist.Remove(playlistid=xbmc.PLAYLIST_MUSIC, position=0) + + self.player.trigger('playlist.changed') + + def updatePlayQueue(self, delay=False): + if not self.playQueue: + return + + self.playQueue.refresh(delay=delay) + + def updatePlayQueueTrack(self, track): + if not self.playQueue: + return + + self.playQueue.selectedId = track.playQueueItemID or None + + @property + def trueTime(self): + try: + return self.player.getTime() + except: + return self.player.currentTime + + def stampCurrentTime(self): + try: + self.player.currentTime = self.player.getTime() + except RuntimeError: # Not playing + pass + + def onMonitorInit(self): + self.extractTrackInfo() + self.updateNowPlaying(state='playing') + + def onPlayBackStarted(self): + self.player.lastPlayWasBGM = False + self.updatePlayQueue(delay=True) + self.extractTrackInfo() + self.updateNowPlaying(state='playing') + + def onPlayBackResumed(self): + self.updateNowPlaying(state='playing') + + def onPlayBackPaused(self): + self.updateNowPlaying(state='paused') + + def onPlayBackStopped(self): + self.updatePlayQueue() + self.updateNowPlaying(state='stopped') + self.finish() + + def onPlayBackEnded(self): + self.updatePlayQueue() + self.updateNowPlaying(state='stopped') + self.finish() + + def onPlayBackFailed(self): + return True + + def finish(self): + self.player.trigger('session.ended') + util.setGlobalProperty('track.ID', '') + + def tick(self): + if not self.player.isPlayingAudio() or util.MONITOR.abortRequested(): + return + + self.stampCurrentTime() + self.updateNowPlaying(force=True) + + +class BGMPlayerHandler(BasePlayerHandler): + def __init__(self, player, rating_key): + BasePlayerHandler.__init__(self, player) + self.timelineType = 'music' + self.currentlyPlaying = rating_key + util.setGlobalProperty('track.ID', '') + util.setGlobalProperty('theme_playing', '1') + + self.oldVolume = util.rpc.Application.GetProperties(properties=["volume"])["volume"] + + def onPlayBackStarted(self): + util.DEBUG_LOG("BGM: playing theme for %s" % self.currentlyPlaying) + self.player.bgmPlaying = True + + def _setVolume(self, vlm): + xbmc.executebuiltin("SetVolume({})".format(vlm)) + + def setVolume(self, volume=None, reset=False): + vlm = self.oldVolume if reset else volume + curVolume = self.getVolume() + + if curVolume != vlm: + util.DEBUG_LOG("BGM: {}setting volume to: {}".format("re-" if reset else "", vlm)) + self._setVolume(vlm) + else: + util.DEBUG_LOG("BGM: Volume already at {}".format(vlm)) + return + + waited = 0 + waitMax = 5 + while curVolume != vlm and waited < waitMax: + util.DEBUG_LOG("Waiting for volume to change from {} to {}".format(curVolume, vlm)) + xbmc.sleep(100) + waited += 1 + curVolume = self.getVolume() + + if waited == waitMax: + util.DEBUG_LOG("BGM: Timeout setting volume to {} (is: {}). Might have been externally changed in the " + "meantime".format(vlm, self.getVolume())) + + def resetVolume(self): + self.setVolume(reset=True) + + def onPlayBackStopped(self): + util.DEBUG_LOG("BGM: stopped theme for {}".format(self.currentlyPlaying)) + util.setGlobalProperty('theme_playing', '') + self.player.bgmPlaying = False + self.resetVolume() + + def onPlayBackEnded(self): + self.onPlayBackStopped() + + def onPlayBackFailed(self): + self.onPlayBackStopped() + + def close(self): + self.player.stopAndWait() + self.onPlayBackStopped() + + +class BGMPlayerTask(backgroundthread.Task): + def setup(self, source, player, *args, **kwargs): + self.source = source + self.player = player + return self + + def cancel(self): + self.player.stopAndWait() + self.player = None + backgroundthread.Task.cancel(self) + + def run(self): + if self.isCanceled(): + return + + self.player.play(self.source, windowed=True) + + +class PlexPlayer(xbmc.Player, signalsmixin.SignalsMixin): + STATE_STOPPED = "stopped" + STATE_PLAYING = "playing" + STATE_PAUSED = "paused" + STATE_BUFFERING = "buffering" + + OFFSET_RE = re.compile(r'(offset=)\d+') + + def __init__(self, *args, **kwargs): + xbmc.Player.__init__(self, *args, **kwargs) + signalsmixin.SignalsMixin.__init__(self) + self.handler = AudioPlayerHandler(self) + + def init(self): + self._closed = False + self._nextItem = None + self.started = False + self.bgmPlaying = False + self.lastPlayWasBGM = False + self.BGMTask = None + self.pauseAfterPlaybackStarted = False + self.video = None + self.hasOSD = False + self.hasSeekOSD = False + self.handler = AudioPlayerHandler(self) + self.playerObject = None + self.currentTime = 0 + self.thread = None + self.ignoreStopEvents = False + if xbmc.getCondVisibility('Player.HasMedia'): + self.started = True + self.resume = False + self.open() + + return self + + def open(self): + self._closed = False + self.monitor() + + def close(self, shutdown=False): + self._closed = True + + def reset(self): + self.video = None + self.started = False + self.bgmPlaying = False + self.playerObject = None + self.pauseAfterPlaybackStarted = False + self.ignoreStopEvents = False + #self.handler = AudioPlayerHandler(self) + self.currentTime = 0 + + def control(self, cmd): + if cmd == 'play': + self.pauseAfterPlaybackStarted = False + util.DEBUG_LOG('Player - Control: Command=Play') + if xbmc.getCondVisibility('Player.Paused | !Player.Playing'): + util.DEBUG_LOG('Player - Control: Playing') + xbmc.executebuiltin('PlayerControl(Play)') + elif cmd == 'pause': + util.DEBUG_LOG('Player - Control: Command=Pause') + if not xbmc.getCondVisibility('Player.Paused'): + util.DEBUG_LOG('Player - Control: Pausing') + xbmc.executebuiltin('PlayerControl(Play)') + + @property + def playState(self): + if xbmc.getCondVisibility('Player.Playing'): + return self.STATE_PLAYING + elif xbmc.getCondVisibility('Player.Caching'): + return self.STATE_BUFFERING + elif xbmc.getCondVisibility('Player.Paused'): + return self.STATE_PAUSED + + return self.STATE_STOPPED + + def videoIsFullscreen(self): + return xbmc.getCondVisibility('VideoPlayer.IsFullscreen') + + def currentTrack(self): + if self.handler.media and self.handler.media.type == 'track': + return self.handler.media + return None + + def playAt(self, path, ms): + """ + Plays the video specified by path. + Optionally set the start position with h,m,s,ms keyword args. + """ + seconds = ms / 1000.0 + + h = int(seconds / 3600) + m = int((seconds % 3600) / 60) + s = int(seconds % 60) + ms = int((seconds % 1) * 1000) + + kodijsonrpc.rpc.Player.Open( + item={'file': path}, + options={'resume': {'hours': h, 'minutes': m, 'seconds': s, 'milliseconds': ms}} + ) + + def play(self, *args, **kwargs): + self.started = False + xbmc.Player.play(self, *args, **kwargs) + + def playBackgroundMusic(self, source, volume, rating_key, *args, **kwargs): + if self.isPlaying(): + if not self.lastPlayWasBGM: + return + + else: + # don't re-queue the currently playing theme + if self.handler.currentlyPlaying == rating_key: + return + + # cancel any currently playing theme before starting the new one + else: + self.stopAndWait() + + if self.BGMTask and self.BGMTask.isValid(): + self.BGMTask.cancel() + + self.started = False + self.handler = BGMPlayerHandler(self, rating_key) + + # store current volume if it's different from the BGM volume + curVol = self.handler.getVolume() + if volume < curVol: + util.setSetting('last_good_volume', curVol) + + self.lastPlayWasBGM = True + + self.handler.setVolume(volume) + + self.BGMTask = BGMPlayerTask().setup(source, self, *args, **kwargs) + backgroundthread.BGThreader.addTask(self.BGMTask) + + def playVideo(self, video, resume=False, force_update=False, session_id=None, handler=None): + if self.bgmPlaying: + self.stopAndWait() + + self.handler = handler if handler and isinstance(handler, SeekPlayerHandler) \ + else SeekPlayerHandler(self, session_id) + + self.video = video + self.resume = resume + self.open() + self._playVideo(resume and video.viewOffset.asInt() or 0, force_update=force_update) + + def getOSSPathHint(self, meta): + # only hint the path one folder above for a movie, two folders above for TV + try: + head1, tail1 = os.path.split(meta.path) + head2, tail2 = os.path.split(head1) + if self.video.type == "episode": + head3, tail3 = os.path.split(head2) + cleaned_path = os.path.join(tail3, tail2, tail1) + else: + cleaned_path = os.path.join(tail2, tail1) + except: + cleaned_path = "" + return cleaned_path + + def _playVideo(self, offset=0, seeking=0, force_update=False, playerObject=None): + self.trigger('new.video', video=self.video) + self.trigger( + 'change.background', + url=self.video.defaultArt.asTranscodedImageURL(1920, 1080, opacity=60, background=colors.noAlpha.Background) + ) + try: + if not playerObject: + self.playerObject = plexplayer.PlexPlayer(self.video, offset, forceUpdate=force_update) + self.playerObject.build() + self.playerObject = self.playerObject.getServerDecision() + except plexplayer.DecisionFailure as e: + util.showNotification(e.reason, header=util.T(32448, 'Playback Failed!')) + return + except: + util.ERROR(notify=True) + return + + meta = self.playerObject.metadata + + # Kodi 19 will try to look for subtitles in the directory containing the file. '/' and `/file.mkv` both point + # to the file, and Kodi will happily try to read the whole file without recognizing it isn't a directory. + # To get around that, we omit the filename here since it is unnecessary. + url = meta.streamUrls[0].replace("file.mkv", "").replace("file.mp4", "") + + bifURL = self.playerObject.getBifUrl() + util.DEBUG_LOG('Playing URL(+{1}ms): {0}{2}'.format(plexnetUtil.cleanToken(url), offset, bifURL and ' - indexed' or '')) + + self.ignoreStopEvents = True + self.stopAndWait() # Stop before setting up the handler to prevent player events from causing havoc + self.ignoreStopEvents = False + + self.handler.setup(self.video.duration.asInt(), meta, offset, bifURL, title=self.video.grandparentTitle, + title2=self.video.title, seeking=seeking, chapters=self.video.chapters) + + # try to get an early intro offset so we can skip it if necessary + introOffset = None + if not offset: + # in case we're transcoded, instruct the marker handler to set the marker a skipped, so we don't re-skip it + # after seeking + probOff = self.handler.getIntroOffset(offset, setSkipped=meta.isTranscoded) + if probOff: + introOffset = probOff + + if meta.isTranscoded: + self.handler.mode = self.handler.MODE_RELATIVE + + if introOffset: + # cheat our way into an early intro skip by modifying the offset in the stream URL + util.DEBUG_LOG("Immediately seeking behind intro: {}".format(introOffset)) + url = self.OFFSET_RE.sub(r"\g<1>{}".format(introOffset // 1000), url) + self.handler.dialog.baseOffset = introOffset + + # probably not necessary + meta.playStart = introOffset // 1000 + else: + if offset: + util.DEBUG_LOG("Using as SeekOnStart: {0}; offset: {1}".format(meta.playStart, offset)) + self.handler.seekOnStart = meta.playStart * 1000 + elif introOffset: + util.DEBUG_LOG("Seeking behind intro after playstart: {}".format(introOffset)) + self.handler.seekOnStart = introOffset + + self.handler.mode = self.handler.MODE_ABSOLUTE + + url = util.addURLParams(url, { + 'X-Plex-Client-Profile-Name': 'Generic', + 'X-Plex-Client-Identifier': plexapp.util.INTERFACE.getGlobal('clientIdentifier') + }) + li = xbmcgui.ListItem(self.video.title, path=url) + vtype = self.video.type if self.video.type in ('movie', 'episode', 'musicvideo') else 'video' + + util.setGlobalProperty("current_path", self.getOSSPathHint(meta), base='videoinfo.{0}') + util.setGlobalProperty("current_size", str(meta.size), base='videoinfo.{0}') + li.setInfo('video', { + 'mediatype': vtype, + 'title': self.video.title, + 'originaltitle': self.video.title, + 'tvshowtitle': self.video.grandparentTitle, + 'episode': vtype == "episode" and self.video.index.asInt() or '', + 'season': vtype == "episode" and self.video.parentIndex.asInt() or '', + #'year': self.video.year.asInt(), + 'plot': self.video.summary, + 'path': meta.path, + 'size': meta.size, + }) + li.setArt({ + 'poster': self.video.defaultThumb.asTranscodedImageURL(347, 518), + 'fanart': self.video.defaultArt.asTranscodedImageURL(1920, 1080), + 'thumb': self.video.defaultThumb.asTranscodedImageURL(256, 256), + }) + + self.play(url, li) + + def playVideoPlaylist(self, playlist, resume=False, handler=None, session_id=None): + if self.bgmPlaying: + self.stopAndWait() + + if handler and isinstance(handler, SeekPlayerHandler): + self.handler = handler + else: + self.handler = SeekPlayerHandler(self, session_id) + + self.handler.playlist = playlist + if playlist.isRemote: + self.handler.playQueue = playlist + self.video = playlist.current() + self.video.softReload(includeChapters=1) + self.resume = resume + self.open() + self._playVideo(resume and self.video.viewOffset.asInt() or 0, seeking=handler and handler.SEEK_PLAYLIST or 0, force_update=True) + + # def createVideoListItem(self, video, index=0): + # url = 'plugin://script.plex/play?{0}'.format(base64.urlsafe_b64encode(video.serialize())) + # li = xbmcgui.ListItem(self.video.title, path=url, thumbnailImage=self.video.defaultThumb.asTranscodedImageURL(256, 256)) + # vtype = self.video.type if self.video.vtype in ('movie', 'episode', 'musicvideo') else 'video' + # li.setInfo('video', { + # 'mediatype': vtype, + # 'playcount': index, + # 'title': video.title, + # 'tvshowtitle': video.grandparentTitle, + # 'episode': video.index.asInt(), + # 'season': video.parentIndex.asInt(), + # 'year': video.year.asInt(), + # 'plot': video.summary + # }) + # li.setArt({ + # 'poster': self.video.defaultThumb.asTranscodedImageURL(347, 518), + # 'fanart': self.video.defaultArt.asTranscodedImageURL(1920, 1080), + # }) + + # return url, li + + def playAudio(self, track, fanart=None, **kwargs): + if self.bgmPlaying: + self.stopAndWait() + + self.handler = AudioPlayerHandler(self) + url, li = self.createTrackListItem(track, fanart) + self.stopAndWait() + self.play(url, li, **kwargs) + + def playAlbum(self, album, startpos=-1, fanart=None, **kwargs): + if self.bgmPlaying: + self.stopAndWait() + + self.handler = AudioPlayerHandler(self) + plist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC) + plist.clear() + index = 1 + for track in album.tracks(): + url, li = self.createTrackListItem(track, fanart, index=index) + plist.add(url, li) + index += 1 + xbmc.executebuiltin('PlayerControl(RandomOff)') + self.stopAndWait() + self.play(plist, startpos=startpos, **kwargs) + + def playAudioPlaylist(self, playlist, startpos=-1, fanart=None, **kwargs): + if self.bgmPlaying: + self.stopAndWait() + + self.handler = AudioPlayerHandler(self) + plist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC) + plist.clear() + index = 1 + for track in playlist.items(): + url, li = self.createTrackListItem(track, fanart, index=index) + plist.add(url, li) + index += 1 + + if playlist.isRemote: + self.handler.setPlayQueue(playlist) + else: + if playlist.startShuffled: + plist.shuffle() + xbmc.executebuiltin('PlayerControl(RandomOn)') + else: + xbmc.executebuiltin('PlayerControl(RandomOff)') + self.stopAndWait() + self.play(plist, startpos=startpos, **kwargs) + + def createTrackListItem(self, track, fanart=None, index=0): + data = base64.urlsafe_b64encode(track.serialize().encode("utf8")).decode("utf8") + url = 'plugin://script.plexmod/play?{0}'.format(data) + li = xbmcgui.ListItem(track.title, path=url) + li.setInfo('music', { + 'artist': six.text_type(track.originalTitle or track.grandparentTitle), + 'title': six.text_type(track.title), + 'album': six.text_type(track.parentTitle), + 'discnumber': track.parentIndex.asInt(), + 'tracknumber': track.get('index').asInt(), + 'duration': int(track.duration.asInt() / 1000), + 'playcount': index, + 'comment': 'PLEX-{0}:{1}'.format(track.ratingKey, data) + }) + art = fanart or track.defaultArt + li.setArt({ + 'fanart': art.asTranscodedImageURL(1920, 1080), + 'landscape': util.backgroundFromArt(art), + 'thumb': track.defaultThumb.asTranscodedImageURL(800, 800), + }) + if fanart: + li.setArt({'fanart': fanart}) + return (url, li) + + def onPrePlayStarted(self): + util.DEBUG_LOG('Player - PRE-PLAY; handler: %r' % self.handler) + self.trigger('preplay.started') + if not self.handler: + return + self.handler.onPrePlayStarted() + + def onPlayBackStarted(self): + util.DEBUG_LOG('Player - STARTED') + self.trigger('playback.started') + self.started = True + if self.pauseAfterPlaybackStarted: + self.control('pause') + self.pauseAfterPlaybackStarted = False + + if not self.handler: + return + self.handler.onPlayBackStarted() + + def onAVChange(self): + util.DEBUG_LOG('Player - AVChange') + if not self.handler: + return + self.handler.onAVChange() + + def onAVStarted(self): + util.DEBUG_LOG('Player - AVStarted: {}'.format(self.handler)) + self.trigger('av.started') + if not self.handler: + return + self.handler.onAVStarted() + + def onPlayBackPaused(self): + util.DEBUG_LOG('Player - PAUSED') + if not self.handler: + return + self.handler.onPlayBackPaused() + + def onPlayBackResumed(self): + util.DEBUG_LOG('Player - RESUMED') + if not self.handler: + return + + self.handler.onPlayBackResumed() + + def onPlayBackStopped(self): + util.DEBUG_LOG('Player - STOPPED' + (not self.started and ': FAILED' or '')) + if self.ignoreStopEvents: + return + + if not self.started: + self.onPlayBackFailed() + + if not self.handler: + return + self.handler.onPlayBackStopped() + + def onPlayBackEnded(self): + util.DEBUG_LOG('Player - ENDED' + (not self.started and ': FAILED' or '')) + if self.ignoreStopEvents: + return + + if not self.started: + self.onPlayBackFailed() + + if not self.handler: + return + self.handler.onPlayBackEnded() + + def onPlayBackSeek(self, time, offset): + util.DEBUG_LOG('Player - SEEK: %i' % offset) + if not self.handler: + return + self.handler.onPlayBackSeek(time, offset) + + def onPlayBackFailed(self): + util.DEBUG_LOG('Player - FAILED: {}'.format(self.handler)) + if not self.handler: + return + + if self.handler.onPlayBackFailed(): + util.showNotification(util.T(32448, 'Playback Failed!')) + self.stopAndWait() + self.close() + # xbmcgui.Dialog().ok('Failed', 'Playback failed') + + def onVideoWindowOpened(self): + util.DEBUG_LOG('Player: Video window opened') + try: + self.handler.onVideoWindowOpened() + except: + util.ERROR() + + def onVideoWindowClosed(self): + util.DEBUG_LOG('Player: Video window closed') + try: + self.handler.onVideoWindowClosed() + # self.stop() + except: + util.ERROR() + + def onVideoOSD(self): + util.DEBUG_LOG('Player: Video OSD opened') + try: + self.handler.onVideoOSD() + except: + util.ERROR() + + def onSeekOSD(self): + util.DEBUG_LOG('Player: Seek OSD opened') + try: + self.handler.onSeekOSD() + except: + util.ERROR() + + def stopAndWait(self): + if self.isPlaying(): + util.DEBUG_LOG('Player: Stopping and waiting...') + self.stop() + while not util.MONITOR.waitForAbort(0.1) and self.isPlaying(): + pass + util.MONITOR.waitForAbort(0.2) + util.DEBUG_LOG('Player: Stopping and waiting...Done') + + def monitor(self): + if not self.thread or not self.thread.is_alive(): + self.thread = threading.Thread(target=self._monitor, name='PLAYER:MONITOR') + self.thread.start() + + def _monitor(self): + try: + while not util.MONITOR.abortRequested() and not self._closed: + if not self.isPlaying(): + util.DEBUG_LOG('Player: Idling...') + + while not self.isPlaying() and not util.MONITOR.abortRequested() and not self._closed: + util.MONITOR.waitForAbort(0.1) + + if self.isPlayingVideo(): + util.DEBUG_LOG('Monitoring video...') + self._videoMonitor() + elif self.isPlayingAudio(): + util.DEBUG_LOG('Monitoring audio...') + self._audioMonitor() + elif self.isPlaying(): + util.DEBUG_LOG('Monitoring pre-play...') + + # note: this might never be triggered depending on how fast the video playback starts. + # don't rely on it in any way. + self._preplayMonitor() + + self.handler.close() + self.close() + util.DEBUG_LOG('Player: Closed') + finally: + self.trigger('session.ended') + + def _preplayMonitor(self): + self.onPrePlayStarted() + while self.isPlaying() and not self.isPlayingVideo() and not self.isPlayingAudio() and not util.MONITOR.abortRequested() and not self._closed: + util.MONITOR.waitForAbort(0.1) + + if not self.isPlayingVideo() and not self.isPlayingAudio(): + self.onPlayBackFailed() + + def _videoMonitor(self): + hasFullScreened = False + + ct = 0 + while self.isPlayingVideo() and not util.MONITOR.abortRequested() and not self._closed: + try: + self.currentTime = self.getTime() + except RuntimeError: + break + + util.MONITOR.waitForAbort(0.1) + if xbmc.getCondVisibility('Window.IsActive(videoosd)'): + if not self.hasOSD: + self.hasOSD = True + self.onVideoOSD() + else: + self.hasOSD = False + + if xbmc.getCondVisibility('Window.IsActive(seekbar)'): + if not self.hasSeekOSD: + self.hasSeekOSD = True + self.onSeekOSD() + else: + self.hasSeekOSD = False + + if xbmc.getCondVisibility('VideoPlayer.IsFullscreen'): + if not hasFullScreened: + hasFullScreened = True + self.onVideoWindowOpened() + elif hasFullScreened and not xbmc.getCondVisibility('Window.IsVisible(busydialog)'): + hasFullScreened = False + self.onVideoWindowClosed() + + ct += 1 + if ct > 9: + ct = 0 + self.handler.tick() + + if hasFullScreened: + self.onVideoWindowClosed() + + def _audioMonitor(self): + self.started = True + self.handler.onMonitorInit() + ct = 0 + while self.isPlayingAudio() and not util.MONITOR.abortRequested() and not self._closed: + try: + self.currentTime = self.getTime() + except RuntimeError: + break + + util.MONITOR.waitForAbort(0.1) + + ct += 1 + if ct > 9: + ct = 0 + self.handler.tick() + + +def shutdown(): + global PLAYER + PLAYER.close(shutdown=True) + del PLAYER + + +PLAYER = PlexPlayer().init() diff --git a/script.plexmod/lib/plex.py b/script.plexmod/lib/plex.py new file mode 100644 index 0000000000..0576f537bb --- /dev/null +++ b/script.plexmod/lib/plex.py @@ -0,0 +1,454 @@ +from __future__ import absolute_import +import sys +import platform +import traceback +import uuid +import json +import threading +import time +import requests +import six + +from kodi_six import xbmc, xbmcaddon + +from plexnet import plexapp, myplex, util as plexnet_util, asyncadapter, http as pnhttp + +from .playback_utils import PlaybackManager +from . windows.settings import PlayedThresholdSetting +from . import util +from six.moves import range + +if six.PY2: + _Event = threading._Event +else: + _Event = threading.Event + + +class PlexTimer(plexapp.util.Timer): + def shouldAbort(self): + return util.MONITOR.abortRequested() + + +def abortFlag(): + return util.MONITOR.abortRequested() + + +plexapp.util.setTimer(PlexTimer) +plexapp.setAbortFlagFunction(abortFlag) + +maxVideoRes = plexapp.Res((3840, 2160)) # INTERFACE.globals["supports4k"] and plexapp.Res((3840, 2160)) or plexapp.Res((1920, 1080)) + +CLIENT_ID = util.getSetting('client.ID') +if not CLIENT_ID: + CLIENT_ID = str(uuid.uuid4()) + util.setSetting('client.ID', CLIENT_ID) + + +def defaultUserAgent(): + """Return a string representing the default user agent.""" + _implementation = platform.python_implementation() + + if _implementation == 'CPython': + _implementation_version = platform.python_version() + elif _implementation == 'PyPy': + _implementation_version = '%s.%s.%s' % (sys.pypy_version_info.major, + sys.pypy_version_info.minor, + sys.pypy_version_info.micro) + if sys.pypy_version_info.releaselevel != 'final': + _implementation_version = ''.join([_implementation_version, sys.pypy_version_info.releaselevel]) + elif _implementation == 'Jython': + _implementation_version = platform.python_version() # Complete Guess + elif _implementation == 'IronPython': + _implementation_version = platform.python_version() # Complete Guess + else: + _implementation_version = 'Unknown' + + try: + p_system = platform.system() + p_release = platform.release() + except IOError: + p_system = 'Unknown' + p_release = 'Unknown' + + return " ".join(['%s/%s' % ('PM4K', util.ADDON.getAddonInfo('version')), + '%s/%s' % ('Kodi', xbmc.getInfoLabel('System.BuildVersion').replace(' ', '-')), + '%s/%s' % (_implementation, _implementation_version), + '%s/%s' % (p_system, p_release)]) + + +class PlexInterface(plexapp.AppInterface): + _regs = { + None: {}, + } + _globals = { + 'platform': 'Kodi', + 'appVersionStr': util.ADDON.getAddonInfo('version'), + 'clientIdentifier': CLIENT_ID, + 'platformVersion': xbmc.getInfoLabel('System.BuildVersion'), + 'product': 'PM4K', + 'provides': 'player', + 'device': util.getPlatform() or plexapp.PLATFORM, + 'model': 'Unknown', + 'friendlyName': util.rpc.Settings.GetSettingValue(setting='services.devicename').get('value') or 'Kodi', + 'supports1080p60': True, + 'vp9Support': True, + 'audioChannels': '2.0', + 'transcodeVideoQualities': [ + "10", "20", "30", "30", "40", "60", "60", "75", "100", "60", "75", "90", "100", "100" + ], + 'transcodeVideoResolutions': [ + plexapp.Res((220, 180)), + plexapp.Res((220, 128)), + plexapp.Res((284, 160)), + plexapp.Res((420, 240)), + plexapp.Res((576, 320)), + plexapp.Res((720, 480)), + plexapp.Res((1024, 768)), + plexapp.Res((1280, 720)), + plexapp.Res((1280, 720)), + maxVideoRes, maxVideoRes, maxVideoRes, maxVideoRes, maxVideoRes + ], + 'transcodeVideoBitrates': [ + "64", "96", "208", "320", "720", "1500", "2000", "3000", "4000", "8000", "10000", "12000", "20000", "400000" + ], + 'deviceInfo': plexapp.DeviceInfo() + } + + bingeModeManager = None + + def getPreference(self, pref, default=None): + if pref == 'manual_connections': + return self.getManualConnections() + else: + return util.getSetting(pref, default) + + def getManualConnections(self): + conns = [] + for i in range(2): + ip = util.getSetting('manual_ip_{0}'.format(i)) + if not ip: + continue + port = util.getSetting('manual_port_{0}'.format(i), 32400) + conns.append({'connection': ip, 'port': port}) + return json.dumps(conns) + + def setPreference(self, pref, value): + util.setSetting(pref, value) + + def getRegistry(self, reg, default=None, sec=None): + if sec == 'myplex' and reg == 'MyPlexAccount': + ret = util.getSetting('{0}.{1}'.format(sec, reg), default) + if ret: + return ret + return json.dumps({'authToken': util.getSetting('auth.token')}) + else: + return util.getSetting('{0}.{1}'.format(sec, reg), default) + + def setRegistry(self, reg, value, sec=None): + util.setSetting('{0}.{1}'.format(sec, reg), value) + + def clearRegistry(self, reg, sec=None): + util.setSetting('{0}.{1}'.format(sec, reg), '') + + def addInitializer(self, sec): + pass + + def clearInitializer(self, sec): + pass + + def getGlobal(self, glbl, default=None): + if glbl == 'transcodeVideoResolutions': + maxres = self.getPreference('allow_4k', True) and plexapp.Res((3840, 2160)) or plexapp.Res((1920, 1080)) + self._globals['transcodeVideoResolutions'][-5:] = [maxres] * 5 + elif glbl == 'audioChannels': + try: + self._globals['audioChannels'] = \ + util.CHANNELMAPPING[util.rpc.Settings.GetSettingValue(setting='audiooutput.channels').get('value')] + except: + util.DEBUG_LOG("Limiting audio channel definition to 2.0 due to error: %s" % traceback.format_exc()) + self._globals['audioChannels'] = "2.0" + + return self._globals.get(glbl, default) + + def getCapabilities(self): + return '' + + def LOG(self, msg): + util.DEBUG_LOG('API: {0}'.format(msg)) + + def DEBUG_LOG(self, msg): + self.LOG('DEBUG: {0}'.format(msg)) + + def WARN_LOG(self, msg): + self.LOG('WARNING: {0}'.format(msg)) + + def ERROR_LOG(self, msg): + self.LOG('ERROR: {0}'.format(msg)) + + def ERROR(self, msg=None, err=None): + if err: + self.LOG('ERROR: {0} - {1}'.format(msg, getattr(err, "message", "Unknown Error"))) + else: + util.ERROR() + + def supportsAudioStream(self, codec, channels): + return True + # if codec = invalid then return true + + # canDownmix = (m.globals["audioDownmix"][codec] <> invalid) + # supportsSurroundSound = m.SupportsSurroundSound() + + # if not supportsSurroundSound and canDownmix then + # maxChannels = m.globals["audioDownmix"][codec] + # else + # maxChannels = firstOf(m.globals["audioDecoders"][codec], 0) + # end if + + # if maxChannels > 2 and not canDownmix and not supportsSurroundSound then + # ' It's a surround sound codec and we can't do surround sound + # supported = false + # else if maxChannels = 0 or maxChannels < channels then + # ' The codec is either unsupported or can't handle the requested channels + # supported = false + # else + # supported = true + + # return supported + + def supportsSurroundSound(self): + return True + + def getQualityIndex(self, qualityType): + if qualityType == self.QUALITY_LOCAL: + return self.getPreference("local_quality", 13) + elif qualityType == self.QUALITY_ONLINE: + return self.getPreference("online_quality", 13) + else: + return self.getPreference("remote_quality", 13) + + def getMaxResolution(self, quality_type, allow4k=False): + qualityIndex = self.getQualityIndex(quality_type) + + if qualityIndex >= 9: + if self.getPreference('allow_4k', True): + return allow4k and 2160 or 1088 + else: + return 1088 + elif qualityIndex >= 6: + return 720 + elif qualityIndex >= 5: + return 480 + else: + return 360 + + def getThemeMusicValue(self): + index = 10 - self.getPreference("theme_music", 5) + if index > 0: + return index * 10 + return 0 + + def getPlayedThresholdValue(self): + values = list(reversed(PlayedThresholdSetting.options)) + return int(values[self.getPreference("played_threshold", 1)].replace(" %", "")) / 100.0 + + +def onSmartDiscoverLocalChange(value=None, **kwargs): + plexnet_util.CHECK_LOCAL = value + plexapp.refreshResources(True) + + +def onPreferLANChange(value=None, **kwargs): + plexnet_util.LOCAL_OVER_SECURE = value + plexapp.refreshResources(True) + + +def onPreferLocalChange(**kwargs): + plexapp.refreshResources(True) + + +def onManualIPChange(**kwargs): + plexapp.refreshResources(True) + + +plexapp.util.setInterface(PlexInterface()) +plexapp.util.INTERFACE.playbackManager = PlaybackManager() +plexapp.util.APP.on('change:smart_discover_local', onSmartDiscoverLocalChange) +plexapp.util.APP.on('change:prefer_local', onPreferLANChange) +plexapp.util.APP.on('change:same_network', onPreferLocalChange) +plexapp.util.APP.on('change:manual_ip_0', onManualIPChange) +plexapp.util.APP.on('change:manual_ip_1', onManualIPChange) +plexapp.util.APP.on('change:manual_port_0', onManualIPChange) +plexapp.util.APP.on('change:manual_port_1', onManualIPChange) + +plexapp.util.CHECK_LOCAL = util.getSetting('smart_discover_local', True) +plexapp.util.LOCAL_OVER_SECURE = util.getSetting('prefer_local', False) + +# set requests timeout +TIMEOUT = float(util.advancedSettings.requestsTimeout) +CONNCHECK_TIMEOUT = float(util.advancedSettings.connCheckTimeout) +plexapp.util.TIMEOUT = TIMEOUT +plexapp.util.CONN_CHECK_TIMEOUT = asyncadapter.AsyncTimeout(CONNCHECK_TIMEOUT).setConnectTimeout(CONNCHECK_TIMEOUT) +plexapp.util.LAN_REACHABILITY_TIMEOUT = util.advancedSettings.localReachTimeout / 1000.0 +pnhttp.DEFAULT_TIMEOUT = asyncadapter.AsyncTimeout(TIMEOUT).setConnectTimeout(TIMEOUT) +asyncadapter.DEFAULT_TIMEOUT = pnhttp.DEFAULT_TIMEOUT +plexapp.util.ACCEPT_LANGUAGE = util.ACCEPT_LANGUAGE_CODE +plexapp.setUserAgent(defaultUserAgent()) + + +class CallbackEvent(plexapp.util.CompatEvent): + def __init__(self, context, signal, timeout=15, *args, **kwargs): + plexnet_util.Event.__init__(self, *args, **kwargs) + self.start = time.time() + self.context = context + self.signal = signal + self.timeout = timeout + self.context.on(self.signal, self.set) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.wait() + + def __repr__(self): + return '<{0}:{1}>'.format(self.__class__.__name__, self.signal) + + def set(self, **kwargs): + plexnet_util.Event.set(self) + + def wait(self): + if not plexnet_util.Event.wait(self, self.timeout): + util.DEBUG_LOG('{0}: TIMED-OUT'.format(self)) + self.close() + + def triggeredOrTimedOut(self, timeout=None): + try: + if time.time() - self.start > self.timeout: + util.DEBUG_LOG('{0}: TIMED-OUT'.format(self)) + return True + + if timeout: + plexnet_util.Event.wait(self, timeout) + finally: + return self.isSet() + + def close(self): + self.set() + self.context.off(self.signal, self.set) + + +def init(): + util.DEBUG_LOG('Initializing...') + + with CallbackEvent(plexapp.util.APP, 'init'): + plexapp.init() + util.DEBUG_LOG('Waiting for account initialization...') + + util.DEBUG_LOG('Account initialized: {}'.format(plexapp.ACCOUNT.ID)) + + retry = True + + while retry: + retry = False + if not plexapp.ACCOUNT.authToken: + util.DEBUG_LOG("No auth token, authorizing") + token = authorize() + + if not token: + util.DEBUG_LOG('FAILED TO AUTHORIZE') + return False + + with CallbackEvent(plexapp.util.APP, 'account:response'): + plexapp.ACCOUNT.validateToken(token) + util.DEBUG_LOG('Waiting for account initialization...') + + # if not PLEX: + # util.messageDialog('Connection Error', u'Unable to connect to any servers') + # util.DEBUG_LOG('SIGN IN: Failed to connect to any servers') + # return False + + # util.DEBUG_LOG('SIGN IN: Connected to server: {0} - {1}'.format(PLEX.friendlyName, PLEX.baseuri)) + success = requirePlexPass() + if success == 'RETRY': + retry = True + continue + + return success + + +def requirePlexPass(): + return True + # if not plexapp.ACCOUNT.hasPlexPass(): + # from windows import signin, background + # background.setSplash(False) + # w = signin.SignInPlexPass.open() + # retry = w.retry + # del w + # util.DEBUG_LOG('PlexPass required. Signing out...') + # plexapp.ACCOUNT.signOut() + # plexapp.SERVERMANAGER.clearState() + # if retry: + # return 'RETRY' + # else: + # return False + + # return True + + +def authorize(): + from .windows import signin, background + + background.setSplash(False) + + back = signin.Background.create() + + pre = signin.PreSignInWindow.open() + try: + if not pre.doSignin: + return None + finally: + del pre + + try: + while True: + pinLoginWindow = signin.PinLoginWindow.create() + try: + pl = myplex.PinLogin() + except requests.ConnectionError: + util.ERROR() + util.messageDialog(util.T(32427, 'Failed'), util.T(32449, 'Sign-in failed. Cound not connect to plex.tv')) + return + + pinLoginWindow.setPin(pl.pin) + + try: + pl.startTokenPolling() + while not pl.finished(): + if pinLoginWindow.abort: + util.DEBUG_LOG('SIGN IN: Pin login aborted') + pl.abort() + return None + xbmc.sleep(100) + else: + if not pl.expired(): + if pl.authenticationToken: + pinLoginWindow.setLinking() + return pl.authenticationToken + else: + return None + finally: + pinLoginWindow.doClose() + del pinLoginWindow + + if pl.expired(): + util.DEBUG_LOG('SIGN IN: Pin expired') + expiredWindow = signin.ExpiredWindow.open() + try: + if not expiredWindow.refresh: + util.DEBUG_LOG('SIGN IN: Pin refresh aborted') + return None + finally: + del expiredWindow + finally: + back.doClose() + del back diff --git a/script.plexmod/lib/util.py b/script.plexmod/lib/util.py new file mode 100644 index 0000000000..cd7a2d5d7b --- /dev/null +++ b/script.plexmod/lib/util.py @@ -0,0 +1,1009 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +import gc +import sys +import re +import binascii +import json +import threading +import math +import time +import datetime +import contextlib +import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error +import six +import os +import struct +import requests + +from .kodijsonrpc import rpc +from kodi_six import xbmc +from kodi_six import xbmcgui +from kodi_six import xbmcaddon +from kodi_six import xbmcvfs + +from . import colors +from plexnet import signalsmixin, plexapp + +DEBUG = True +_SHUTDOWN = False + +ADDON = xbmcaddon.Addon() + +SETTINGS_LOCK = threading.Lock() + +_build = None +# buildversion looks like: XX.X[-TAG] (a+.b+.c+) (.+); there are kodi builds that don't set the build version +sys_ver = xbmc.getInfoLabel('System.BuildVersion') +_ver = sys_ver +if ' ' in sys_ver and '(' in sys_ver: + _ver, _build = sys_ver.split()[:2] + +_splitver = _ver.split(".") +KODI_VERSION_MAJOR, KODI_VERSION_MINOR = int(_splitver[0].split("-")[0].strip()), \ + int(_splitver[1].split("-")[0].strip()) + +_bmajor, _bminor, _bpatch = (KODI_VERSION_MAJOR, KODI_VERSION_MINOR, 0) +if _build: + _bmajor, _bminor, _bpatch = _build[1:-1].split(".") +else: + xbmc.log('script.plex: Couldn\'t determine build version, falling back to Kodi version', xbmc.LOGINFO) + +# calculate a comparable build number +KODI_BUILD_NUMBER = int("{0}{1:02d}{2:03d}".format(_bmajor, int(_bminor), int(_bpatch))) +xbmc.log('script.plex: Kodi {0}.{1} (build {2})'.format(KODI_VERSION_MAJOR, KODI_VERSION_MINOR, KODI_BUILD_NUMBER), + xbmc.LOGINFO) + + +if KODI_VERSION_MAJOR > 18: + translatePath = xbmcvfs.translatePath +else: + translatePath = xbmc.translatePath + +PROFILE = translatePath(ADDON.getAddonInfo('profile')) + + +def getChannelMapping(): + data = rpc.Settings.GetSettings(filter={"section": "system", "category": "audio"})["settings"] + return list(filter(lambda i: i["id"] == "audiooutput.channels", data))[0]["options"] + + +# retrieve labels for mapping audio channel settings values +try: + CHANNELMAPPING = dict((t["value"], t["label"]) for t in getChannelMapping()) +except: + CHANNELMAPPING = None + + +def getLanguageCode(add_def=None): + data = rpc.Settings.GetSettingValue(setting='locale.language')['value'].replace('resource.language.', '') + lang = "" + if "_" in data: + base, variant = data.split("_") + lang += "{}-{},{}".format(base, variant.upper(), base) + else: + lang = data + if add_def and lang not in add_def: + lang += ",{}".format(add_def) + return lang + + +try: + ACCEPT_LANGUAGE_CODE = getLanguageCode(add_def='en-US,en') +except: + ACCEPT_LANGUAGE_CODE = 'en-US,en' + + +def getSetting(key, default=None): + with SETTINGS_LOCK: + setting = ADDON.getSetting(key) + return _processSetting(setting, default) + + +def getUserSetting(key, default=None): + if not plexapp.ACCOUNT: + return default + + key = '{}.{}'.format(key, plexapp.ACCOUNT.ID) + with SETTINGS_LOCK: + setting = ADDON.getSetting(key) + return _processSetting(setting, default) + + +def _processSetting(setting, default): + if not setting: + return default + if isinstance(default, bool): + return setting.lower() == 'true' + elif isinstance(default, float): + return float(setting) + elif isinstance(default, int): + return int(float(setting or 0)) + elif isinstance(default, list): + if setting: + return json.loads(binascii.unhexlify(setting)) + else: + return default + + return setting + + +class AdvancedSettings(object): + """ + @DynamicAttrs + """ + + _proxiedSettings = ( + ("debug", False), + ("kodi_skip_stepping", False), + ("auto_seek", True), + ("auto_seek_delay", 1), + ("dynamic_timeline_seek", False), + ("fast_back", False), + ("dynamic_backgrounds", True), + ("background_art_blur_amount2", 0), + ("background_art_opacity_amount2", 20), + ("screensaver_quiz", False), + ("postplay_always", False), + ("postplay_timeout", 16), + ("skip_intro_button_timeout", 10), + ("skip_credits_button_timeout", 10), + ("playlist_visit_media", True), + ("intro_skip_early", False), + ("show_media_ends_info", True), + ("show_media_ends_label", True), + ("background_colour", None), + ("oldprofile", False), + ("skip_intro_button_show_early_threshold1", 60), + ("requests_timeout", 5.0), + ("local_reach_timeout", 10), + ("auto_skip_offset", 2.5), + ("conn_check_timeout", 2.5), + ("postplayCancel", True), + ("skip_marker_timer_cancel", True), + ("skip_marker_timer_immediate", False), + ("low_drift_timer", True), + ("player_show_buffer", True), + ("buffer_wait_max", 120), + ("buffer_insufficient_wait", 10), + ("continue_use_thumb", True), + ("use_bg_fallback", False), + ("dbg_crossfade", True), + ("subtitle_use_extended_title", True), + ("dialog_flicker_fix", True), + ("poster_resolution_scale_perc", 100), + ) + + def __init__(self): + # register every known setting camelCased as an attribute to this instance + for setting, default in self._proxiedSettings: + name_split = setting.split("_") + setattr(self, name_split[0] + ''.join(x.capitalize() or '_' for x in name_split[1:]), + getSetting(setting, default)) + + +advancedSettings = AdvancedSettings() + + +def LOG(msg, level=xbmc.LOGINFO): + xbmc.log('script.plex: {0}'.format(msg), level) + + +def DEBUG_LOG(msg): + if _SHUTDOWN: + return + + if not advancedSettings.debug and not xbmc.getCondVisibility('System.GetBool(debug.showloginfo)'): + return + + LOG(msg) + + +def ERROR(txt='', hide_tb=False, notify=False, time_ms=3000): + short = str(sys.exc_info()[1]) + if hide_tb: + xbmc.log('script.plex: ERROR: {0} - {1}'.format(txt, short), xbmc.LOGERROR) + return short + + import traceback + tb = traceback.format_exc() + xbmc.log("_________________________________________________________________________________", xbmc.LOGERROR) + xbmc.log('script.plex: ERROR: ' + txt, xbmc.LOGERROR) + for l in tb.splitlines(): + xbmc.log(' ' + l, xbmc.LOGERROR) + xbmc.log("_________________________________________________________________________________", xbmc.LOGERROR) + xbmc.log("`", xbmc.LOGERROR) + if notify: + showNotification('ERROR: {0}'.format(txt or short), time_ms=time_ms) + return short + + +def TEST(msg): + xbmc.log('---TEST: {0}'.format(msg), xbmc.LOGINFO) + + +class UtilityMonitor(xbmc.Monitor, signalsmixin.SignalsMixin): + def __init__(self, *args, **kwargs): + xbmc.Monitor.__init__(self, *args, **kwargs) + signalsmixin.SignalsMixin.__init__(self) + + def watchStatusChanged(self): + self.trigger('changed.watchstatus') + + def actionStop(self): + self.stopPlayback() + + def actionQuit(self): + LOG('OnSleep: Exit Kodi') + xbmc.executebuiltin('Quit') + + def actionReboot(self): + LOG('OnSleep: Reboot') + xbmc.restart() + + def actionShutdown(self): + LOG('OnSleep: Shutdown') + xbmc.shutdown() + + def actionHibernate(self): + LOG('OnSleep: Hibernate') + xbmc.executebuiltin('Hibernate') + + def actionSuspend(self): + LOG('OnSleep: Suspend') + xbmc.executebuiltin('Suspend') + + def actionCecstandby(self): + LOG('OnSleep: CEC Standby') + xbmc.executebuiltin('CECStandby') + + def actionLogoff(self): + LOG('OnSleep: Sign Out') + xbmc.executebuiltin('System.LogOff') + + def onNotification(self, sender, method, data): + LOG("Notification: {} {} {}".format(sender, method, data)) + if sender == 'script.plexmod' and method.endswith('RESTORE'): + from .windows import kodigui + if not kodigui.BaseFunctions.lastWinID: + ERROR("Addon never properly started, can't reactivate") + setGlobalProperty('stop_running', '1') + return + if kodigui.BaseFunctions.lastWinID > 13000: + xbmc.executebuiltin('ActivateWindow({0})'.format(kodigui.BaseFunctions.lastWinID)) + else: + ERROR("Addon never properly started, can't reactivate") + setGlobalProperty('stop_running', '1') + return + + getAdvancedSettings() + populateTimeFormat() + + elif sender == "xbmc" and method == "System.OnSleep" and getSetting('action_on_sleep', "none") != "none": + getattr(self, "action{}".format(getSetting('action_on_sleep', "none").capitalize()))() + + def stopPlayback(self): + LOG('Monitor: Stopping media playback') + xbmc.Player().stop() + + def onScreensaverActivated(self): + DEBUG_LOG("Monitor: OnScreensaverActivated") + if getSetting('player_stop_on_screensaver', True) and xbmc.Player().isPlayingVideo(): + self.stopPlayback() + + def onDPMSActivated(self): + DEBUG_LOG("Monitor: OnDPMSActivated") + #self.stopPlayback() + + +MONITOR = UtilityMonitor() + +ADV_MSIZE_RE = re.compile(r'(\d+)') +ADV_RFACT_RE = re.compile(r'(\d+)') +ADV_CACHE_RE = re.compile(r'\s*.*', re.S | re.I) + + +class KodiCacheManager(object): + """ + A pretty cheap approach at managing the section of advancedsettings.xml + + Starting with build 20.90.821 (Kodi 21.0-BETA2) a lot of caching issues have been fixed and + readfactor behaves better. We need to adjust for that. + """ + _cleanData = None + useModernAPI = False + memorySize = 20 # in MB + readFactor = 4 + defRF = 4 + defRFSM = 20 + recRFRange = (4, 10) + template = None + orig_tpl_path = os.path.join(ADDON.getAddonInfo('path'), "pm4k_cache_template.xml") + custom_tpl_path = "special://profile/pm4k_cache_template.xml" + translated_ctpl_path = translatePath(custom_tpl_path) + + # give Android a little more leeway with its sometimes weird memory management; otherwise stick with 23% of free mem + safeFactor = .20 if xbmc.getCondVisibility('System.Platform.Android') else .23 + + def __init__(self): + if KODI_BUILD_NUMBER >= 2090821: + self.memorySize = rpc.Settings.GetSettingValue(setting='filecache.memorysize')['value'] + self.readFactor = rpc.Settings.GetSettingValue(setting='filecache.readfactor')['value'] / 100.0 + if self.readFactor % 1 == 0: + self.readFactor = int(self.readFactor) + DEBUG_LOG("Not using advancedsettings.xml for cache/buffer management, we're at least Kodi 21 non-alpha") + self.useModernAPI = True + self.defRFSM = 7 + self.recRFRange = (1.5, 4) + + else: + self.load() + self.template = self.getTemplate() + + plexapp.util.APP.on('change:slow_connection', + lambda value=None, **kwargs: self.write(readFactor=value and self.defRFSM or self.defRF)) + + def getTemplate(self): + if xbmcvfs.exists(self.custom_tpl_path): + try: + f = xbmcvfs.File(self.custom_tpl_path) + data = f.read() + f.close() + if data: + return data + except: + pass + + DEBUG_LOG("Custom pm4k_cache_template.xml not found, using default") + f = xbmcvfs.File(self.orig_tpl_path) + data = f.read() + f.close() + return data + + def load(self): + try: + f = xbmcvfs.File("special://profile/advancedsettings.xml") + data = f.read() + f.close() + except: + LOG('script.plex: No advancedsettings.xml found') + else: + cachexml_match = ADV_CACHE_RE.search(data) + if cachexml_match: + cachexml = cachexml_match.group(0) + + try: + self.memorySize = int(ADV_MSIZE_RE.search(cachexml).group(1)) // 1024 // 1024 + except (ValueError, IndexError, TypeError): + DEBUG_LOG("script.plex: invalid or not found memorysize in advancedsettings.xml") + + try: + self.readFactor = int(ADV_RFACT_RE.search(cachexml).group(1)) + except (ValueError, IndexError, TypeError): + DEBUG_LOG("script.plex: invalid or not found readfactor in advancedsettings.xml") + + self._cleanData = data.replace(cachexml, "") + else: + self._cleanData = data + + def write(self, memorySize=None, readFactor=None): + memorySize = self.memorySize = memorySize if memorySize is not None else self.memorySize + readFactor = self.readFactor = readFactor if readFactor is not None else self.readFactor + + if self.useModernAPI: + # kodi cache settings have moved to Services>Caching + try: + rpc.Settings.SetSettingValue(setting='filecache.memorysize', value=self.memorySize) + rpc.Settings.SetSettingValue(setting='filecache.readfactor', value=int(self.readFactor * 100)) + except: + pass + return + + cd = self._cleanData + if not cd: + cd = "\n" + + finalxml = "{}\n".format( + cd.replace("", self.template.format(memorysize=memorySize * 1024 * 1024, + readfactor=readFactor)) + ) + + try: + f = xbmcvfs.File("special://profile/advancedsettings.xml", "w") + f.write(finalxml) + f.close() + except: + ERROR("Couldn't write advancedsettings.xml") + + def clamp16(self, x): + return x - x % 16 + + @property + def viableOptions(self): + default = list(filter(lambda x: x < self.recMax, + [16, 20, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024])) + + # add option to overcommit slightly + overcommit = [] + if xbmc.getCondVisibility('System.Platform.Android'): + overcommit.append(min(self.clamp16(int(self.free * 0.23)), 2048)) + + overcommit.append(min(self.clamp16(int(self.free * 0.26)), 2048)) + overcommit.append(min(self.clamp16(int(self.free * 0.3)), 2048)) + + # re-append current memorySize here, as recommended max might have changed + return list(sorted(list(set(default + [self.memorySize, self.recMax] + overcommit)))) + + @property + def readFactorOpts(self): + return list(sorted(list(set([1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5, 7, 10, 15, 20, 30, 50] + [self.readFactor])))) + + @property + def free(self): + return float(xbmc.getInfoLabel('System.Memory(free)')[:-2]) + + @property + def recMax(self): + freeMem = self.free + recMem = min(int(freeMem * self.safeFactor), 2048) + LOG("Free memory: {} MB, recommended max: {} MB".format(freeMem, recMem)) + return recMem + + +kcm = KodiCacheManager() + +CACHE_SIZE = kcm.memorySize + + +def T(ID, eng=''): + return ADDON.getLocalizedString(ID) + + +hasCustomBGColour = False +if KODI_VERSION_MAJOR > 18: + hasCustomBGColour = not advancedSettings.dynamicBackgrounds and advancedSettings.backgroundColour and \ + advancedSettings.backgroundColour != "-" + + +def getAdvancedSettings(): + # yes, global, hang me! + global advancedSettings + advancedSettings = AdvancedSettings() + + +def setSetting(key, value): + with SETTINGS_LOCK: + value = _processSettingForWrite(value) + ADDON.setSetting(key, value) + + +def _processSettingForWrite(value): + if isinstance(value, list): + value = binascii.hexlify(json.dumps(value)) + elif isinstance(value, bool): + value = value and 'true' or 'false' + return str(value) + + +def setGlobalProperty(key, val, base='script.plex.{0}'): + xbmcgui.Window(10000).setProperty(base.format(key), val) + + +def setGlobalBoolProperty(key, boolean, base='script.plex.{0}'): + xbmcgui.Window(10000).setProperty(base.format(key), boolean and '1' or '') + + +def getGlobalProperty(key): + return xbmc.getInfoLabel('Window(10000).Property(script.plex.{0})'.format(key)) + + +def showNotification(message, time_ms=3000, icon_path=None, header=ADDON.getAddonInfo('name')): + try: + icon_path = icon_path or translatePath(ADDON.getAddonInfo('icon')) + xbmc.executebuiltin('Notification({0},{1},{2},{3})'.format(header, message, time_ms, icon_path)) + except RuntimeError: # Happens when disabling the addon + LOG(message) + + +def videoIsPlaying(): + return xbmc.getCondVisibility('Player.HasVideo') + + +def messageDialog(heading='Message', msg=''): + from .windows import optionsdialog + optionsdialog.show(heading, msg, 'OK') + + +def showTextDialog(heading, text): + t = TextBox() + t.setControls(heading, text) + + +def sortTitle(title): + return title.startswith('The ') and title[4:] or title + + +def durationToText(seconds): + """ + Converts seconds to a short user friendly string + Example: 143 -> 2m 23s + """ + days = int(seconds / 86400000) + if days: + return '{0} day{1}'.format(days, days > 1 and 's' or '') + left = seconds % 86400000 + hours = int(left / 3600000) + if hours: + hours = '{0} hr{1} '.format(hours, hours > 1 and 's' or '') + else: + hours = '' + left = left % 3600000 + mins = int(left / 60000) + if mins: + return hours + '{0} min{1}'.format(mins, mins > 1 and 's' or '') + elif hours: + return hours.rstrip() + secs = int(left % 60000) + if secs: + secs /= 1000 + return '{0} sec{1}'.format(secs, secs > 1 and 's' or '') + return '0 seconds' + + +def durationToShortText(seconds): + """ + Converts seconds to a short user friendly string + Example: 143 -> 2m 23s + """ + days = int(seconds / 86400000) + if days: + return '{0} d'.format(days) + left = seconds % 86400000 + hours = int(left / 3600000) + if hours: + hours = '{0} h '.format(hours) + else: + hours = '' + left = left % 3600000 + mins = int(left / 60000) + if mins: + return hours + '{0} m'.format(mins) + elif hours: + return hours.rstrip() + secs = int(left % 60000) + if secs: + secs /= 1000 + return '{0} s'.format(secs) + return '0 s' + + +def cleanLeadingZeros(text): + if not text: + return '' + return re.sub(r'(?<= )0(\d)', r'\1', text) + + +def removeDups(dlist): + return [ii for n, ii in enumerate(dlist) if ii not in dlist[:n]] + + +SIZE_NAMES = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") + + +def simpleSize(size): + """ + Converts bytes to a short user friendly string + Example: 12345 -> 12.06 KB + """ + s = 0 + if size > 0: + i = int(math.floor(math.log(size, 1024))) + p = math.pow(1024, i) + s = round(size / p, 2) + if (s > 0): + return '%s %s' % (s, SIZE_NAMES[i]) + else: + return '0B' + + +def timeDisplay(ms, cutHour=False): + h = ms / 3600000 + m = (ms % 3600000) / 60000 + s = (ms % 60000) / 1000 + if h >= 1 or not cutHour: + return '{0:0>2}:{1:0>2}:{2:0>2}'.format(int(h), int(m), int(s)) + return '{0:0>2}:{1:0>2}'.format(int(m), int(s)) + + +def simplifiedTimeDisplay(ms): + left, right = timeDisplay(ms).rsplit(':', 1) + left = left.lstrip('0:') or '0' + return left + ':' + right + + +def shortenText(text, size): + if len(text) < size: + return text + + return u'{0}\u2026'.format(text[:size - 1]) + + +def scaleResolution(w, h, by=None): + if by is None: + by = advancedSettings.posterResolutionScalePerc + + if 0 < by != 100.0: + px = w * h * (by / 100.0) + wratio = h / float(w) + hratio = w / float(h) + return int(round((px / wratio) ** .5)), int(round((px / hratio) ** .5)) + return w, h + + +class TextBox: + # constants + WINDOW = 10147 + CONTROL_LABEL = 1 + CONTROL_TEXTBOX = 5 + + def __init__(self, *args, **kwargs): + # activate the text viewer window + xbmc.executebuiltin("ActivateWindow(%d)" % (self.WINDOW, )) + # get window + self.win = xbmcgui.Window(self.WINDOW) + # give window time to initialize + xbmc.sleep(1000) + + def setControls(self, heading, text): + # set heading + self.win.getControl(self.CONTROL_LABEL).setLabel(heading) + # set text + self.win.getControl(self.CONTROL_TEXTBOX).setText(text) + + +class SettingControl: + def __init__(self, setting, log_display, disable_value=''): + self.setting = setting + self.logDisplay = log_display + self.disableValue = disable_value + self._originalMode = None + self.store() + + def disable(self): + rpc.Settings.SetSettingValue(setting=self.setting, value=self.disableValue) + DEBUG_LOG('{0}: DISABLED'.format(self.logDisplay)) + + def set(self, value): + rpc.Settings.SetSettingValue(setting=self.setting, value=value) + DEBUG_LOG('{0}: SET={1}'.format(self.logDisplay, value)) + + def store(self): + try: + self._originalMode = rpc.Settings.GetSettingValue(setting=self.setting).get('value') + DEBUG_LOG('{0}: Mode stored ({1})'.format(self.logDisplay, self._originalMode)) + except: + ERROR() + + def restore(self): + if self._originalMode is None: + return + rpc.Settings.SetSettingValue(setting=self.setting, value=self._originalMode) + DEBUG_LOG('{0}: RESTORED'.format(self.logDisplay)) + + @contextlib.contextmanager + def suspend(self): + self.disable() + yield + self.restore() + + @contextlib.contextmanager + def save(self): + yield + self.restore() + + +def timeInDayLocalSeconds(): + now = datetime.datetime.now() + sod = datetime.datetime(year=now.year, month=now.month, day=now.day) + sod = int(time.mktime(sod.timetuple())) + return int(time.time() - sod) + + +def getKodiSkipSteps(): + try: + return rpc.Settings.GetSettingValue(setting="videoplayer.seeksteps")["value"] + except: + return + + +def getKodiSlideshowInterval(): + try: + return rpc.Settings.GetSettingValue(setting="slideshow.staytime")["value"] + except: + return 3 + + +kodiSkipSteps = getKodiSkipSteps() +slideshowInterval = getKodiSlideshowInterval() + + +CRON = None + + +class CronReceiver(): + def tick(self): + pass + + def halfHour(self): + pass + + def day(self): + pass + + +class Cron(threading.Thread): + def __init__(self, interval): + threading.Thread.__init__(self, name='CRON') + self.stopped = threading.Event() + self.force = threading.Event() + self.interval = interval + self._lastHalfHour = self._getHalfHour() + self._receivers = [] + + global CRON + + CRON = self + + def __enter__(self): + self.start() + DEBUG_LOG('Cron started') + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.stop() + self.join() + + def _wait(self): + ct = 0 + while ct < self.interval: + xbmc.sleep(100) + ct += 0.1 + if self.force.isSet(): + self.force.clear() + return True + if MONITOR.abortRequested() or self.stopped.isSet(): + return False + return True + + def forceTick(self): + self.force.set() + + def stop(self): + self.stopped.set() + + def run(self): + while self._wait(): + self._tick() + DEBUG_LOG('Cron stopped') + + def _getHalfHour(self): + tid = timeInDayLocalSeconds() / 60 + return tid - (tid % 30) + + def _tick(self): + receivers = list(self._receivers) + receivers = self._halfHour(receivers) + for r in receivers: + try: + r.tick() + except: + ERROR() + + def _halfHour(self, receivers): + hh = self._getHalfHour() + if hh == self._lastHalfHour: + return receivers + try: + receivers = self._day(receivers, hh) + ret = [] + for r in receivers: + try: + if not r.halfHour(): + ret.append(r) + except: + ret.append(r) + ERROR() + return ret + finally: + self._lastHalfHour = hh + + def _day(self, receivers, hh): + if hh >= self._lastHalfHour: + return receivers + ret = [] + for r in receivers: + try: + if not r.day(): + ret.append(r) + except: + ret.append(r) + ERROR() + return ret + + def registerReceiver(self, receiver): + if receiver not in self._receivers: + DEBUG_LOG('Cron: Receiver added: {0}'.format(receiver)) + self._receivers.append(receiver) + + def cancelReceiver(self, receiver): + if receiver in self._receivers: + DEBUG_LOG('Cron: Receiver canceled: {0}'.format(receiver)) + self._receivers.pop(self._receivers.index(receiver)) + + +def getTimeFormat(): + """ + Generic: + Use locale.timeformat setting to get and make use of the format. + + Possible values: + HH:mm:ss -> %H:%M:%S + regional -> legacy + H:mm:ss -> %-H:%M:%S + + Legacy: Not necessarily true for Omega?; regional spices things up (depending on Kodi version?) + Get global time format. + Kodi's time format handling is weird, as they return incompatible formats for strftime. + %H%H can be returned for manually set zero-padded values, in case of a regional zero-padded hour component, + only %H is returned. + + For now, sail around that by testing the current time for padded hour values. + + Tests of the values returned by xbmc.getRegion("time") as of Kodi Nexus (I believe): + %I:%M:%S %p = h:mm:ss, non-zero-padded, 12h PM + %I:%M:%S = 12h, h:mm:ss, non-zero-padded, regional + %I%I:%M:%S = 12h, zero padded, hh:mm:ss + %H%H:%M:%S = 24h, zero padded, hh:mm:ss + %H:%M:%S = 24h, zero padded, regional, regional (central europe) + + :return: tuple of strftime-compatible format, boolean padHour + """ + + fmt = None + nonPadHF = "%-H" if sys.platform != "win32" else "%#H" + nonPadIF = "%-I" if sys.platform != "win32" else "%#I" + + try: + fmt = rpc.Settings.GetSettingValue(setting="locale.timeformat")["value"] + except: + DEBUG_LOG("Couldn't get locale.timeformat setting, falling back to legacy detection") + + if fmt and fmt != "regional": + # HH = padded 24h + # hh = padded 12h + # H = unpadded 24h + # h = unpadded 12h + + # handle non-padded hour first + if fmt.startswith("H:") or fmt.startswith("h:"): + adjustedFmt = fmt.replace("H", nonPadHF).replace("h", nonPadIF) + else: + adjustedFmt = fmt.replace("HH", "%H").replace("hh", "%I") + + padHour = adjustedFmt.startswith("%H") or adjustedFmt.startswith("%I") + + else: + DEBUG_LOG("Regional time format detected, falling back to legacy detection of hour-padding") + # regional is weirdly always unpadded (unless the broken %H%H/%I%I notation is used + origFmt = xbmc.getRegion('time') + + adjustedFmt = origFmt.replace("%H%H", "%H").replace("%I%I", "%I") + + # Checking for %H%H or %I%I only would be the obvious way here to determine whether the hour should be padded, + # but the formats returned for regional settings with padding might only have %H in them. + # Use a fallback (unreliable). + currentTime = xbmc.getInfoLabel('System.Time') + padHour = "%H%H" in origFmt or "%I%I" in origFmt or (currentTime[0] == "0" and currentTime[1] != ":") + + # Kodi Omega on Android seems to have borked the regional format returned separately + # (not happening on Windows at least). Format returned can be "%H:mm:ss", which is incompatible with strftime; fix. + adjustedFmt = adjustedFmt.replace("mm", "%M").replace("ss", "%S").replace("xx", "%p") + adjustedFmtKN = adjustedFmt.replace("%M", "mm").replace("%H", "hh").replace("%I", "h").replace("%S", "ss").\ + replace("%p", "xx").replace(nonPadIF, "h").replace(nonPadHF, "h") + + return adjustedFmt, adjustedFmtKN, padHour + + +timeFormat, timeFormatKN, padHour = getTimeFormat() + + +def populateTimeFormat(): + global timeFormat, timeFormatKN, padHour + timeFormat, timeFormatKN, padHour = getTimeFormat() + + +def getPlatform(): + for key in [ + 'System.Platform.Android', + 'System.Platform.Linux.RaspberryPi', + 'System.Platform.Linux', + 'System.Platform.Windows', + 'System.Platform.OSX', + 'System.Platform.IOS', + 'System.Platform.Darwin', + 'System.Platform.ATV2' + ]: + if xbmc.getCondVisibility(key): + return key.rsplit('.', 1)[-1] + + +def getProgressImage(obj): + if not obj.get('viewOffset') or not obj.get('duration'): + return '' + pct = int((obj.viewOffset.asInt() / obj.duration.asFloat()) * 100) + pct = pct - pct % 2 # Round to even number - we have even numbered progress only + pct = max(pct, 2) + return 'script.plex/progress/{0}.png'.format(pct) + + +def backgroundFromArt(art, width=1920, height=1080, background=colors.noAlpha.Background): + if not art: + return + return art.asTranscodedImageURL( + width, height, + blur=advancedSettings.backgroundArtBlurAmount2, + opacity=advancedSettings.backgroundArtOpacityAmount2, + background=background + ) + + +def trackIsPlaying(track): + return xbmc.getCondVisibility('String.StartsWith(MusicPlayer.Comment,{0})'.format('PLEX-{0}:'.format(track.ratingKey))) + + +def addURLParams(url, params): + if '?' in url: + url += '&' + else: + url += '?' + url += six.moves.urllib.parse.urlencode(params) + return url + + +OSS_CHUNK = 65536 + + +def getOpenSubtitlesHash(size, url): + long_long_format = "q" # long long + byte_size = struct.calcsize(long_long_format) + hash_ = filesize = size + if filesize < OSS_CHUNK * 2: + return + + buffer = b'' + for _range in ((0, OSS_CHUNK), (filesize-OSS_CHUNK, filesize)): + try: + r = requests.get(url, headers={"range": "bytes={0}-{1}".format(*_range)}, stream=True) + except: + return '' + buffer += r.raw.read(OSS_CHUNK) + + for x in range(int(OSS_CHUNK / byte_size) * 2): + size = x * byte_size + (l_value,) = struct.unpack(long_long_format, buffer[size:size + byte_size]) + hash_ += l_value + hash_ = hash_ & 0xFFFFFFFFFFFFFFFF + + return format(hash_, "016x") + + +def garbageCollect(): + gc.collect(2) + + +def shutdown(): + global MONITOR, ADDON, T, _SHUTDOWN + _SHUTDOWN = True + del MONITOR + del T + del ADDON diff --git a/script.plexmod/lib/windows/__init__.py b/script.plexmod/lib/windows/__init__.py new file mode 100644 index 0000000000..f96b690080 --- /dev/null +++ b/script.plexmod/lib/windows/__init__.py @@ -0,0 +1,5 @@ +from __future__ import absolute_import +from . import kodigui +from lib import util + +kodigui.MONITOR = util.MONITOR diff --git a/script.plexmod/lib/windows/background.py b/script.plexmod/lib/windows/background.py new file mode 100644 index 0000000000..8940d1c6bd --- /dev/null +++ b/script.plexmod/lib/windows/background.py @@ -0,0 +1,43 @@ +from __future__ import absolute_import +from . import kodigui +from lib import util + +util.setGlobalProperty('background.busy', '') +util.setGlobalProperty('background.shutdown', '') +util.setGlobalProperty('background.splash', '') + + +class BackgroundWindow(kodigui.BaseWindow): + xmlFile = 'script-plex-background.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + def __init__(self, *args, **kwargs): + kodigui.BaseWindow.__init__(self, *args, **kwargs) + self.function = kwargs.get('function') + + def onFirstInit(self): + self.function() + self.doClose() + + def onAction(self, action): + pass + + +def setBusy(on=True): + util.setGlobalProperty('background.busy', on and '1' or '') + + +def setSplash(on=True): + util.setGlobalProperty('background.splash', on and '1' or '') + + +def setShutdown(on=True): + util.setGlobalProperty('background.shutdown', on and '1' or '') + + +def killMonitor(): + kodigui.MONITOR = None diff --git a/script.plexmod/lib/windows/busy.py b/script.plexmod/lib/windows/busy.py new file mode 100644 index 0000000000..1f128c5ecb --- /dev/null +++ b/script.plexmod/lib/windows/busy.py @@ -0,0 +1,142 @@ +from __future__ import absolute_import +from . import kodigui +from lib import util +from kodi_six import xbmcgui +import threading + + +class BusyWindow(kodigui.BaseDialog): + xmlFile = 'script-plex-busy.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + +class BusyClosableWindow(BusyWindow): + ctx = None + + def onAction(self, action): + if action in (xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_STOP): + self.ctx.shouldClose = True + + +class BusyClosableMsgWindow(BusyClosableWindow): + xmlFile = 'script-plex-busy_msg.xml' + + def setMessage(self, msg): + self.setProperty("message", msg) + + +def dialog(msg='LOADING', condition=None, delay=True): + def methodWrap(func): + def inner(*args, **kwargs): + timer = None + w = BusyWindow.create(show=not delay) + + if delay: + timer = threading.Timer(0.5, w.show) + timer.start() + + try: + return func(*args, **kwargs) + finally: + if timer and timer.is_alive(): + timer.cancel() + timer.join() + del timer + w.doClose() + try: + del w + except: + pass + util.garbageCollect() + + if condition is not None: + return condition() and inner or func + return inner + + return methodWrap + + +def widthDialog(method, msg, *args, **kwargs): + return dialog(msg or 'LOADING')(method)(*args, **kwargs) + + +class BusyContext(object): + w = None + timer = None + shouldClose = False + window_cls = BusyWindow + delay = False + + def __enter__(self): + self.w = self.window_cls.create(show=not self.delay) + if self.delay: + self.timer = threading.Timer(0.5, lambda: self.w.show()) + self.w.ctx = self + return self + + def __exit__(self, exc_type, exc_value, tb): + if exc_type is not None: + util.ERROR() + + if self.timer and self.timer.is_alive(): + self.timer.cancel() + self.timer.join() + + self.w.doClose() + del self.w + self.w = None + util.garbageCollect() + return True + + +class BusyMsgContext(BusyContext): + window_cls = BusyClosableMsgWindow + + def setMessage(self, msg): + self.w.setMessage(msg) + + +class BusySignalContext(BusyMsgContext): + """ + Duplicates functionality of plex.CallbackEvent to a certain degree + """ + window_cls = BusyWindow + delay = True + + def __init__(self, context, signal, wait_max=10, delay=True): + self.wfSignal = signal + self.signalEmitter = context + self.waitMax = wait_max + self.ignoreSignal = False + self.signalReceived = False + self.delay = delay + + super(BusySignalContext, self).__init__() + + context.on(signal, self.onSignal) + + def onSignal(self, *args, **kwargs): + self.signalReceived = True + + def __exit__(self, exc_type, exc_val, exc_tb): + if exc_type is not None: + util.ERROR() + + try: + if not self.ignoreSignal: + waited = 0 + while not self.signalReceived and waited < self.waitMax: + util.MONITOR.waitForAbort(0.1) + waited += 0.1 + finally: + self.signalEmitter.off(self.wfSignal, self.onSignal) + + return super(BusySignalContext, self).__exit__(exc_type, exc_val, exc_tb) + + +class BusyClosableMsgContext(BusyMsgContext): + pass diff --git a/script.plexmod/lib/windows/currentplaylist.py b/script.plexmod/lib/windows/currentplaylist.py new file mode 100644 index 0000000000..91dffd23a1 --- /dev/null +++ b/script.plexmod/lib/windows/currentplaylist.py @@ -0,0 +1,337 @@ +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import kodigui + +from . import busy +from . import windowutils +from . import dropdown +from . import opener + +from lib import util +from lib import player +from lib import kodijsonrpc + +from lib.util import T + + +class CurrentPlaylistWindow(kodigui.ControlledWindow, windowutils.UtilMixin): + xmlFile = 'script-plex-music_current_playlist.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + LI_THUMB_DIM = (64, 64) + ALBUM_THUMB_DIM = util.scaleResolution(639, 639) + + PLAYLIST_LIST_ID = 101 + + SEEK_BUTTON_ID = 500 + SEEK_IMAGE_ID = 510 + + POSITION_IMAGE_ID = 201 + SELECTION_INDICATOR = 202 + SELECTION_BOX = 203 + + REPEAT_BUTTON_ID = 401 + SHUFFLE_BUTTON_ID = 402 + SHUFFLE_REMOTE_BUTTON_ID = 422 + SKIP_PREV_BUTTON_ID = 404 + SKIP_NEXT_BUTTON_ID = 409 + PLAYLIST_BUTTON_ID = 410 + OPTIONS_BUTTON_ID = 411 + STOP_BUTTON_ID = 407 + + SEEK_IMAGE_WIDTH = 819 + SELECTION_BOX_WIDTH = 101 + SELECTION_INDICATOR_Y = 896 + + BAR_X = 0 + BAR_Y = 921 + BAR_RIGHT = 819 + BAR_BOTTOM = 969 + + def __init__(self, *args, **kwargs): + kodigui.ControlledWindow.__init__(self, *args, **kwargs) + self.selectedOffset = 0 + self.setDuration() + self.exitCommand = None + self.musicPlayerWinID = kwargs.get('winID') + + def doClose(self, **kwargs): + player.PLAYER.off('playback.started', self.onPlayBackStarted) + player.PLAYER.off('playlist.changed', self.playQueueCallback) + if player.PLAYER.handler.playQueue and player.PLAYER.handler.playQueue.isRemote: + player.PLAYER.handler.playQueue.off('change', self.updateProperties) + kodigui.ControlledWindow.doClose(self) + + def onFirstInit(self): + self.playlistListControl = kodigui.ManagedControlList(self, self.PLAYLIST_LIST_ID, 9) + self.setupSeekbar() + + self.fillPlaylist() + self.selectPlayingItem() + self.setFocusId(self.PLAYLIST_LIST_ID) + + self.updateProperties() + if player.PLAYER.handler.playQueue and player.PLAYER.handler.playQueue.isRemote: + player.PLAYER.handler.playQueue.on('change', self.updateProperties) + player.PLAYER.on('playlist.changed', self.playQueueCallback) + + def onAction(self, action): + try: + controlID = self.getFocusId() + if self.checkSeekActions(action, controlID): + return + except: + util.ERROR() + + kodigui.ControlledWindow.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.PLAYLIST_LIST_ID: + self.playlistListClicked() + elif controlID == self.SEEK_BUTTON_ID: + self.seekButtonClicked() + elif controlID == self.SHUFFLE_BUTTON_ID: + self.fillPlaylist() + elif controlID == self.SHUFFLE_REMOTE_BUTTON_ID: + player.PLAYER.handler.playQueue.setShuffle() + elif controlID == self.REPEAT_BUTTON_ID: + self.repeatButtonClicked() + elif controlID == self.SKIP_PREV_BUTTON_ID: + self.skipPrevButtonClicked() + elif controlID == self.SKIP_NEXT_BUTTON_ID: + self.skipNextButtonClicked() + elif controlID == self.OPTIONS_BUTTON_ID: + self.optionsButtonClicked() + elif controlID == self.STOP_BUTTON_ID: + self.stopButtonClicked() + + def onFocus(self, controlID): + if controlID == self.SEEK_BUTTON_ID: + try: + if player.PLAYER.isPlaying(): + self.selectedOffset = player.PLAYER.getTime() * 1000 + else: + self.selectedOffset = 0 + except RuntimeError: + self.selectedOffset = 0 + + self.updateSelectedProgress() + + def onPlayBackStarted(self, **kwargs): + xbmc.sleep(2000) + self.setDuration() + + def repeatButtonClicked(self): + if player.PLAYER.handler.playQueue and player.PLAYER.handler.playQueue.isRemote: + if xbmc.getCondVisibility('Playlist.IsRepeatOne'): + xbmc.executebuiltin('PlayerControl(RepeatOff)') + elif player.PLAYER.handler.playQueue.isRepeat: + player.PLAYER.handler.playQueue.setRepeat(False) + player.PLAYER.handler.playQueue.refresh(force=True) + xbmc.executebuiltin('PlayerControl(RepeatOne)') + else: + player.PLAYER.handler.playQueue.setRepeat(True) + player.PLAYER.handler.playQueue.refresh(force=True) + else: + xbmc.executebuiltin('PlayerControl(Repeat)') + + def skipPrevButtonClicked(self): + if not xbmc.getCondVisibility('MusicPlayer.HasPrevious') and player.PLAYER.handler.playQueue and player.PLAYER.handler.playQueue.isRemote: + util.DEBUG_LOG('MusicPlayer: No previous in Kodi playlist - refreshing remote PQ') + if not player.PLAYER.handler.playQueue.refresh(force=True, wait=True): + return + + xbmc.executebuiltin('PlayerControl(Previous)') + + def skipNextButtonClicked(self): + if not xbmc.getCondVisibility('MusicPlayer.HasNext') and player.PLAYER.handler.playQueue and player.PLAYER.handler.playQueue.isRemote: + util.DEBUG_LOG('MusicPlayer: No next in Kodi playlist - refreshing remote PQ') + if not player.PLAYER.handler.playQueue.refresh(force=True, wait=True): + return + + xbmc.executebuiltin('PlayerControl(Next)') + + def optionsButtonClicked(self, pos=(670, 1060)): + track = player.PLAYER.currentTrack() + if not track: + return + + options = [] + + options.append({'key': 'to_album', 'display': T(32300, 'Go to Album')}) + options.append({'key': 'to_artist', 'display': T(32301, 'Go to Artist')}) + options.append({'key': 'to_section', 'display': T(32302, u'Go to {0}').format(track.getLibrarySectionTitle())}) + + choice = dropdown.showDropdown(options, pos, close_direction='down', pos_is_bottom=True, close_on_playback_ended=True) + if not choice: + return + + if choice['key'] == 'to_album': + self.processCommand(opener.open(track.parentRatingKey)) + elif choice['key'] == 'to_artist': + self.processCommand(opener.open(track.grandparentRatingKey)) + elif choice['key'] == 'to_section': + self.goHome(track.getLibrarySectionId()) + + def stopButtonClicked(self): + xbmc.executebuiltin('Action(Back, {})'.format(self.musicPlayerWinID)) + xbmc.sleep(500) + self.doClose() + + def selectPlayingItem(self): + for mli in self.playlistListControl: + if xbmc.getCondVisibility('String.StartsWith(MusicPlayer.Comment,{0})'.format(mli.dataSource['comment'].split(':', 1)[0])): + self.playlistListControl.selectItem(mli.pos()) + break + + def playQueueCallback(self, **kwargs): + self.setProperty('pq.isshuffled', player.PLAYER.handler.playQueue.isShuffled and '1' or '') + mli = self.playlistListControl.getSelectedItem() + pi = mli.dataSource + plexID = pi['comment'].split(':', 1)[0] + viewPos = self.playlistListControl.getViewPosition() + + self.fillPlaylist() + + for ni in self.playlistListControl: + if ni.dataSource['comment'].split(':', 1)[0] == plexID: + self.playlistListControl.selectItem(ni.pos()) + break + + xbmc.sleep(100) + + newViewPos = self.playlistListControl.getViewPosition() + if viewPos != newViewPos: + diff = newViewPos - viewPos + self.playlistListControl.shiftView(diff, True) + + def seekButtonClicked(self): + player.PLAYER.seekTime(self.selectedOffset / 1000.0) + + def playlistListClicked(self): + mli = self.playlistListControl.getSelectedItem() + if not mli: + return + player.PLAYER.playselected(mli.pos()) + + def createListItem(self, pi, idx): + label2 = '{0} / {1}'.format(pi['artist'][0], pi['album']) + plexInfo = pi['comment'] + mli = kodigui.ManagedListItem(pi['title'], label2, thumbnailImage=pi['thumbnail'], data_source=pi) + mli.setProperty('track.duration', util.simplifiedTimeDisplay(pi['duration'] * 1000)) + if plexInfo.startswith('PLEX-'): + mli.setProperty('track.ID', plexInfo.split('-', 1)[-1].split(':', 1)[0]) + mli.setProperty('track.number', str(pi['playcount'])) + else: + mli.setProperty('track.ID', '!NONE!') + mli.setProperty('track.number', str(pi['track'])) + mli.setProperty('playlist.position', str(idx)) + + mli.setProperty('file', pi['file']) + return mli + + @busy.dialog() + def fillPlaylist(self): + items = [] + idx = 1 + for pi in kodijsonrpc.rpc.PlayList.GetItems( + playlistid=xbmc.PLAYLIST_MUSIC, properties=['title', 'artist', 'album', 'track', 'thumbnail', 'duration', 'playcount', 'comment', 'file'] + )['items']: + mli = self.createListItem(pi, idx) + if mli: + mli.setProperty('index', str(idx)) + items.append(mli) + idx += 1 + + self.playlistListControl.reset() + self.playlistListControl.addItems(items) + + def setupSeekbar(self): + self.seekbarControl = self.getControl(self.SEEK_IMAGE_ID) + self.selectionIndicator = self.getControl(self.SELECTION_INDICATOR) + self.selectionBox = self.getControl(self.SELECTION_BOX) + self.selectionBoxHalf = self.SELECTION_BOX_WIDTH // 2 + self.selectionBoxMax = self.SEEK_IMAGE_WIDTH + player.PLAYER.on('playback.started', self.onPlayBackStarted) + + def checkSeekActions(self, action, controlID): + if controlID == self.SEEK_BUTTON_ID: + if action == xbmcgui.ACTION_MOUSE_MOVE: + self.seekMouse(action) + return True + elif action in (xbmcgui.ACTION_MOVE_RIGHT, xbmcgui.ACTION_NEXT_ITEM): + self.seekForward(3000) + return True + elif action in (xbmcgui.ACTION_MOVE_LEFT, xbmcgui.ACTION_PREV_ITEM): + self.seekBack(3000) + return True + # elif action == xbmcgui.ACTION_MOVE_UP: + # self.seekForward(60000) + # elif action == xbmcgui.ACTION_MOVE_DOWN: + # self.seekBack(60000) + elif action == xbmcgui.ACTION_STOP: + self.stopButtonClicked() + return True + + def setDuration(self): + try: + self.duration = player.PLAYER.getTotalTime() * 1000 + except RuntimeError: # Not playing + self.duration = 0 + + def seekForward(self, offset): + self.selectedOffset += offset + if self.selectedOffset > self.duration: + self.selectedOffset = self.duration + + self.updateSelectedProgress() + + def seekBack(self, offset): + self.selectedOffset -= offset + if self.selectedOffset < 0: + self.selectedOffset = 0 + + self.updateSelectedProgress() + + def seekMouse(self, action): + x = self.mouseXTrans(action.getAmount1()) + y = self.mouseYTrans(action.getAmount2()) + if not (self.BAR_Y <= y <= self.BAR_BOTTOM): + return + + if not (self.BAR_X <= x <= self.BAR_RIGHT): + return + + self.selectedOffset = int((x - self.BAR_X) / float(self.SEEK_IMAGE_WIDTH) * self.duration) + self.updateSelectedProgress() + + def updateSelectedProgress(self): + ratio = self.selectedOffset / float(self.duration) + w = int(ratio * self.SEEK_IMAGE_WIDTH) + self.seekbarControl.setWidth(w or 1) + + self.selectionIndicator.setPosition(w, self.SELECTION_INDICATOR_Y) + if w < self.selectionBoxHalf - 3: + self.selectionBox.setPosition((-self.selectionBoxHalf + (self.selectionBoxHalf - w)) - 3, 0) + elif w > self.selectionBoxMax: + self.selectionBox.setPosition((-self.SELECTION_BOX_WIDTH + (self.SEEK_IMAGE_WIDTH - w)) + 3, 0) + else: + self.selectionBox.setPosition(-self.selectionBoxHalf, 0) + self.setProperty('time.selection', util.simplifiedTimeDisplay(int(self.selectedOffset))) + + def updateProperties(self, **kwargs): + pq = player.PLAYER.handler.playQueue + if pq: + if pq.isRemote: + self.setProperty('pq.isRemote', '1') + self.setProperty('pq.hasnext', pq.allowSkipNext and '1' or '') + self.setProperty('pq.hasprev', pq.allowSkipPrev and '1' or '') + self.setProperty('pq.repeat', pq.isRepeat and '1' or '') + self.setProperty('pq.shuffled', pq.isShuffled and '1' or '') + else: + self.setProperties(('pq.isRemote', 'pq.hasnext', 'pq.hasprev', 'pq.repeat', 'pq.shuffled'), '') diff --git a/script.plexmod/lib/windows/dropdown.py b/script.plexmod/lib/windows/dropdown.py new file mode 100644 index 0000000000..dc973b02b9 --- /dev/null +++ b/script.plexmod/lib/windows/dropdown.py @@ -0,0 +1,247 @@ +from __future__ import absolute_import +from kodi_six import xbmc, xbmcgui +from . import kodigui + +from lib import util + +SEPARATOR = None + + +class DropdownDialog(kodigui.BaseDialog): + xmlFile = 'script-plex-dropdown.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + GROUP_ID = 100 + OPTIONS_LIST_ID = 250 + + def __init__(self, *args, **kwargs): + kodigui.BaseDialog.__init__(self, *args, **kwargs) + self.options = kwargs.get('options') + self.pos = kwargs.get('pos') + self.lastSelectedItem = None + self.optionsList = None + self.roundRobin = kwargs.get('round_robin', True) + self.posIsBottom = kwargs.get('pos_is_bottom') + self.closeDirection = kwargs.get('close_direction') + self.setDropdownProp = kwargs.get('set_dropdown_prop', False) + self.withIndicator = kwargs.get('with_indicator', False) + self.suboptionCallback = kwargs.get('suboption_callback') + self.closeOnPlaybackEnded = kwargs.get('close_on_playback_ended', False) + self.closeOnlyWithBack = kwargs.get('close_only_with_back', False) + self.alignItems = kwargs.get('align_items', 'center') + self.optionsCallback = kwargs.get('options_callback', None) + self.header = kwargs.get('header') + self.selectIndex = kwargs.get('select_index') + self.onCloseCallback = kwargs.get('onclose_callback') + self.choice = None + + @property + def x(self): + return min(self.width - 360, self.pos[0]) + + @property + def y(self): + y = self.pos[1] + if self.posIsBottom: + y -= (len(self.options) * 66) + 80 + return y + + def onFirstInit(self): + self.setProperty('dropdown', self.setDropdownProp and '1' or '') + self.setProperty('header', self.header) + self.optionsList = kodigui.ManagedControlList(self, self.OPTIONS_LIST_ID, 8) + self.showOptions() + height = min(66 * 14, (len(self.options) * 66)) + 80 + self.getControl(100).setPosition(self.x, self.y) + + shadowControl = self.getControl(110) + if self.header: + shadowControl.setHeight(height + 86) + self.getControl(111).setHeight(height + 6) + else: + shadowControl.setHeight(height) + + self.setProperty('show', '1') + self.setProperty('close.direction', self.closeDirection) + if self.closeOnPlaybackEnded: + from lib import player + player.PLAYER.on('session.ended', self.playbackSessionEnded) + + def onAction(self, action): + try: + pass + except: + util.ERROR() + + if self.roundRobin and action in (xbmcgui.ACTION_MOVE_UP, xbmcgui.ACTION_MOVE_DOWN) and \ + self.getFocusId() == self.OPTIONS_LIST_ID: + to_pos = None + last_index = self.optionsList.size() - 1 + + if last_index > 0: + if action == xbmcgui.ACTION_MOVE_UP and self.lastSelectedItem in (0, None) \ + and self.optionsList.topHasFocus(): + to_pos = last_index + + elif action == xbmcgui.ACTION_MOVE_DOWN and self.lastSelectedItem == last_index \ + and self.optionsList.bottomHasFocus(): + to_pos = 0 + + if to_pos is not None: + self.optionsList.setSelectedItemByPos(to_pos) + self.lastSelectedItem = to_pos + return + + self.lastSelectedItem = self.optionsList.control.getSelectedPosition() + + kodigui.BaseDialog.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.OPTIONS_LIST_ID: + self.setChoice() + else: + self.doClose() + + def playbackSessionEnded(self, **kwargs): + self.doClose() + + def doClose(self): + if self.closeOnPlaybackEnded: + from lib import player + player.PLAYER.off('session.ended', self.playbackSessionEnded) + + self.optionsList.reset() + self.optionsList = None + + self.setProperty('show', '') + + super(DropdownDialog, self).doClose() + + def onClosed(self): + if self.onCloseCallback: + self.onCloseCallback(self.choice) + + def setChoice(self): + mli = self.optionsList.getSelectedItem() + if not mli: + return + + choice = self.options[self.optionsList.getSelectedPosition()] + + if choice.get('ignore'): + return + + if self.suboptionCallback: + options = self.suboptionCallback(choice) + if options: + sub = showDropdown(options, (self.x + 290, self.y + 10), close_direction='left', with_indicator=True) + if not sub: + return + + choice['sub'] = sub + + self.choice = choice + if self.optionsCallback: + self.optionsCallback(self.optionsList, mli) + + del mli + + if not self.closeOnlyWithBack: + self.doClose() + + def showOptions(self): + items = [] + options = [] + for oo in self.options: + if oo: + o = oo.copy() + item = kodigui.ManagedListItem(o['display'], thumbnailImage=o.get('indicator', ''), data_source=o) + item.setProperty('with.indicator', self.withIndicator and '1' or '') + item.setProperty('align', self.alignItems) + items.append(item) + options.append(o) + else: + if items: + items[-1].setProperty('separator', '1') + + self.options = options + + if len(items) > 1: + items[0].setProperty('first', '1') + items[-1].setProperty('last', '1') + elif items: + items[0].setProperty('only', '1') + + self.optionsList.reset() + self.optionsList.addItems(items) + + self.setFocusId(self.OPTIONS_LIST_ID) + + if self.selectIndex is not None: + self.optionsList.setSelectedItemByPos(self.selectIndex) + self.lastSelectedItem = self.selectIndex + + +class DropdownHeaderDialog(DropdownDialog): + xmlFile = 'script-plex-dropdown_header.xml' + + +def showDropdown( + options, pos=None, + pos_is_bottom=False, + close_direction='top', + set_dropdown_prop=True, + with_indicator=False, + suboption_callback=None, + close_on_playback_ended=False, + close_only_with_back=False, + align_items='center', + options_callback=None, + header=None, + select_index=None, + onclose_callback=None, +): + + if header: + pos = pos or (660, 400) + w = DropdownHeaderDialog.open( + options=options, pos=pos, + pos_is_bottom=pos_is_bottom, + close_direction=close_direction, + set_dropdown_prop=set_dropdown_prop, + with_indicator=with_indicator, + suboption_callback=suboption_callback, + close_on_playback_ended=close_on_playback_ended, + close_only_with_back=close_only_with_back, + align_items=align_items, + options_callback=options_callback, + header=header, + select_index=select_index, + onclose_callback=onclose_callback, + ) + else: + pos = pos or (810, 400) + w = DropdownDialog.open( + options=options, pos=pos, + pos_is_bottom=pos_is_bottom, + close_direction=close_direction, + set_dropdown_prop=set_dropdown_prop, + with_indicator=with_indicator, + suboption_callback=suboption_callback, + close_on_playback_ended=close_on_playback_ended, + close_only_with_back=close_only_with_back, + align_items=align_items, + options_callback=options_callback, + header=header, + select_index=select_index, + onclose_callback=onclose_callback, + ) + choice = w.choice + w = None + del w + util.garbageCollect() + return choice diff --git a/script.plexmod/lib/windows/episodes.py b/script.plexmod/lib/windows/episodes.py new file mode 100644 index 0000000000..65af087540 --- /dev/null +++ b/script.plexmod/lib/windows/episodes.py @@ -0,0 +1,1202 @@ +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import kodigui + +from lib import util +from lib import backgroundthread +from lib import metadata +from lib import player + +from plexnet import plexapp, playlist, plexplayer +from plexnet.util import INTERFACE + +from . import busy +from . import videoplayer +from . import dropdown +from . import windowutils +from . import opener +from . import search +from . import playersettings +from . import info +from . import optionsdialog +from . import preplayutils +from . import pagination +from . import playbacksettings + +from lib.util import T +from .mixins import SeasonsMixin + +VIDEO_RELOAD_KW = dict(includeExtras=1, includeExtrasCount=10, includeChapters=1) + + +class EpisodeReloadTask(backgroundthread.Task): + def setup(self, episode, callback, with_progress=False): + self.episode = episode + self.callback = callback + self.withProgress = with_progress + return self + + def run(self): + if self.isCanceled(): + return + + if not plexapp.SERVERMANAGER.selectedServer: + # Could happen during sign-out for instance + return + + try: + self.episode.reload(checkFiles=1, includeChapters=1, fromMediaChoice=self.episode.mediaChoice is not None) + if self.isCanceled(): + return + self.callback(self, self.episode, with_progress=self.withProgress) + except: + util.ERROR() + + +class EpisodesPaginator(pagination.MCLPaginator): + thumbFallback = 'script.plex/thumb_fallbacks/show.png' + _currentEpisode = None + + def reset(self): + super(EpisodesPaginator, self).reset() + self._currentEpisode = None + + def getData(self, offset, amount): + return (self.parentWindow.season or self.parentWindow.show_).episodes(offset=offset, limit=amount) + + def createListItem(self, data): + mli = super(EpisodesPaginator, self).createListItem(data) + self.parentWindow.setItemInfo(data, mli) + return mli + + def prepareListItem(self, data, mli): + if not mli.dataSource.isWatched: + mli.setProperty('unwatched.count', str(mli.dataSource.unViewedLeafCount)) + mli.setProperty('progress', util.getProgressImage(mli.dataSource)) + + def setEpisode(self, ep): + self._currentEpisode = ep + + @property + def initialPage(self): + episode = self.parentWindow.episode + offset = 0 + amount = self.initialPageSize + if episode: + self.setEpisode(episode) + # try cutting the query short while not querying all episodes, to find the slice with the currently + # selected episode in it + episodes = [] + _amount = self.initialPageSize + self.orphans + epSeasonIndex = int(episode.index or 1) - 1 # .index is 1-based + if _amount < self.leafCount: + _amount = self.initialPageSize * 2 + notFound = False + while episode not in episodes: + offset = int(max(0, epSeasonIndex - _amount / 2)) + episodes = self.getData(offset, int(_amount)) + + if _amount >= self.leafCount: + # ep not found? + notFound = True + break + + # in case the episode wasn't found inside the slice, increase the slice's size + _amount *= 2 + + if notFound: + # search conservatively + util.DEBUG_LOG("Episode not found with intelligent index-based search, re-trying conservatively") + _amount = self.initialPageSize * 2 + offset = 0 + episodes = self.getData(offset, int(_amount)) + while episode not in episodes: + offset = _amount + episodes = self.getData(offset, int(_amount)) + + if _amount >= self.leafCount: + break + + _amount *= 2 + else: + # shortcut for short seasons + episodes = self.getData(offset, int(_amount)) + + else: + return super(EpisodesPaginator, self).initialPage + + episodeFound = episode and episode in episodes + if episodeFound: + if self.initialPageSize + self.orphans < self.leafCount: + # slice around the episode + # Clamp the left side dynamically based on the item index and how many items are left in the season. + # The episodes list might be longer than our limit, because the season doesn't necessarily have all the + # episodes in it and we're basing the initial load on the current episode's index, which is the actual + # index of the episode in the season, not what's physically there. To find the episode, we're + # dynamically increasing the window size above. Re-clamp to :amount:, adding slack to both sides if + # the remaining episodes would fit inside half of :amount:. + tmpEpIdx = episodes.index(episode) + leftBoundary = self.initialPageSize - len(episodes[tmpEpIdx:tmpEpIdx + self.orphans]) + + left = max(tmpEpIdx - leftBoundary, 0) + offset += left + epsLeft = self.leafCount - offset + # avoid short pages on the right end + if epsLeft <= self.initialPageSize + self.orphans: + amount = epsLeft + + # avoid short pages on the left end + if offset < self.orphans and amount + offset < self.initialPageSize + self.orphans: + amount += offset + left = 0 + offset = 0 + + episodes = episodes[left:left + amount] + + self.offset = offset + self._currentAmount = len(episodes) + + return episodes + + def selectItem(self, amount, more_left=False, more_right=False, items=None): + if not super(EpisodesPaginator, self).selectItem(amount, more_left): + if (self._currentEpisode and items) and self._currentEpisode in items: + self.control.selectItem(items.index(self._currentEpisode) + (1 if more_left else 0)) + + +class RelatedPaginator(pagination.BaseRelatedPaginator): + def getData(self, offset, amount): + return self.parentWindow.show_.getRelated(offset=offset, limit=amount) + + +class EpisodesWindow(kodigui.ControlledWindow, windowutils.UtilMixin, SeasonsMixin, + playbacksettings.PlaybackSettingsMixin): + xmlFile = 'script-plex-episodes.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + THUMB_AR16X9_DIM = util.scaleResolution(657, 393) + POSTER_DIM = util.scaleResolution(420, 630) + RELATED_DIM = util.scaleResolution(268, 397) + EXTRA_DIM = util.scaleResolution(329, 185) + ROLES_DIM = util.scaleResolution(334, 334) + + LIST_OPTIONS_BUTTON_ID = 111 + + EPISODE_LIST_ID = 400 + SEASONS_LIST_ID = 401 + EXTRA_LIST_ID = 402 + RELATED_LIST_ID = 403 + ROLES_LIST_ID = 404 + + OPTIONS_GROUP_ID = 200 + + HOME_BUTTON_ID = 201 + SEARCH_BUTTON_ID = 202 + PLAYER_STATUS_BUTTON_ID = 204 + + PROGRESS_IMAGE_ID = 250 + + PLAY_BUTTON_ID = 301 + SHUFFLE_BUTTON_ID = 302 + OPTIONS_BUTTON_ID = 303 + INFO_BUTTON_ID = 304 + SETTINGS_BUTTON_ID = 305 + MEDIA_BUTTON_ID = 307 + + SEASONS_CONTROL_ATTR = "seasonsListControl" + + def __init__(self, *args, **kwargs): + kodigui.ControlledWindow.__init__(self, *args, **kwargs) + windowutils.UtilMixin.__init__(self) + self.episode = None + self.reset(kwargs.get('episode'), kwargs.get('season'), kwargs.get('show')) + self.initialEpisode = kwargs.get('episode') + self.parentList = kwargs.get('parentList') + self.lastItem = None + self.lastFocusID = None + self.lastNonOptionsFocusID = None + self.episodesPaginator = None + self.relatedPaginator = None + self.cameFrom = kwargs.get('came_from') + self.tasks = backgroundthread.Tasks() + self.initialized = False + self.closing = False + self._reloadVideos = [] + + def reset(self, episode, season=None, show=None): + self.episode = episode + self.season = season if season is not None else self.episode.season() + try: + self.show_ = show or (self.episode or self.season).show().reload(includeExtras=1, includeExtrasCount=10) + except IndexError: + raise util.NoDataException + + self.parentList = None + self.seasons = None + self._reloadVideos = [] + #self.initialized = False + + def doClose(self): + self.closing = True + self.episodesPaginator = None + self.relatedPaginator = None + kodigui.ControlledWindow.doClose(self) + if self.tasks: + self.tasks.cancel() + self.tasks = None + try: + player.PLAYER.off('new.video', self.onNewVideo) + except KeyError: + pass + + @busy.dialog() + def _onFirstInit(self): + self.episodeListControl = kodigui.ManagedControlList(self, self.EPISODE_LIST_ID, 5) + self.progressImageControl = self.getControl(self.PROGRESS_IMAGE_ID) + + self.extraListControl = kodigui.ManagedControlList(self, self.EXTRA_LIST_ID, 5) + self.relatedListControl = kodigui.ManagedControlList(self, self.RELATED_LIST_ID, 5) + self.rolesListControl = kodigui.ManagedControlList(self, self.ROLES_LIST_ID, 5) + self.seasonsListControl = kodigui.ManagedControlList(self, self.SEASONS_LIST_ID, 5) + + self._setup() + self.postSetup() + + def doAutoPlay(self): + # First reload the video to get all the other info + self.initialEpisode.reload(checkFiles=1, **VIDEO_RELOAD_KW) + return self.playButtonClicked(force_episode=self.initialEpisode) + + def onFirstInit(self): + self._onFirstInit() + + if self.show_ and self.show_.theme and not util.getSetting("slow_connection", False) and \ + (not self.cameFrom or self.cameFrom != self.show_.ratingKey): + volume = self.show_.settings.getThemeMusicValue() + if volume > 0: + player.PLAYER.playBackgroundMusic(self.show_.theme.asURL(True), volume, + self.show_.ratingKey) + + @busy.dialog() + def onReInit(self): + if not self.tasks: + self.tasks = backgroundthread.Tasks() + + try: + self.selectEpisode() + except AttributeError: + raise util.NoDataException + + mli = self.episodeListControl.getSelectedItem() + if not mli or not self.episodesPaginator: + return + + reloadItems = [mli] + for v in self._reloadVideos: + for m in self.episodeListControl: + if m.dataSource == v: + reloadItems.append(m) + self.episodesPaginator.prepareListItem(v, m) + + # re-set current item's progress to a loading state + if util.getSetting("slow_connection", False): + self.progressImageControl.setWidth(1) + mli.setProperty('remainingTime', T(32914, "Loading")) + + self.reloadItems(items=reloadItems, with_progress=True) + self.episodesPaginator.setEpisode(self._reloadVideos and self._reloadVideos[-1] or mli) + self._reloadVideos = [] + self.fillRelated() + + def postSetup(self, from_select_episode=False): + self.selectEpisode(from_select_episode=from_select_episode) + self.checkForHeaderFocus(xbmcgui.ACTION_MOVE_DOWN) + self.setFocusId(self.PLAY_BUTTON_ID) + self.initialized = True + + @busy.dialog() + def setup(self): + self._setup() + + def _setup(self, from_select_episode=False): + player.PLAYER.on('new.video', self.onNewVideo) + (self.season or self.show_).reload(checkFiles=1, **VIDEO_RELOAD_KW) + + if not from_select_episode or not self.episodesPaginator: + self.episodesPaginator = EpisodesPaginator(self.episodeListControl, + leaf_count=int(self.season.leafCount) if self.season else 0, + parent_window=self) + + if not from_select_episode or not self.episodesPaginator: + self.relatedPaginator = RelatedPaginator(self.relatedListControl, leaf_count=int(self.show_.relatedCount), + parent_window=self) + + self.updateProperties() + self.setBoolProperty("initialized", True) + self.fillEpisodes() + hasSeasons = self.fillSeasons(self.show_, seasonsFilter=lambda x: len(x) > 1, selectSeason=self.season) + hasPrev = self.fillExtras(hasSeasons) + + if not hasPrev and hasSeasons: + hasPrev = True + hasPrev = self.fillRelated(hasPrev) + self.fillRoles(hasPrev) + + def selectEpisode(self, from_select_episode=False): + if not self.episode: + return + + for mli in self.episodeListControl: + if mli.dataSource == self.episode: + self.episodeListControl.selectItem(mli.pos()) + self.episodesPaginator.setEpisode(self.episode) + break + else: + if not from_select_episode: + self.reset(self.episode) + self._setup(from_select_episode=True) + self.postSetup(from_select_episode=True) + + self.episode = None + + def onAction(self, action): + try: + controlID = self.getFocusId() + + if not controlID and self.lastFocusID and not action == xbmcgui.ACTION_MOUSE_MOVE: + self.setFocusId(self.lastFocusID) + + if action == xbmcgui.ACTION_LAST_PAGE and xbmc.getCondVisibility('ControlGroup(300).HasFocus(0)'): + next(self) + elif action == xbmcgui.ACTION_NEXT_ITEM: + next(self) + elif action == xbmcgui.ACTION_FIRST_PAGE and xbmc.getCondVisibility('ControlGroup(300).HasFocus(0)'): + self.prev() + elif action == xbmcgui.ACTION_PREV_ITEM: + self.prev() + + if action == xbmcgui.ACTION_MOVE_UP and controlID in (self.EPISODE_LIST_ID, self.SEASONS_LIST_ID): + self.updateBackgroundFrom((self.show_ or self.season.show())) + + if controlID == self.EPISODE_LIST_ID: + if self.checkForHeaderFocus(action): + return + + elif controlID == self.RELATED_LIST_ID: + if self.relatedPaginator.boundaryHit: + self.relatedPaginator.paginate() + return + elif action in (xbmcgui.ACTION_MOVE_LEFT, xbmcgui.ACTION_MOVE_RIGHT): + self.updateBackgroundFrom(self.relatedListControl.getSelectedItem().dataSource) + + if controlID == self.LIST_OPTIONS_BUTTON_ID and self.checkOptionsAction(action): + return + elif action == xbmcgui.ACTION_CONTEXT_MENU: + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)): + self.lastNonOptionsFocusID = self.lastFocusID + self.setFocusId(self.OPTIONS_GROUP_ID) + return + else: + if self.lastNonOptionsFocusID: + self.setFocusId(self.lastNonOptionsFocusID) + self.lastNonOptionsFocusID = None + return + + elif action == xbmcgui.ACTION_NAV_BACK: + if (not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format( + self.OPTIONS_GROUP_ID)) or not controlID) and \ + not util.advancedSettings.fastBack: + if self.getProperty('on.extras'): + self.setFocusId(self.OPTIONS_GROUP_ID) + return + + if action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): + self.doClose() + except: + util.ERROR() + + kodigui.ControlledWindow.onAction(self, action) + + def onNewVideo(self, video=None, **kwargs): + if not video: + return + + if not video.type == 'episode': + return + + util.DEBUG_LOG('Updating selected episode: {0}'.format(video)) + self.episode = video + self._reloadVideos.append(video) + + return True + + def checkOptionsAction(self, action): + if action == xbmcgui.ACTION_MOVE_UP: + mli = self.episodeListControl.getSelectedItem() + if not mli or mli.getProperty("is.boundary"): + return False + pos = mli.pos() - 1 + if self.episodeListControl.positionIsValid(pos): + self.setFocusId(self.EPISODE_LIST_ID) + self.episodeListControl.selectItem(pos) + return True + elif action == xbmcgui.ACTION_MOVE_DOWN: + mli = self.episodeListControl.getSelectedItem() + if not mli or mli.getProperty("is.boundary"): + return False + pos = mli.pos() + 1 + if self.episodeListControl.positionIsValid(pos): + self.setFocusId(self.EPISODE_LIST_ID) + self.episodeListControl.selectItem(pos) + return True + + return False + + def onClick(self, controlID): + if controlID == self.HOME_BUTTON_ID: + self.goHome() + elif controlID == self.EPISODE_LIST_ID: + self.episodeListClicked() + elif controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() + elif controlID == self.PLAY_BUTTON_ID: + self.playButtonClicked() + elif controlID == self.SHUFFLE_BUTTON_ID: + self.shuffleButtonClicked() + elif controlID == self.OPTIONS_BUTTON_ID: + self.optionsButtonClicked() + elif controlID == self.SETTINGS_BUTTON_ID: + self.settingsButtonClicked() + elif controlID == self.MEDIA_BUTTON_ID: + self.mediaButtonClicked() + elif controlID == self.INFO_BUTTON_ID: + self.infoButtonClicked() + elif controlID == self.SEARCH_BUTTON_ID: + self.searchButtonClicked() + elif controlID == self.SEASONS_LIST_ID: + mli = self.seasonsListControl.getSelectedItem() + if not mli: + return + item = mli.dataSource + if item != self.season: + self.openItem(self.seasonsListControl, came_from=self.season.parentRatingKey) + else: + self.setFocusId(self.EPISODE_LIST_ID) + elif controlID == self.EXTRA_LIST_ID: + self.openItem(self.extraListControl) + elif controlID == self.RELATED_LIST_ID: + self.openItem(self.relatedListControl) + elif controlID == self.ROLES_LIST_ID: + self.roleClicked() + + def onFocus(self, controlID): + self.lastFocusID = controlID + + if 399 < controlID < 500: + self.setProperty('hub.focus', str(controlID - 400)) + if controlID == self.RELATED_LIST_ID: + self.updateBackgroundFrom(self.relatedListControl.getSelectedItem().dataSource) + if xbmc.getCondVisibility('ControlGroup(50).HasFocus(0) + ControlGroup(300).HasFocus(0)'): + self.setProperty('on.extras', '') + elif xbmc.getCondVisibility('ControlGroup(50).HasFocus(0) + !ControlGroup(300).HasFocus(0)'): + self.setProperty('on.extras', '1') + + if player.PLAYER.bgmPlaying and player.PLAYER.handler.currentlyPlaying != self.season.show().ratingKey: + player.PLAYER.stopAndWait() + + def openItem(self, control=None, item=None, came_from=None): + if not item: + mli = control.getSelectedItem() + if not mli: + return + item = mli.dataSource + + self.processCommand(opener.open(item, came_from=came_from)) + + def roleClicked(self): + mli = self.rolesListControl.getSelectedItem() + if not mli: + return + + sectionRoles = busy.widthDialog(mli.dataSource.sectionRoles, '') + + if not sectionRoles: + util.DEBUG_LOG('No sections found for actor') + return + + if len(sectionRoles) > 1: + x, y = self.getRoleItemDDPosition() + + options = [{'role': r, 'display': r.reasonTitle} for r in sectionRoles] + choice = dropdown.showDropdown(options, (x, y), pos_is_bottom=True, close_direction='bottom') + + if not choice: + return + + role = choice['role'] + else: + role = sectionRoles[0] + + self.processCommand(opener.open(role)) + + def getRoleItemDDPosition(self): + y = 980 + if xbmc.getCondVisibility('Control.IsVisible(500)'): + y += 360 + if xbmc.getCondVisibility('Control.IsVisible(501)'): + y += 520 + if xbmc.getCondVisibility('Control.IsVisible(502)'): + y += 520 + if xbmc.getCondVisibility('!String.IsEmpty(Window.Property(on.extras))'): + y -= 125 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),0) + Control.IsVisible(500)'): + y -= 500 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),1) + Control.IsVisible(501)'): + y -= 500 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),1) + Control.IsVisible(502)'): + y -= 500 + + focus = int(xbmc.getInfoLabel('Container(403).Position')) + + x = ((focus + 1) * 304) - 100 + return x, y + + def getSeasons(self): + if not self.seasons: + self.seasons = self.show_.seasons() + + if not self.seasons: + return False + + return True + + def next(self): + if not self._next(): + return + self.setup() + + __next__ = next + + @busy.dialog() + def _next(self): + if self.parentList: + mli = self.parentList.getListItemByDataSource(self.season) + if not mli: + return False + + pos = mli.pos() + 1 + if not self.parentList.positionIsValid(pos): + pos = 0 + + self.season = self.parentList.getListItem(pos).dataSource + else: + if not self.getSeasons(): + return False + + if self.season not in self.seasons: + return False + + pos = self.seasons.index(self.season) + pos += 1 + if pos >= len(self.seasons): + pos = 0 + + self.season = self.seasons[pos] + + return True + + def prev(self): + if not self._prev(): + return + self.setup() + + @busy.dialog() + def _prev(self): + if self.parentList: + mli = self.parentList.getListItemByDataSource(self.season) + if not mli: + return False + + pos = mli.pos() - 1 + if pos < 0: + pos = self.parentList.size() - 1 + + self.season = self.parentList.getListItem(pos).dataSource + else: + if not self.getSeasons(): + return False + + if self.season not in self.seasons: + return False + + pos = self.seasons.index(self.season) + pos -= 1 + if pos < 0: + pos = len(self.seasons) - 1 + + self.season = self.seasons[pos] + + return True + + def searchButtonClicked(self): + section_id = self.show_.getLibrarySectionId() + self.processCommand(search.dialog(self, section_id=section_id or None)) + + def playButtonClicked(self, shuffle=False, force_episode=None): + if shuffle: + seasonOrShow = self.season or self.show_ + items = seasonOrShow.all() + pl = playlist.LocalPlaylist(items, seasonOrShow.getServer()) + + pl.shuffle(shuffle, first=True) + videoplayer.play(play_queue=pl) + return True + + else: + return self.episodeListClicked(force_episode=force_episode) + + def shuffleButtonClicked(self): + self.playButtonClicked(shuffle=True) + + def settingsButtonClicked(self): + mli = self.episodeListControl.getSelectedItem() + if not mli or mli.getProperty("is.boundary"): + return + + episode = mli.dataSource + + if not episode.mediaChoice: + playerObject = plexplayer.PlexPlayer(episode) + playerObject.build() + playersettings.showDialog(video=episode, non_playback=True) + self.setItemAudioAndSubtitleInfo(episode, mli) + + def infoButtonClicked(self): + mli = self.episodeListControl.getSelectedItem() + if not mli or mli.getProperty("is.boundary"): + return + + episode = mli.dataSource + + if episode.index: + subtitle = u'{0} {1} {2} {3}'.format(T(32303, 'Season'), episode.parentIndex, T(32304, 'Episode'), episode.index) + else: + subtitle = episode.originallyAvailableAt.asDatetime('%B %d, %Y') + + opener.handleOpen( + info.InfoWindow, + title=episode.title, + sub_title=subtitle, + thumb=episode.thumb, + thumb_fallback='script.plex/thumb_fallbacks/show.png', + info=episode.summary, + background=self.getProperty('background'), + is_16x9=True, + video=episode + ) + + def episodeListClicked(self, force_episode=None): + if not force_episode: + mli = self.episodeListControl.getSelectedItem() + if not mli or mli.getProperty("is.boundary"): + return + + episode = mli.dataSource + else: + episode = force_episode + + if not episode.available(): + util.messageDialog(T(32312, 'unavailable'), T(32332, 'This item is currently unavailable.')) + return + + resume = False + if episode.viewOffset.asInt(): + choice = dropdown.showDropdown( + options=[ + {'key': 'resume', 'display': T(32429, 'Resume from {0}').format(util.timeDisplay(episode.viewOffset.asInt()).lstrip('0').lstrip(':'))}, + {'key': 'play', 'display': T(32317, 'Play from beginning')} + ], + pos=(660, 441), + close_direction='none', + set_dropdown_prop=False, + header=T(32314, 'In Progress') + ) + + if not choice: + return + + if choice['key'] == 'resume': + resume = True + if util.advancedSettings.dialogFlickerFix: + xbmc.sleep(750) + + self._reloadVideos.append(episode) + + pl = playlist.LocalPlaylist(self.show_.all(), self.show_.getServer()) + try: + if len(pl): # Don't use playlist if it's only this video + pl.setCurrent(episode) + self.processCommand(videoplayer.play(play_queue=pl, resume=resume)) + return True + + self.processCommand(videoplayer.play(video=episode, resume=resume)) + return True + except util.NoDataException: + util.ERROR("No data - disconnected?", notify=True, time_ms=5000) + self.doClose() + + def optionsButtonClicked(self, from_item=False): + options = [] + + mli = self.episodeListControl.getSelectedItem() + + if mli and not mli.getProperty("is.boundary"): + inProgress = mli.dataSource.viewOffset.asInt() + if not mli.dataSource.isWatched or inProgress: + options.append({'key': 'mark_watched', 'display': T(32319, 'Mark Played')}) + if mli.dataSource.isWatched or inProgress: + options.append({'key': 'mark_unwatched', 'display': T(32318, 'Mark Unplayed')}) + + # if True: + # options.append({'key': 'add_to_playlist', 'display': '[COLOR FF808080]Add To Playlist[/COLOR]'}) + + if xbmc.getCondVisibility('Player.HasAudio + MusicPlayer.HasNext'): + options.append({'key': 'play_next', 'display': T(32325, 'Play Next')}) + + if self.season: + if self.season.isWatched: + options.append({'key': 'mark_season_unwatched', 'display': T(32320, 'Mark Season Unplayed')}) + else: + options.append({'key': 'mark_season_watched', 'display': T(32321, 'Mark Season Played')}) + + if self.show_: + if options: + options.append(dropdown.SEPARATOR) + + options.append({'key': 'playback_settings', 'display': T(32925, 'Playback Settings')}) + options.append(dropdown.SEPARATOR) + + if mli.dataSource.server.allowsMediaDeletion: + options.append({'key': 'delete', 'display': T(32322, 'Delete')}) + + # if xbmc.getCondVisibility('Player.HasAudio') and self.section.TYPE == 'artist': + # options.append({'key': 'add_to_queue', 'display': 'Add To Queue'}) + + if options: + options.append(dropdown.SEPARATOR) + + options.append({'key': 'to_show', 'display': T(32323, 'Go To Show')}) + options.append({'key': 'to_section', 'display': T(32324, u'Go to {0}').format( + self.show_.getLibrarySectionTitle())}) + + pos = (500, 620) + bottom = False + setDropdownProp = False + if from_item: + viewPos = self.episodeListControl.getViewPosition() + if viewPos > 6: + pos = (1490, 312 + (viewPos * 100)) + bottom = True + else: + pos = (1490, 167 + (viewPos * 100)) + bottom = False + setDropdownProp = True + + choice = dropdown.showDropdown(options, pos, pos_is_bottom=bottom, close_direction='left', + set_dropdown_prop=setDropdownProp) + if not choice: + return + + if choice['key'] == 'play_next': + xbmc.executebuiltin('PlayerControl(Next)') + elif choice['key'] == 'mark_watched': + mli.dataSource.markWatched() + self.updateItems(mli) + util.MONITOR.watchStatusChanged() + elif choice['key'] == 'mark_unwatched': + mli.dataSource.markUnwatched() + self.updateItems(mli) + util.MONITOR.watchStatusChanged() + elif choice['key'] == 'mark_season_watched': + self.season.markWatched() + self.updateItems() + util.MONITOR.watchStatusChanged() + elif choice['key'] == 'mark_season_unwatched': + self.season.markUnwatched() + self.updateItems() + util.MONITOR.watchStatusChanged() + elif choice['key'] == 'to_show': + if util.advancedSettings.dialogFlickerFix: + xbmc.sleep(750) + self.processCommand(opener.open( + self.season.parentRatingKey, + came_from=self.season.parentRatingKey) + ) + elif choice['key'] == 'to_section': + self.goHome(self.show_.getLibrarySectionId()) + elif choice['key'] == 'delete': + self.delete() + elif choice['key'] == 'playback_settings': + self.playbackSettings(self.show_, pos, bottom) + + def mediaButtonClicked(self): + options = [] + mli = self.episodeListControl.getSelectedItem() + ds = mli.dataSource + for media in ds.media: + ind = '' + if ds.mediaChoice and media.id == ds.mediaChoice.media.id: + ind = 'script.plex/home/device/check.png' + options.append({'key': media, 'display': media.versionString(), 'indicator': ind}) + choice = dropdown.showDropdown(options, header=T(32450, 'Choose Version'), with_indicator=True) + if not choice: + return False + + for media in ds.media: + media.set('selected', '') + + ds.setMediaChoice(choice['key']) + choice['key'].set('selected', 1) + self.setPostReloadItemInfo(ds, mli) + + def delete(self): + button = optionsdialog.show( + T(32326, 'Really delete?'), + T(32327, 'Are you sure you really want to delete this media?'), + T(32328, 'Yes'), + T(32329, 'No') + ) + + if button != 0: + return + + if not self._delete(): + util.messageDialog(T(32330, 'Message'), T(32331, 'There was a problem while attempting to delete the media.')) + + @busy.dialog() + def _delete(self): + mli = self.episodeListControl.getSelectedItem() + if not mli or mli.getProperty("is.boundary"): + return + + video = mli.dataSource + success = video.delete() + util.LOG('Media DELETE: {0} - {1}'.format(video, success and 'SUCCESS' or 'FAILED')) + if success: + self.episodeListControl.removeItem(mli.pos()) + if not self.episodeListControl.size(): + self.doClose() + else: + (self.season or self.show_).reload() + return success + + def checkForHeaderFocus(self, action): + # don't continue if we're still waiting for tasks + if self.tasks or not self.episodesPaginator: + if self.tasks: + util.DEBUG_LOG("Episodes: Moving too fast through paginator, throttling.") + return + + if self.episodesPaginator.boundaryHit: + items = self.episodesPaginator.paginate() + self.reloadItems(items) + return True + + mli = self.episodeListControl.getSelectedItem() + if not mli or mli.getProperty("is.boundary"): + return + + lastItem = self.lastItem + + if action in (xbmcgui.ACTION_MOVE_RIGHT, xbmcgui.ACTION_MOVE_LEFT) and lastItem: + items = self.episodesPaginator.wrap(mli, lastItem, action) + xbmc.sleep(100) + mli = self.episodeListControl.getSelectedItem() + if items: + self.reloadItems(items) + return True + + if mli != self.lastItem and not mli.getProperty("is.boundary"): + self.lastItem = mli + self.setProgress(mli) + + if action in (xbmcgui.ACTION_MOVE_UP, xbmcgui.ACTION_PAGE_UP): + if mli.getProperty('is.header'): + xbmc.executebuiltin('Action(up)') + if action in (xbmcgui.ACTION_MOVE_DOWN, xbmcgui.ACTION_PAGE_DOWN, xbmcgui.ACTION_MOVE_LEFT, xbmcgui.ACTION_MOVE_RIGHT): + if mli.getProperty('is.header'): + xbmc.executebuiltin('Action(down)') + + def updateProperties(self): + showTitle = self.show_ and self.show_.title or '' + + self.updateBackgroundFrom(self.show_ or self.season.show()) + self.setProperty('season.thumb', (self.season or self.show_).thumb.asTranscodedImageURL(*self.POSTER_DIM)) + self.setProperty('show.title', showTitle) + self.setProperty('season.title', (self.season or self.show_).title) + + if self.season: + self.setProperty('episodes.header', u'{0} \u2022 {1} {2}'.format(showTitle, T(32303, 'Season'), self.season.index)) + self.setProperty('extras.header', u'{0} \u2022 {1} {2}'.format(T(32305, 'Extras'), T(32303, 'Season'), self.season.index)) + else: + self.setProperty('episodes.header', u'Episodes') + self.setProperty('extras.header', u'Extras') + + self.setProperty('seasons.header', + u'{0} \u2022 {1}'.format(showTitle, T(32942, 'Seasons'))) + self.setProperty('related.header', T(32306, 'Related Shows')) + self.genre = self.show_.genres() and self.show_.genres()[0].tag or '' + + @busy.dialog() + def updateItems(self, item=None): + if item: + item.setProperty('unwatched', not item.dataSource.isWatched and '1' or '') + self.setProgress(item) + item.setProperty('progress', util.getProgressImage(item.dataSource)) + (self.season or self.show_).reload() + else: + self.fillEpisodes(update=True) + + if self.episode: + self.episode.reload() + + def setItemInfo(self, video, mli): + # video.reload(checkFiles=1) + mli.setProperty('background', util.backgroundFromArt(video.art, width=self.width, height=self.height)) + mli.setProperty('title', video.title) + mli.setProperty('show.title', video.grandparentTitle or (self.show_.title if self.show_ else '')) + mli.setProperty('duration', util.durationToText(video.duration.asInt())) + mli.setProperty('summary', video.summary.strip().replace('\t', ' ')) + mli.setProperty('video.rendering', video.videoCodecRendering) + + if video.index: + mli.setProperty('season', u'{0} {1}'.format(T(32303, 'Season'), video.parentIndex)) + mli.setProperty('episode', u'{0} {1}'.format(T(32304, 'Episode'), video.index)) + else: + mli.setProperty('season', '') + mli.setProperty('episode', '') + + mli.setProperty('date', util.cleanLeadingZeros(video.originallyAvailableAt.asDatetime('%B %d, %Y'))) + + # mli.setProperty('related.header', 'Related Shows') + mli.setProperty('year', video.year) + mli.setProperty('content.rating', video.contentRating.split('/', 1)[-1]) + mli.setProperty('genre', self.genre) + + if video.get('userRating'): + stars = str(int(round((video.userRating.asFloat() / 10) * 5))) + mli.setProperty('rating.stars', stars) + # elif video.rating: + # stars = str(int(round((video.rating.asFloat() / 10) * 5))) + # mli.setProperty('rating.stars', stars) + + if video.get('ratingImage'): + rating = video.rating + audienceRating = video.audienceRating + if video.ratingImage.startswith('rottentomatoes:'): + rating = '{0}%'.format(int(rating.asFloat() * 10)) + if audienceRating: + audienceRating = '{0}%'.format(int(audienceRating.asFloat() * 10)) + + mli.setProperty('rating', rating) + mli.setProperty('rating.image', 'script.plex/ratings/{0}.png'.format(video.ratingImage.replace('://', '/'))) + if video.get('audienceRatingImage'): + mli.setProperty('rating2', audienceRating) + mli.setProperty('rating2.image', 'script.plex/ratings/{0}.png'.format(video.audienceRatingImage.replace('://', '/'))) + else: + mli.setProperty('rating', video.rating) + + def setPostReloadItemInfo(self, video, mli): + self.setItemAudioAndSubtitleInfo(video, mli) + mli.setProperty('unwatched', not video.isWatched and '1' or '') + mli.setProperty('video.res', video.resolutionString()) + mli.setProperty('audio.codec', video.audioCodecString()) + mli.setProperty('video.codec', video.videoCodecString()) + mli.setProperty('audio.channels', video.audioChannelsString(metadata.apiTranslate)) + mli.setProperty('video.rendering', video.videoCodecRendering) + mli.setBoolProperty('unavailable', not video.available()) + + defW = 176 + defH = 140 + ids = [301, 302, 303, 304, 305] + if len(list(filter(lambda x: x.isAccessible(), video.media()))) > 1: + mli.setBoolProperty('media.multiple', True) + # adjust button sizes + ids.append(307) + for id in ids: + ctrl = self.getControl(id) + ctrl.setWidth(161) + ctrl.setHeight(125) + del ctrl + else: + mli.setBoolProperty('media.multiple', False) + # reset button sizes + for id in ids: + ctrl = self.getControl(id) + ctrl.setWidth(defW) + ctrl.setHeight(defH) + del ctrl + + def setItemAudioAndSubtitleInfo(self, video, mli): + sas = video.selectedAudioStream() + mli.setProperty('audio', sas and sas.getTitle(metadata.apiTranslate) or T(32309, 'None')) + + sss = video.selectedSubtitleStream(forced_subtitles_override= + util.getSetting("forced_subtitles_override", False)) + if sss: + if len(video.subtitleStreams) > 1: + mli.setProperty( + 'subtitles', u'{0} \u2022 {1} {2}'.format(sss.getTitle(metadata.apiTranslate), len(video.subtitleStreams) - 1, T(32307, 'More')) + ) + else: + mli.setProperty('subtitles', sss.getTitle(metadata.apiTranslate)) + else: + if video.subtitleStreams: + mli.setProperty('subtitles', u'{0} \u2022 {1} {2}'.format(T(32309, 'None'), len(video.subtitleStreams), T(32308, 'Available'))) + else: + mli.setProperty('subtitles', T(32309, 'None')) + + def setProgress(self, mli): + video = mli.dataSource + if video.viewOffset.asInt(): + width = video.viewOffset.asInt() and (1 + int((video.viewOffset.asInt() / video.duration.asFloat()) * self.width)) or 1 + self.progressImageControl.setWidth(width) + else: + self.progressImageControl.setWidth(1) + + if video.viewOffset.asInt(): + mli.setProperty('remainingTime', T(33615, "{time} left").format(time=video.remainingTimeString)) + else: + mli.setProperty('remainingTime', '') + + def createListItem(self, episode): + if episode.index: + subtitle = u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), episode.parentIndex, T(32311, 'E'), episode.index) + else: + subtitle = episode.originallyAvailableAt.asDatetime('%m/%d/%y') + + mli = kodigui.ManagedListItem( + episode.title, + subtitle, + thumbnailImage=episode.thumb.asTranscodedImageURL(*self.THUMB_AR16X9_DIM), + data_source=episode + ) + mli.setProperty('episode.number', str(episode.index) or '') + mli.setProperty('episode.duration', util.durationToText(episode.duration.asInt())) + mli.setProperty('unwatched', not episode.isWatched and '1' or '') + # mli.setProperty('progress', util.getProgressImage(obj)) + return mli + + def fillEpisodes(self, update=False): + items = self.episodesPaginator.paginate() + self.reloadItems(items) + + def reloadItems(self, items, with_progress=False): + tasks = [] + for mli in items: + if not mli.dataSource: + continue + + task = EpisodeReloadTask().setup(mli.dataSource, self.reloadItemCallback, with_progress=with_progress) + self.tasks.add(task) + tasks.append(task) + + backgroundthread.BGThreader.addTasks(tasks) + + def reloadItemCallback(self, task, episode, with_progress=False): + self.tasks.remove(task) + del task + + if self.closing: + return + + selected = self.episodeListControl.getSelectedItem() + + for mli in self.episodeListControl: + if mli.dataSource == episode: + if not episode.mediaChoice: + episode.setMediaChoice() + + self.setPostReloadItemInfo(episode, mli) + if with_progress: + self.episodesPaginator.prepareListItem(None, mli) + if mli == selected: + self.lastItem = mli + self.setProgress(mli) + return + + def fillExtras(self, has_prev=False): + items = [] + idx = 0 + + seasonOrShow = self.season or self.show_ + + if not seasonOrShow.extras: + self.extraListControl.reset() + return False + + for extra in seasonOrShow.extras(): + mli = kodigui.ManagedListItem( + extra.title or '', + metadata.EXTRA_MAP.get(extra.extraType.asInt(), ''), + thumbnailImage=extra.thumb.asTranscodedImageURL(*self.EXTRA_DIM), + data_source=extra + ) + + if mli: + mli.setProperty('index', str(idx)) + mli.setProperty( + 'thumb.fallback', 'script.plex/thumb_fallbacks/{0}.png'.format(extra.type in ('show', 'season', 'episode') and 'show' or 'movie') + ) + items.append(mli) + idx += 1 + + if not items: + return False + + self.extraListControl.reset() + self.extraListControl.addItems(items) + + self.setProperty('divider.{0}'.format(self.EXTRA_LIST_ID), has_prev and '1' or '') + return True + + def fillRelated(self, has_prev=False): + if not self.relatedPaginator.leafCount: + self.relatedListControl.reset() + return has_prev + + items = self.relatedPaginator.paginate() + if not items: + return False + + self.setProperty('divider.{0}'.format(self.RELATED_LIST_ID), has_prev and '1' or '') + + return True + + def fillRoles(self, has_prev=False): + items = [] + idx = 0 + + if not self.show_.roles: + self.rolesListControl.reset() + return False + + for role in self.show_.roles(): + mli = kodigui.ManagedListItem(role.tag, role.role, thumbnailImage=role.thumb.asTranscodedImageURL(*self.ROLES_DIM), data_source=role) + mli.setProperty('index', str(idx)) + items.append(mli) + idx += 1 + + if not items: + return False + + self.setProperty('divider.{0}'.format(self.ROLES_LIST_ID), has_prev and '1' or '') + + self.rolesListControl.reset() + self.rolesListControl.addItems(items) + return True diff --git a/script.plexmod/lib/windows/home.py b/script.plexmod/lib/windows/home.py new file mode 100644 index 0000000000..0e0584cbb4 --- /dev/null +++ b/script.plexmod/lib/windows/home.py @@ -0,0 +1,1388 @@ +from __future__ import absolute_import +import time +import threading +import re + +from kodi_six import xbmc +from kodi_six import xbmcgui + +from . import kodigui +from lib import util +from lib import backgroundthread +from lib import colors +from lib import player + +import plexnet +from plexnet import plexapp + +from . import windowutils +from . import playlists +from . import busy +from . import opener +from . import search +from . import optionsdialog + +from lib.util import T +from six.moves import range + + +HUBS_REFRESH_INTERVAL = 300 # 5 Minutes +HUB_PAGE_SIZE = 10 + +MOVE_SET = frozenset( + ( + xbmcgui.ACTION_MOVE_LEFT, + xbmcgui.ACTION_MOVE_RIGHT, + xbmcgui.ACTION_MOVE_UP, + xbmcgui.ACTION_MOVE_DOWN, + xbmcgui.ACTION_MOUSE_MOVE, + xbmcgui.ACTION_PAGE_UP, + xbmcgui.ACTION_PAGE_DOWN, + xbmcgui.ACTION_FIRST_PAGE, + xbmcgui.ACTION_LAST_PAGE, + xbmcgui.ACTION_MOUSE_WHEEL_DOWN, + xbmcgui.ACTION_MOUSE_WHEEL_UP + ) +) + + +class HubsList(list): + def init(self): + self.lastUpdated = time.time() + return self + + +class SectionHubsTask(backgroundthread.Task): + def setup(self, section, callback): + self.section = section + self.callback = callback + return self + + def run(self): + if self.isCanceled(): + return + + if not plexapp.SERVERMANAGER.selectedServer: + # Could happen during sign-out for instance + return + + try: + hubs = HubsList(plexapp.SERVERMANAGER.selectedServer.hubs(self.section.key, count=HUB_PAGE_SIZE)).init() + if self.isCanceled(): + return + self.callback(self.section, hubs) + except plexnet.exceptions.BadRequest: + util.DEBUG_LOG('404 on section: {0}'.format(repr(self.section.title))) + self.callback(self.section, False) + except TypeError: + util.ERROR("No data - disconnected?", notify=True, time_ms=5000) + self.cancel() + + +class UpdateHubTask(backgroundthread.Task): + def setup(self, hub, callback): + self.hub = hub + self.callback = callback + return self + + def run(self): + if self.isCanceled(): + return + + if not plexapp.SERVERMANAGER.selectedServer: + # Could happen during sign-out for instance + return + + try: + self.hub.reload(limit=HUB_PAGE_SIZE) + if self.isCanceled(): + return + self.callback(self.hub) + except plexnet.exceptions.BadRequest: + util.DEBUG_LOG('404 on section: {0}'.format(repr(self.section.title))) + + +class ExtendHubTask(backgroundthread.Task): + def setup(self, hub, callback, canceledCallback=None): + self.hub = hub + self.callback = callback + self.canceledCallback = canceledCallback + return self + + def run(self): + if self.isCanceled(): + if self.canceledCallback: + self.canceledCallback(self.hub) + return + + if not plexapp.SERVERMANAGER.selectedServer: + # Could happen during sign-out for instance + return + + try: + start = self.hub.offset.asInt() + self.hub.size.asInt() + items = self.hub.extend(start=start, size=HUB_PAGE_SIZE) + if self.isCanceled(): + if self.canceledCallback: + self.canceledCallback(self.hub) + return + self.callback(self.hub, items) + except plexnet.exceptions.BadRequest: + util.DEBUG_LOG('404 on hub: {0}'.format(repr(self.hub.hubIdentifier))) + if self.canceledCallback: + self.canceledCallback(self.hub) + + +class HomeSection(object): + key = None + type = 'home' + title = T(32332, 'Home') + + +class PlaylistsSection(object): + key = 'playlists' + type = 'playlists' + title = T(32333, 'Playlists') + + +class ServerListItem(kodigui.ManagedListItem): + uuid = None + + def hookSignals(self): + self.dataSource.on('completed:reachability', self.onReachability) + self.dataSource.on('started:reachability', self.onReachability) + + def unHookSignals(self): + try: + self.dataSource.off('completed:reachability', self.onReachability) + self.dataSource.off('started:reachability', self.onReachability) + except: + pass + + def setRefreshing(self): + self.safeSetProperty('status', 'refreshing.gif') + + def safeSetProperty(self, key, value): + # For if we catch the item in the middle of being removed + try: + self.setProperty(key, value) + return True + except AttributeError: + pass + + return False + + def safeSetLabel(self, value, func="setLabel"): + if value is None: + return False + try: + getattr(self, func)(value) + return True + except AttributeError: + pass + + return False + + def safeGetDSProperty(self, prop): + return getattr(self.dataSource, prop, None) + + def onReachability(self, **kwargs): + plexapp.util.APP.trigger('sli:reachability:received') + return self.onUpdate(**kwargs) + + def onUpdate(self, **kwargs): + if not self.listItem: # ex. can happen on Kodi shutdown + return + + if self.dataSource == kodigui.DUMMY_DATA_SOURCE: + return + + # this looks a little ridiculous, but we're experiencing timing issues here + isSupported = self.safeGetDSProperty("isSupported") + isReachable = False + isReachableFunc = self.safeGetDSProperty("isReachable") + isSecure = self.safeGetDSProperty("isSecure") + isLocal = self.safeGetDSProperty("isLocal") + name = self.safeGetDSProperty("name") + pendingReachabilityRequests = self.safeGetDSProperty("pendingReachabilityRequests") + owned = not self.safeGetDSProperty("owned") and self.safeGetDSProperty("owner") or '' + if isReachableFunc: + isReachable = isReachableFunc() + + if not isSupported or not isReachable: + if pendingReachabilityRequests is not None and pendingReachabilityRequests > 0: + self.safeSetProperty('status', 'refreshing.gif') + else: + self.safeSetProperty('status', 'unreachable.png') + else: + self.safeSetProperty('status', isSecure and 'secure.png' or '') + self.safeSetProperty('secure', isSecure and '1' or '') + self.safeSetProperty('local', isLocal and '1' or '') + + self.safeSetProperty('current', plexapp.SERVERMANAGER.selectedServer.uuid == self.uuid and '1' or '') + if name: + self.safeSetLabel(name) + + if owned: + self.safeSetLabel(owned, func="setLabel2") + + def onDestroy(self): + self.unHookSignals() + + +class HomeWindow(kodigui.BaseWindow, util.CronReceiver): + xmlFile = 'script-plex-home.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + OPTIONS_GROUP_ID = 200 + + SECTION_LIST_ID = 101 + SERVER_BUTTON_ID = 201 + + USER_BUTTON_ID = 202 + USER_LIST_ID = 250 + + SEARCH_BUTTON_ID = 203 + SERVER_LIST_ID = 260 + REFRESH_SL_ID = 262 + + PLAYER_STATUS_BUTTON_ID = 204 + + HUB_AR16X9_00 = 400 + HUB_POSTER_01 = 401 + HUB_POSTER_02 = 402 + HUB_POSTER_03 = 403 + HUB_POSTER_04 = 404 + HUB_SQUARE_05 = 405 + HUB_AR16X9_06 = 406 + HUB_POSTER_07 = 407 + HUB_POSTER_08 = 408 + HUB_SQUARE_09 = 409 + HUB_SQUARE_10 = 410 + HUB_SQUARE_11 = 411 + HUB_SQUARE_12 = 412 + HUB_POSTER_13 = 413 + HUB_POSTER_14 = 414 + HUB_POSTER_15 = 415 + HUB_POSTER_16 = 416 + HUB_AR16X9_17 = 417 + HUB_AR16X9_18 = 418 + HUB_AR16X9_19 = 419 + + HUB_SQUARE_20 = 420 + HUB_SQUARE_21 = 421 + HUB_SQUARE_22 = 422 + + HUB_AR16X9_23 = 423 + + HUBMAP = { + # HOME + 'home.continue': {'index': 0, 'with_progress': True, 'with_art': True, 'do_updates': True, 'text2lines': True}, + 'home.ondeck': {'index': 1, 'with_progress': True, 'do_updates': True, 'text2lines': True}, + 'home.television.recent': {'index': 2, 'do_updates': True, 'with_progress': True, 'text2lines': True}, + 'home.movies.recent': {'index': 4, 'do_updates': True, 'with_progress': True, 'text2lines': True}, + 'home.music.recent': {'index': 5, 'text2lines': True}, + 'home.videos.recent': {'index': 6, 'with_progress': True, 'ar16x9': True}, + #'home.playlists': {'index': 9}, # No other Plex home screen shows playlists so removing it from here + 'home.photos.recent': {'index': 10, 'text2lines': True}, + # SHOW + 'tv.ondeck': {'index': 1, 'with_progress': True, 'do_updates': True, 'text2lines': True}, + 'tv.recentlyaired': {'index': 2, 'do_updates': True, 'with_progress': True, 'text2lines': True}, + 'tv.recentlyadded': {'index': 3, 'do_updates': True, 'with_progress': True, 'text2lines': True}, + 'tv.inprogress': {'index': 4, 'with_progress': True, 'do_updates': True, 'text2lines': True}, + 'tv.startwatching': {'index': 7, 'with_progress': True, 'do_updates': True}, + 'tv.rediscover': {'index': 8, 'with_progress': True, 'do_updates': True}, + 'tv.morefromnetwork': {'index': 13, 'with_progress': True, 'do_updates': True}, + 'tv.toprated': {'index': 14, 'with_progress': True, 'do_updates': True}, + 'tv.moreingenre': {'index': 15, 'with_progress': True, 'do_updates': True}, + 'tv.recentlyviewed': {'index': 16, 'with_progress': True, 'text2lines': True, 'do_updates': True}, + # MOVIE + 'movie.inprogress': {'index': 0, 'with_progress': True, 'with_art': True, 'do_updates': True, 'text2lines': True}, + 'movie.recentlyreleased': {'index': 1, 'do_updates': True, 'with_progress': True, 'text2lines': True}, + 'movie.recentlyadded': {'index': 2, 'do_updates': True, 'with_progress': True, 'text2lines': True}, + 'movie.genre': {'index': 3, 'with_progress': True, 'text2lines': True, 'do_updates': True}, + 'movie.by.actor.or.director': {'index': 7, 'with_progress': True, 'text2lines': True, 'do_updates': True}, + 'movie.topunwatched': {'index': 13, 'text2lines': True, 'do_updates': True}, + 'movie.recentlyviewed': {'index': 14, 'with_progress': True, 'text2lines': True, 'do_updates': True}, + # ARTIST + 'music.recent.played': {'index': 5, 'do_updates': True}, + 'music.recent.added': {'index': 9, 'text2lines': True}, + 'music.recent.artist': {'index': 10, 'text2lines': True}, + 'music.recent.genre': {'index': 11, 'text2lines': True}, + 'music.top.period': {'index': 12, 'text2lines': True}, + 'music.popular': {'index': 20, 'text2lines': True}, + 'music.recent.label': {'index': 21, 'text2lines': True}, + 'music.touring': {'index': 22}, + 'music.videos.popular.new': {'index': 18}, + 'music.videos.new': {'index': 19}, + 'music.videos.recent.artists': {'index': 23}, + # PHOTO + 'photo.recent': {'index': 5, 'text2lines': True}, + 'photo.random.year': {'index': 9, 'text2lines': True}, + 'photo.random.decade': {'index': 10, 'text2lines': True}, + 'photo.random.dayormonth': {'index': 11, 'text2lines': True}, + # VIDEO + 'video.recent': {'index': 0, 'with_progress': True, 'ar16x9': True}, + 'video.random.year': {'index': 6, 'with_progress': True, 'ar16x9': True}, + 'video.random.decade': {'index': 17, 'with_progress': True, 'ar16x9': True}, + 'video.inprogress': {'index': 18, 'with_progress': True, 'ar16x9': True}, + 'video.unwatched.random': {'index': 19, 'ar16x9': True}, + 'video.recentlyviewed': {'index': 23, 'with_progress': True, 'ar16x9': True}, + # PLAYLISTS + 'playlists.audio': {'index': 5, 'text2lines': True, 'title': T(32048, 'Audio')}, + 'playlists.video': {'index': 6, 'text2lines': True, 'ar16x9': True, 'title': T(32053, 'Video')}, + } + + THUMB_POSTER_DIM = util.scaleResolution(244, 361) + THUMB_AR16X9_DIM = util.scaleResolution(532, 299) + THUMB_SQUARE_DIM = util.scaleResolution(244, 244) + + def __init__(self, *args, **kwargs): + kodigui.BaseWindow.__init__(self, *args, **kwargs) + self.lastSection = HomeSection + self.tasks = [] + self.closeOption = None + self.hubControls = None + self.backgroundSet = False + self.sectionChangeThread = None + self.sectionChangeTimeout = 0 + self.lastFocusID = None + self.lastNonOptionsFocusID = None + self.sectionHubs = {} + self.updateHubs = {} + self.changingServer = False + self._shuttingDown = False + windowutils.HOME = self + + self.lock = threading.Lock() + + util.setGlobalBoolProperty('off.sections', '') + + def onFirstInit(self): + # set last BG image if possible + if util.advancedSettings.dynamicBackgrounds: + bgUrl = util.getSetting("last_bg_url") + if bgUrl: + self.windowSetBackground(bgUrl) + + # set good volume if we've missed re-setting BGM volume before + lastGoodVlm = util.getSetting('last_good_volume', 0) + BGMVlm = plexapp.util.INTERFACE.getThemeMusicValue() + if lastGoodVlm and BGMVlm and util.rpc.Application.GetProperties(properties=["volume"])["volume"] == BGMVlm: + util.DEBUG_LOG("Setting volume to {}, we probably missed the " + "re-set on the last BGM encounter".format(lastGoodVlm)) + xbmc.executebuiltin("SetVolume({})".format(lastGoodVlm)) + + self.sectionList = kodigui.ManagedControlList(self, self.SECTION_LIST_ID, 7) + self.serverList = kodigui.ManagedControlList(self, self.SERVER_LIST_ID, 10) + self.userList = kodigui.ManagedControlList(self, self.USER_LIST_ID, 3) + + self.hubControls = ( + kodigui.ManagedControlList(self, self.HUB_AR16X9_00, 5), + kodigui.ManagedControlList(self, self.HUB_POSTER_01, 5), + kodigui.ManagedControlList(self, self.HUB_POSTER_02, 5), + kodigui.ManagedControlList(self, self.HUB_POSTER_03, 5), + kodigui.ManagedControlList(self, self.HUB_POSTER_04, 5), + kodigui.ManagedControlList(self, self.HUB_SQUARE_05, 5), + kodigui.ManagedControlList(self, self.HUB_AR16X9_06, 5), + kodigui.ManagedControlList(self, self.HUB_POSTER_07, 5), + kodigui.ManagedControlList(self, self.HUB_POSTER_08, 5), + kodigui.ManagedControlList(self, self.HUB_SQUARE_09, 5), + kodigui.ManagedControlList(self, self.HUB_SQUARE_10, 5), + kodigui.ManagedControlList(self, self.HUB_SQUARE_11, 5), + kodigui.ManagedControlList(self, self.HUB_SQUARE_12, 5), + kodigui.ManagedControlList(self, self.HUB_POSTER_13, 5), + kodigui.ManagedControlList(self, self.HUB_POSTER_14, 5), + kodigui.ManagedControlList(self, self.HUB_POSTER_15, 5), + kodigui.ManagedControlList(self, self.HUB_POSTER_16, 5), + kodigui.ManagedControlList(self, self.HUB_AR16X9_17, 5), + kodigui.ManagedControlList(self, self.HUB_AR16X9_18, 5), + kodigui.ManagedControlList(self, self.HUB_AR16X9_19, 5), + kodigui.ManagedControlList(self, self.HUB_SQUARE_20, 5), + kodigui.ManagedControlList(self, self.HUB_SQUARE_21, 5), + kodigui.ManagedControlList(self, self.HUB_SQUARE_22, 5), + kodigui.ManagedControlList(self, self.HUB_AR16X9_23, 5), + ) + + self.hubFocusIndexes = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 17, 18, 19, 20, 21, 22, 13, 14, 15, 23) + + self.bottomItem = 0 + if self.serverRefresh(): + self.setFocusId(self.SECTION_LIST_ID) + + self.hookSignals() + util.CRON.registerReceiver(self) + + def onReInit(self): + if self.lastFocusID: + # try focusing the last focused ID. if that's a hub and it's empty (=not focusable), try focusing the + # next best hub + if 399 < self.lastFocusID < 500: + hubControlIndex = self.lastFocusID - 400 + + if hubControlIndex in self.hubFocusIndexes and self.hubControls[hubControlIndex]: + # this is basically just used for setting the background upon reinit + # fixme: declutter, separation of concerns + self.checkHubItem(self.lastFocusID) + else: + util.DEBUG_LOG("Focus requested on {}, which can't focus. Trying next hub".format(self.lastFocusID)) + self.focusFirstValidHub(hubControlIndex) + + else: + self.setFocusId(self.lastFocusID) + + def focusFirstValidHub(self, startIndex=None): + indices = self.hubFocusIndexes + if startIndex is not None: + try: + indices = self.hubFocusIndexes[self.hubFocusIndexes.index(startIndex):] + util.DEBUG_LOG("Trying to focus the next best hub after: %i" % (400 + startIndex)) + except IndexError: + pass + + for index in indices: + if self.hubControls[index]: + util.DEBUG_LOG("Focusing hub: %i" % (400 + index)) + self.setFocusId(400+index) + self.checkHubItem(400+index) + return + + if startIndex is not None: + util.DEBUG_LOG("Tried all possible hubs after %i. Continuing from the top" % (400 + startIndex)) + else: + util.DEBUG_LOG("Can't find any suitable hub to focus. This is bad.") + self.setFocusId(self.SECTION_LIST_ID) + return + + return self.focusFirstValidHub() + + def hookSignals(self): + plexapp.SERVERMANAGER.on('new:server', self.onNewServer) + plexapp.SERVERMANAGER.on('remove:server', self.onRemoveServer) + plexapp.SERVERMANAGER.on('reachable:server', self.onReachableServer) + plexapp.SERVERMANAGER.on('reachable:server', self.displayServerAndUser) + + plexapp.util.APP.on('change:selectedServer', self.onSelectedServerChange) + plexapp.util.APP.on('account:response', self.displayServerAndUser) + plexapp.util.APP.on('sli:reachability:received', self.displayServerAndUser) + + player.PLAYER.on('session.ended', self.updateOnDeckHubs) + util.MONITOR.on('changed.watchstatus', self.updateOnDeckHubs) + + def unhookSignals(self): + plexapp.SERVERMANAGER.off('new:server', self.onNewServer) + plexapp.SERVERMANAGER.off('remove:server', self.onRemoveServer) + plexapp.SERVERMANAGER.off('reachable:server', self.onReachableServer) + plexapp.SERVERMANAGER.off('reachable:server', self.displayServerAndUser) + + plexapp.util.APP.off('change:selectedServer', self.onSelectedServerChange) + plexapp.util.APP.off('account:response', self.displayServerAndUser) + + player.PLAYER.off('session.ended', self.updateOnDeckHubs) + util.MONITOR.off('changed.watchstatus', self.updateOnDeckHubs) + + def tick(self): + if not self.lastSection: + return + + hubs = self.sectionHubs.get(self.lastSection.key) + if not hubs: + return + + if time.time() - hubs.lastUpdated > HUBS_REFRESH_INTERVAL: + self.showHubs(self.lastSection, update=True) + + def shutdown(self): + self._shuttingDown = True + try: + self.serverList.reset() + except AttributeError: + pass + + self.unhookSignals() + + if util.advancedSettings.dynamicBackgrounds: + # store BG url of first hub, first item, as this is most likely to be the one we're focusing on the + # next start + try: + indices = self.hubFocusIndexes + for index in indices: + if self.hubControls[index]: + ds = self.hubControls[index][0].dataSource + util.setSetting("last_bg_url", + util.backgroundFromArt(ds.art, width=self.width, height=self.height)) + return + except: + util.LOG("Couldn't store last background") + + def onAction(self, action): + controlID = self.getFocusId() + + try: + if not controlID and not action == xbmcgui.ACTION_MOUSE_MOVE: + if self.lastFocusID: + self.setFocusId(self.lastFocusID) + + if controlID == self.SECTION_LIST_ID: + self.checkSectionItem(action=action) + + if controlID == self.SERVER_BUTTON_ID: + if action == xbmcgui.ACTION_SELECT_ITEM: + self.showServers() + return + elif action == xbmcgui.ACTION_MOUSE_LEFT_CLICK: + self.showServers(mouse=True) + self.setBoolProperty('show.servers', True) + return + elif controlID == self.USER_BUTTON_ID: + if action == xbmcgui.ACTION_SELECT_ITEM: + self.showUserMenu() + return + elif action == xbmcgui.ACTION_MOUSE_LEFT_CLICK: + self.showUserMenu(mouse=True) + self.setBoolProperty('show.options', True) + return + elif controlID == self.SERVER_LIST_ID: + if action == xbmcgui.ACTION_SELECT_ITEM: + self.setFocusId(self.SERVER_BUTTON_ID) + return + + if controlID == self.SERVER_BUTTON_ID and action == xbmcgui.ACTION_MOVE_RIGHT: + self.setFocusId(self.USER_BUTTON_ID) + elif controlID == self.USER_BUTTON_ID and action == xbmcgui.ACTION_MOVE_LEFT: + self.setFocusId(self.SERVER_BUTTON_ID) + elif controlID == self.SEARCH_BUTTON_ID and action == xbmcgui.ACTION_MOVE_RIGHT: + if xbmc.getCondVisibility('Player.HasMedia + Control.IsVisible({0})'.format(self.PLAYER_STATUS_BUTTON_ID)): + self.setFocusId(self.PLAYER_STATUS_BUTTON_ID) + else: + self.setFocusId(self.SERVER_BUTTON_ID) + elif controlID == self.PLAYER_STATUS_BUTTON_ID and action == xbmcgui.ACTION_MOVE_RIGHT: + self.setFocusId(self.SERVER_BUTTON_ID) + elif 399 < controlID < 500: + if action.getId() in MOVE_SET: + self.checkHubItem(controlID) + elif action.getId() == xbmcgui.ACTION_PLAYER_PLAY: + self.hubItemClicked(controlID, auto_play=True) + return + + if action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_CONTEXT_MENU): + optionsFocused = xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)) + offSections = util.getGlobalProperty('off.sections') + if action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): + # fixme: cheap way of avoiding an early exit after a server change + if self.changingServer: + return + + if self.getFocusId() == self.USER_LIST_ID: + self.setFocusId(self.USER_BUTTON_ID) + return + elif self.getFocusId() == self.SERVER_LIST_ID: + self.setFocusId(self.SERVER_BUTTON_ID) + return + + if util.advancedSettings.fastBack and not optionsFocused and offSections \ + and self.lastFocusID not in (self.USER_BUTTON_ID, self.SERVER_BUTTON_ID, + self.SEARCH_BUTTON_ID, self.SECTION_LIST_ID): + self.setProperty('hub.focus', '0') + self.setFocusId(self.SECTION_LIST_ID) + return + + if action in(xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_CONTEXT_MENU): + if not optionsFocused and offSections \ + and (not util.advancedSettings.fastBack or action == xbmcgui.ACTION_CONTEXT_MENU): + self.lastNonOptionsFocusID = self.lastFocusID + self.setFocusId(self.OPTIONS_GROUP_ID) + return + elif action == xbmcgui.ACTION_CONTEXT_MENU and optionsFocused and offSections \ + and self.lastNonOptionsFocusID: + self.setFocusId(self.lastNonOptionsFocusID) + self.lastNonOptionsFocusID = None + return + + if action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): + ex = self.confirmExit() + # 0 = exit; 1 = minimize; 2 = cancel + if ex in (2, None): + return + elif ex == 1: + xbmc.executebuiltin('ActivateWindow(10000)') + return + elif ex == 0: + self._shuttingDown = True + # 0 passes the action to the BaseWindow and exits HOME + except: + util.ERROR() + + kodigui.BaseWindow.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.SECTION_LIST_ID: + self.sectionClicked() + # elif controlID == self.SERVER_BUTTON_ID: + # self.showServers() + elif controlID == self.SERVER_LIST_ID: + self.setBoolProperty('show.servers', False) + self.selectServer() + # elif controlID == self.USER_BUTTON_ID: + # self.showUserMenu() + elif controlID == self.USER_LIST_ID: + self.doUserOption() + self.setBoolProperty('show.options', False) + self.setFocusId(self.USER_BUTTON_ID) + elif controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() + elif 399 < controlID < 500: + self.hubItemClicked(controlID) + elif controlID == self.SEARCH_BUTTON_ID: + self.searchButtonClicked() + + def onFocus(self, controlID): + if controlID != 204 and controlID < 500: + # don't store focus for mini music player + self.lastFocusID = controlID + + if 399 < controlID < 500: + self.setProperty('hub.focus', str(self.hubFocusIndexes[controlID - 400])) + + if controlID == self.SECTION_LIST_ID and not self.changingServer: + self.checkSectionItem() + + if xbmc.getCondVisibility('ControlGroup(50).HasFocus(0) + ControlGroup(100).HasFocus(0)'): + util.setGlobalBoolProperty('off.sections', '') + elif controlID != 250 and xbmc.getCondVisibility('ControlGroup(50).HasFocus(0) + !ControlGroup(100).HasFocus(0)'): + util.setGlobalBoolProperty('off.sections', '1') + + if player.PLAYER.bgmPlaying: + player.PLAYER.stopAndWait() + + def confirmExit(self): + button = optionsdialog.show( + T(32334, 'Confirm Exit'), + T(32335, 'Are you ready to exit Plex?'), + T(32336, 'Exit'), + T(32924, 'Minimize'), + T(32337, 'Cancel') + ) + + return button + + def searchButtonClicked(self): + self.processCommand(search.dialog(self)) + + def updateOnDeckHubs(self, **kwargs): + if util.getSetting("speedy_home_hubs2", False): + util.DEBUG_LOG("Using alternative home hub refresh") + sections = set() + for mli in self.sectionList: + if mli.dataSource is not None and mli.dataSource != self.lastSection: + sections.add(mli.dataSource) + tasks = [SectionHubsTask().setup(s, self.sectionHubsCallback) for s in [self.lastSection] + list(sections)] + else: + tasks = [UpdateHubTask().setup(hub, self.updateHubCallback) for hub in self.updateHubs.values()] + self.tasks += tasks + backgroundthread.BGThreader.addTasks(tasks) + + def showBusy(self, on=True): + self.setProperty('busy', on and '1' or '') + + @busy.dialog() + def serverRefresh(self): + backgroundthread.BGThreader.reset() + if self.tasks: + for task in self.tasks: + task.cancel() + + with self.lock: + self.setProperty('hub.focus', '') + self.displayServerAndUser() + if not plexapp.SERVERMANAGER.selectedServer: + self.setFocusId(self.USER_BUTTON_ID) + return False + + self.showSections() + self.backgroundSet = False + self.showHubs(HomeSection) + return True + + def hubItemClicked(self, hubControlID, auto_play=False): + control = self.hubControls[hubControlID - 400] + mli = control.getSelectedItem() + if not mli: + return + + if mli.dataSource is None: + return + + try: + command = opener.open(mli.dataSource, auto_play=auto_play) + if command == "NODATA": + raise util.NoDataException + except util.NoDataException: + util.ERROR("No data - disconnected?", notify=True, time_ms=5000) + return + + self.updateListItem(mli) + + if not mli: + return + + if not mli.dataSource.exists(): + try: + control.removeItem(mli.pos()) + except (ValueError, TypeError): + # fixme: why? + pass + + if not control.size(): + idx = self.hubFocusIndexes[hubControlID - 400] + while idx > 0: + idx -= 1 + controlID = 400 + self.hubFocusIndexes.index(idx) + control = self.hubControls[self.hubFocusIndexes.index(idx)] + if control.size(): + self.setFocusId(controlID) + break + else: + self.setFocusId(self.SECTION_LIST_ID) + + self.processCommand(command) + + def processCommand(self, command): + if command.startswith('HOME:'): + sectionID = command.split(':', 1)[-1] + for mli in self.sectionList: + if mli.dataSource and mli.dataSource.key == sectionID: + self.sectionList.selectItem(mli.pos()) + self.lastSection = mli.dataSource + self.sectionChanged() + + def checkSectionItem(self, force=False, action=None): + item = self.sectionList.getSelectedItem() + if not item: + return + + if not item.getProperty('item'): + if action and action == xbmcgui.ACTION_MOVE_RIGHT: + self.sectionList.selectItem(0) + item = self.sectionList[0] + else: + self.sectionList.selectItem(self.bottomItem) + item = self.sectionList[self.bottomItem] + + if item.dataSource != self.lastSection: + self.lastSection = item.dataSource + self.sectionChanged(force) + + def checkHubItem(self, controlID): + control = self.hubControls[controlID - 400] + mli = control.getSelectedItem() + is_valid_mli = mli and mli.getProperty('is.end') != '1' + + if util.advancedSettings.dynamicBackgrounds and is_valid_mli: + self.updateBackgroundFrom(mli.dataSource) + + if not mli or not mli.getProperty('is.end') or mli.getProperty('is.updating') == '1': + return + + mli.setBoolProperty('is.updating', True) + self.cleanTasks() + task = ExtendHubTask().setup(control.dataSource, self.extendHubCallback, + canceledCallback=lambda hub: mli.setBoolProperty('is.updating', False)) + self.tasks.append(task) + backgroundthread.BGThreader.addTask(task) + + def displayServerAndUser(self, **kwargs): + title = plexapp.ACCOUNT.title or plexapp.ACCOUNT.username or ' ' + self.setProperty('user.name', title) + self.setProperty('user.avatar', plexapp.ACCOUNT.thumb) + self.setProperty('user.avatar.letter', title[0].upper()) + + if plexapp.SERVERMANAGER.selectedServer: + self.setProperty('server.name', plexapp.SERVERMANAGER.selectedServer.name) + self.setProperty('server.icon', + 'script.plex/home/device/plex.png') # TODO: Set dynamically to whatever it should be if that's how it even works :) + self.setProperty('server.iconmod', + plexapp.SERVERMANAGER.selectedServer.isSecure and 'script.plex/home/device/lock.png' or '') + self.setProperty('server.iconmod2', + plexapp.SERVERMANAGER.selectedServer.isLocal and 'script.plex/home/device/home_small.png' + or '') + else: + self.setProperty('server.name', T(32338, 'No Servers Found')) + self.setProperty('server.icon', 'script.plex/home/device/error.png') + self.setProperty('server.iconmod', '') + self.setProperty('server.iconmod2', '') + + def cleanTasks(self): + self.tasks = [t for t in self.tasks if t.isValid()] + + def sectionChanged(self, force=False): + self.sectionChangeTimeout = time.time() + 0.3 + if not self.sectionChangeThread or not self.sectionChangeThread.is_alive() or force: + self.sectionChangeThread = threading.Thread(target=self._sectionChanged, name="sectionchanged") + self.sectionChangeThread.start() + + def _sectionChanged(self): + while not util.MONITOR.waitForAbort(0.1): + if time.time() >= self.sectionChangeTimeout: + break + + self._sectionReallyChanged() + + def _sectionReallyChanged(self): + with self.lock: + section = self.lastSection + self.setProperty('hub.focus', '') + if util.advancedSettings.dynamicBackgrounds: + self.backgroundSet = False + + util.DEBUG_LOG('Section changed ({0}): {1}'.format(section.key, repr(section.title))) + self.showHubs(section) + self.lastSection = section + self.checkSectionItem(force=True) + + def sectionHubsCallback(self, section, hubs): + with self.lock: + update = bool(self.sectionHubs.get(section.key)) + self.sectionHubs[section.key] = hubs + if self.lastSection == section: + self.showHubs(section, update=update) + + def updateHubCallback(self, hub, items=None): + with self.lock: + for mli in self.sectionList: + section = mli.dataSource + if not section: + continue + + hubs = self.sectionHubs.get(section.key, ()) + for idx, ihub in enumerate(hubs): + if ihub == hub: + if self.lastSection == section: + util.DEBUG_LOG('Hub {0} updated - refreshing section: {1}'.format(hub.hubIdentifier, repr(section.title))) + hubs[idx] = hub + self.showHub(hub, items=items) + return + + def extendHubCallback(self, hub, items): + util.DEBUG_LOG('ExtendHub called: {0} [{1}]'.format(hub.hubIdentifier, len(hub.items))) + self.updateHubCallback(hub, items) + + def showSections(self): + self.sectionHubs = {} + items = [] + + homemli = kodigui.ManagedListItem(T(32332, 'Home'), data_source=HomeSection) + homemli.setProperty('is.home', '1') + homemli.setProperty('item', '1') + items.append(homemli) + + pl = plexapp.SERVERMANAGER.selectedServer.playlists() + if pl: + plli = kodigui.ManagedListItem('Playlists', thumbnailImage='script.plex/home/type/playlists.png', data_source=PlaylistsSection) + plli.setProperty('is.playlists', '1') + plli.setProperty('item', '1') + items.append(plli) + + try: + sections = plexapp.SERVERMANAGER.selectedServer.library.sections() + except plexnet.exceptions.BadRequest: + self.setFocusId(self.SERVER_BUTTON_ID) + util.messageDialog("Error", "Bad request") + return + + if plexapp.SERVERMANAGER.selectedServer.hasHubs(): + self.tasks = [SectionHubsTask().setup(s, self.sectionHubsCallback) for s in [HomeSection, PlaylistsSection] + sections] + backgroundthread.BGThreader.addTasks(self.tasks) + + for section in sections: + mli = kodigui.ManagedListItem(section.title, thumbnailImage='script.plex/home/type/{0}.png'.format(section.type), data_source=section) + mli.setProperty('item', '1') + items.append(mli) + + self.bottomItem = len(items) - 1 + + for x in range(len(items), 8): + mli = kodigui.ManagedListItem() + items.append(mli) + + self.lastSection = HomeSection + self.sectionList.reset() + self.sectionList.addItems(items) + + if items: + self.setFocusId(self.SECTION_LIST_ID) + else: + self.setFocusId(self.SERVER_BUTTON_ID) + + def showHubs(self, section=None, update=False): + self.setBoolProperty('no.content', False) + if not update: + self.setProperty('drawing', '1') + try: + self._showHubs(section=section, update=update) + finally: + self.setProperty('drawing', '') + + def _showHubs(self, section=None, update=False): + if not update: + self.clearHubs() + + if not plexapp.SERVERMANAGER.selectedServer.hasHubs(): + return + + if section.key is False: + self.showBusy(False) + return + + self.showBusy(True) + + hubs = self.sectionHubs.get(section.key) + if hubs is False: + self.showBusy(False) + self.setBoolProperty('no.content', True) + return + + if not hubs: + for task in self.tasks: + if task.section == section: + backgroundthread.BGThreader.moveToFront(task) + break + + if section.type != "home": + self.showBusy(False) + self.setBoolProperty('no.content', True) + return + + if time.time() - hubs.lastUpdated > HUBS_REFRESH_INTERVAL: + util.DEBUG_LOG('Section is stale: REFRESHING - update: {0}'.format(update)) + hubs.lastUpdated = time.time() + self.cleanTasks() + if not update: + if section.key in self.sectionHubs: + self.sectionHubs[section.key] = None + self.tasks.append(SectionHubsTask().setup(section, self.sectionHubsCallback)) + backgroundthread.BGThreader.addTask(self.tasks[-1]) + return + + util.DEBUG_LOG('Showing hubs - Section: {0} - Update: {1}'.format(section.key, update)) + try: + hasContent = False + skip = {} + for hub in hubs: + identifier = hub.getCleanHubIdentifier() + + if identifier not in self.HUBMAP: + util.DEBUG_LOG('UNHANDLED - Hub: {0} [{1}]({2})'.format(hub.hubIdentifier, identifier, len(hub.items))) + continue + + skip[self.HUBMAP[identifier]['index']] = 1 + + if self.showHub(hub): + if hub.items: + hasContent = True + if self.HUBMAP[identifier].get('do_updates'): + self.updateHubs[identifier] = hub + + if not hasContent: + self.setBoolProperty('no.content', True) + + lastSkip = 0 + if skip: + lastSkip = min(skip.keys()) + + focus = None + if update: + for i, control in enumerate(self.hubControls): + if i in skip: + lastSkip = i + continue + if self.getFocusId() == control.getId(): + focus = lastSkip + control.reset() + + if focus is not None: + self.setFocusId(focus) + finally: + self.showBusy(False) + + def showHub(self, hub, items=None): + identifier = hub.getCleanHubIdentifier() + + if identifier in self.HUBMAP: + util.DEBUG_LOG('HUB: {0} [{1}]({2}, {3})'.format(hub.hubIdentifier, + identifier, + len(hub.items), + len(items) if items else None)) + self._showHub(hub, hubitems=items, **self.HUBMAP[identifier]) + return True + else: + util.DEBUG_LOG('UNHANDLED - Hub: {0} [{1}]({1})'.format(hub.hubIdentifier, identifier, len(hub.items))) + return + + def createGrandparentedListItem(self, obj, thumb_w, thumb_h, with_grandparent_title=False): + if with_grandparent_title and obj.get('grandparentTitle') and obj.title: + title = u'{0} - {1}'.format(obj.grandparentTitle, obj.title) + else: + title = obj.get('grandparentTitle') or obj.get('parentTitle') or obj.title or '' + mli = kodigui.ManagedListItem(title, thumbnailImage=obj.defaultThumb.asTranscodedImageURL(thumb_w, thumb_h), data_source=obj) + return mli + + def createParentedListItem(self, obj, thumb_w, thumb_h, with_parent_title=False): + if with_parent_title and obj.parentTitle and obj.title: + title = u'{0} - {1}'.format(obj.parentTitle, obj.title) + else: + title = obj.parentTitle or obj.title or '' + mli = kodigui.ManagedListItem(title, thumbnailImage=obj.defaultThumb.asTranscodedImageURL(thumb_w, thumb_h), data_source=obj) + return mli + + def createSimpleListItem(self, obj, thumb_w, thumb_h): + mli = kodigui.ManagedListItem(obj.title or '', thumbnailImage=obj.defaultThumb.asTranscodedImageURL(thumb_w, thumb_h), data_source=obj) + return mli + + def createEpisodeListItem(self, obj, wide=False): + mli = self.createGrandparentedListItem(obj, *self.THUMB_POSTER_DIM) + if obj.index: + subtitle = u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), obj.parentIndex, T(32311, 'E'), obj.index) + else: + subtitle = obj.originallyAvailableAt.asDatetime('%m/%d/%y') + + if wide: + mli.setLabel2(u'{0} - {1}'.format(util.shortenText(obj.title, 35), subtitle)) + else: + mli.setLabel2(subtitle) + + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/show.png') + if not obj.isWatched: + mli.setProperty('unwatched', '1') + return mli + + def createSeasonListItem(self, obj, wide=False): + mli = self.createParentedListItem(obj, *self.THUMB_POSTER_DIM) + # mli.setLabel2('Season {0}'.format(obj.index)) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/show.png') + if not obj.isWatched: + mli.setProperty('unwatched.count', str(obj.unViewedLeafCount)) + return mli + + def createMovieListItem(self, obj, wide=False): + mli = kodigui.ManagedListItem(obj.defaultTitle, obj.year, thumbnailImage=obj.defaultThumb.asTranscodedImageURL(*self.THUMB_POSTER_DIM), data_source=obj) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/movie.png') + if not obj.isWatched: + mli.setProperty('unwatched', '1') + return mli + + def createShowListItem(self, obj, wide=False): + mli = self.createSimpleListItem(obj, *self.THUMB_POSTER_DIM) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/show.png') + if not obj.isWatched: + mli.setProperty('unwatched.count', str(obj.unViewedLeafCount)) + return mli + + def createAlbumListItem(self, obj, wide=False): + mli = self.createParentedListItem(obj, *self.THUMB_SQUARE_DIM) + mli.setLabel2(obj.title) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/music.png') + return mli + + def createTrackListItem(self, obj, wide=False): + mli = self.createGrandparentedListItem(obj, *self.THUMB_SQUARE_DIM) + mli.setLabel2(obj.title) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/music.png') + return mli + + def createPhotoListItem(self, obj, wide=False): + mli = self.createSimpleListItem(obj, *self.THUMB_SQUARE_DIM) + if obj.type == 'photo': + mli.setLabel2(obj.originallyAvailableAt.asDatetime('%d %B %Y')) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/photo.png') + return mli + + def createClipListItem(self, obj, wide=False): + mli = self.createGrandparentedListItem(obj, *self.THUMB_AR16X9_DIM, with_grandparent_title=True) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/movie16x9.png') + return mli + + def createArtistListItem(self, obj, wide=False): + mli = self.createSimpleListItem(obj, *self.THUMB_SQUARE_DIM) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/music.png') + return mli + + def createPlaylistListItem(self, obj, wide=False): + if obj.playlistType == 'audio': + w, h = self.THUMB_SQUARE_DIM + thumb = obj.buildComposite(width=w, height=h, media='thumb') + else: + w, h = self.THUMB_AR16X9_DIM + thumb = obj.buildComposite(width=w, height=h, media='art') + + mli = kodigui.ManagedListItem( + obj.title or '', + util.durationToText(obj.duration.asInt()), + # thumbnailImage=obj.composite.asTranscodedImageURL(*self.THUMB_DIMS[obj.playlistType]['item.thumb']), + thumbnailImage=thumb, + data_source=obj + ) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/{0}.png'.format(obj.playlistType == 'audio' and 'music' or 'movie')) + return mli + + def unhandledHub(self, self2, obj, wide=False): + util.DEBUG_LOG('Unhandled Hub item: {0}'.format(obj.type)) + + CREATE_LI_MAP = { + 'episode': createEpisodeListItem, + 'season': createSeasonListItem, + 'movie': createMovieListItem, + 'show': createShowListItem, + 'album': createAlbumListItem, + 'track': createTrackListItem, + 'photo': createPhotoListItem, + 'photodirectory': createPhotoListItem, + 'clip': createClipListItem, + 'artist': createArtistListItem, + 'playlist': createPlaylistListItem + } + + def createListItem(self, obj, wide=False): + return self.CREATE_LI_MAP.get(obj.type, self.unhandledHub)(self, obj, wide) + + def clearHubs(self): + for control in self.hubControls: + control.reset() + + def _showHub(self, hub, hubitems=None, index=None, with_progress=False, with_art=False, ar16x9=False, + text2lines=False, **kwargs): + control = self.hubControls[index] + control.dataSource = hub + + if not hub.items and not hubitems: + control.reset() + return + + if not hubitems: + hub.reset() + + self.setProperty('hub.4{0:02d}'.format(index), hub.title or kwargs.get('title')) + self.setProperty('hub.text2lines.4{0:02d}'.format(index), text2lines and '1' or '') + + items = [] + + for obj in hubitems or hub.items: + if not self.backgroundSet: + if self.updateBackgroundFrom(obj): + self.backgroundSet = True + mli = self.createListItem(obj, wide=with_art) + if mli: + items.append(mli) + + if with_progress: + for mli in items: + mli.setProperty('progress', util.getProgressImage(mli.dataSource)) + if with_art: + for mli in items: + thumb = (util.advancedSettings.continueUseThumb + and mli.dataSource.type == 'episode' + and mli.dataSource.thumb + ) \ + or mli.dataSource.art + mli.setThumbnailImage(thumb.asTranscodedImageURL(*self.THUMB_AR16X9_DIM)) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/movie16x9.png') + if ar16x9: + for mli in items: + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/movie16x9.png') + + if hub.more.asBool(): + end = kodigui.ManagedListItem('') + end.setBoolProperty('is.end', True) + items.append(end) + + if hubitems: + end = control.size() - 1 + control.replaceItem(end, items[0]) + control.addItems(items[1:]) + control.selectItem(end) + else: + control.replaceItems(items) + + def updateListItem(self, mli): + if not mli or not mli.dataSource: # May have become invalid + return + + obj = mli.dataSource + if obj.type in ('episode', 'movie'): + mli.setProperty('unwatched', not obj.isWatched and '1' or '') + elif obj.type in ('season', 'show', 'album'): + if obj.isWatched: + mli.setProperty('unwatched.count', '') + else: + mli.setProperty('unwatched.count', str(obj.unViewedLeafCount)) + + def sectionClicked(self): + item = self.sectionList.getSelectedItem() + if not item: + return + + section = item.dataSource + + if section.type in ('show', 'movie', 'artist', 'photo'): + self.processCommand(opener.sectionClicked(section)) + elif section.type in ('playlists',): + self.processCommand(opener.handleOpen(playlists.PlaylistsWindow)) + + def onNewServer(self, **kwargs): + self.showServers(from_refresh=True) + + def onRemoveServer(self, **kwargs): + self.onNewServer() + + def onReachableServer(self, server=None, **kwargs): + for mli in self.serverList: + if mli.uuid == server.uuid: + mli.unHookSignals() + mli.dataSource = server + mli.hookSignals() + mli.onUpdate() + return + else: + self.onNewServer() + + def onSelectedServerChange(self, **kwargs): + if self.serverRefresh(): + self.setFocusId(self.SECTION_LIST_ID) + self.changingServer = False + + def showServers(self, from_refresh=False, mouse=False): + with self.lock: + selection = None + if from_refresh: + mli = self.serverList.getSelectedItem() + if mli: + selection = mli.uuid + + servers = sorted( + plexapp.SERVERMANAGER.getServers(), + key=lambda x: (x.owned and '0' or '1') + x.name.lower() + ) + + items = [] + for s in servers: + item = ServerListItem(s.name, not s.owned and s.owner or '', data_source=s) + item.uuid = s.uuid + item.onUpdate() + item.setProperty('current', plexapp.SERVERMANAGER.selectedServer.uuid == s.uuid and '1' or '') + items.append(item) + + if len(items) > 1: + items[0].setProperty('first', '1') + elif items: + items[0].setProperty('only', '1') + + self.serverList.replaceItems(items) + + self.getControl(800).setHeight((min(len(items), 9) * 100) + 80) + + for item in items: + if item.dataSource != kodigui.DUMMY_DATA_SOURCE: + item.hookSignals() + + if selection: + for mli in self.serverList: + if mli.uuid == selection: + self.serverList.selectItem(mli.pos()) + + if not from_refresh and items and not mouse: + self.setFocusId(self.SERVER_LIST_ID) + + if not from_refresh: + plexapp.refreshResources() + + def selectServer(self): + if self._shuttingDown: + return + + mli = self.serverList.getSelectedItem() + if not mli: + return + + self.changingServer = True + + # this is broken + with busy.BusySignalContext(plexapp.util.APP, "change:selectedServer") as bc: + self.setFocusId(self.SECTION_LIST_ID) + + server = mli.dataSource + + # fixme: this might still trigger a dialog, re-triggering the previously opened windows + if not self._shuttingDown and not server.isReachable(): + if server.pendingReachabilityRequests > 0: + util.messageDialog(T(32339, 'Server is not accessible'), T(32340, 'Connection tests are in ' + 'progress. Please wait.')) + else: + util.messageDialog( + T(32339, 'Server is not accessible'), T(32341, 'Server is not accessible. Please sign into ' + 'your server and check your connection.') + ) + bc.ignoreSignal = True + return + + changed = plexapp.SERVERMANAGER.setSelectedServer(server, force=True) + if not changed: + bc.ignoreSignal = True + self.changingServer = False + + def showUserMenu(self, mouse=False): + items = [] + if plexapp.ACCOUNT.isSignedIn: + if len(plexapp.ACCOUNT.homeUsers) > 1: + items.append(kodigui.ManagedListItem(T(32342, 'Switch User'), data_source='switch')) + items.append(kodigui.ManagedListItem(T(32343, 'Settings'), data_source='settings')) + if plexapp.ACCOUNT.isSignedIn: + items.append(kodigui.ManagedListItem(T(32344, 'Sign Out'), data_source='signout')) + elif plexapp.ACCOUNT.isOffline: + items.append(kodigui.ManagedListItem(T(32459, 'Offline Mode'), data_source='go_online')) + else: + items.append(kodigui.ManagedListItem(T(32460, 'Sign In'), data_source='signin')) + + if len(items) > 1: + items[0].setProperty('first', '1') + items[-1].setProperty('last', '1') + else: + items[0].setProperty('only', '1') + + self.userList.reset() + self.userList.addItems(items) + + self.getControl(801).setHeight((len(items) * 66) + 80) + + if not mouse: + self.setFocusId(self.USER_LIST_ID) + + def doUserOption(self): + mli = self.userList.getSelectedItem() + if not mli: + return + + option = mli.dataSource + + self.setFocusId(self.USER_BUTTON_ID) + + if option == 'settings': + from . import settings + settings.openWindow() + elif option == 'go_online': + plexapp.ACCOUNT.refreshAccount() + else: + self.closeOption = option + self.doClose() + + def showAudioPlayer(self): + from . import musicplayer + self.processCommand(opener.handleOpen(musicplayer.MusicPlayerWindow)) + + def finished(self): + if self.tasks: + for task in self.tasks: + task.cancel() diff --git a/script.plexmod/lib/windows/info.py b/script.plexmod/lib/windows/info.py new file mode 100644 index 0000000000..4c3374cd29 --- /dev/null +++ b/script.plexmod/lib/windows/info.py @@ -0,0 +1,149 @@ +from __future__ import absolute_import +from . import kodigui +from . import windowutils +from lib import util +from plexnet.video import Episode, Movie, Clip + +import os + + +def split2len(s, n): + def _f(s, n): + while s: + yield s[:n] + s = s[n:] + return list(_f(s, n)) + + +class InfoWindow(kodigui.ControlledWindow, windowutils.UtilMixin): + xmlFile = 'script-plex-info.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + PLAYER_STATUS_BUTTON_ID = 204 + + THUMB_DIM_POSTER = util.scaleResolution(519, 469) + THUMB_DIM_SQUARE = util.scaleResolution(519, 519) + + def __init__(self, *args, **kwargs): + kodigui.ControlledWindow.__init__(self, *args, **kwargs) + self.title = kwargs.get('title') + self.subTitle = kwargs.get('sub_title') + self.thumb = kwargs.get('thumb') + self.thumbFallback = kwargs.get('thumb_fallback') + self.info = kwargs.get('info') + self.background = kwargs.get('background') + self.isSquare = kwargs.get('is_square') + self.is16x9 = kwargs.get('is_16x9') + self.isPoster = not (self.isSquare or self.is16x9) + self.thumbDim = self.isSquare and self.THUMB_DIM_SQUARE or self.THUMB_DIM_POSTER + self.video = kwargs.get('video') + + def getVideoInfo(self): + """ + Append media/part/stream info to summary + """ + if not isinstance(self.video, (Episode, Movie, Clip)): + return self.info + + summary = [self.info] + medias = self.video.media() + mediaCount = len(medias) + onlyOneMedia = mediaCount == 1 + partCount = sum(len(m.parts) for m in medias) + pcInfo = [] + if not onlyOneMedia: + pcInfo.append("Files: {}".format(mediaCount)) + if partCount > 1: + pcInfo.append("Parts: {}".format(partCount)) + pcInfoStr = ", ".join(pcInfo) + + addMedia = ["\n\n\n\nMedia{}\n".format(" ({})".format(pcInfoStr) if pcInfoStr else "")] + for media_ in medias: + if not media_.isAccessible(): + addMedia.append("Unavailable: {}\n\n".format(", ".join(os.path.basename(pf.file) for pf in media_.parts))) + continue + + for part in media_.parts: + if not part: + addMedia.append("Unavailable: {}".format(os.path.basename(part.file))) + continue + + addMedia.append("File: ") + splitFnAt = 74 + fnLen = len(os.path.basename(part.file)) + appended = False + for s in split2len(os.path.basename(part.file), splitFnAt): + if fnLen > splitFnAt and not appended: + addMedia.append("{}\n".format(s)) + appended = True + continue + addMedia.append("{}\n".format(s)) + addMedia.append("Duration: {}, Size: {}\n".format(util.durationToShortText(int(part.duration)), + util.simpleSize(int(part.size)))) + + subs = [] + subsOver = 0 + for stream in part.streams: + streamtype = stream.streamType.asInt() + # video + if streamtype == 1: + addMedia.append("Video: {}x{}, {} {}/{}bit/{}/{}@{} kBit, {} fps\n".format( + stream.width, stream.height, stream.videoCodecRendering, stream.codec.upper(), + stream.bitDepth, stream.chromaSubsampling, stream.colorPrimaries, stream.bitrate, + stream.frameRate)) + # audio + elif streamtype == 2: + addMedia.append("Audio: {}{}, {}/{}ch@{} kBit, {} Hz\n".format( + stream.language, + " (default)" if stream.default else "", + stream.codec.upper(), + stream.channels, stream.bitrate, + stream.samplingRate)) + # subtitle + elif streamtype == 3: + if len(subs) > 4: + subsOver += 1 + continue + subs.append("{} ({})".format(stream.language, stream.codec.upper())) + + if subs: + addMedia.append("Subtitles: {}{}\n".format(", ".join(subs), + subsOver and " (+{})".format(subsOver) or '')) + if not onlyOneMedia: + addMedia.append("--------------\n") + + chapters = [] + chOver = 0 + for index, chapter in enumerate(self.video.chapters): + if len(chapters) > 4: + chOver += 1 + continue + chapters.append(chapter.tag or "Chapter #{}".format(str(index+1))) + + if chapters: + addMedia.append("Chapters: {}{}\n".format(", ".join(chapters), chOver and " (+{})".format(chOver) or '')) + + if self.video.markers: + addMedia.append("Markers: {}".format(", ".join(name for off, name in sorted( + (int(marker.startTimeOffset), marker.type) for marker in self.video.markers)))) + + return "".join(summary + addMedia) + + def onFirstInit(self): + self.setProperty('is.poster', self.isPoster and '1' or '') + self.setProperty('is.square', self.isSquare and '1' or '') + self.setProperty('is.16x9', self.is16x9 and '1' or '') + self.setProperty('title.main', self.title) + self.setProperty('title.sub', self.subTitle) + self.setProperty('thumb.fallback', self.thumbFallback) + self.setProperty('thumb', self.thumb.asTranscodedImageURL(*self.thumbDim)) + self.setProperty('info', self.getVideoInfo()) + self.setProperty('background', self.background) + + def onClick(self, controlID): + if controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() diff --git a/script.plexmod/lib/windows/kodigui.py b/script.plexmod/lib/windows/kodigui.py new file mode 100644 index 0000000000..3796339206 --- /dev/null +++ b/script.plexmod/lib/windows/kodigui.py @@ -0,0 +1,1105 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcgui +import time +import threading +import traceback +from six.moves import range +from six.moves import zip +from .. import util + +MONITOR = None + + +class BaseFunctions: + xmlFile = '' + path = '' + theme = '' + res = '720p' + width = 1280 + height = 720 + + usesGenerate = False + lastWinID = None + lastDialogID = None + + def __init__(self): + self.isOpen = True + + def onWindowFocus(self): + # Not automatically called. Can be used by an external window manager + pass + + def onClosed(self): + pass + + @classmethod + def open(cls, **kwargs): + window = cls(cls.xmlFile, cls.path, cls.theme, cls.res, **kwargs) + window.modal() + return window + + @classmethod + def create(cls, show=True, **kwargs): + window = cls(cls.xmlFile, cls.path, cls.theme, cls.res, **kwargs) + if show: + window.show() + if xbmcgui.getCurrentWindowId() < 13000: + window.isOpen = False + return window + + window.isOpen = xbmcgui.getCurrentWindowId() >= 13000 + return window + + def modal(self): + self.isOpen = True + try: + self.doModal() + except SystemExit: + pass + self.onClosed() + self.isOpen = False + + def activate(self): + if not self._winID: + self._winID = xbmcgui.getCurrentWindowId() + xbmc.executebuiltin('ReplaceWindow({0})'.format(self._winID)) + + def mouseXTrans(self, val): + return int((val / self.getWidth()) * self.width) + + def mouseYTrans(self, val): + return int((val / self.getHeight()) * self.height) + + def closing(self): + return self._closing + + @classmethod + def generate(self): + return None + + def setProperties(self, prop_list, val_list_or_val): + if isinstance(val_list_or_val, list) or isinstance(val_list_or_val, tuple): + val_list = val_list_or_val + else: + val_list = [val_list_or_val] * len(prop_list) + + for prop, val in zip(prop_list, val_list): + self.setProperty(prop, val) + + def propertyContext(self, prop, val='1'): + return WindowProperty(self, prop, val) + + def setBoolProperty(self, key, boolean): + self.setProperty(key, boolean and '1' or '') + + +LAST_BG_URL = None + + +class BaseWindow(xbmcgui.WindowXML, BaseFunctions): + def __init__(self, *args, **kwargs): + BaseFunctions.__init__(self) + self._closing = False + self._winID = None + self.started = False + self.finishedInit = False + + def onInit(self): + global LAST_BG_URL + self._winID = xbmcgui.getCurrentWindowId() + BaseFunctions.lastWinID = self._winID + self.setProperty('use_solid_background', util.hasCustomBGColour and '1' or '') + if util.hasCustomBGColour: + bgColour = util.advancedSettings.backgroundColour if util.advancedSettings.backgroundColour != "-" \ + else "ff000000" + self.setProperty('background_colour', "0x%s" % bgColour.lower()) + self.setProperty('background_colour_opaque', "0x%s" % bgColour.lower()) + else: + # set background color to 0 to avoid kodi UI BG clearing, improves performance + if util.advancedSettings.dbgCrossfade: + self.setProperty('background_colour', "0x00000000") + else: + self.setProperty('background_colour', "0xff111111") + self.setProperty('background_colour_opaque', "0xff111111") + + self.setBoolProperty('use_bg_fallback', util.advancedSettings.useBgFallback) + + try: + if self.started: + self.onReInit() + else: + self.started = True + if LAST_BG_URL: + self.windowSetBackground(LAST_BG_URL) + self.onFirstInit() + self.finishedInit = True + except util.NoDataException: + self.exitCommand = "NODATA" + self.doClose() + + def onFirstInit(self): + pass + + def onReInit(self): + pass + + def setProperty(self, key, value): + if self._closing: + return + + if not self._winID: + self._winID = xbmcgui.getCurrentWindowId() + + try: + xbmcgui.Window(self._winID).setProperty(key, value) + xbmcgui.WindowXML.setProperty(self, key, value) + except RuntimeError: + xbmc.log('kodigui.BaseWindow.setProperty: Missing window', xbmc.LOGDEBUG) + + def updateBackgroundFrom(self, ds): + if util.advancedSettings.dynamicBackgrounds: + return self.windowSetBackground(util.backgroundFromArt(ds.art, width=self.width, + height=self.height)) + + def windowSetBackground(self, value): + if not util.advancedSettings.dbgCrossfade: + if not value: + return + self.setProperty("background_static", value) + return value + + global LAST_BG_URL + + if not value: + if LAST_BG_URL: + self.setProperty("background_static", LAST_BG_URL) + return LAST_BG_URL + return + + cur1 = self.getProperty('background') + if not cur1: + self.setProperty("background_static", value) + self.setProperty("background", value) + + elif LAST_BG_URL != value: + self.setProperty("background_static", LAST_BG_URL) + self.setProperty("background", value) + + LAST_BG_URL = value + return value + + def doClose(self): + if not self.isOpen: + return + self._closing = True + self.isOpen = False + self.close() + + def show(self): + self._closing = False + #self.isOpen = True + xbmcgui.WindowXML.show(self) + self.isOpen = xbmcgui.getCurrentWindowId() >= 13000 + + def onClosed(self): + pass + + +class BaseDialog(xbmcgui.WindowXMLDialog, BaseFunctions): + def __init__(self, *args, **kwargs): + BaseFunctions.__init__(self) + self._closing = False + self._winID = '' + self.started = False + + def onInit(self): + self._winID = xbmcgui.getCurrentWindowDialogId() + BaseFunctions.lastDialogID = self._winID + if self.started: + self.onReInit() + else: + self.started = True + self.onFirstInit() + + def onFirstInit(self): + pass + + def onReInit(self): + pass + + def setProperty(self, key, value): + if self._closing: + return + + if not self._winID: + self._winID = xbmcgui.getCurrentWindowId() + + try: + xbmcgui.Window(self._winID).setProperty(key, value) + xbmcgui.WindowXMLDialog.setProperty(self, key, value) + except RuntimeError: + xbmc.log('kodigui.BaseDialog.setProperty: Missing window', xbmc.LOGDEBUG) + + def doClose(self): + self._closing = True + self.close() + self.isOpen = False + + def show(self): + self._closing = False + xbmcgui.WindowXMLDialog.show(self) + self.isOpen = True + + def onClosed(self): + pass + + +class ControlledBase: + def doModal(self): + self.show() + self.wait() + + def wait(self): + while not self._closing and not MONITOR.waitForAbort(0.1): + pass + + def close(self): + self._closing = True + + +class ControlledWindow(ControlledBase, BaseWindow): + def onAction(self, action): + try: + if action in (xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK): + self.doClose() + return + except: + traceback.print_exc() + + BaseWindow.onAction(self, action) + + +class ControlledDialog(ControlledBase, BaseDialog): + def onAction(self, action): + try: + if action in (xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK): + self.doClose() + return + except: + traceback.print_exc() + + BaseDialog.onAction(self, action) + + +DUMMY_LIST_ITEM = xbmcgui.ListItem() + + +class DummyDataSource(object): + def __nonzero__(self): + return False + + __bool__ = __nonzero__ + + def exists(self): + return False + + +DUMMY_DATA_SOURCE = DummyDataSource() + + +class ManagedListItem(object): + def __init__(self, label='', label2='', iconImage='', thumbnailImage='', path='', data_source=None, properties=None): + self._listItem = xbmcgui.ListItem(label, label2, path=path) + self._listItem.setArt({"thumb": thumbnailImage, "icon": iconImage}) + self.dataSource = data_source + self.properties = {} + self.label = label + self.label2 = label2 + self.iconImage = iconImage + self.thumbnailImage = thumbnailImage + self.path = path + self._ID = None + self._manager = None + self._valid = True + if properties: + for k, v in properties.items(): + self.setProperty(k, v) + + def __nonzero__(self): + return self._valid + + @property + def listItem(self): + if not self._listItem: + if not self._manager: + return None + + try: + self._listItem = self._manager.getListItemFromManagedItem(self) + except RuntimeError: + return None + + return self._listItem + + def invalidate(self): + self._valid = False + self._listItem = DUMMY_LIST_ITEM + self.dataSource = DUMMY_DATA_SOURCE + + def _takeListItem(self, manager, lid): + self._manager = manager + self._ID = lid + self._listItem.setProperty('__ID__', lid) + li = self._listItem + self._listItem = None + self._manager._properties.update(self.properties) + return li + + def _updateListItem(self): + self.listItem.setProperty('__ID__', self._ID) + self.listItem.setLabel(self.label) + self.listItem.setLabel2(self.label2) + self.listItem.setArt({"thumb": self.thumbnailImage, "icon": self.iconImage}) + self.listItem.setPath(self.path) + for k in self._manager._properties.keys(): + self.listItem.setProperty(k, self.properties.get(k) or '') + + def clear(self): + self.label = '' + self.label2 = '' + self.iconImage = '' + self.thumbnailImage = '' + self.path = '' + for k in self.properties: + self.properties[k] = '' + self._updateListItem() + + def pos(self): + if not self._manager: + return None + return self._manager.getManagedItemPosition(self) + + def addContextMenuItems(self, items, replaceItems=False): + self.listItem.addContextMenuItems(items, replaceItems) + + def addStreamInfo(self, stype, values): + self.listItem.addStreamInfo(stype, values) + + def getLabel(self): + return self.label + + def getLabel2(self): + return self.label2 + + def getProperty(self, key): + return self.properties.get(key, '') + + def getdescription(self): + return self.listItem.getdescription() + + def getduration(self): + return self.listItem.getduration() + + def getfilename(self): + return self.listItem.getfilename() + + def isSelected(self): + return self.listItem.isSelected() + + def select(self, selected): + return self.listItem.select(selected) + + def setArt(self, values): + return self.listItem.setArt(values) + + def setIconImage(self, icon): + self.iconImage = icon + return self.listItem.setArt({"icon": self.iconImage}) + + def setInfo(self, itype, infoLabels): + return self.listItem.setInfo(itype, infoLabels) + + def setLabel(self, label): + self.label = label + return self.listItem.setLabel(label) + + def setLabel2(self, label): + self.label2 = label + return self.listItem.setLabel2(label) + + def setMimeType(self, mimetype): + return self.listItem.setMimeType(mimetype) + + def setPath(self, path): + self.path = path + return self.listItem.setPath(path) + + def setProperty(self, key, value): + if self._manager: + self._manager._properties[key] = 1 + self.properties[key] = value + self.listItem.setProperty(key, value) + return self + + def setBoolProperty(self, key, boolean): + return self.setProperty(key, boolean and '1' or '') + + def setSubtitles(self, subtitles): + return self.listItem.setSubtitles(subtitles) # List of strings - HELIX + + def setThumbnailImage(self, thumb): + self.thumbnailImage = thumb + return self.listItem.setArt({"thumb": self.thumbnailImage}) + + def onDestroy(self): + pass + + +class ManagedControlList(object): + def __init__(self, window, control_id, max_view_index, data_source=None): + self.controlID = control_id + self.control = window.getControl(control_id) + self.items = [] + self._sortKey = None + self._idCounter = 0 + self._maxViewIndex = max_view_index + self._properties = {} + self.dataSource = data_source + + def __getattr__(self, name): + return getattr(self.control, name) + + def __getitem__(self, idx): + if isinstance(idx, slice): + return self.items[idx] + else: + return self.getListItem(idx) + + def __iter__(self): + for i in self.items: + yield i + + def __len__(self): + return self.size() + + def _updateItems(self, bottom=None, top=None): + if bottom is None: + bottom = 0 + top = self.size() + + try: + for idx in range(bottom, top): + try: + li = self.control.getListItem(idx) + except RuntimeError: + continue + + mli = self.items[idx] + self._properties.update(mli.properties) + mli._manager = self + mli._listItem = li + mli._updateListItem() + mli.setProperty('index', str(idx)) + except RuntimeError: + #xbmc.log('kodigui.ManagedControlList._updateItems: Runtime error', xbmc.LOGINFO) + util.ERROR('kodigui.ManagedControlList._updateItems: Runtime error') + return False + + return True + + def _nextID(self): + self._idCounter += 1 + return str(self._idCounter) + + def reInit(self, window, control_id): + self.controlID = control_id + self.control = window.getControl(control_id) + self.control.addItems([i._takeListItem(self, self._nextID()) for i in self.items]) + + def setSort(self, sort): + self._sortKey = sort + + def addItem(self, managed_item): + self.items.append(managed_item) + self.control.addItem(managed_item._takeListItem(self, self._nextID())) + + def addItems(self, managed_items): + self.items += managed_items + self.control.addItems([i._takeListItem(self, self._nextID()) for i in managed_items]) + + def replaceItem(self, pos, mli): + self[pos].onDestroy() + self[pos].invalidate() + self.items[pos] = mli + li = self.control.getListItem(pos) + mli._manager = self + mli._listItem = li + mli._updateListItem() + + def replaceItems(self, managed_items): + if not self.items: + self.addItems(managed_items) + return True + + oldSize = self.size() + + for i in self.items: + i.onDestroy() + i.invalidate() + + self.items = managed_items + size = self.size() + if size != oldSize: + pos = self.getSelectedPosition() + + if size > oldSize: + for i in range(0, size - oldSize): + self.control.addItem(xbmcgui.ListItem()) + elif size < oldSize: + diff = oldSize - size + idx = oldSize - 1 + while diff: + self.control.removeItem(idx) + idx -= 1 + diff -= 1 + + if self.positionIsValid(pos): + self.selectItem(pos) + elif pos >= size: + self.selectItem(size - 1) + + return self._updateItems(0, self.size()) + + def getListItem(self, pos): + li = self.control.getListItem(pos) + mli = self.items[pos] + mli._listItem = li + return mli + + def getListItemByDataSource(self, data_source): + for mli in self: + if data_source == mli.dataSource: + return mli + return None + + def getSelectedItem(self): + pos = self.control.getSelectedPosition() + if not self.positionIsValid(pos): + pos = self.size() - 1 + + if pos < 0: + return None + return self.getListItem(pos) + + def setSelectedItemByPos(self, pos): + if self.positionIsValid(pos): + self.control.selectItem(pos) + + def removeItem(self, index): + old = self.items.pop(index) + old.onDestroy() + old.invalidate() + + self.control.removeItem(index) + top = self.control.size() - 1 + if top < 0: + return + if top < index: + index = top + self.control.selectItem(index) + + def removeManagedItem(self, mli): + self.removeItem(mli.pos()) + + def insertItem(self, index, managed_item): + pos = self.getSelectedPosition() + 1 + + if index >= self.size() or index < 0: + self.addItem(managed_item) + else: + self.items.insert(index, managed_item) + self.control.addItem(managed_item._takeListItem(self, self._nextID())) + self._updateItems(index, self.size()) + + if self.positionIsValid(pos): + self.selectItem(pos) + + def moveItem(self, mli, dest_idx): + source_idx = mli.pos() + if source_idx < dest_idx: + rstart = source_idx + rend = dest_idx + 1 + # dest_idx-=1 + else: + rstart = dest_idx + rend = source_idx + 1 + mli = self.items.pop(source_idx) + self.items.insert(dest_idx, mli) + + self._updateItems(rstart, rend) + + def swapItems(self, pos1, pos2): + if not self.positionIsValid(pos1) or not self.positionIsValid(pos2): + return False + + item1 = self.items[pos1] + item2 = self.items[pos2] + li1 = item1._listItem + li2 = item2._listItem + item1._listItem = li2 + item2._listItem = li1 + + item1._updateListItem() + item2._updateListItem() + self.items[pos1] = item2 + self.items[pos2] = item1 + + return True + + def shiftView(self, shift, hold_selected=False): + if not self._maxViewIndex: + return + selected = self.getSelectedItem() + selectedPos = selected.pos() + viewPos = self.getViewPosition() + + if shift > 0: + pushPos = selectedPos + (self._maxViewIndex - viewPos) + shift + if pushPos >= self.size(): + pushPos = self.size() - 1 + self.selectItem(pushPos) + newViewPos = self._maxViewIndex + elif shift < 0: + pushPos = (selectedPos - viewPos) + shift + if pushPos < 0: + pushPos = 0 + self.selectItem(pushPos) + newViewPos = 0 + + if hold_selected: + self.selectItem(selected.pos()) + else: + diff = newViewPos - viewPos + fix = pushPos - diff + # print '{0} {1} {2}'.format(newViewPos, viewPos, fix) + if self.positionIsValid(fix): + self.selectItem(fix) + + def reset(self): + self.dataSource = None + for i in self.items: + i.onDestroy() + i.invalidate() + self.items = [] + self.control.reset() + + def size(self): + return len(self.items) + + def getViewPosition(self): + try: + return int(xbmc.getInfoLabel('Container({0}).Position'.format(self.controlID))) + except: + return 0 + + def getViewRange(self): + viewPosition = self.getViewPosition() + selected = self.getSelectedPosition() + return list(range(max(selected - viewPosition, 0), min(selected + (self._maxViewIndex - viewPosition) + 1, self.size() - 1))) + + def positionIsValid(self, pos): + return 0 <= pos < self.size() + + def sort(self, sort=None, reverse=False): + sort = sort or self._sortKey + + self.items.sort(key=sort, reverse=reverse) + + self._updateItems(0, self.size()) + + def reverse(self): + self.items.reverse() + self._updateItems(0, self.size()) + + def getManagedItemPosition(self, mli): + return self.items.index(mli) + + def isLastItem(self, mli=None): + return self.getManagedItemPosition(mli or self.getSelectedItem()) + 1 == len(self) + + def getListItemFromManagedItem(self, mli): + pos = self.items.index(mli) + return self.control.getListItem(pos) + + def topHasFocus(self): + return self.getSelectedPosition() == 0 + + def bottomHasFocus(self): + return self.getSelectedPosition() == self.size() - 1 + + def invalidate(self): + for item in self.items: + item._listItem = DUMMY_LIST_ITEM + + def newControl(self, window=None, control_id=None): + self.controlID = control_id or self.controlID + self.control = window.getControl(self.controlID) + self.control.addItems([xbmcgui.ListItem() for i in range(self.size())]) + self._updateItems() + + +class _MWBackground(ControlledWindow): + def __init__(self, *args, **kwargs): + self._multiWindow = kwargs.get('multi_window') + self.started = False + BaseWindow.__init__(self, *args, **kwargs) + + def onInit(self): + if self.started: + return + self.started = True + self._multiWindow._open() + self.close() + + +class MultiWindow(object): + def __init__(self, windows=None, default_window=None, **kwargs): + self._windows = windows + self._next = default_window or self._windows[0] + self._properties = {} + self._current = None + self._allClosed = False + self.exitCommand = None + + def __getattr__(self, name): + return getattr(self._current, name) + + def setWindows(self, windows): + self._windows = windows + + def setDefault(self, default): + self._next = default or self._windows[0] + + def windowIndex(self, window): + if hasattr(window, 'MULTI_WINDOW_ID'): + for i, w in enumerate(self._windows): + if window.MULTI_WINDOW_ID == w.MULTI_WINDOW_ID: + return i + return 0 + else: + return self._windows.index(window.__class__) + + def nextWindow(self, window=None): + if window is False: + window = self._windows[self.windowIndex(self._current)] + + if window: + if window.__class__ == self._current.__class__: + return None + else: + idx = self.windowIndex(self._current) + idx += 1 + if idx >= len(self._windows): + idx = 0 + window = self._windows[idx] + + self._next = window + self._current.doClose() + return self._next + + def _setupCurrent(self, cls): + self._current = cls(cls.xmlFile, cls.path, cls.theme, cls.res) + self._current.onFirstInit = self._onFirstInit + self._current.onReInit = self.onReInit + self._current.onClick = self.onClick + self._current.onFocus = self.onFocus + + self._currentOnAction = self._current.onAction + self._current.onAction = self.onAction + + @classmethod + def open(cls, **kwargs): + mw = cls(**kwargs) + b = _MWBackground(mw.bgXML, mw.path, mw.theme, mw.res, multi_window=mw) + b.modal() + del b + import gc + gc.collect(2) + return mw + + def _open(self): + while not MONITOR.abortRequested() and not self._allClosed: + self._setupCurrent(self._next) + self._current.modal() + + self._current.doClose() + del self._current + del self._next + del self._currentOnAction + + def setProperty(self, key, value): + self._properties[key] = value + self._current.setProperty(key, value) + + def _onFirstInit(self): + for k, v in self._properties.items(): + self._current.setProperty(k, v) + self.onFirstInit() + + def doClose(self): + self._allClosed = True + self._current.doClose() + + def onFirstInit(self): + pass + + def onReInit(self): + pass + + def onAction(self, action): + if action == xbmcgui.ACTION_PREVIOUS_MENU or action == xbmcgui.ACTION_NAV_BACK: + self.doClose() + self._currentOnAction(action) + + def onClick(self, controlID): + pass + + def onFocus(self, controlID): + pass + + +class SafeControlEdit(object): + CHARS_LOWER = 'abcdefghijklmnopqrstuvwxyz' + CHARS_UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + CHARS_NUMBERS = '0123456789' + CURSOR = '[COLOR FFCC7B19]|[/COLOR]' + + def __init__(self, control_id, label_id, window, key_callback=None, grab_focus=False): + self.controlID = control_id + self.labelID = label_id + self._win = window + self._keyCallback = key_callback + self.grabFocus = grab_focus + self._text = '' + self._compatibleMode = False + self.setup() + + def setup(self): + self._labelControl = self._win.getControl(self.labelID) + self._winOnAction = self._win.onAction + self._win.onAction = self.onAction + self.updateLabel() + + def setCompatibleMode(self, on): + self._compatibleMode = on + + def onAction(self, action): + try: + controlID = self._win.getFocusId() + if controlID == self.controlID: + if self.processAction(action.getId()): + return + elif self.grabFocus: + if self.processOffControlAction(action.getButtonCode()): + self._win.setFocusId(self.controlID) + return + except: + traceback.print_exc() + + self._winOnAction(action) + + def processAction(self, action_id): + if not self._compatibleMode: + oldVal = self._text + self._text = self._win.getControl(self.controlID).getText() + + if self._keyCallback: + self._keyCallback(action_id, oldVal, self._text) + + self.updateLabel() + + return True + oldVal = self.getText() + + if 61793 <= action_id <= 61818: # Lowercase + self.processChar(self.CHARS_LOWER[action_id - 61793]) + elif 61761 <= action_id <= 61786: # Uppercase + self.processChar(self.CHARS_UPPER[action_id - 61761]) + elif 61744 <= action_id <= 61753: + self.processChar(self.CHARS_NUMBERS[action_id - 61744]) + elif action_id == 61728: # Space + self.processChar(' ') + elif action_id == 61448: + self.delete() + else: + return False + + if self._keyCallback: + self._keyCallback(action_id, oldVal, self.getText()) + + return True + + def processOffControlAction(self, action_id): + oldVal = self.getText() if self._compatibleMode else self._text + if 61505 <= action_id <= 61530: # Lowercase + self.processChar(self.CHARS_LOWER[action_id - 61505]) + elif 192577 <= action_id <= 192602: # Uppercase + self.processChar(self.CHARS_UPPER[action_id - 192577]) + elif 61488 <= action_id <= 61497: + self.processChar(self.CHARS_NUMBERS[action_id - 61488]) + elif 61552 <= action_id <= 61561: + self.processChar(self.CHARS_NUMBERS[action_id - 61552]) + elif action_id == 61472: # Space + self.processChar(' ') + else: + return False + + if self._keyCallback: + self._keyCallback(action_id, oldVal, self.getText()) + + return True + + def _setText(self, text): + self._text = text + + if not self._compatibleMode: + self._win.getControl(self.controlID).setText(text) + self.updateLabel() + + def _getText(self): + if not self._compatibleMode and self._win.getFocusId() == self.controlID: + return self._win.getControl(self.controlID).getText() + else: + return self._text + + def updateLabel(self): + self._labelControl.setLabel(self._getText() + self.CURSOR) + + def processChar(self, char): + self._setText(self.getText() + char) + + def setText(self, text): + self._setText(text) + + def getText(self): + return self._getText() + + def append(self, text): + self._setText(self.getText() + text) + + def delete(self): + self._setText(self.getText()[:-1]) + + +class PropertyTimer(): + def __init__(self, window_id, timeout, property_, value='', init_value='1', addon_id=None, callback=None): + self._winID = window_id + self._timeout = timeout + self._property = property_ + self._value = value + self._initValue = init_value + self._endTime = 0 + self._thread = None + self._addonID = addon_id + self._closeWin = None + self._closed = False + self._callback = callback + + def _onTimeout(self): + self._endTime = 0 + xbmcgui.Window(self._winID).setProperty(self._property, self._value) + if self._addonID: + xbmcgui.Window(10000).setProperty('{0}.{1}'.format(self._addonID, self._property), self._value) + if self._closeWin: + self._closeWin.doClose() + if self._callback: + self._callback() + + def _wait(self): + while not MONITOR.abortRequested() and time.time() < self._endTime: + xbmc.sleep(100) + if MONITOR.abortRequested(): + return + if self._endTime == 0: + return + self._onTimeout() + + def _stopped(self): + return not self._thread or not self._thread.is_alive() + + def _reset(self): + self._endTime = time.time() + self._timeout + + def _start(self): + self.init(self._initValue) + self._thread = threading.Thread(target=self._wait) + self._thread.start() + + def stop(self, trigger=False): + self._endTime = trigger and 1 or 0 + if not self._stopped(): + self._thread.join() + + def close(self): + self._closed = True + self.stop() + + def init(self, val): + if val is False: + return + elif val is None: + val = self._initValue + + xbmcgui.Window(self._winID).setProperty(self._property, val) + if self._addonID: + xbmcgui.Window(10000).setProperty('{0}.{1}'.format(self._addonID, self._property), val) + + def reset(self, close_win=None, init=None): + self.init(init) + + if self._closed: + return + + if not self._timeout: + return + + self._closeWin = close_win + self._reset() + + if self._stopped: + self._start() + + +class WindowProperty(): + def __init__(self, win, prop, val='1', end=None): + self.win = win + self.prop = prop + self.val = val + self.end = end + self.old = self.win.getProperty(self.prop) + + def __enter__(self): + self.win.setProperty(self.prop, self.val) + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.win.setProperty(self.prop, self.end or self.old) + + +class GlobalProperty(): + def __init__(self, prop, val='1', end=None): + from kodi_six import xbmcaddon + self._addonID = xbmcaddon.Addon().getAddonInfo('id') + self.prop = prop + self.val = val + self.end = end + self.old = xbmc.getInfoLabel('Window(10000).Property({0}}.{1})'.format(self._addonID, prop)) + + def __enter__(self): + xbmcgui.Window(10000).setProperty('{0}.{1}'.format(self._addonID, self.prop), self.val) + return self + + def __exit__(self, exc_type, exc_value, traceback): + xbmcgui.Window(10000).setProperty('{0}.{1}'.format(self._addonID, self.prop), self.end or self.old) diff --git a/script.plexmod/lib/windows/library.py b/script.plexmod/lib/windows/library.py new file mode 100644 index 0000000000..62245203ad --- /dev/null +++ b/script.plexmod/lib/windows/library.py @@ -0,0 +1,1868 @@ +from __future__ import absolute_import +import os +import random +import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error +import json +import time +import threading + +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import kodigui + +from lib import util +from lib import backgroundthread +from lib import player + +from . import busy +from . import subitems +from . import preplay +from . import search +import plexnet +from . import dropdown +from . import opener +from . import windowutils + +from plexnet import playqueue + +from lib.util import T +import six +from six.moves import range + +CHUNK_SIZE = 200 +# CHUNK_SIZE = 30 + +KEYS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + +MOVE_SET = frozenset( + ( + xbmcgui.ACTION_MOVE_LEFT, + xbmcgui.ACTION_MOVE_RIGHT, + xbmcgui.ACTION_MOVE_UP, + xbmcgui.ACTION_MOVE_DOWN, + xbmcgui.ACTION_MOUSE_MOVE, + xbmcgui.ACTION_PAGE_UP, + xbmcgui.ACTION_PAGE_DOWN, + xbmcgui.ACTION_FIRST_PAGE, + xbmcgui.ACTION_LAST_PAGE, + xbmcgui.ACTION_MOUSE_WHEEL_DOWN, + xbmcgui.ACTION_MOUSE_WHEEL_UP + ) +) + +THUMB_POSTER_DIM = util.scaleResolution(268, 397) +THUMB_AR16X9_DIM = util.scaleResolution(619, 348) +THUMB_SQUARE_DIM = util.scaleResolution(355, 355) +ART_AR16X9_DIM = util.scaleResolution(630, 355) + +TYPE_KEYS = { + 'episode': { + 'fallback': 'show', + 'thumb_dim': THUMB_POSTER_DIM, + }, + 'season': { + 'fallback': 'show', + 'thumb_dim': THUMB_POSTER_DIM + }, + 'movie': { + 'fallback': 'movie', + 'thumb_dim': THUMB_POSTER_DIM, + 'art_dim': ART_AR16X9_DIM + }, + 'show': { + 'fallback': 'show', + 'thumb_dim': THUMB_POSTER_DIM, + 'art_dim': ART_AR16X9_DIM + }, + 'collection': { + 'fallback': 'movie', + 'thumb_dim': THUMB_POSTER_DIM, + 'art_dim': ART_AR16X9_DIM + }, + 'album': { + 'fallback': 'music', + 'thumb_dim': THUMB_SQUARE_DIM + }, + 'artist': { + 'fallback': 'music', + 'thumb_dim': THUMB_SQUARE_DIM + }, + 'track': { + 'fallback': 'music', + 'thumb_dim': THUMB_SQUARE_DIM + }, + 'photo': { + 'fallback': 'photo', + 'thumb_dim': THUMB_SQUARE_DIM + }, + 'clip': { + 'fallback': 'movie16x9', + 'thumb_dim': THUMB_POSTER_DIM + }, +} + +TYPE_PLURAL = { + 'artist': T(32347, 'artists'), + 'album': T(32461, 'albums'), + 'movie': T(32348, 'Movies'), + 'photo': T(32349, 'photos'), + 'show': T(32350, 'Shows'), + 'episode': T(32458, 'Episodes'), + 'collection': T(32490, 'Collections'), + 'folder': T(32491, 'Folders'), +} + +SORT_KEYS = { + 'movie': { + 'titleSort': {'title': T(32357, 'By Name'), 'display': T(32358, 'Name'), 'defSortDesc': False}, + 'addedAt': {'title': T(32351, 'By Date Added'), 'display': T(32352, 'Date Added'), 'defSortDesc': True}, + 'originallyAvailableAt': {'title': T(32353, 'By Release Date'), 'display': T(32354, 'Release Date'), + 'defSortDesc': True}, + 'lastViewedAt': {'title': T(32355, 'By Date Viewed'), 'display': T(32356, 'Date Viewed'), 'defSortDesc': True}, + 'rating': {'title': T(33107, 'By Critic Rating'), 'display': T(33108, ' Critic Rating'), 'defSortDesc': True}, + 'audienceRating': {'title': T(33101, 'By Audience Rating'), 'display': T(33102, 'Audience Rating'), + 'defSortDesc': True}, + # called "Rating" in PlexWeb, using more obvious "This is this user's rating" here + 'userRating': {'title': T(33103, 'By my Rating'), 'display': T(33104, 'My Rating'), 'defSortDesc': True}, + 'contentRating': {'title': T(33105, 'By Content Rating'), 'display': T(33106, 'Content Rating'), + 'defSortDesc': True}, + 'resolution': {'title': T(32361, 'By Resolution'), 'display': T(32362, 'Resolution'), 'defSortDesc': True}, + 'duration': {'title': T(32363, 'By Duration'), 'display': T(32364, 'Duration'), 'defSortDesc': True}, + 'unwatched': {'title': T(32367, 'By Unplayed'), 'display': T(32368, 'Unplayed'), 'defSortDesc': False}, + 'viewCount': {'title': T(32371, 'By Play Count'), 'display': T(32372, 'Play Count'), 'defSortDesc': True} + }, + 'show': { + 'titleSort': {'title': T(32357, 'By Name'), 'display': T(32358, 'Name'), 'defSortDesc': False}, + 'show.titleSort': {'title': T(32457, 'By Show'), 'display': T(32456, 'Show'), 'defSortDesc': False}, + 'originallyAvailableAt': {'title': T(32365, 'By First Aired'), 'display': T(32366, 'First Aired'), + 'defSortDesc': False}, + 'unviewedLeafCount': {'title': T(32367, 'By Unplayed'), 'display': T(32368, 'Unplayed'), 'defSortDesc': True}, + 'rating': {'title': T(33107, 'By Critic Rating'), 'display': T(33108, ' Critic Rating'), 'defSortDesc': True}, + 'audienceRating': {'title': T(33101, 'By Audience Rating'), 'display': T(33102, 'Audience Rating'), + 'defSortDesc': True}, + # called "Rating" in PlexWeb, using more obvious "This is this user's rating" here + 'userRating': {'title': T(33103, 'By my Rating'), 'display': T(33104, 'My Rating'), 'defSortDesc': True}, + 'contentRating': {'title': T(33105, 'By Content Rating'), 'display': T(33106, 'Content Rating'), + 'defSortDesc': True}, + }, + 'artist': { + 'titleSort': {'title': T(32357, 'By Name'), 'display': T(32358, 'Name'), 'defSortDesc': False}, + 'artist.titleSort': {'title': T(32463, 'By Artist'), 'display': T(32462, 'Artist'), 'defSortDesc': False}, + 'lastViewedAt': {'title': T(32369, 'By Date Played'), 'display': T(32370, 'Date Played'), 'defSortDesc': False}, + }, + 'photo': { + 'titleSort': {'title': T(32357, 'By Name'), 'display': T(32358, 'Name'), 'defSortDesc': False}, + 'originallyAvailableAt': {'title': T(32373, 'By Date Taken'), 'display': T(32374, 'Date Taken'), + 'defSortDesc': True} + }, + 'photodirectory': {}, + 'collection': {} +} + +ITEM_TYPE = None + + +def setItemType(type_=None): + assert type_ is not None, "Invalid type: None" + global ITEM_TYPE + ITEM_TYPE = type_ + util.setGlobalProperty('item.type', str(ITEM_TYPE)) + + +class ChunkRequestTask(backgroundthread.Task): + def setup(self, section, start, size, callback, filter_=None, sort=None, unwatched=False, subDir=False): + self.section = section + self.start = start + self.size = size + self.callback = callback + self.filter = filter_ + self.sort = sort + self.unwatched = unwatched + self.subDir = subDir + return self + + def contains(self, pos): + return self.start <= pos <= (self.start + self.size) + + def run(self): + if self.isCanceled(): + return + + try: + type_ = None + if ITEM_TYPE == 'episode': + type_ = 4 + elif ITEM_TYPE == 'album': + type_ = 9 + elif ITEM_TYPE == 'collection': + type_ = 18 + + if ITEM_TYPE == 'folder': + items = self.section.folder(self.start, self.size, self.subDir) + else: + items = self.section.all(self.start, self.size, self.filter, self.sort, self.unwatched, type_=type_) + + if self.isCanceled(): + return + self.callback(items, self.start) + except plexnet.exceptions.BadRequest: + util.DEBUG_LOG('404 on section: {0}'.format(repr(self.section.title))) + + +class PhotoPropertiesTask(backgroundthread.Task): + def setup(self, photo, callback): + self.photo = photo + self.callback = callback + return self + + def run(self): + if self.isCanceled(): + return + + try: + self.photo.reload() + self.callback(self.photo) + except plexnet.exceptions.BadRequest: + util.DEBUG_LOG('404 on photo reload: {0}'.format(self.photo)) + + +class LibrarySettings(object): + def __init__(self, section_or_server_id, ignoreLibrarySettings=False): + self.ignoreLibrarySettings = ignoreLibrarySettings + if isinstance(section_or_server_id, six.string_types): + self.serverID = section_or_server_id + self.sectionID = None + else: + self.serverID = section_or_server_id.getServer().uuid + self.sectionID = section_or_server_id.key + + self._loadSettings() + + def _loadSettings(self): + if self.ignoreLibrarySettings: + self._settings = {} + return + + if not self.sectionID: + return + + jsonString = util.getSetting('library.settings.{0}'.format(self.serverID), '') + self._settings = {} + try: + self._settings = json.loads(jsonString) + except ValueError: + pass + except: + util.ERROR() + + setItemType(self.getItemType() or ITEM_TYPE) + + def getItemType(self): + if not self._settings or self.sectionID not in self._settings: + return None + + return self._settings[self.sectionID].get('ITEM_TYPE') + + def setItemType(self, item_type): + setItemType(item_type) + + if self.sectionID not in self._settings: + self._settings[self.sectionID] = {} + + self._settings[self.sectionID]['ITEM_TYPE'] = item_type + + self._saveSettings() + + def _saveSettings(self): + jsonString = json.dumps(self._settings) + util.setSetting('library.settings.{0}'.format(self.serverID), jsonString) + + def setSection(self, section_id): + self.sectionID = section_id + + def getSetting(self, setting, default=None): + if not self._settings or self.sectionID not in self._settings: + return default + + if ITEM_TYPE not in self._settings[self.sectionID]: + return default + + return self._settings[self.sectionID][ITEM_TYPE].get(setting, default) + + def setSetting(self, setting, value): + if self.sectionID not in self._settings: + self._settings[self.sectionID] = {} + + if ITEM_TYPE not in self._settings[self.sectionID]: + self._settings[self.sectionID][ITEM_TYPE] = {} + + self._settings[self.sectionID][ITEM_TYPE][setting] = value + + self._saveSettings() + + +class ChunkedWrapList(kodigui.ManagedControlList): + LIST_MAX = CHUNK_SIZE * 3 + + def __getitem__(self, idx): + # if isinstance(idx, slice): + # return self.items[idx] + # else: + idx = idx % self.LIST_MAX + return self.items[idx] + # return self.getListItem(idx) + + +class ChunkModeWrapped(object): + ALL_MAX = CHUNK_SIZE * 2 + + def __init__(self): + self.reset() + + def reset(self): + self.midStart = 0 + self.itemCount = 0 + self.keys = {} + + def addKeyRange(self, key, krange): + self.keys[key] = krange + + def getKey(self, pos): + for k, krange in self.keys.items(): + if krange[0] <= pos <= krange[1]: + return k + + def isAtBeginning(self): + return self.midStart == 0 + + def posIsForward(self, pos): + if self.itemCount <= self.ALL_MAX: + return False + return pos >= self.midStart + CHUNK_SIZE + + def posIsBackward(self, pos): + if self.itemCount <= self.ALL_MAX: + return False + return pos < self.midStart + + def posIsValid(self, pos): + return self.midStart - CHUNK_SIZE <= pos < self.midStart + (CHUNK_SIZE * 2) + + def shift(self, mod): + if mod < 0 and self.midStart == 0: + return None + elif mod > 0 and self.midStart + CHUNK_SIZE >= self.itemCount: + return None + + offset = CHUNK_SIZE * mod + self.midStart += offset + start = self.midStart + offset + + return start + + def shiftToKey(self, key, keyStart=None): + if keyStart is None: + if key not in self.keys: + util.DEBUG_LOG('CHUNK MODE: NO ITEMS FOR KEY') + return + + keyStart = self.keys[key][0] + self.midStart = keyStart - keyStart % CHUNK_SIZE + return keyStart, max(self.midStart - CHUNK_SIZE, 0) + + def addObjects(self, pos, objects): + if not self.posIsValid(pos): + return + + if pos == self.midStart - CHUNK_SIZE: + self.objects = objects + self.objects[CHUNK_SIZE:] + elif pos == self.midStart: + self.objects = self.objects[:CHUNK_SIZE] + objects + self.objects[CHUNK_SIZE * 2:] + elif pos == self.midStart + CHUNK_SIZE: + self.objects = self.objects[:CHUNK_SIZE * 2] + objects + + +class CustomScrollBar(object): + def __init__(self, window, bar_group_id, bar_image_id, bar_image_focus_id, button_id, min_bar_height=20): + self._barGroup = window.getControl(bar_group_id) + self._barImage = window.getControl(bar_image_id) + self._barImageFocus = window.getControl(bar_image_focus_id) + self._button = window.getControl(button_id) + self.height = self._button.getHeight() + self.x, self.y = self._barGroup.getPosition() + self._minBarHeight = min_bar_height + self._barHeight = min_bar_height + self.reset() + + def reset(self): + self.size = 0 + self.count = 0 + self.pos = 0 + + def setSizeAndCount(self, size, count): + self.size = size + self.count = count + self._barHeight = min(self.height, max(self._minBarHeight, int(self.height * (count / float(size))))) + self._moveHeight = self.height - self._barHeight + self._barImage.setHeight(self._barHeight) + self._barImageFocus.setHeight(self._barHeight) + self.setPosition(0) + + def setPosition(self, pos): + self.pos = pos + offset = int((pos / float(max(self.size, 2) - 1)) * self._moveHeight) + self._barGroup.setPosition(self.x, self.y + offset) + + def getPosFromY(self, y): + y -= int(self._barHeight / 2) + 150 + y = min(max(y, 0), self._moveHeight) + return int((self.size - 1) * (y / float(self._moveHeight))) + + def onMouseDrag(self, window, action): + y = window.mouseYTrans(action.getAmount2()) + y -= int(self._barHeight / 2) + 150 + y = min(max(y, 0), self._moveHeight) + self._barGroup.setPosition(self.x, self.y) + + +class LibraryWindow(kodigui.MultiWindow, windowutils.UtilMixin): + bgXML = 'script-plex-blank.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + + def __init__(self, *args, **kwargs): + kodigui.MultiWindow.__init__(self, *args, **kwargs) + windowutils.UtilMixin.__init__(self) + self.section = kwargs.get('section') + self.filter = kwargs.get('filter_') + self.subDir = kwargs.get('subDir') + self.keyItems = {} + self.firstOfKeyItems = {} + self.tasks = backgroundthread.Tasks() + self.backgroundSet = False + self.showPanelControl = None + self.keyListControl = None + self.lastItem = None + self.lastFocusID = None + self.lastNonOptionsFocusID = None + self.refill = False + + self.dcpjPos = 0 + self.dcpjThread = None + self.dcpjTimeout = 0 + + self.dragging = False + + self.cleared = True + self.librarySettings = LibrarySettings(self.section, + ignoreLibrarySettings=kwargs.get("ignoreLibrarySettings", False)) + self.reset() + + self.lock = threading.Lock() + + def reset(self): + util.setGlobalProperty('sort', '') + self.filterUnwatched = self.librarySettings.getSetting('filter.unwatched', False) + self.sort = self.librarySettings.getSetting('sort', 'titleSort') + self.sortDesc = self.librarySettings.getSetting('sort.desc', False) + + self.chunkMode = None + #if ITEM_TYPE in ('episode', 'album'): + # self.chunkMode = ChunkModeWrapped() + + key = self.section.key + if not key.isdigit(): + key = self.section.getLibrarySectionId() + viewtype = util.getSetting('viewtype.{0}.{1}'.format(self.section.server.uuid, key)) + + if self.chunkMode: + if self.section.TYPE in ('artist', 'photo', 'photodirectory'): + self.setWindows(VIEWS_SQUARE_CHUNKED.get('all')) + self.setDefault(VIEWS_SQUARE_CHUNKED.get(viewtype)) + else: + self.setWindows(VIEWS_POSTER_CHUNKED.get('all')) + self.setDefault(VIEWS_POSTER_CHUNKED.get(viewtype)) + else: + if self.section.TYPE in ('artist', 'photo', 'photodirectory'): + self.setWindows(VIEWS_SQUARE.get('all')) + self.setDefault(VIEWS_SQUARE.get(viewtype)) + else: + self.setWindows(VIEWS_POSTER.get('all')) + self.setDefault(VIEWS_POSTER.get(viewtype)) + + @busy.dialog() + def doClose(self): + self.tasks.kill() + kodigui.MultiWindow.doClose(self) + + def onFirstInit(self): + self.scrollBar = None + #if ITEM_TYPE in ('episode', 'album'): + # self.scrollBar = CustomScrollBar(self, 950, 952, 953, 951) + + if self.showPanelControl and not self.refill: + self.showPanelControl.newControl(self) + self.keyListControl.newControl(self) + self.showPanelControl.selectItem(0) + self.setFocusId(self.VIEWTYPE_BUTTON_ID) + self.setBoolProperty("initialized", True) + else: + if self.chunkMode: + self.showPanelControl = ChunkedWrapList(self, self.POSTERS_PANEL_ID, 5) + else: + self.showPanelControl = kodigui.ManagedControlList(self, self.POSTERS_PANEL_ID, 5) + + hideFilterOptions = self.section.TYPE == 'photodirectory' or self.section.TYPE == 'collection' + + self.keyListControl = kodigui.ManagedControlList(self, self.KEY_LIST_ID, 27) + self.setProperty('subDir', self.subDir and '1' or '') + self.setProperty('no.options', self.section.TYPE != 'photodirectory' and '1' or '') + self.setProperty('unwatched.hascount', self.section.TYPE == 'show' and '1' or '') + util.setGlobalProperty('sort', self.sort) + self.setProperty('filter1.display', self.filterUnwatched and T(32368, 'UNPLAYED') or T(32345, 'All')) + self.setProperty('sort.display', SORT_KEYS[self.section.TYPE].get(self.sort, SORT_KEYS['movie'].get(self.sort))['title']) + self.setProperty('media.itemType', ITEM_TYPE or self.section.TYPE) + self.setProperty('media.type', TYPE_PLURAL.get(ITEM_TYPE or self.section.TYPE, self.section.TYPE)) + self.setProperty('media', self.section.TYPE) + self.setProperty('hide.filteroptions', hideFilterOptions and '1' or '') + + self.setTitle() + self.setBoolProperty("initialized", True) + self.fill() + self.refill = False + if self.getProperty('no.content') or self.getProperty('no.content.filtered'): + self.setFocusId(self.HOME_BUTTON_ID) + else: + self.setFocusId(self.POSTERS_PANEL_ID) + + def onAction(self, action): + try: + if self.dragging: + if not action == xbmcgui.ACTION_MOUSE_DRAG: + self.dragging = False + self.setBoolProperty('dragging', self.dragging) + + if action.getId() in MOVE_SET: + if util.advancedSettings.dynamicBackgrounds: + mli = self.showPanelControl.getSelectedItem() + if mli and mli.dataSource: + self.updateBackgroundFrom(mli.dataSource) + + controlID = self.getFocusId() + if controlID == self.POSTERS_PANEL_ID or controlID == self.SCROLLBAR_ID: + self.updateKey() + self.checkChunkedNav(action) + elif controlID == self.CUSTOM_SCOLLBAR_BUTTON_ID: + if action == xbmcgui.ACTION_MOVE_UP: + self.shiftSelection(-12) + elif action == xbmcgui.ACTION_MOVE_DOWN: + self.shiftSelection(12) + # elif action == xbmcgui.KEY_MOUSE_DRAG_START: + # self.onMouseDragStart(action) + # elif action == xbmcgui.KEY_MOUSE_DRAG_END: + # self.onMouseDragEnd(action) + elif action == xbmcgui.ACTION_MOUSE_DRAG: + self.onMouseDrag(action) + elif action == xbmcgui.ACTION_CONTEXT_MENU: + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)): + self.lastNonOptionsFocusID = self.lastFocusID + self.setFocusId(self.OPTIONS_GROUP_ID) + return + else: + if self.lastNonOptionsFocusID: + self.setFocusId(self.lastNonOptionsFocusID) + self.lastNonOptionsFocusID = None + return + + elif action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_CONTEXT_MENU): + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)) and \ + (not util.advancedSettings.fastBack or action == xbmcgui.ACTION_CONTEXT_MENU): + if xbmc.getCondVisibility('Integer.IsGreater(Container(101).ListItem.Property(index),5)'): + self.showPanelControl.selectItem(0) + return + + self.updateItem() + + except: + util.ERROR() + + kodigui.MultiWindow.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.HOME_BUTTON_ID: + self.goHome() + elif controlID == self.POSTERS_PANEL_ID: + self.showPanelClicked() + elif controlID == self.KEY_LIST_ID: + self.keyClicked() + elif controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() + elif controlID == self.PLAY_BUTTON_ID: + self.playButtonClicked() + elif controlID == self.SHUFFLE_BUTTON_ID: + self.shuffleButtonClicked() + elif controlID == self.OPTIONS_BUTTON_ID: + self.optionsButtonClicked() + elif controlID == self.VIEWTYPE_BUTTON_ID: + self.viewTypeButtonClicked() + elif controlID == self.SORT_BUTTON_ID: + self.sortButtonClicked() + elif controlID == self.FILTER1_BUTTON_ID: + self.filter1ButtonClicked() + elif controlID == self.ITEM_TYPE_BUTTON_ID: + self.itemTypeButtonClicked() + elif controlID == self.SEARCH_BUTTON_ID: + self.searchButtonClicked() + + def onFocus(self, controlID): + self.lastFocusID = controlID + + if controlID == self.KEY_LIST_ID: + self.selectKey() + + if player.PLAYER.bgmPlaying: + player.PLAYER.stopAndWait() + + def onItemChanged(self, mli): + if not mli: + return + + if not mli.dataSource or not mli.dataSource.TYPE == 'photo': + return + + self.showPhotoItemProperties(mli.dataSource) + + def onMouseDragStart(self, action): + if not self.scrollBar: + return + + controlID = self.getFocusId() + if controlID != self.CUSTOM_SCOLLBAR_BUTTON_ID: + return + + self.dragging = True + self.setBoolProperty('dragging', self.dragging) + + def onMouseDragEnd(self, action): + if not self.scrollBar: + return + + if not self.dragging: + return + + self.dragging = False + self.setBoolProperty('dragging', self.dragging) + + y = self.mouseYTrans(action.getAmount2()) + + pos = self.scrollBar.getPosFromY(y) + self.shiftSelection(pos=pos) + + def onMouseDrag(self, action): + if not self.scrollBar: + return + + if not self.dragging: + controlID = self.getFocusId() + if controlID != self.CUSTOM_SCOLLBAR_BUTTON_ID: + return + + self.onMouseDragStart(action) + if not self.dragging: + return + + # self.scrollBar.onMouseDrag(self, action) + + y = self.mouseYTrans(action.getAmount2()) + + pos = self.scrollBar.getPosFromY(y) + if self.chunkMode.posIsForward(pos) or self.chunkMode.posIsBackward(pos): + self.shiftSelection(pos=pos) + else: + self.showPanelControl.selectItem(pos) + self.checkChunkedNav() + + def shiftSelection(self, offset=0, pos=None): + if pos is not None: + self.scrollBar.setPosition(pos) + return self.delayedChunkedPosJump(pos) + else: + mli = self.showPanelControl.getSelectedItem() + + try: + idx = int(mli.getProperty('index')) + except ValueError: + return + + target = idx + offset + if target >= self.chunkMode.itemCount: + pos = self.chunkMode.itemCount - 1 + elif target < 0: + pos = 0 + else: + pos = self.showPanelControl.getSelectedPosition() + pos += offset + + if pos < 0 or pos >= self.showPanelControl.size(): + pos = pos % self.showPanelControl.size() + + self.showPanelControl.selectItem(pos) + self.checkChunkedNav(idx=pos) + + def updateKey(self, mli=None): + mli = mli or self.showPanelControl.getSelectedItem() + if not mli: + return + + if self.lastItem != mli: + self.lastItem = mli + self.onItemChanged(mli) + + util.setGlobalProperty('key', mli.getProperty('key')) + + self.selectKey(mli) + + def checkChunkedNav(self, action=None, idx=None): + if not self.chunkMode: + return + + # if action == xbmcgui.ACTION_PAGE_DOWN: + # idx = self.showPanelControl.getSelectedPosition() - 5 + # if idx < 0: + # idx += self.showPanelControl.size() + # mli = self.showPanelControl.getListItem(idx) + # self.showPanelControl.selectItem(idx) + # elif action == xbmcgui.ACTION_PAGE_UP: + # idx = self.showPanelControl.getSelectedPosition() + 5 + # if idx >= self.showPanelControl.size(): + # idx %= self.showPanelControl.size() + # mli = self.showPanelControl.getListItem(idx) + # self.showPanelControl.selectItem(idx) + # else: + mli = self.showPanelControl.getSelectedItem() + + try: + if idx is not None: + pos = int(self.showPanelControl[idx].getProperty('index')) + else: + pos = int(mli.getProperty('index')) + + if pos >= self.chunkMode.itemCount: + raise ValueError + except ValueError: + if self.chunkMode.isAtBeginning() and action not in (xbmcgui.ACTION_MOVE_DOWN, xbmcgui.ACTION_PAGE_DOWN): + idx = 0 + else: + idx = ((self.chunkMode.itemCount - 1) % self.showPanelControl.LIST_MAX) + + self.showPanelControl.selectItem(idx) + mli = self.showPanelControl[idx] + self.updateKey(mli) + if self.scrollBar: + try: + pos = int(mli.getProperty('index')) + self.scrollBar.setPosition(pos) + except ValueError: + pass + + if idx == 0 and action == xbmcgui.ACTION_MOVE_UP: + self.setFocusId(600) + + return + + if self.scrollBar: + self.scrollBar.setPosition(pos) + + if self.chunkMode.posIsForward(pos): + self.shiftChunks() + elif self.chunkMode.posIsBackward(pos): + self.shiftChunks(-1) + + def shiftChunks(self, mod=1): + start = self.chunkMode.shift(mod) + if start is None: + return + + if start < 0: + self.chunkCallback([None] * CHUNK_SIZE, -CHUNK_SIZE) + else: + self.chunkCallback([False] * CHUNK_SIZE, start) + task = ChunkRequestTask().setup( + self.section, start, CHUNK_SIZE, self.chunkCallback, filter_=self.getFilterOpts(), sort=self.getSortOpts(), unwatched=self.filterUnwatched, subDir=self.subDir + ) + + self.tasks.add(task) + backgroundthread.BGThreader.addTasksToFront([task]) + + def selectKey(self, mli=None): + if not mli: + mli = self.showPanelControl.getSelectedItem() + if not mli: + return + + li = self.keyItems.get(mli.getProperty('key')) + if not li: + return + self.keyListControl.selectItem(li.pos()) + + def searchButtonClicked(self): + self.processCommand(search.dialog(self, section_id=self.section.key)) + + def delayedChunkedPosJump(self, pos): + if not self.cleared: + self.chunkCallback(None, None, clear=True) + self.dcpjTimeout = time.time() + 0.5 + self.dcpjPos = pos + if not self.dcpjThread or not self.dcpjThread.is_alive(): + self.dcpjThread = threading.Thread(target=self._chunkedPosJump) + self.dcpjThread.start() + + def _chunkedPosJump(self): + while not util.MONITOR.waitForAbort(0.1): + if time.time() >= self.dcpjTimeout: + break + else: + return + + keyStart_start = self.chunkMode.shiftToKey(None, keyStart=self.dcpjPos) + if not keyStart_start: + return + + keyStart, start = keyStart_start + pos = keyStart % self.showPanelControl.LIST_MAX + self.chunkedPosJump(pos, start) + self.showPanelControl.selectItem(pos) + + def chunkedPosJump(self, pos, start=None): + if start is None: + start = max(pos - CHUNK_SIZE, 0) + + mul = 3 + if not start: + mul = 2 + + tasks = [] + for x in range(mul): + task = ChunkRequestTask().setup( + self.section, + start + (CHUNK_SIZE * x), + CHUNK_SIZE, + self.chunkCallback, + filter_=self.getFilterOpts(), + sort=self.getSortOpts(), + unwatched=self.filterUnwatched, + subDir=self.subDir + ) + + self.tasks.add(task) + tasks.append(task) + + mid = tasks.pop(1) + backgroundthread.BGThreader.addTasksToFront([mid] + tasks) + + def keyClicked(self): + li = self.keyListControl.getSelectedItem() + if not li: + return + + if self.chunkMode: + keyStart_start = self.chunkMode.shiftToKey(li.dataSource) + if not keyStart_start: + return + keyStart, start = keyStart_start + + pos = keyStart % self.showPanelControl.LIST_MAX + self.chunkedPosJump(pos, start) + else: + mli = self.firstOfKeyItems.get(li.dataSource) + if not mli: + return + pos = mli.pos() + + self.showPanelControl.selectItem(pos) + self.setFocusId(self.POSTERS_PANEL_ID) + util.setGlobalProperty('key', li.dataSource) + + def playButtonClicked(self, shuffle=False): + filter_ = self.getFilterOpts() + sort = self.getSortOpts() + args = {} + if filter_: + args[filter_[0]] = filter_[1] + + if sort: + args['sort'] = '{0}:{1}'.format(*sort) + + if self.section.TYPE == 'movie': + args['sourceType'] = '1' + elif self.section.TYPE == 'show': + args['sourceType'] = '2' + elif self.section.TYPE != 'collection': + args['sourceType'] = '8' + + # When the list is filtered by unwatched, play and shuffle button should only play unwatched videos + if self.filterUnwatched: + args['unwatched'] = '1' + + pq = playqueue.createPlayQueueForItem(self.section, options={'shuffle': shuffle}, args=args) + opener.open(pq) + + def shuffleButtonClicked(self): + self.playButtonClicked(shuffle=True) + + def optionsButtonClicked(self): + options = [] + if xbmc.getCondVisibility('Player.HasAudio + MusicPlayer.HasNext'): + options.append({'key': 'play_next', 'display': T(32325, 'Play Next')}) + + # if self.section.TYPE not in ('artist', 'photo', 'photodirectory'): + # options.append({'key': 'mark_watched', 'display': 'Mark All Watched'}) + # options.append({'key': 'mark_unwatched', 'display': 'Mark All Unwatched'}) + + # if xbmc.getCondVisibility('Player.HasAudio') and self.section.TYPE == 'artist': + # options.append({'key': 'add_to_queue', 'display': 'Add To Queue'}) + + # if False: + # options.append({'key': 'add_to_playlist', 'display': 'Add To Playlist'}) + + if self.section.TYPE == 'photodirectory': + if options: + options.append(dropdown.SEPARATOR) + options.append({'key': 'to_section', 'display': T(32324, u'Go to {0}').format(self.section.getLibrarySectionTitle())}) + + choice = dropdown.showDropdown(options, (255, 205)) + if not choice: + return + + if choice['key'] == 'play_next': + xbmc.executebuiltin('PlayerControl(Next)') + elif choice['key'] == 'to_section': + self.goHome(self.section.getLibrarySectionId()) + + def itemTypeButtonClicked(self): + options = [] + + if self.section.TYPE == 'show': + for t in ('show', 'episode', 'collection'): + options.append({'type': t, 'display': TYPE_PLURAL.get(t, t)}) + elif self.section.TYPE == 'movie': + for t in ('movie', 'collection', 'folder'): + options.append({'type': t, 'display': TYPE_PLURAL.get(t, t)}) + elif self.section.TYPE == 'artist': + for t in ('artist', 'album', 'collection'): + options.append({'type': t, 'display': TYPE_PLURAL.get(t, t)}) + else: + return + + result = dropdown.showDropdown(options, (1280, 106), with_indicator=True) + if not result: + return + + choice = result['type'] + + if choice == ITEM_TYPE: + return + + self.tasks.cancel() + + self.showPanelControl = None # TODO: Need to do some check here I think + + self.librarySettings.setItemType(choice) + + self.reset() + + self.clearFilters() + self.resetSort() + + if not self.nextWindow(False): + self.setProperty('media.type', TYPE_PLURAL.get(ITEM_TYPE or self.section.TYPE, self.section.TYPE)) + self.setProperty('sort.display', SORT_KEYS[self.section.TYPE].get(self.sort, SORT_KEYS['movie'].get(self.sort))['title']) + self.fill() + + def sortButtonClicked(self): + desc = 'script.plex/indicators/arrow-down.png' + asc = 'script.plex/indicators/arrow-up.png' + ind = self.sortDesc and desc or asc + + options = [] + defSortByOption = {} + + if self.section.TYPE == 'movie': + searchTypes = ['titleSort', 'addedAt', 'originallyAvailableAt', 'lastViewedAt', 'rating', 'audienceRating', + 'userRating', 'contentRating', 'resolution', 'duration'] + if ITEM_TYPE == 'collection': + searchTypes = ['titleSort', 'addedAt', 'contentRating'] + + for stype in searchTypes: + option = SORT_KEYS['movie'].get(stype).copy() + option['type'] = stype + option['indicator'] = self.sort == stype and ind or '' + defSortByOption[stype] = option.get('defSortDesc') + options.append(option) + elif self.section.TYPE == 'show': + searchTypes = ['titleSort', 'addedAt', 'lastViewedAt', 'originallyAvailableAt', 'rating', + 'audienceRating', 'userRating', 'contentRating', 'unviewedLeafCount'] + if ITEM_TYPE == 'episode': + searchTypes = ['titleSort', 'show.titleSort', 'addedAt', 'originallyAvailableAt', 'lastViewedAt', 'rating', + 'audienceRating', 'userRating'] + elif ITEM_TYPE == 'collection': + searchTypes = ['titleSort', 'addedAt'] + + for stype in searchTypes: + option = SORT_KEYS['show'].get(stype, SORT_KEYS['movie'].get(stype)).copy() + option['type'] = stype + option['indicator'] = self.sort == stype and ind or '' + defSortByOption[stype] = option.get('defSortDesc') + options.append(option) + elif self.section.TYPE == 'artist': + searchTypes = ['titleSort', 'addedAt', 'lastViewedAt', 'viewCount'] + if ITEM_TYPE == 'album': + searchTypes = ['titleSort', 'artist.titleSort', 'addedAt', 'lastViewedAt', 'viewCount', 'originallyAvailableAt', 'rating'] + elif ITEM_TYPE == 'collection': + searchTypes = ['titleSort', 'addedAt'] + + for stype in searchTypes: + option = SORT_KEYS['artist'].get(stype, SORT_KEYS['movie'].get(stype)).copy() + option['type'] = stype + option['indicator'] = self.sort == stype and ind or '' + defSortByOption[stype] = option.get('defSortDesc') + options.append(option) + elif self.section.TYPE == 'photo': + searchTypes = ['titleSort', 'addedAt', 'originallyAvailableAt', 'rating'] + for stype in searchTypes: + option = SORT_KEYS['photo'].get(stype, SORT_KEYS['movie'].get(stype)).copy() + option['type'] = stype + option['indicator'] = self.sort == stype and ind or '' + defSortByOption[stype] = option.get('defSortDesc') + options.append(option) + else: + return + + result = dropdown.showDropdown(options, (1280, 106), with_indicator=True) + if not result: + return + + choice = result['type'] + + forceRefresh = False + if choice == self.sort: + self.sortDesc = not self.sortDesc + else: + self.sortDesc = defSortByOption.get(choice, False) + if choice == 'titleSort': + forceRefresh = True + + self.sort = choice + + self.librarySettings.setSetting('sort', self.sort) + self.librarySettings.setSetting('sort.desc', self.sortDesc) + + util.setGlobalProperty('sort', choice) + self.setProperty('sort.display', result['title']) + + self.sortShowPanel(choice, forceRefresh) + + def viewTypeButtonClicked(self): + for task in self.tasks: + if task.isValid(): + task.cancel() + self.refill = True + + with self.lock: + self.showPanelControl.invalidate() + win = self.nextWindow() + + key = self.section.key + if not key.isdigit(): + key = self.section.getLibrarySectionId() + util.setSetting('viewtype.{0}.{1}'.format(self.section.server.uuid, key), win.VIEWTYPE) + + def sortShowPanel(self, choice, force_refresh=False): + if force_refresh or self.chunkMode or self.showPanelControl.size() == 0: + self.fillShows() + return + + if choice == 'addedAt': + self.showPanelControl.sort(lambda i: i.dataSource.addedAt, reverse=self.sortDesc) + elif choice == 'originallyAvailableAt': + self.showPanelControl.sort(lambda i: i.dataSource.get('originallyAvailableAt'), reverse=self.sortDesc) + elif choice == 'lastViewedAt': + self.showPanelControl.sort(lambda i: i.dataSource.get('lastViewedAt'), reverse=self.sortDesc) + elif choice == 'viewCount': + self.showPanelControl.sort(lambda i: i.dataSource.get('titleSort') or i.dataSource.title) + self.showPanelControl.sort(lambda i: i.dataSource.get('viewCount').asInt(), reverse=self.sortDesc) + elif choice == 'titleSort': + self.showPanelControl.sort(lambda i: i.dataSource.get('titleSort') or i.dataSource.title, reverse=self.sortDesc) + self.keyListControl.sort(lambda i: i.getProperty('original'), reverse=self.sortDesc) + elif choice == 'show.titleSort': + self.showPanelControl.sort(lambda i: i.label, reverse=self.sortDesc) + self.keyListControl.sort(lambda i: i.getProperty('original'), reverse=self.sortDesc) + elif choice == 'artist.titleSort': + self.showPanelControl.sort(lambda i: i.label, reverse=self.sortDesc) + self.keyListControl.sort(lambda i: i.getProperty('original'), reverse=self.sortDesc) + elif choice == 'rating': + self.showPanelControl.sort(lambda i: i.dataSource.get('titleSort') or i.dataSource.title) + self.showPanelControl.sort(lambda i: i.dataSource.get('rating').asFloat(), reverse=self.sortDesc) + elif choice == 'audienceRating': + self.showPanelControl.sort(lambda i: i.dataSource.get('titleSort') or i.dataSource.title) + self.showPanelControl.sort(lambda i: i.dataSource.get('audienceRating').asFloat(), reverse=self.sortDesc) + elif choice == 'userRating': + self.showPanelControl.sort(lambda i: i.dataSource.get('titleSort') or i.dataSource.title) + self.showPanelControl.sort(lambda i: i.dataSource.get('userRating').asFloat(), reverse=self.sortDesc) + elif choice == 'contentRating': + self.showPanelControl.sort(lambda i: i.dataSource.get('titleSort') or i.dataSource.title) + self.showPanelControl.sort(lambda i: i.dataSource.get('contentRating'), reverse=self.sortDesc) + elif choice == 'resolution': + self.showPanelControl.sort(lambda i: i.dataSource.maxHeight, reverse=self.sortDesc) + elif choice == 'duration': + self.showPanelControl.sort(lambda i: i.dataSource.duration.asInt(), reverse=self.sortDesc) + elif choice == 'unviewedLeafCount': + self.showPanelControl.sort(lambda i: i.dataSource.unViewedLeafCount, reverse=self.sortDesc) + + self.showPanelControl.selectItem(0) + self.setFocusId(self.POSTERS_PANEL_ID) + self.backgroundSet = False + self.setBackground([item.dataSource for item in self.showPanelControl], 0, randomize=not util.advancedSettings.dynamicBackgrounds) + + def subOptionCallback(self, option): + check = 'script.plex/home/device/check.png' + options = None + subKey = None + if self.filter: + if self.filter.get('sub'): + subKey = self.filter['sub']['val'] + + if option['type'] in ( + 'year', 'decade', 'genre', 'contentRating', 'collection', 'director', 'actor', 'country', 'studio', 'resolution', 'labels', + 'make', 'model', 'aperture', 'exposure', 'iso', 'lens' + ): + options = [{'val': o.key, 'display': o.title, 'indicator': o.key == subKey and check or ''} for o in self.section.listChoices(option['type'])] + if not options: + options = [{'val': None, 'display': T(32375, 'No filters available'), 'ignore': True}] + + return options + + def hasFilter(self, ftype): + if not self.filter: + return False + + return self.filter['type'] == ftype + + def filter1ButtonClicked(self): + check = 'script.plex/home/device/check.png' + + options = [] + + if self.section.TYPE in ('movie', 'show'): + options.append({'type': 'unwatched', 'display': T(32368, 'UNPLAYED').upper(), 'indicator': self.filterUnwatched and check or ''}) + + if self.filter: + options.append({'type': 'clear_filter', 'display': T(32376, 'CLEAR FILTER').upper(), 'indicator': 'script.plex/indicators/remove.png'}) + + if options: + options.append(None) # Separator + + optionsMap = { + 'year': {'type': 'year', 'display': T(32377, 'Year'), 'indicator': self.hasFilter('year') and check or ''}, + 'decade': {'type': 'decade', 'display': T(32378, 'Decade'), 'indicator': self.hasFilter('decade') and check or ''}, + 'genre': {'type': 'genre', 'display': T(32379, 'Genre'), 'indicator': self.hasFilter('genre') and check or ''}, + 'contentRating': {'type': 'contentRating', 'display': T(32380, 'Content Rating'), 'indicator': self.hasFilter('contentRating') and check or ''}, + 'network': {'type': 'studio', 'display': T(32381, 'Network'), 'indicator': self.hasFilter('studio') and check or ''}, + 'collection': {'type': 'collection', 'display': T(32382, 'Collection'), 'indicator': self.hasFilter('collection') and check or ''}, + 'director': {'type': 'director', 'display': T(32383, 'Director'), 'indicator': self.hasFilter('director') and check or ''}, + 'actor': {'type': 'actor', 'display': T(32384, 'Actor'), 'indicator': self.hasFilter('actor') and check or ''}, + 'country': {'type': 'country', 'display': T(32385, 'Country'), 'indicator': self.hasFilter('country') and check or ''}, + 'studio': {'type': 'studio', 'display': T(32386, 'Studio'), 'indicator': self.hasFilter('studio') and check or ''}, + 'resolution': {'type': 'resolution', 'display': T(32362, 'Resolution'), 'indicator': self.hasFilter('resolution') and check or ''}, + 'labels': {'type': 'labels', 'display': T(32387, 'Labels'), 'indicator': self.hasFilter('labels') and check or ''}, + + 'make': {'type': 'make', 'display': T(32388, 'Camera Make'), 'indicator': self.hasFilter('make') and check or ''}, + 'model': {'type': 'model', 'display': T(32389, 'Camera Model'), 'indicator': self.hasFilter('model') and check or ''}, + 'aperture': {'type': 'aperture', 'display': T(32390, 'Aperture'), 'indicator': self.hasFilter('aperture') and check or ''}, + 'exposure': {'type': 'exposure', 'display': T(32391, 'Shutter Speed'), 'indicator': self.hasFilter('exposure') and check or ''}, + 'iso': {'type': 'iso', 'display': 'ISO', 'indicator': self.hasFilter('iso') and check or ''}, + 'lens': {'type': 'lens', 'display': T(32392, 'Lens'), 'indicator': self.hasFilter('lens') and check or ''} + } + + if self.section.TYPE == 'movie': + for k in ('year', 'decade', 'genre', 'contentRating', 'collection', 'director', 'actor', 'country', 'studio', 'resolution', 'labels'): + options.append(optionsMap[k]) + elif self.section.TYPE == 'show': + if ITEM_TYPE == 'episode': + for k in ('year', 'collection', 'resolution'): + options.append(optionsMap[k]) + elif ITEM_TYPE == 'album': + for k in ('genre', 'year', 'decade', 'collection', 'labels'): + options.append(optionsMap[k]) + else: + for k in ('year', 'genre', 'contentRating', 'network', 'collection', 'actor', 'labels'): + options.append(optionsMap[k]) + elif self.section.TYPE == 'artist': + for k in ('genre', 'country', 'collection'): + options.append(optionsMap[k]) + elif self.section.TYPE == 'photo': + for k in ('year', 'make', 'model', 'aperture', 'exposure', 'iso', 'lens', 'labels'): + options.append(optionsMap[k]) + + result = dropdown.showDropdown(options, (980, 106), with_indicator=True, suboption_callback=self.subOptionCallback) + if not result: + return + + choice = result['type'] + + if choice == 'clear_filter': + self.filter = None + elif choice == 'unwatched': + self.filterUnwatched = not self.filterUnwatched + self.librarySettings.setSetting('filter.unwatched', self.filterUnwatched) + else: + self.filter = result + + self.updateFilterDisplay() + + if self.filter or choice in ('clear_filter', 'unwatched'): + self.fill() + + def clearFilters(self): + self.filter = None + self.filterUnwatched = False + self.librarySettings.setSetting('filter.unwatched', self.filterUnwatched) + self.updateFilterDisplay() + + def resetSort(self): + self.sort = 'titleSort' + self.sortDesc = False + + self.librarySettings.setSetting('sort', self.sort) + self.librarySettings.setSetting('sort.desc', self.sortDesc) + + util.setGlobalProperty('sort', self.sort) + self.setProperty('sort.display', SORT_KEYS[self.section.TYPE].get(self.sort, SORT_KEYS['movie'].get(self.sort))['title']) + + def updateFilterDisplay(self): + if self.filter: + disp = self.filter['display'] + if self.filter.get('sub'): + disp = u'{0}: {1}'.format(disp, self.filter['sub']['display']) + self.setProperty('filter1.display', disp) + self.setProperty('filter2.display', self.filterUnwatched and T(32368, 'Unplayed') or '') + else: + self.setProperty('filter2.display', '') + self.setProperty('filter1.display', self.filterUnwatched and T(32368, 'Unplayed') or T(32345, 'All')) + + def showPanelClicked(self): + mli = self.showPanelControl.getSelectedItem() + if not mli or not mli.dataSource: + return + + sectionType = self.section.TYPE + + updateUnwatchedAndProgress = False + + if mli.dataSource.TYPE == 'collection': + prevItemType = self.librarySettings.getItemType() + self.processCommand(opener.open(mli.dataSource)) + self.librarySettings.setItemType(prevItemType) + elif self.section.TYPE == 'show' or mli.dataSource.TYPE == 'show' or mli.dataSource.TYPE == 'season' or mli.dataSource.TYPE == 'episode': + if ITEM_TYPE == 'episode' or mli.dataSource.TYPE == 'episode' or mli.dataSource.TYPE == 'season': + self.openItem(mli.dataSource) + else: + self.processCommand(opener.handleOpen(subitems.ShowWindow, media_item=mli.dataSource, parent_list=self.showPanelControl)) + if mli.dataSource.TYPE != 'season': # NOTE: A collection with Seasons doesn't have the leafCount/viewedLeafCount until you actually go into the season so we can't update the unwatched count here + updateUnwatchedAndProgress = True + elif self.section.TYPE == 'movie' or mli.dataSource.TYPE == 'movie': + datasource = mli.dataSource + if datasource.isDirectory(): + cls = self.section.__class__ + section = cls(self.section.data, self.section.initpath, self.section.server, self.section.container) + sectionId = section.key + if not sectionId.isdigit(): + sectionId = section.getLibrarySectionId() + + section.set('librarySectionID', sectionId) + section.key = datasource.key + section.title = datasource.title + + self.processCommand(opener.handleOpen(LibraryWindow, windows=self._windows, default_window=self._next, section=section, filter_=self.filter, subDir=True)) + self.librarySettings.setItemType(self.librarySettings.getItemType()) + else: + self.processCommand(opener.handleOpen(preplay.PrePlayWindow, video=datasource, parent_list=self.showPanelControl)) + updateUnwatchedAndProgress = True + elif self.section.TYPE == 'artist' or mli.dataSource.TYPE == 'artist' or mli.dataSource.TYPE == 'album' or mli.dataSource.TYPE == 'track': + if ITEM_TYPE == 'album' or mli.dataSource.TYPE == 'album' or mli.dataSource.TYPE == 'track': + self.openItem(mli.dataSource) + else: + self.processCommand(opener.handleOpen(subitems.ArtistWindow, media_item=mli.dataSource, parent_list=self.showPanelControl)) + elif self.section.TYPE in ('photo', 'photodirectory'): + self.showPhoto(mli.dataSource) + + if not mli: + return + + if mli.dataSource and not mli.dataSource.exists(): + self.showPanelControl.removeItem(mli.pos()) + return + + if updateUnwatchedAndProgress: + self.updateUnwatchedAndProgress(mli) + + def showPhoto(self, photo): + if isinstance(photo, plexnet.photo.Photo) or photo.TYPE == 'clip': + self.processCommand(opener.open(photo)) + else: + self.processCommand(opener.sectionClicked(photo)) + + def updateUnwatchedAndProgress(self, mli): + mli.dataSource.reload() + if mli.dataSource.isWatched: + mli.setProperty('unwatched', '') + mli.setProperty('unwatched.count', '') + else: + if self.section.TYPE == 'show' or mli.dataSource.TYPE == 'show' or mli.dataSource.TYPE == 'season': + mli.setProperty('unwatched.count', str(mli.dataSource.unViewedLeafCount)) + else: + mli.setProperty('unwatched', '1') + mli.setProperty('progress', util.getProgressImage(mli.dataSource)) + + def setTitle(self): + if self.section.TYPE == 'artist': + self.setProperty('screen.title', T(32394, 'MUSIC').upper()) + elif self.section.TYPE in ('photo', 'photodirectory'): + self.setProperty('screen.title', T(32349, 'photos').upper()) + elif self.section.TYPE == 'collection': + self.setProperty('screen.title', T(32382, 'COLLECTION').upper()) + else: + self.setProperty('screen.title', self.section.TYPE == 'show' and T(32393, 'TV SHOWS').upper() or T(32348, 'movies').upper()) + + self.updateFilterDisplay() + + def updateItem(self, mli=None): + mli = mli or self.showPanelControl.getSelectedItem() + if not mli or mli.dataSource: + return + + for task in self.tasks: + if task.contains(mli.pos()): + util.DEBUG_LOG('Moving task to front: {0}'.format(task)) + backgroundthread.BGThreader.moveToFront(task) + break + + def setBackground(self, items, position, randomize=True): + if self.backgroundSet: + return + + if randomize: + item = random.choice(items) + self.updateBackgroundFrom(item) + else: + # we want the first item of the first chunk + if position != 0: + return + + self.updateBackgroundFrom(items[0]) + self.backgroundSet = True + + def fill(self): + if self.chunkMode: + self.chunkMode.reset() + + self.backgroundSet = False + + if self.section.TYPE in ('photo', 'photodirectory'): + self.fillPhotos() + else: + self.fillShows() + + def getFilterOpts(self): + if not self.filter: + return None + + if not self.filter.get('sub'): + util.DEBUG_LOG('Filter missing sub-filter data') + return None + + return (self.filter['type'], six.moves.urllib.parse.unquote_plus(self.filter['sub']['val'])) + + def getSortOpts(self): + if not self.sort: + return None + + return (self.sort, self.sortDesc and 'desc' or 'asc') + + @busy.dialog() + def fillShows(self): + self.setBoolProperty('no.content', False) + self.setBoolProperty('no.content.filtered', False) + items = [] + jitems = [] + self.keyItems = {} + self.firstOfKeyItems = {} + totalSize = 0 + + type_ = None + if ITEM_TYPE == 'episode': + type_ = 4 + elif ITEM_TYPE == 'album': + type_ = 9 + elif ITEM_TYPE == 'collection': + type_ = 18 + + idx = 0 + fallback = 'script.plex/thumb_fallbacks/{0}.png'.format(TYPE_KEYS.get(self.section.type, TYPE_KEYS['movie'])['fallback']) + + if self.sort != 'titleSort' or ITEM_TYPE == 'folder' or self.subDir or self.section.TYPE == "collection": + if ITEM_TYPE == 'folder': + sectionAll = self.section.folder(0, 0, self.subDir) + else: + sectionAll = self.section.all(0, 0, filter_=self.getFilterOpts(), sort=self.getSortOpts(), unwatched=self.filterUnwatched, type_=type_) + + totalSize = sectionAll.totalSize.asInt() + + if not totalSize: + self.showPanelControl.reset() + self.keyListControl.reset() + + if self.filter or self.filterUnwatched: + self.setBoolProperty('no.content.filtered', True) + else: + self.setBoolProperty('no.content', True) + else: + if not self.chunkMode: + for x in range(totalSize): + mli = kodigui.ManagedListItem('') + mli.setProperty('thumb.fallback', fallback) + mli.setProperty('index', str(x)) + items.append(mli) + else: + jumpList = self.section.jumpList(filter_=self.getFilterOpts(), sort=self.getSortOpts(), unwatched=self.filterUnwatched, type_=type_) + + if not jumpList: + self.showPanelControl.reset() + self.keyListControl.reset() + + if self.filter or self.filterUnwatched: + self.setBoolProperty('no.content.filtered', True) + else: + self.setBoolProperty('no.content', True) + + if jumpList is None: + util.messageDialog("Error", "There was an error.") + + return + + for kidx, ji in enumerate(jumpList): + mli = kodigui.ManagedListItem(ji.title, data_source=ji.key) + mli.setProperty('key', ji.key) + mli.setProperty('original', '{0:02d}'.format(kidx)) + self.keyItems[ji.key] = mli + jitems.append(mli) + totalSize += ji.size.asInt() + + if self.chunkMode: + self.chunkMode.addKeyRange(ji.key, (idx, (idx + ji.size.asInt()) - 1)) + idx += ji.size.asInt() + else: + for x in range(ji.size.asInt()): + mli = kodigui.ManagedListItem('') + mli.setProperty('key', ji.key) + mli.setProperty('thumb.fallback', fallback) + mli.setProperty('index', str(idx)) + items.append(mli) + if not x: # i.e. first item + self.firstOfKeyItems[ji.key] = mli + idx += 1 + + util.setGlobalProperty('key', jumpList[0].key) + + if self.scrollBar: + self.scrollBar.setSizeAndCount(totalSize, 12) + + if self.chunkMode: + self.chunkMode.itemCount = totalSize + items = [ + kodigui.ManagedListItem('', properties={'index': str(i)}) for i in range(CHUNK_SIZE * 2) + ] + [ + kodigui.ManagedListItem('') for i in range(CHUNK_SIZE) + ] + + self.showPanelControl.reset() + self.keyListControl.reset() + + self.showPanelControl.addItems(items) + self.keyListControl.addItems(jitems) + + self.showPanelControl.selectItem(0) + self.setFocusId(self.POSTERS_PANEL_ID) + + tasks = [] + ct = 0 + for start in range(0, totalSize, CHUNK_SIZE): + tasks.append( + ChunkRequestTask().setup( + self.section, start, CHUNK_SIZE, self.chunkCallback, filter_=self.getFilterOpts(), sort=self.getSortOpts(), unwatched=self.filterUnwatched, subDir=self.subDir + ) + ) + ct += 1 + + if self.chunkMode and ct > 1: + break + + self.tasks.add(tasks) + backgroundthread.BGThreader.addTasksToFront(tasks) + + def showPhotoItemProperties(self, photo): + if photo.isFullObject(): + return + + task = PhotoPropertiesTask().setup(photo, self._showPhotoItemProperties) + self.tasks.add(task) + backgroundthread.BGThreader.addTasksToFront([task]) + + def _showPhotoItemProperties(self, photo): + mli = self.showPanelControl.getSelectedItem() + if not mli or not mli.dataSource.TYPE == 'photo': + for mli in self.showPanelControl: + if mli.dataSource == photo: + break + else: + return + + mli.setProperty('camera.model', photo.media[0].model) + mli.setProperty('camera.lens', photo.media[0].lens) + + attrib = [] + if photo.media[0].height: + attrib.append(u'{0} x {1}'.format(photo.media[0].width, photo.media[0].height)) + + orientation = photo.media[0].parts[0].orientation + if orientation: + attrib.append(u'{0} Mo'.format(orientation)) + + container = photo.media[0].container_ or os.path.splitext(photo.media[0].parts[0].file)[-1][1:].lower() + if container == 'jpg': + container = 'jpeg' + attrib.append(container.upper()) + if attrib: + mli.setProperty('photo.dims', u' \u2022 '.join(attrib)) + + settings = [] + if photo.media[0].iso: + settings.append('ISO {0}'.format(photo.media[0].iso)) + if photo.media[0].aperture: + settings.append('{0}'.format(photo.media[0].aperture)) + if photo.media[0].exposure: + settings.append('{0}'.format(photo.media[0].exposure)) + mli.setProperty('camera.settings', u' \u2022 '.join(settings)) + mli.setProperty('photo.summary', photo.get('summary')) + + @busy.dialog() + def fillPhotos(self): + self.setBoolProperty('no.content', False) + self.setBoolProperty('no.content.filtered', False) + items = [] + keys = [] + self.firstOfKeyItems = {} + idx = 0 + + if self.section.TYPE == 'photodirectory': + photos = self.section.all() + else: + photos = self.section.all(filter_=self.getFilterOpts(), sort=self.getSortOpts(), unwatched=self.filterUnwatched) + + if not photos: + return + + photo = random.choice(photos) + self.updateBackgroundFrom(photo) + thumbDim = TYPE_KEYS.get(self.section.type, TYPE_KEYS['movie'])['thumb_dim'] + fallback = 'script.plex/thumb_fallbacks/{0}.png'.format(TYPE_KEYS.get(self.section.type, TYPE_KEYS['movie'])['fallback']) + + if not photos: + if self.filter or self.filterUnwatched: + self.setBoolProperty('no.content.filtered', True) + else: + self.setBoolProperty('no.content', True) + return + + for photo in photos: + title = photo.title + if photo.TYPE == 'photodirectory': + thumb = photo.composite.asTranscodedImageURL(*thumbDim) + mli = kodigui.ManagedListItem(title, thumbnailImage=thumb, data_source=photo) + mli.setProperty('is.folder', '1') + else: + thumb = photo.defaultThumb.asTranscodedImageURL(*thumbDim) + label2 = util.cleanLeadingZeros(photo.originallyAvailableAt.asDatetime('%d %B %Y')) + mli = kodigui.ManagedListItem(title, label2, thumbnailImage=thumb, data_source=photo) + + mli.setProperty('thumb.fallback', fallback) + mli.setProperty('index', str(idx)) + + key = title[0].upper() + if key not in KEYS: + key = '#' + if key not in keys: + self.firstOfKeyItems[key] = mli + keys.append(key) + mli.setProperty('key', str(key)) + items.append(mli) + idx += 1 + + litems = [] + self.keyItems = {} + for i, key in enumerate(keys): + mli = kodigui.ManagedListItem(key, data_source=key) + mli.setProperty('key', key) + mli.setProperty('original', '{0:02d}'.format(i)) + self.keyItems[key] = mli + litems.append(mli) + + self.showPanelControl.reset() + self.keyListControl.reset() + + self.showPanelControl.addItems(items) + self.keyListControl.addItems(litems) + + if keys: + util.setGlobalProperty('key', keys[0]) + + def chunkCallback(self, items, start, clear=False): + if clear: + with self.lock: + items = [kodigui.ManagedListItem('') for i in range(CHUNK_SIZE * 3)] + + self.showPanelControl.reset() + self.showPanelControl.addItems(items) + + self.cleared = True + return + + if self.cleared: + self.cleared = False + busy.widthDialog(self._chunkCallback, self, items, start) + else: + self._chunkCallback(items, start) + + def _chunkCallback(self, items, start): + if self.chunkMode and not self.chunkMode.posIsValid(start): + return + + with self.lock: + if self.chunkMode and not self.chunkMode.posIsValid(start): + return + pos = start + self.setBackground(items, pos, randomize=not util.advancedSettings.dynamicBackgrounds) + + thumbDim = TYPE_KEYS.get(self.section.type, TYPE_KEYS['movie'])['thumb_dim'] + artDim = TYPE_KEYS.get(self.section.type, TYPE_KEYS['movie']).get('art_dim', (256, 256)) + + showUnwatched = False + if (self.section.TYPE in ('movie', 'show') and items[0].TYPE != 'collection') or (self.section.TYPE == 'collection' and items[0].TYPE in ('movie', 'show', 'episode')): # NOTE: A collection with Seasons doesn't have the leafCount/viewedLeafCount until you actually go into the season so we can't update the unwatched count here + showUnwatched = True + + if self.chunkMode and len(items) < CHUNK_SIZE: + items += [None] * (CHUNK_SIZE - len(items)) + + if ITEM_TYPE == 'episode': + for offset, obj in enumerate(items): + mli = self.showPanelControl[pos] + if obj: + mli.dataSource = obj + mli.setProperty('index', str(pos)) + if obj.index: + subtitle = u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), obj.parentIndex, T(32311, 'E'), obj.index) + mli.setProperty('subtitle', subtitle) + subtitle = "\n" + subtitle + else: + subtitle = ' - ' + obj.originallyAvailableAt.asDatetime('%m/%d/%y') + mli.setLabel((obj.defaultTitle or '') + subtitle) + + mli.setThumbnailImage(obj.defaultThumb.asTranscodedImageURL(*thumbDim)) + + mli.setProperty('summary', obj.summary) + + # # mli.setProperty('key', self.chunkMode.getKey(pos)) + + mli.setLabel2(util.durationToText(obj.fixedDuration())) + mli.setProperty('art', obj.defaultArt.asTranscodedImageURL(*artDim)) + if not obj.isWatched: + mli.setProperty('unwatched', '1') + else: + mli.clear() + if obj is False: + mli.setProperty('index', str(pos)) + else: + mli.setProperty('index', '') + + pos += 1 + + elif ITEM_TYPE == 'album': + for offset, obj in enumerate(items): + mli = self.showPanelControl[pos] + if obj: + mli.dataSource = obj + mli.setProperty('index', str(pos)) + mli.setLabel(u'{0}\n{1}'.format(obj.parentTitle, obj.title)) + + mli.setThumbnailImage(obj.defaultThumb.asTranscodedImageURL(*thumbDim)) + + mli.setProperty('summary', obj.summary) + + # # mli.setProperty('key', self.chunkMode.getKey(pos)) + + mli.setLabel2(obj.year) + + if self.chunkMode: + mli.setProperty('key', self.chunkMode.getKey(pos)) + + else: + mli.clear() + if obj is False: + mli.setProperty('index', str(pos)) + else: + mli.setProperty('index', '') + + pos += 1 + else: + for offset, obj in enumerate(items): + mli = self.showPanelControl[pos] + if obj: + mli.setProperty('index', str(pos)) + mli.setLabel(obj.defaultTitle or '') + mli.setThumbnailImage(obj.defaultThumb.asTranscodedImageURL(*thumbDim)) + mli.dataSource = obj + mli.setProperty('summary', obj.get('summary')) + + #if self.chunkMode: + # mli.setProperty('key', self.chunkMode.getKey(pos)) + #else: + # mli.setProperty('key', obj.key) + + if showUnwatched and obj.TYPE != 'collection': + if not obj.isDirectory(): + mli.setLabel2(util.durationToText(obj.fixedDuration())) + mli.setProperty('art', obj.defaultArt.asTranscodedImageURL(*artDim)) + if not obj.isWatched and obj.TYPE != "Directory": + if self.section.TYPE == 'show' or obj.TYPE == 'show' or obj.TYPE == 'season': + mli.setProperty('unwatched.count', str(obj.unViewedLeafCount)) + else: + mli.setProperty('unwatched', '1') + + mli.setProperty('progress', util.getProgressImage(obj)) + else: + mli.clear() + if obj is False: + mli.setProperty('index', str(pos)) + else: + mli.setProperty('index', '') + + pos += 1 + + +class PostersWindow(kodigui.ControlledWindow): + xmlFile = 'script-plex-posters.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + POSTERS_PANEL_ID = 101 + KEY_LIST_ID = 151 + SCROLLBAR_ID = 152 + + OPTIONS_GROUP_ID = 200 + + HOME_BUTTON_ID = 201 + SEARCH_BUTTON_ID = 202 + PLAYER_STATUS_BUTTON_ID = 204 + + SORT_BUTTON_ID = 210 + FILTER1_BUTTON_ID = 211 + FILTER2_BUTTON_ID = 212 + ITEM_TYPE_BUTTON_ID = 312 + + PLAY_BUTTON_ID = 301 + SHUFFLE_BUTTON_ID = 302 + OPTIONS_BUTTON_ID = 303 + VIEWTYPE_BUTTON_ID = 304 + + VIEWTYPE = 'panel' + MULTI_WINDOW_ID = 0 + + CUSTOM_SCOLLBAR_BUTTON_ID = 951 + + +class PostersSmallWindow(PostersWindow): + xmlFile = 'script-plex-posters-small.xml' + VIEWTYPE = 'panel2' + MULTI_WINDOW_ID = 1 + + +class PostersChunkedWindow(PostersWindow): + xmlFile = 'script-plex-listview-16x9-chunked.xml' + VIEWTYPE = 'list' + MULTI_WINDOW_ID = 0 + + +class ListView16x9Window(PostersWindow): + xmlFile = 'script-plex-listview-16x9.xml' + VIEWTYPE = 'list' + MULTI_WINDOW_ID = 2 + + +class ListView16x9ChunkedWindow(PostersWindow): + xmlFile = 'script-plex-listview-16x9-chunked.xml' + VIEWTYPE = 'list' + MULTI_WINDOW_ID = 1 + + +class SquaresWindow(PostersWindow): + xmlFile = 'script-plex-squares.xml' + VIEWTYPE = 'panel' + MULTI_WINDOW_ID = 0 + + +class SquaresChunkedWindow(PostersWindow): + xmlFile = 'script-plex-listview-square-chunked.xml' + VIEWTYPE = 'list' + MULTI_WINDOW_ID = 0 + + +class ListViewSquareWindow(PostersWindow): + xmlFile = 'script-plex-listview-square.xml' + VIEWTYPE = 'list' + MULTI_WINDOW_ID = 1 + + +class ListViewSquareChunkedWindow(PostersWindow): + xmlFile = 'script-plex-listview-square-chunked.xml' + VIEWTYPE = 'list' + MULTI_WINDOW_ID = 1 + + +VIEWS_POSTER = { + 'panel': PostersWindow, + 'panel2': PostersSmallWindow, + 'list': ListView16x9Window, + 'all': (PostersWindow, PostersSmallWindow, ListView16x9Window) +} + +VIEWS_POSTER_CHUNKED = { + 'panel': PostersChunkedWindow, + 'list': ListView16x9ChunkedWindow, + 'all': (PostersChunkedWindow, ListView16x9ChunkedWindow) +} + +VIEWS_SQUARE = { + 'panel': SquaresWindow, + 'list': ListViewSquareWindow, + 'all': (SquaresWindow, ListViewSquareWindow) +} + +VIEWS_SQUARE_CHUNKED = { + 'panel': SquaresChunkedWindow, + 'list': ListViewSquareChunkedWindow, + 'all': (SquaresChunkedWindow, ListViewSquareChunkedWindow) +} \ No newline at end of file diff --git a/script.plexmod/lib/windows/mixins.py b/script.plexmod/lib/windows/mixins.py new file mode 100644 index 0000000000..1e35868471 --- /dev/null +++ b/script.plexmod/lib/windows/mixins.py @@ -0,0 +1,61 @@ +# coding=utf-8 + +from lib import util + +from . import kodigui + + +class SeasonsMixin(): + SEASONS_CONTROL_ATTR = "subItemListControl" + + THUMB_DIMS = { + 'show': { + 'main.thumb': util.scaleResolution(347, 518), + 'item.thumb': util.scaleResolution(174, 260) + }, + 'episode': { + 'main.thumb': util.scaleResolution(347, 518), + 'item.thumb': util.scaleResolution(198, 295) + }, + 'artist': { + 'main.thumb': util.scaleResolution(519, 519), + 'item.thumb': util.scaleResolution(215, 215) + } + } + + def _createListItem(self, mediaItem, obj): + mli = kodigui.ManagedListItem( + obj.title or '', + thumbnailImage=obj.defaultThumb.asTranscodedImageURL(*self.THUMB_DIMS[mediaItem.type]['item.thumb']), + data_source=obj + ) + return mli + + def fillSeasons(self, mediaItem, update=False, seasonsFilter=None, selectSeason=None): + seasons = mediaItem.seasons() + if not seasons or (seasonsFilter and not seasonsFilter(seasons)): + return False + + items = [] + idx = 0 + for season in seasons: + if selectSeason and season == selectSeason: + continue + + mli = self._createListItem(mediaItem, season) + if mli: + mli.setProperty('index', str(idx)) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/show.png') + mli.setProperty('unwatched.count', not season.isWatched and str(season.unViewedLeafCount) or '') + items.append(mli) + idx += 1 + + subItemListControl = getattr(self, self.SEASONS_CONTROL_ATTR) + if update: + subItemListControl.replaceItems(items) + else: + subItemListControl.reset() + subItemListControl.addItems(items) + + return True + diff --git a/script.plexmod/lib/windows/musicplayer.py b/script.plexmod/lib/windows/musicplayer.py new file mode 100644 index 0000000000..d2277eb5ee --- /dev/null +++ b/script.plexmod/lib/windows/musicplayer.py @@ -0,0 +1,169 @@ +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import kodigui +from . import currentplaylist +from . import opener + +from lib import player +from lib import util + + +def timeDisplay(ms): + h = ms / 3600000 + m = (ms % 3600000) / 60000 + s = (ms % 60000) / 1000 + return '{0:0>2}:{1:0>2}:{2:0>2}'.format(h, m, s) + + +def simplifiedTimeDisplay(ms): + left, right = timeDisplay(ms).rsplit(':', 1) + left = left.lstrip('0:') or '0' + return left + ':' + right + + +class MusicPlayerWindow(currentplaylist.CurrentPlaylistWindow): + xmlFile = 'script-plex-music_player.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + SEEK_BUTTON_ID = 100 + SEEK_IMAGE_ID = 200 + SHUFFLE_REMOTE_BUTTON_ID = 422 + REPEAT_BUTTON_ID = 401 + SKIP_PREV_BUTTON_ID = 404 + SKIP_NEXT_BUTTON_ID = 409 + STOP_BUTTON_ID = 407 + + SEEK_IMAGE_WIDTH = 1920 + + BAR_RIGHT = 1920 + + def __init__(self, *args, **kwargs): + kodigui.ControlledWindow.__init__(self, *args, **kwargs) + self.track = kwargs.get('track') + self.playlist = kwargs.get('playlist') + self.album = kwargs.get('album') + self.selectedOffset = 0 + self.exitCommand = None + + if self.track: + self.duration = self.track.duration.asInt() + else: + self.setDuration() + + def onFirstInit(self): + if self.playlist and self.playlist.isRemote: + self.playlist.on('change', self.updateProperties) + self.setupSeekbar() + self.selectionBoxMax = self.SEEK_IMAGE_WIDTH - (self.selectionBoxHalf - 3) + + self.updateProperties() + self.play() + self.setFocusId(406) + + def doClose(self, **kwargs): + player.PLAYER.off('playback.started', self.onPlayBackStarted) + if self.playlist and self.playlist.isRemote: + self.playlist.off('change', self.updateProperties) + kodigui.ControlledWindow.doClose(self) + + def onAction(self, action): + try: + if action == xbmcgui.ACTION_STOP: + self.stopButtonClicked() + return + except: + util.ERROR() + + super().onAction(action) + + def onClick(self, controlID): + if controlID == self.PLAYLIST_BUTTON_ID: + self.showPlaylist() + elif controlID == self.SEEK_BUTTON_ID: + self.seekButtonClicked() + elif controlID == self.SHUFFLE_REMOTE_BUTTON_ID: + self.playlist.setShuffle() + elif controlID == self.REPEAT_BUTTON_ID: + self.repeatButtonClicked() + elif controlID == self.SKIP_PREV_BUTTON_ID: + self.skipPrevButtonClicked() + elif controlID == self.SKIP_NEXT_BUTTON_ID: + self.skipNextButtonClicked() + elif controlID == self.OPTIONS_BUTTON_ID: + self.optionsButtonClicked((1240, 1060)) + elif controlID == self.STOP_BUTTON_ID: + self.stopButtonClicked() + + def repeatButtonClicked(self): + if self.playlist and self.playlist.isRemote: + if xbmc.getCondVisibility('Playlist.IsRepeatOne'): + xbmc.executebuiltin('PlayerControl(RepeatOff)') + elif self.playlist.isRepeat: + self.playlist.setRepeat(False) + self.playlist.refresh(force=True) + xbmc.executebuiltin('PlayerControl(RepeatOne)') + else: + self.playlist.setRepeat(True) + self.playlist.refresh(force=True) + else: + xbmc.executebuiltin('PlayerControl(Repeat)') + + def skipPrevButtonClicked(self): + if not xbmc.getCondVisibility('MusicPlayer.HasPrevious') and self.playlist and self.playlist.isRemote: + util.DEBUG_LOG('MusicPlayer: No previous in Kodi playlist - refreshing remote PQ') + if not self.playlist.refresh(force=True, wait=True): + return + + xbmc.executebuiltin('PlayerControl(Previous)') + + def skipNextButtonClicked(self): + if not xbmc.getCondVisibility('MusicPlayer.HasNext') and self.playlist and self.playlist.isRemote: + util.DEBUG_LOG('MusicPlayer: No next in Kodi playlist - refreshing remote PQ') + if not self.playlist.refresh(force=True, wait=True): + return + + xbmc.executebuiltin('PlayerControl(Next)') + + def showPlaylist(self): + self.processCommand(opener.handleOpen(currentplaylist.CurrentPlaylistWindow, winID=xbmcgui.getCurrentWindowId())) + + def stopButtonClicked(self): + self.doClose() + + def updateProperties(self, **kwargs): + if self.playlist: + if self.playlist.isRemote: + self.setProperty('pq.isRemote', '1') + self.setProperty('pq.hasnext', self.playlist.allowSkipNext and '1' or '') + self.setProperty('pq.hasprev', self.playlist.allowSkipPrev and '1' or '') + self.setProperty('pq.repeat', self.playlist.isRepeat and '1' or '') + self.setProperty('pq.shuffled', self.playlist.isShuffled and '1' or '') + else: + self.setProperties(('pq.isRemote', 'pq.hasnext', 'pq.hasprev', 'pq.repeat', 'pq.shuffled'), '') + + def play(self): + if not self.track: + return + + if util.trackIsPlaying(self.track): + return + + fanart = None + if self.playlist: + fanart = self.playlist.get('composite') or self.playlist.defaultArt + # player.PLAYER.playAudio(self.track, fanart=self.getProperty('background')) + if self.album: + index = 0 + for i, track in enumerate(self.album.tracks()): + if track == self.track: + index = i + player.PLAYER.playAlbum(self.album, startpos=index, fanart=fanart) + elif self.playlist: + player.PLAYER.playAudioPlaylist(self.playlist, startpos=list(self.playlist.items()).index(self.track), fanart=fanart) + else: + player.PLAYER.playAudio(self.track) diff --git a/script.plexmod/lib/windows/opener.py b/script.plexmod/lib/windows/opener.py new file mode 100644 index 0000000000..4aed06b2dc --- /dev/null +++ b/script.plexmod/lib/windows/opener.py @@ -0,0 +1,169 @@ +from __future__ import absolute_import +from . import busy + +from plexnet import playqueue, plexapp, plexlibrary +from lib import util +import six + + +def open(obj, **kwargs): + if isinstance(obj, playqueue.PlayQueue): + if busy.widthDialog(obj.waitForInitialization, None): + if obj.type == 'audio': + from . import musicplayer + return handleOpen(musicplayer.MusicPlayerWindow, track=obj.current(), playlist=obj) + elif obj.type == 'photo': + from . import photos + return handleOpen(photos.PhotoWindow, play_queue=obj) + else: + from . import videoplayer + videoplayer.play(play_queue=obj) + return '' + elif isinstance(obj, six.string_types): + key = obj + if not obj.startswith('/'): + key = '/library/metadata/{0}'.format(obj) + return open(plexapp.SERVERMANAGER.selectedServer.getObject(key), **kwargs) + elif obj.TYPE == 'episode': + return episodeClicked(obj, **kwargs) + elif obj.TYPE == 'movie': + return playableClicked(obj, **kwargs) + elif obj.TYPE in ('show'): + return showClicked(obj, **kwargs) + elif obj.TYPE in ('artist'): + return artistClicked(obj, **kwargs) + elif obj.TYPE in ('season'): + return seasonClicked(obj, **kwargs) + elif obj.TYPE in ('album'): + return albumClicked(obj, **kwargs) + elif obj.TYPE in ('photo',): + return photoClicked(obj, **kwargs) + elif obj.TYPE in ('photodirectory'): + return photoDirectoryClicked(obj, **kwargs) + elif obj.TYPE in ('track'): + return trackClicked(obj, **kwargs) + elif obj.TYPE in ('playlist'): + return playlistClicked(obj, **kwargs) + elif obj.TYPE in ('clip'): + from . import videoplayer + return videoplayer.play(video=obj) + elif obj.TYPE in ('collection'): + return collectionClicked(obj, **kwargs) + elif obj.TYPE in ('Genre'): + return genreClicked(obj, **kwargs) + elif obj.TYPE in ('Director'): + return directorClicked(obj, **kwargs) + elif obj.TYPE in ('Role'): + return actorClicked(obj, **kwargs) + + +def handleOpen(winclass, **kwargs): + w = None + try: + autoPlay = kwargs.pop("auto_play", False) + if autoPlay and hasattr(winclass, "doAutoPlay"): + w = winclass.create(show=False, **kwargs) + if w.doAutoPlay(): + w.modal() + else: + w = winclass.open(**kwargs) + return w.exitCommand or '' + except AttributeError: + pass + except util.NoDataException: + raise + finally: + del w + util.garbageCollect() + + return '' + + +def playableClicked(playable, **kwargs): + from . import preplay + return handleOpen(preplay.PrePlayWindow, video=playable, **kwargs) + + +def episodeClicked(episode, **kwargs): + from . import episodes + return handleOpen(episodes.EpisodesWindow, episode=episode, **kwargs) + + +def showClicked(show, **kwargs): + from . import subitems + return handleOpen(subitems.ShowWindow, media_item=show, **kwargs) + + +def artistClicked(artist, **kwargs): + from . import subitems + return handleOpen(subitems.ArtistWindow, media_item=artist, **kwargs) + + +def seasonClicked(season, **kwargs): + from . import episodes + return handleOpen(episodes.EpisodesWindow, season=season, **kwargs) + + +def albumClicked(album, **kwargs): + from . import tracks + return handleOpen(tracks.AlbumWindow, album=album, **kwargs) + + +def photoClicked(photo, **kwargs): + from . import photos + return handleOpen(photos.PhotoWindow, photo=photo, **kwargs) + + +def trackClicked(track, **kwargs): + from . import musicplayer + return handleOpen(musicplayer.MusicPlayerWindow, track=track, **kwargs) + + +def photoDirectoryClicked(photodirectory, **kwargs): + return sectionClicked(photodirectory, **kwargs) + + +def playlistClicked(pl, **kwargs): + from . import playlist + return handleOpen(playlist.PlaylistWindow, playlist=pl, **kwargs) + + +def collectionClicked(collection, **kwargs): + return sectionClicked(collection, **kwargs) + + +def sectionClicked(section, filter_=None, **kwargs): + from . import library + library.ITEM_TYPE = section.TYPE + key = section.key + if not key.isdigit(): + key = section.getLibrarySectionId() + viewtype = util.getSetting('viewtype.{0}.{1}'.format(section.server.uuid, key)) + if section.TYPE in ('artist', 'photo', 'photodirectory'): + default = library.VIEWS_SQUARE.get(viewtype) + return handleOpen( + library.LibraryWindow, windows=library.VIEWS_SQUARE.get('all'), default_window=default, section=section, filter_=filter_, **kwargs + ) + else: + default = library.VIEWS_POSTER.get(viewtype) + return handleOpen( + library.LibraryWindow, windows=library.VIEWS_POSTER.get('all'), default_window=default, section=section, filter_=filter_, **kwargs + ) + + +def genreClicked(genre, **kwargs): + section = plexlibrary.LibrarySection.fromFilter(genre) + filter_ = {'type': genre.FILTER, 'display': 'Genre', 'sub': {'val': genre.id, 'display': genre.tag}} + return sectionClicked(section, filter_, **kwargs) + + +def directorClicked(director, **kwargs): + section = plexlibrary.LibrarySection.fromFilter(director) + filter_ = {'type': director.FILTER, 'display': 'Director', 'sub': {'val': director.id, 'display': director.tag}} + return sectionClicked(section, filter_, **kwargs) + + +def actorClicked(actor, **kwargs): + section = plexlibrary.LibrarySection.fromFilter(actor) + filter_ = {'type': actor.FILTER, 'display': 'Actor', 'sub': {'val': actor.id, 'display': actor.tag}} + return sectionClicked(section, filter_, ignoreLibrarySettings=True, **kwargs) diff --git a/script.plexmod/lib/windows/optionsdialog.py b/script.plexmod/lib/windows/optionsdialog.py new file mode 100644 index 0000000000..dbbd0961e6 --- /dev/null +++ b/script.plexmod/lib/windows/optionsdialog.py @@ -0,0 +1,55 @@ +from __future__ import absolute_import +from . import kodigui + +from lib import util + + +class OptionsDialog(kodigui.BaseDialog): + xmlFile = 'script-plex-options_dialog.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + GROUP_ID = 100 + BUTTON_IDS = (1001, 1002, 1003) + + def __init__(self, *args, **kwargs): + kodigui.BaseDialog.__init__(self, *args, **kwargs) + self.header = kwargs.get('header') + self.info = kwargs.get('info') + self.button0 = kwargs.get('button0') + self.button1 = kwargs.get('button1') + self.button2 = kwargs.get('button2') + self.buttonChoice = None + + def onFirstInit(self): + self.setProperty('header', self.header) + self.setProperty('info', self.info) + + if self.button2: + self.setProperty('button.2', self.button2) + + if self.button1: + self.setProperty('button.1', self.button1) + + if self.button0: + self.setProperty('button.0', self.button0) + + self.setBoolProperty('initialized', True) + util.MONITOR.waitForAbort(0.1) + self.setFocusId(self.BUTTON_IDS[0]) + + def onClick(self, controlID): + if controlID in self.BUTTON_IDS: + self.buttonChoice = self.BUTTON_IDS.index(controlID) + self.doClose() + + +def show(header, info, button0=None, button1=None, button2=None): + w = OptionsDialog.open(header=header, info=info, button0=button0, button1=button1, button2=button2) + choice = w.buttonChoice + del w + util.garbageCollect() + return choice diff --git a/script.plexmod/lib/windows/pagination.py b/script.plexmod/lib/windows/pagination.py new file mode 100644 index 0000000000..474be481c7 --- /dev/null +++ b/script.plexmod/lib/windows/pagination.py @@ -0,0 +1,274 @@ +from __future__ import absolute_import +from . import kodigui +from kodi_six import xbmcgui +from lib import util + + +class MCLPaginator(object): + """ + A paginator for ManagedControlList instances + """ + control = None + pageSize = 8 + initialPageSize = 18 # + orphans = 26 + + # the amount of overhang allowed for both sides; don't show pagination when the overhang fits the current item count + orphans = pageSize + offset = 0 + leafCount = None + parentWindow = None + thumbFallback = None + + _direction = None + _currentAmount = None + _lastAmount = None + _boundaryHit = False + + def __init__(self, control, parent_window, page_size=None, orphans=None, leaf_count=None): + self.control = control + self.pageSize = page_size if page_size is not None else self.pageSize + self.orphans = orphans if orphans is not None else self.orphans + self.leafCount = leaf_count + self.parentWindow = parent_window + + self.reset() + + def reset(self): + self.offset = 0 + self._currentAmount = 0 + self._lastAmount = None + self._boundaryHit = False + self._direction = None + + def getData(self, offset, amount): + raise NotImplementedError + + def createListItem(self, data): + return self.parentWindow.createListItem(data) + + def prepareListItem(self, data, mli): + pass + + def readyForPaging(self): + return self.parentWindow.initialized + + @property + def _readyForPaging(self): + return self.readyForPaging() + + @property + def boundaryHit(self): + self._boundaryHit = False + + if not self._readyForPaging: + return + + mli = self.control.getSelectedItem() + if mli and mli.getProperty("is.boundary") and not mli.getProperty("is.updating"): + direction = "left" if mli.getProperty("left.boundary") else "right" + mli.setBoolProperty("is.updating", True) + self.offset = int(mli.getProperty("orig.index")) + self._direction = direction + self._boundaryHit = True + + return self._boundaryHit + + @property + def nextPage(self): + leafCount = self.leafCount + offset = self.offset + amount = self.pageSize + + if self._direction == "left": + if offset <= self.initialPageSize: + # return to initial page + offset = 0 + amount = self.initialPageSize + else: + # move the slice to the left by :amount: based on :offset: + amount = min(offset, self.pageSize) + offset -= amount + + # avoid short pages on the left end + if 0 < offset < self.orphans: + amount += offset + offset = 0 + + else: + # move the slice to the right + itemsLeft = leafCount - offset + # avoid short pages on the right end + if itemsLeft <= self.pageSize + self.orphans: + amount = self.pageSize + self.orphans + + self.offset = offset + data = self.getData(offset, amount) + self._lastAmount = self._currentAmount + self._currentAmount = len(data) + return data + + @property + def initialPage(self): + amount = self.initialPageSize + if self.initialPageSize + self.orphans >= self.leafCount: + amount = self.initialPageSize + self.orphans + + data = self.getData(self.offset, amount) + if data: + self._lastAmount = self._currentAmount + self._currentAmount = len(data) + return data + + def populate(self, items): + """ + Populates the current page to the bound Control List. Adds prev/next MLIs and selects the correct control + after doing so. + :param items: + :return: + """ + idx = 0 + moreLeft = self.offset > 0 + moreRight = self.offset + self._currentAmount < self.leafCount + + finalItems = [] + thumbFallback = self.thumbFallback + + if items: + for item in items: + mli = self.createListItem(item) + + if mli: + mli.setProperty('index', str(idx)) + self.prepareListItem(item, mli) + if thumbFallback: + if callable(thumbFallback): + mli.setProperty('thumb.fallback', thumbFallback(item)) + else: + mli.setProperty('thumb.fallback', thumbFallback) + + finalItems.append(mli) + idx += 1 + + if moreRight: + end = kodigui.ManagedListItem('') + end.setBoolProperty('is.boundary', True) + end.setBoolProperty('right.boundary', True) + end.setProperty("orig.index", str(int(self.offset + self._currentAmount))) + finalItems.append(end) + else: + # no boundary, rightmost item + finalItems[-1].setBoolProperty('last.item', True) + + if moreLeft: + start = kodigui.ManagedListItem('') + start.setBoolProperty('is.boundary', True) + start.setBoolProperty('left.boundary', True) + start.setProperty("orig.index", str(int(self.offset))) + finalItems.insert(0, start) + + self.control.replaceItems(finalItems) + self.selectItem(self._currentAmount, more_left=moreLeft, more_right=moreRight, items=items) + + return finalItems + + def selectItem(self, amount, more_left=False, more_right=False, items=None): + if self._direction: + if self._direction == "left": + self.control.selectItem(amount - (1 if not more_left else 0)) + return True + + elif self._direction == "right": + self.control.selectItem(1) + return True + + def paginate(self, force_page=False): + """ + Triggers the pagination for the currently selected view. In case of a hit boundary, show the next or previous + page, otherwise show the initial page. + :return: + """ + if self._boundaryHit or force_page: + items = self.nextPage + + else: + items = self.initialPage + + return self.populate(items) + + @property + def canSimpleWrap(self): + return self.initialPageSize + self.orphans >= self.leafCount + + def wrap(self, mli, last_mli, action): + """ + Wraps around the list if the first or last item is currently selected and the user requests to round robin. + :param mli: current item + :param last_mli: previous item + :param action: xbmcgui action + :return: + """ + + index = int(mli.getProperty("index")) + last_mli_index = int(last_mli.getProperty("index")) + + # special case for our absolute last item + is_rightmost = action == xbmcgui.ACTION_MOVE_RIGHT \ + and mli.getProperty('last.item') \ + and last_mli.getProperty('last.item') + + # _lastAmount is used to immediately wrap again after a wrap has happened; potentially an issue + if not is_rightmost and last_mli_index not in \ + (0, self._currentAmount - 1, (self._lastAmount - 1) if self._lastAmount else None) \ + or self._currentAmount < 2: + return + + onlyTwo = self._currentAmount == 2 + + items = None + if action == xbmcgui.ACTION_MOVE_LEFT and index == 0: + if onlyTwo and last_mli_index == self._currentAmount - 1: + return + + if not self.canSimpleWrap: + self._direction = "right" + self.offset = self.leafCount - self.orphans - self.pageSize + items = self.paginate(force_page=True) + self.control.selectItem(self._currentAmount) + else: + self.control.selectItem(self.leafCount - 1) + elif action == xbmcgui.ACTION_MOVE_RIGHT and (index == self._currentAmount - 1 or is_rightmost): + if onlyTwo and last_mli_index == 0: + return + + if not self.canSimpleWrap: + self._direction = "left" + self.offset = 0 + items = self.paginate() + self.control.selectItem(0) + + if items: + return items + + +class BaseRelatedPaginator(MCLPaginator): + initialPageSize = 8 + pageSize = initialPageSize + orphans = initialPageSize // 2 + + thumbFallback = lambda self, rel: 'script.plex/thumb_fallbacks/{0}.png'.format( + rel.type in ('show', 'season', 'episode') and 'show' or 'movie') + + def createListItem(self, rel): + return kodigui.ManagedListItem( + rel.title or '', + thumbnailImage=rel.defaultThumb.asTranscodedImageURL(*self.parentWindow.RELATED_DIM), + data_source=rel + ) + + def prepareListItem(self, data, mli): + if data.type in ('season', 'show'): + if not mli.dataSource.isWatched: + mli.setProperty('unwatched.count', str(mli.dataSource.unViewedLeafCount)) + else: + mli.setProperty('unwatched', not mli.dataSource.isWatched and '1' or '') + mli.setProperty('progress', util.getProgressImage(mli.dataSource)) diff --git a/script.plexmod/lib/windows/photos.py b/script.plexmod/lib/windows/photos.py new file mode 100644 index 0000000000..df43a7e93d --- /dev/null +++ b/script.plexmod/lib/windows/photos.py @@ -0,0 +1,530 @@ +from __future__ import absolute_import +import threading +import time +import os +import tempfile +import shutil +import hashlib +import requests + +from kodi_six import xbmc, xbmcvfs +from kodi_six import xbmcgui + +from . import kodigui +from . import busy + +from lib import util, colors +from plexnet import plexapp, plexplayer, playqueue + + +class PhotoWindow(kodigui.BaseWindow): + xmlFile = 'script-plex-photo.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + OVERLAY_BUTTON_ID = 250 + OSD_GROUP_ID = 200 + + OSD_BUTTONS_GROUP_ID = 400 + REPEAT_BUTTON_ID = 401 + SHUFFLE_BUTTON_ID = 402 + ROTATE_BUTTON_ID = 403 + PREV_BUTTON_ID = 404 + PLAY_PAUSE_BUTTON_ID = 406 + STOP_BUTTON_ID = 407 + NEXT_BUTTON_ID = 409 + PQUEUE_BUTTON_ID = 412 + + PQUEUE_LIST_ID = 500 + PQUEUE_LIST_OVERLAY_BUTTON_ID = 501 + + SLIDESHOW_INTERVAL = util.slideshowInterval + + PHOTO_STACK_SIZE = 10 + tempSubFolder = ("p4k", "photos") + + def __init__(self, *args, **kwargs): + kodigui.BaseWindow.__init__(self, *args, **kwargs) + self.photo = kwargs.get('photo') + self.playQueue = kwargs.get('play_queue') + self.playerObject = None + self.timelineType = 'photo' + self.lastTimelineState = None + self.ignoreTimelines = False + self.trueTime = 0 + self.slideshowThread = None + self.slideshowRunning = False + self.slideshowNext = 0 + self.osdTimer = None + self.lastItem = None + self.showPhotoThread = None + self.showPhotoTimeout = 0 + self.rotate = 0 + self.tempFolder = None + self.photoStack = [] + self.initialLoad = True + + def onFirstInit(self): + self.tempFolder = os.path.join(util.translatePath("special://temp/"), *self.tempSubFolder) + + if not os.path.exists(self.tempFolder): + try: + os.makedirs(self.tempFolder) + except OSError: + if not os.path.isdir(self.tempFolder): + util.ERROR() + + self.pqueueList = kodigui.ManagedControlList(self, self.PQUEUE_LIST_ID, 14) + #self.setProperty('photo', 'script.plex/indicators/busy-photo.gif') + try: + self.getPlayQueue() + except AttributeError: + raise util.NoDataException + self.start() + self.osdTimer = kodigui.PropertyTimer(self._winID, 4, 'OSD', '', init_value=False, callback=self.osdTimerCallback) + self.imageControl = self.getControl(600) + + def osdTimerCallback(self): + self.setFocusId(self.OVERLAY_BUTTON_ID) + + def onAction(self, action): + try: + # controlID = self.getFocusId() + if action == xbmcgui.ACTION_MOVE_LEFT: + if not self.osdVisible() or self.getFocusId() == self.PQUEUE_LIST_OVERLAY_BUTTON_ID: + self.prev() + elif action == xbmcgui.ACTION_MOVE_RIGHT: + if not self.osdVisible() or self.getFocusId() == self.PQUEUE_LIST_OVERLAY_BUTTON_ID: + self.next() + elif action == xbmcgui.ACTION_MOVE_UP: + if self.osdVisible(): + if self.getFocusId() == self.OVERLAY_BUTTON_ID: + self.hideOSD() + else: + self.showOSD() + elif action == xbmcgui.ACTION_MOVE_DOWN: + if self.osdVisible(): + if self.getFocusId() == self.OVERLAY_BUTTON_ID: + self.hideOSD() + else: + self.showOSD() + elif action == xbmcgui.ACTION_STOP: + self.stop() + elif action in (xbmcgui.ACTION_PLAYER_PLAY, xbmcgui.ACTION_PAUSE): + if self.isPlaying(): + self.pause() + else: + self.play() + elif action == xbmcgui.ACTION_PREV_ITEM: + self.prev() + elif action == xbmcgui.ACTION_NEXT_ITEM: + self.next() + elif action in (xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK): + if self.osdVisible(): + self.hideOSD() + return + self.doClose() + return + + self.osdTimer.reset(init=False) + except: + util.ERROR() + + kodigui.BaseWindow.onAction(self, action) + + def checkPqueueListChanged(self): + item = self.pqueueList.getSelectedItem() + if item == self.lastItem: + return + + self.lastItem = item + self.onPqueueListChanged() + + def onClick(self, controlID): + if controlID == self.PREV_BUTTON_ID: + self.prev() + elif controlID == self.NEXT_BUTTON_ID: + next(self) + elif controlID == self.PLAY_PAUSE_BUTTON_ID: + if self.isPlaying(): + self.pause() + else: + self.play() + elif controlID == self.STOP_BUTTON_ID: + self.stop() + elif controlID == self.OVERLAY_BUTTON_ID: + self.showOSD() + elif controlID == self.SHUFFLE_BUTTON_ID: + self.shuffleButtonClicked() + elif controlID == self.REPEAT_BUTTON_ID: + self.repeatButtonClicked() + elif controlID == self.ROTATE_BUTTON_ID: + self.setRotation() + + def shuffleButtonClicked(self): + self.playQueue.setShuffle() + + def repeatButtonClicked(self): + if self.playQueue.isRepeat: + self.playQueue.setRepeat(False) + self.playQueue.refresh(force=True) + else: + self.playQueue.setRepeat(True) + self.playQueue.refresh(force=True) + + def setRotation(self, angle=None): + if angle is None: + self.resetSlideshowTimeout() + self.rotate += 90 + if self.rotate > 270: + self.rotate = 0 + else: + self.rotate = angle + + if self.rotate == 90: + self.imageControl.setPosition(420, -420) + self.imageControl.setWidth(1080) + self.imageControl.setHeight(1920) + elif self.rotate == 180: + self.imageControl.setPosition(0, 0) + self.imageControl.setWidth(1920) + self.imageControl.setHeight(1080) + elif self.rotate == 270: + self.imageControl.setPosition(420, -420) + self.imageControl.setWidth(1080) + self.imageControl.setHeight(1920) + else: + self.imageControl.setPosition(0, 0) + self.imageControl.setWidth(1920) + self.imageControl.setHeight(1080) + + self.setProperty('rotate', str(self.rotate)) + + def isPlaying(self): + return bool(self.getProperty('playing')) + + def getPlayQueue(self, shuffle=False): + if self.playQueue: + self.playQueue.on('items.changed', self.fillPqueueList) + self.playQueue.on('change', self.updateProperties) + self.updateProperties() + self.fillPqueueList() + else: + self.playQueue = playqueue.createPlayQueueForItem(self.photo, options={'shuffle': shuffle}) + self.playQueue.on('items.changed', self.fillPqueueList) + self.playQueue.on('change', self.updateProperties) + + util.DEBUG_LOG('waiting for playQueue to initialize') + if busy.widthDialog(self.playQueue.waitForInitialization, None): + util.DEBUG_LOG('playQueue initialized: {0}'.format(self.playQueue)) + else: + util.DEBUG_LOG('playQueue timed out wating for initialization') + + self.showPhoto() + + def fillPqueueList(self, **kwargs): + items = [] + for qi in self.playQueue.items(): + mli = kodigui.ManagedListItem(thumbnailImage=qi.thumb.asTranscodedImageURL(123, 123), data_source=qi) + items.append(mli) + + self.pqueueList.replaceItems(items) + self.updatePqueueListSelection() + + def updatePqueueListSelection(self, current=None): + selected = self.pqueueList.getListItemByDataSource(current or self.playQueue.current()) + if not selected or not selected.pos(): + return + + self.pqueueList.selectItem(selected.pos()) + + def showPhoto(self, trigger=None, **kwargs): + self.slideshowNext = 0 + + if not self.showPhotoThread or not self.showPhotoThread.is_alive(): + # if trigger is given, trigger it. trigger loads the next or prev item, depending on what was requested + # doing this here, this late prevents erratic behaviour when multiple next/prev calls were made but we were + # still loading images + if trigger: + trigger() + self.updateProperties() + + photo = self.playQueue.current() + + # fixme: video should work. + # bad temporary fix for videos in photo playqueues + if photo.type != "photo": + self.next() + util.DEBUG_LOG("SKIPPING PHOTO: %s" % photo) + return + + self.updatePqueueListSelection(photo) + + self.showPhotoTimeout = time.time() + 0.2 + if not self.showPhotoThread or not self.showPhotoThread.is_alive(): + self.showPhotoThread = threading.Thread(target=self._showPhoto, name="showphoto") + self.showPhotoThread.start() + + # wait for the current thread to end, which might still be loading the surrounding images, for 10 seconds + elif self.showPhotoThread.is_alive(): + waitedFor = 0 + self.setBoolProperty('is.updating', True) + while waitedFor < 100: + if not self.showPhotoThread.is_alive() and not util.MONITOR.abortRequested(): + return self.showPhoto(trigger=trigger, **kwargs) + elif util.MONITOR.abortRequested(): + self.setBoolProperty('is.updating', False) + return + + util.MONITOR.waitForAbort(0.1) + waitedFor += 0.1 + + # fixme raise error here + + def _showPhoto(self): + """ + load the current photo, preload the previous and the next one + :return: + """ + photo = self.playQueue.current() + next = self.playQueue.getNext() + loadItems = (photo, next, self.playQueue.getPrev()) + for item in loadItems: + if item is not None: + item.softReload() + + self.playerObject = plexplayer.PlexPhotoPlayer(photo) + + addToStack = [] + currentFailed = False + try: + for item in loadItems: + if not item: + continue + + if item.type != "photo": + continue + + meta = self.playerObject.build(item=item) + url = photo.server.getImageTranscodeURL(meta.get('url', ''), self.width, self.height) + bgURL = item.thumb.asTranscodedImageURL(self.width, self.height, blur=128, opacity=60, + background=colors.noAlpha.Background) + + isCurrent = currentFailed or item == photo + if isCurrent and not self.initialLoad: + self.setBoolProperty('is.updating', True) + + path, background = self.getCachedPhotoData(url, bgURL) + if not (path and background): + currentFailed = True + continue + + if (path, background) not in self.photoStack: + if item == next: + # move the next image to the top of the stack + addToStack.insert(0, (path, background)) + else: + addToStack.append((path, background)) + + if isCurrent: + self._reallyShowPhoto(item, path, background) + self.setBoolProperty('is.updating', False) + self.initialLoad = False + + # maintain cache folder + self.photoStack = addToStack + self.photoStack + if len(self.photoStack) > self.PHOTO_STACK_SIZE: + clean = self.photoStack[self.PHOTO_STACK_SIZE:] + self.photoStack = self.photoStack[:self.PHOTO_STACK_SIZE] + for remList in clean: + for rem in remList: + try: + os.remove(rem) + except: + pass + finally: + self.setBoolProperty('is.updating', False) + + def getCachedPhotoData(self, url, bgURL): + if not url: + return + + basename = hashlib.sha1(url.encode('utf-8')).hexdigest() + tmpPath = os.path.join(self.tempFolder, basename) + tmpBgPath = os.path.join(self.tempFolder, "%s_bg" % basename) + + for p, url in ((tmpPath, url), (tmpBgPath, bgURL)): + if not os.path.exists(p):# and not xbmc.getCacheThumbName(tmpFn): + try: + r = requests.get(url, allow_redirects=True, timeout=10.0) + r.raise_for_status() + except Exception as e: + util.ERROR("Couldn't load image: %s" % e, notify=True) + return None, None + else: + try: + with open(p, 'wb') as f: + f.write(r.content) + except: + return None, None + + return tmpPath, tmpBgPath + + def _reallyShowPhoto(self, photo, path, background): + self.setRotation(0) + self.setProperty('photo', path) + self.setProperty('background', background) + + self.setProperty('photo.title', photo.title) + self.setProperty('photo.date', util.cleanLeadingZeros(photo.originallyAvailableAt.asDatetime('%d %B %Y'))) + self.setProperty('camera.model', photo.media[0].model) + self.setProperty('camera.lens', photo.media[0].lens) + + if photo.media[0].height: + dims = u'{0} x {1}{2}'.format( + photo.media[0].width, + photo.media[0].height, + photo.media[0].parts[0].orientation and u' \u2022 {0} Mo'.format(photo.media[0].parts[0].orientation) or '' + ) + self.setProperty('photo.dims', dims) + settings = [] + if photo.media[0].iso: + settings.append('ISO {0}'.format(photo.media[0].iso)) + if photo.media[0].aperture: + settings.append('{0}'.format(photo.media[0].aperture)) + if photo.media[0].exposure: + settings.append('{0}'.format(photo.media[0].exposure)) + self.setProperty('camera.settings', u' \u2022 '.join(settings)) + self.setProperty('photo.summary', photo.summary) + container = photo.media[0].container_ or os.path.splitext(photo.media[0].parts[0].file)[-1][1:].lower() + if container == 'jpg': + container = 'jpeg' + self.setProperty('photo.container', container) + self.updateNowPlaying(force=True, refreshQueue=True) + self.resetSlideshowTimeout() + + def updateProperties(self, **kwargs): + self.setProperty('pq.shuffled', self.playQueue.isShuffled and '1' or '') + self.setProperty('pq.repeat', self.playQueue.isRepeat and '1' or '') + if not self.getProperty('hide.prev') and not self.playQueue.hasPrev(): + if self.playQueue.hasNext(): + self.setFocusId(self.NEXT_BUTTON_ID) + else: + self.setFocusId(self.PLAY_PAUSE_BUTTON_ID) + self.setProperty('hide.prev', not self.playQueue.hasPrev() and '1' or '') + if not self.getProperty('hide.next') and not self.playQueue.hasNext(): + if self.playQueue.hasPrev(): + self.setFocusId(self.PREV_BUTTON_ID) + else: + self.setFocusId(self.PLAY_PAUSE_BUTTON_ID) + self.setProperty('hide.next', not self.playQueue.hasNext() and '1' or '') + + def slideshow(self): + util.DEBUG_LOG('Slideshow: STARTED') + self.slideshowRunning = True + + # inhibit screensaver in matrix and above + if util.KODI_VERSION_MAJOR > 18: + xbmc.executebuiltin('InhibitScreensaver(true)') + + self.resetSlideshowTimeout() + while not util.MONITOR.waitForAbort(0.1) and self.slideshowRunning: + if not self.slideshowNext or time.time() < self.slideshowNext: + continue + self.next() + + if util.KODI_VERSION_MAJOR > 18: + xbmc.executebuiltin('InhibitScreensaver(false)') + + util.DEBUG_LOG('Slideshow: STOPPED') + + def resetSlideshowTimeout(self): + self.slideshowNext = time.time() + self.SLIDESHOW_INTERVAL + + def osdVisible(self): + return self.getProperty('OSD') + + def pqueueVisible(self): + return self.getProperty('show.pqueue') + + def start(self): + self.setFocusId(self.OVERLAY_BUTTON_ID) + + def prev(self): + if not self.playQueue.getPrev(): + return + self.showPhoto(trigger=lambda: self.playQueue.prev()) + + def next(self): + if not self.playQueue.getNext(): + return + self.showPhoto(trigger=lambda: self.playQueue.next()) + + __next__ = next + + def play(self): + self.setProperty('playing', '1') + if self.slideshowThread and self.slideshowThread.is_alive(): + return + + self.slideshowThread = threading.Thread(target=self.slideshow, name='slideshow') + self.slideshowThread.start() + + def pause(self): + self.setProperty('playing', '') + self.slideshowRunning = False + + def stop(self): + self.doClose() + + def doClose(self): + self.pause() + shutil.rmtree(self.tempFolder, ignore_errors=True) + + kodigui.BaseWindow.doClose(self) + + def getCurrentItem(self): + if self.playerObject: + return self.playerObject.item + return None + + def shouldSendTimeline(self, item): + return item.ratingKey and item.getServer() + + def updateNowPlaying(self, force=False, refreshQueue=False, state=None): + if self.ignoreTimelines: + return + + item = self.getCurrentItem() + + if not item: + return + + if not self.shouldSendTimeline(item): + return + + state = state or 'paused' + # Avoid duplicates + if state == self.lastTimelineState and not force: + return + + self.lastTimelineState = state + # self.timelineTimer.reset() + + time = int(self.trueTime * 1000) + + # self.trigger("progress", [m, item, time]) + + if refreshQueue and self.playQueue: + self.playQueue.refreshOnTimeline = True + + plexapp.util.APP.nowplayingmanager.updatePlaybackState(self.timelineType, self.playerObject, state, time, self.playQueue) + + def showOSD(self): + self.osdTimer.reset(init=False) + + def hideOSD(self, closing=False): + self.osdTimer.stop(trigger=True) diff --git a/script.plexmod/lib/windows/playbacksettings.py b/script.plexmod/lib/windows/playbacksettings.py new file mode 100644 index 0000000000..5e614e1aec --- /dev/null +++ b/script.plexmod/lib/windows/playbacksettings.py @@ -0,0 +1,64 @@ +# coding=utf-8 +from lib import util +from lib.util import T + +from plexnet.util import INTERFACE + +from . import dropdown + + +class PlaybackSettingsMixin(object): + def playbackSettings(self, show, pos, bottom): + pbs = INTERFACE.playbackManager(show) + pbOpts = [] + transEnabled = T(33507) + transDisabled = T(33508) + + currentSettings = {} + for key, transID in INTERFACE.playbackManager.transMap.items(): + state = getattr(pbs, key) + stateTrans = state and transEnabled or transDisabled + pbOpts.append({'key': key, 'display': "{}: {}".format(stateTrans, T(transID))}) + currentSettings[key] = state + + # create a new dict which we can freely change while the dropdown is open + newSettings = currentSettings.copy() + + # fixme: not sure if garbage collection is necessary here + + def callback(opts, mli, force_off=False): + choice = mli.dataSource + oc = newSettings[choice["key"]] + ic = (not oc) if not force_off else False + + # invalidate any other setting if bingemode enabled + if choice["key"] == "binge_mode" and ic: + for m in opts.items: + if m.dataSource["key"] != "binge_mode": + callback(opts, m, force_off=True) + del m + + # disable bingeMode if any other setting is enabled + elif choice["key"] != "binge_mode" and newSettings["binge_mode"]: + m = opts.getListItem(0) + callback(opts, m, force_off=True) + del m + + newSettings[choice["key"]] = ic + label = choice["display"].replace("{}: ".format(oc and transEnabled or transDisabled), + "{}: ".format(ic and transEnabled or transDisabled)) + mli.setLabel(label) + mli.dataSource["display"] = label + del mli + + # fixme: not sure if garbage collection is necessary here + util.garbageCollect() + pbChoice = dropdown.showDropdown(pbOpts, pos, pos_is_bottom=bottom, close_direction='left', + set_dropdown_prop=True, + header="{}: {}".format(T(32925, 'Playback Settings'), show.defaultTitle), + close_only_with_back=True, align_items='left', + options_callback=callback) + + # write new settings for item if necessary + if newSettings != currentSettings: + INTERFACE.playbackManager(show, kv_dict=newSettings) diff --git a/script.plexmod/lib/windows/playerbackground.py b/script.plexmod/lib/windows/playerbackground.py new file mode 100644 index 0000000000..e34073b15e --- /dev/null +++ b/script.plexmod/lib/windows/playerbackground.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import +import contextlib +from . import kodigui +from lib import util + + +class PlayerBackground(kodigui.BaseWindow): + xmlFile = 'script-plex-player_background.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + def __init__(self, *args, **kwargs): + kodigui.BaseWindow.__init__(self, *args, **kwargs) + self.background = kwargs.get('background', '') + self._closedSet = False + + def onFirstInit(self): + self.setProperty('background', self.background) + + def onReInit(self): + if self._closedSet: + self._closedSet = False + self.doClose() + + @contextlib.contextmanager + def asContext(self): + self.show() + yield + self.doClose() + + def setClosed(self): + self._closedSet = True + self.doClose() + + +class PlayerBackgroundContext(object): + def __init__(self, **kwargs): + self.kwargs = kwargs + self.window = None + + def __enter__(self): + self.window = PlayerBackground.create(**self.kwargs) + + def __exit__(self, exc_type, exc_value, traceback): + self.close() + + def close(self): + if self.window: + self.window.doClose() + del self.window + self.window = None diff --git a/script.plexmod/lib/windows/playersettings.py b/script.plexmod/lib/windows/playersettings.py new file mode 100644 index 0000000000..0ad1c58ed2 --- /dev/null +++ b/script.plexmod/lib/windows/playersettings.py @@ -0,0 +1,340 @@ +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import kodigui + +from lib import util +from lib import metadata +from lib.util import T + +import plexnet + + +class VideoSettingsDialog(kodigui.BaseDialog, util.CronReceiver): + xmlFile = 'script-plex-video_settings_dialog.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + SETTINGS_LIST_ID = 100 + + def __init__(self, *args, **kwargs): + kodigui.BaseDialog.__init__(self, *args, **kwargs) + self.video = kwargs.get('video') + self.viaOSD = kwargs.get('via_osd') + self.nonPlayback = kwargs.get('non_playback') + self.parent = kwargs.get('parent') + self.roundRobin = kwargs.get('round_robin', True) + self.lastSelectedItem = 0 + + if not self.video.mediaChoice: + playerObject = plexnet.plexplayer.PlexPlayer(self.video) + playerObject.build() + + def onFirstInit(self): + self.settingsList = kodigui.ManagedControlList(self, self.SETTINGS_LIST_ID, 6) + self.setProperty('heading', T(32343, 'Settings')) + if self.viaOSD: + self.setProperty('via.OSD', '1') + self.showSettings(True) + util.CRON.registerReceiver(self) + + def onAction(self, action): + try: + if not xbmc.getCondVisibility('Player.HasMedia') and not self.nonPlayback: + self.doClose() + return + except: + util.ERROR() + + if self.roundRobin and action in (xbmcgui.ACTION_MOVE_UP, xbmcgui.ACTION_MOVE_DOWN) and \ + self.getFocusId() == self.SETTINGS_LIST_ID: + to_pos = None + last_index = self.settingsList.size() - 1 + if action == xbmcgui.ACTION_MOVE_UP and self.lastSelectedItem == 0 and self.settingsList.topHasFocus(): + to_pos = last_index + + elif action == xbmcgui.ACTION_MOVE_DOWN and self.lastSelectedItem == last_index \ + and self.settingsList.bottomHasFocus(): + to_pos = 0 + + if to_pos is not None: + self.settingsList.setSelectedItemByPos(to_pos) + self.lastSelectedItem = to_pos + return + + self.lastSelectedItem = self.settingsList.control.getSelectedPosition() + + kodigui.BaseDialog.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.SETTINGS_LIST_ID: + self.editSetting() + + def onClosed(self): + util.CRON.cancelReceiver(self) + + def tick(self): + if self.nonPlayback: + return + + if not xbmc.getCondVisibility('Player.HasMedia'): + self.doClose() + return + + def showSettings(self, init=False): + video = self.video + override = video.settings.getPrefOverride('local_quality') + if override is not None and override < 13: + current = T((32001, 32002, 32003, 32004, 32005, 32006, 32007, 32008, 32009, 32010, 32011, 32012, 32013, 32014)[13 - override]) + else: + current = u'{0} {1} ({2})'.format( + plexnet.util.bitrateToString(video.mediaChoice.media.bitrate.asInt() * 1000), + video.mediaChoice.media.getVideoResolutionString(), + video.mediaChoice.media.title or 'Original' + ) + + audio, subtitle = self.getAudioAndSubtitleInfo() + + options = [ + ('audio', T(32395, 'Audio'), audio), + ('subs', T(32396, 'Subtitles'), subtitle), + ('quality', T(32397, 'Quality'), u'{0}'.format(current)) + ] + + if not self.nonPlayback: + options += [ + ('kodi_video', T(32398, 'Kodi Video Settings'), ''), + ('kodi_audio', T(32399, 'Kodi Audio Settings'), ''), + ] + if util.KODI_VERSION_MAJOR >= 18: + options.append(('kodi_subtitle', T(32492, 'Kodi Subtitle Settings'), '')) + + if self.viaOSD: + if self.parent.getProperty("show.PPI"): + options += [ + ('stream_info', T(32483, 'Hide Stream Info'), ''), + ] + else: + options += [ + ('stream_info', T(32484, 'Show Stream Info'), ''), + ] + + items = [] + for o in options: + item = kodigui.ManagedListItem(o[1], o[2], data_source=o[0]) + items.append(item) + if init: + self.settingsList.reset() + self.settingsList.addItems(items) + else: + self.settingsList.replaceItems(items) + + self.setFocusId(self.SETTINGS_LIST_ID) + + def getAudioAndSubtitleInfo(self): + sas = self.video.selectedAudioStream() + audio = sas and sas.getTitle(metadata.apiTranslate) or T(32309, 'None') + + sss = self.video.selectedSubtitleStream( + forced_subtitles_override=util.getSetting("forced_subtitles_override", False)) + if sss: + if len(self.video.subtitleStreams) > 1: + subtitle = u'{0} \u2022 {1} {2}'.format(sss.getTitle(metadata.apiTranslate), len(self.video.subtitleStreams) - 1, T(32307, 'More')) + else: + subtitle = sss.getTitle(metadata.apiTranslate) + else: + if self.video.subtitleStreams: + subtitle = u'{0} \u2022 {1} {2}'.format(T(32309, 'None'), len(self.video.subtitleStreams), T(32308, 'Available')) + else: + subtitle = T(32309, 'None') + + return audio, subtitle + + def editSetting(self): + mli = self.settingsList.getSelectedItem() + if not mli: + return + + result = mli.dataSource + + if result == 'audio': + showAudioDialog(self.video, non_playback=self.nonPlayback) + elif result == 'subs': + showSubtitlesDialog(self.video, non_playback=self.nonPlayback) + elif result == 'quality': + idx = None + override = self.video.settings.getPrefOverride('local_quality') + if override is not None and override < 13: + idx = 13 - override + showQualityDialog(self.video, non_playback=self.nonPlayback, selected_idx=idx) + elif result == 'kodi_video': + xbmc.executebuiltin('ActivateWindow(OSDVideoSettings)') + elif result == 'kodi_audio': + xbmc.executebuiltin('ActivateWindow(OSDAudioSettings)') + elif result == 'kodi_subtitle': + xbmc.executebuiltin('ActivateWindow(OSDSubtitleSettings)') + elif result == "stream_info": + if self.parent: + if self.parent.getProperty("show.PPI"): + self.parent.hidePPIDialog() + else: + #xbmc.executebuiltin('Action(PlayerProcessInfo)') + self.parent.showPPIDialog() + self.doClose() + return + + self.showSettings() + + +class SelectDialog(kodigui.BaseDialog, util.CronReceiver): + xmlFile = 'script-plex-settings_select_dialog.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + OPTIONS_LIST_ID = 100 + + def __init__(self, *args, **kwargs): + kodigui.BaseDialog.__init__(self, *args, **kwargs) + self.heading = kwargs.get('heading') + self.options = kwargs.get('options') + self.selectedIdx = kwargs.get('selected_idx') + self.choice = None + self.nonPlayback = kwargs.get('non_playback') + self.lastSelectedItem = self.selectedIdx if self.selectedIdx is not None else 0 + self.roundRobin = kwargs.get('round_robin', True) + + def onFirstInit(self): + self.optionsList = kodigui.ManagedControlList(self, self.OPTIONS_LIST_ID, 8) + self.setProperty('heading', self.heading) + self.showOptions() + util.CRON.registerReceiver(self) + + def onAction(self, action): + try: + if not xbmc.getCondVisibility('Player.HasMedia') and not self.nonPlayback: + self.doClose() + return + except: + util.ERROR() + + if self.roundRobin and action in (xbmcgui.ACTION_MOVE_UP, xbmcgui.ACTION_MOVE_DOWN) and \ + self.getFocusId() == self.OPTIONS_LIST_ID: + to_pos = None + last_index = self.optionsList.size() - 1 + + if last_index > 0: + if action == xbmcgui.ACTION_MOVE_UP and self.lastSelectedItem == 0 and self.optionsList.topHasFocus(): + to_pos = last_index + + elif action == xbmcgui.ACTION_MOVE_DOWN and self.lastSelectedItem == last_index \ + and self.optionsList.bottomHasFocus(): + to_pos = 0 + + if to_pos is not None: + self.optionsList.setSelectedItemByPos(to_pos) + self.lastSelectedItem = to_pos + return + + self.lastSelectedItem = self.optionsList.control.getSelectedPosition() + + kodigui.BaseDialog.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.OPTIONS_LIST_ID: + self.setChoice() + + def onClosed(self): + util.CRON.cancelReceiver(self) + + def tick(self): + if self.nonPlayback: + return + + if not xbmc.getCondVisibility('Player.HasMedia'): + self.doClose() + return + + def setChoice(self): + mli = self.optionsList.getSelectedItem() + if not mli: + return + + self.choice = self.options[self.optionsList.getSelectedPosition()][0] + self.doClose() + + def showOptions(self): + items = [] + for o in self.options: + item = kodigui.ManagedListItem(o[1], data_source=o[0]) + items.append(item) + + self.optionsList.reset() + self.optionsList.addItems(items) + + if self.selectedIdx is not None: + self.optionsList.selectItem(self.selectedIdx) + + self.setFocusId(self.OPTIONS_LIST_ID) + + +def showOptionsDialog(heading, options, non_playback=False, selected_idx=None): + w = SelectDialog.open(heading=heading, options=options, non_playback=non_playback, selected_idx=selected_idx) + choice = w.choice + del w + util.garbageCollect() + return choice + + +def showAudioDialog(video, non_playback=False): + options = [] + idx = None + for i, s in enumerate(video.audioStreams): + if s.isSelected(): + idx = i + options.append((s, s.getTitle(metadata.apiTranslate))) + choice = showOptionsDialog(T(32395, 'Audio'), options, non_playback=non_playback, selected_idx=idx) + if choice is None: + return + + video.selectStream(choice) + + +def showSubtitlesDialog(video, non_playback=False): + options = [(plexnet.plexstream.NoneStream(), 'None')] + idx = None + for i, s in enumerate(video.subtitleStreams): + if s.isSelected(): + idx = i + 1 + options.append((s, s.getTitle(metadata.apiTranslate))) + + choice = showOptionsDialog(T(32396, 'Subtitle'), options, non_playback=non_playback, selected_idx=idx) + if choice is None: + return + + video.selectStream(choice) + video.manually_selected_sub_stream = choice.id + + +def showQualityDialog(video, non_playback=False, selected_idx=None): + options = [(13 - i, T(l)) for (i, l) in enumerate((32001, 32002, 32003, 32004, 32005, 32006, 32007, 32008, 32009, + 32010, 32011))] + + choice = showOptionsDialog('Quality', options, non_playback=non_playback, selected_idx=selected_idx) + if choice is None: + return + + video.settings.setPrefOverride('local_quality', choice) + video.settings.setPrefOverride('remote_quality', choice) + video.settings.setPrefOverride('online_quality', choice) + + +def showDialog(video, non_playback=False, via_osd=False, parent=None): + w = VideoSettingsDialog.open(video=video, non_playback=non_playback, via_osd=via_osd, parent=parent) + del w + util.garbageCollect() diff --git a/script.plexmod/lib/windows/playlist.py b/script.plexmod/lib/windows/playlist.py new file mode 100644 index 0000000000..705fed3725 --- /dev/null +++ b/script.plexmod/lib/windows/playlist.py @@ -0,0 +1,325 @@ +from __future__ import absolute_import +import threading + +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import kodigui + +from . import busy +from . import videoplayer +from . import windowutils +from . import dropdown +from . import search +import plexnet +from . import opener + +from lib import colors +from lib import util +from lib import player +from lib import backgroundthread + +from lib.util import T +from six.moves import range + +PLAYLIST_PAGE_SIZE = 500 +PLAYLIST_INITIAL_SIZE = 100 + + +class ChunkRequestTask(backgroundthread.Task): + WINDOW = None + + @classmethod + def reset(cls): + del cls.WINDOW + cls.WINDOW = None + + def setup(self, start, size): + self.start = start + self.size = size + return self + + def contains(self, pos): + return self.start <= pos <= (self.start + self.size) + + def run(self): + if self.isCanceled(): + return + + try: + items = self.WINDOW.playlist.extend(self.start, self.size) + if self.isCanceled(): + return + + if not self.WINDOW: # Window is closed + return + + self.WINDOW.chunkCallback(items, self.start) + except AttributeError: + util.DEBUG_LOG('Playlist window closed, ignoring chunk at index {0}'.format(self.start)) + except plexnet.exceptions.BadRequest: + util.DEBUG_LOG('404 on playlist: {0}'.format(repr(self.WINDOW.playlist.title))) + + +class PlaylistWindow(kodigui.ControlledWindow, windowutils.UtilMixin): + xmlFile = 'script-plex-playlist.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + OPTIONS_GROUP_ID = 200 + HOME_BUTTON_ID = 201 + SEARCH_BUTTON_ID = 202 + PLAYER_STATUS_BUTTON_ID = 204 + + PLAY_BUTTON_ID = 301 + SHUFFLE_BUTTON_ID = 302 + OPTIONS_BUTTON_ID = 303 + + LI_AR16X9_THUMB_DIM = util.scaleResolution(178, 100) + LI_SQUARE_THUMB_DIM = util.scaleResolution(100, 100) + + ALBUM_THUMB_DIM = util.scaleResolution(630, 630) + + PLAYLIST_LIST_ID = 101 + + def __init__(self, *args, **kwargs): + kodigui.ControlledWindow.__init__(self, *args, **kwargs) + self.playlist = kwargs.get('playlist') + self.exitCommand = None + self.tasks = backgroundthread.Tasks() + self.isPlaying = False + ChunkRequestTask.WINDOW = self + + def onFirstInit(self): + self.playlistListControl = kodigui.ManagedControlList(self, self.PLAYLIST_LIST_ID, 5) + self.setProperties() + + self.fillPlaylist() + self.setFocusId(self.PLAYLIST_LIST_ID) + + # def onAction(self, action): + # try: + # if action in(xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_CONTEXT_MENU): + # if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)): + # self.setFocusId(self.OPTIONS_GROUP_ID) + # return + # except: + # util.ERROR() + + # kodigui.ControlledWindow.onAction(self, action) + + def onAction(self, action): + try: + if action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): + self.doClose() + except: + util.ERROR() + + kodigui.ControlledWindow.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.HOME_BUTTON_ID: + self.goHome() + elif controlID == self.PLAYLIST_LIST_ID: + self.playlistListClicked() + elif controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() + elif controlID == self.PLAY_BUTTON_ID: + self.playlistListClicked(no_item=True, shuffle=False) + elif controlID == self.SHUFFLE_BUTTON_ID: + self.playlistListClicked(no_item=True, shuffle=True) + elif controlID == self.OPTIONS_BUTTON_ID: + self.optionsButtonClicked() + elif controlID == self.SEARCH_BUTTON_ID: + self.searchButtonClicked() + + def doClose(self): + kodigui.ControlledWindow.doClose(self) + self.tasks.cancel() + ChunkRequestTask.reset() + + def searchButtonClicked(self): + self.processCommand(search.dialog(self)) + + def playlistListClicked(self, no_item=False, shuffle=False): + if no_item: + mli = None + else: + mli = self.playlistListControl.getSelectedItem() + if not mli or not mli.dataSource: + return + + try: + self.isPlaying = True + self.tasks.cancel() + player.PLAYER.stop() # Necessary because if audio is already playing, it will close the window when that is stopped + if self.playlist.playlistType == 'audio': + if self.playlist.leafCount.asInt() <= PLAYLIST_INITIAL_SIZE: + self.playlist.setShuffle(shuffle) + self.playlist.setCurrent(mli and mli.pos() or 0) + self.showAudioPlayer(track=mli and mli.dataSource or self.playlist.current(), playlist=self.playlist) + else: + args = {'sourceType': '8', 'shuffle': shuffle} + if mli: + args['key'] = mli.dataSource.key + pq = plexnet.playqueue.createPlayQueueForItem(self.playlist, options=args) + opener.open(pq) + elif self.playlist.playlistType == 'video': + if not util.advancedSettings.playlistVisitMedia: + if self.playlist.leafCount.asInt() <= PLAYLIST_INITIAL_SIZE: + self.playlist.setShuffle(shuffle) + self.playlist.setCurrent(mli and mli.pos() or 0) + videoplayer.play(play_queue=self.playlist) + else: + args = {'shuffle': shuffle} + if mli: + args['key'] = mli.dataSource.key + pq = plexnet.playqueue.createPlayQueueForItem(self.playlist, options=args) + opener.open(pq) + else: + if not mli: + firstItem = 0 + if shuffle: + import random + firstItem = random.randint(0, self.playlistListControl.size()-1) + mli = self.playlistListControl.getListItem(firstItem) + self.openItem(mli.dataSource) + + finally: + self.isPlaying = False + self.restartFill() + + def restartFill(self): + threading.Thread(target=self._restartFill).start() + + def _restartFill(self): + util.DEBUG_LOG('Checking if playlist list is full...') + for idx, mli in enumerate(self.playlistListControl): + if self.isPlaying or not self.isOpen or util.MONITOR.abortRequested(): + break + + if not mli.dataSource: + if self.playlist[idx]: + self.updateListItem(idx, self.playlist[idx]) + else: + break + # Update the progress for videos + elif mli.dataSource.type in ('episode', 'movie', 'clip'): + mli.dataSource.reload() + self.updateListItem(idx, mli.dataSource) + else: + util.DEBUG_LOG('Playlist list is full - nothing to do') + return + + util.DEBUG_LOG('Playlist list is not full - finishing') + total = self.playlist.leafCount.asInt() + for start in range(idx, total, PLAYLIST_PAGE_SIZE): + if util.MONITOR.abortRequested(): + break + self.tasks.add(ChunkRequestTask().setup(start, PLAYLIST_PAGE_SIZE)) + + backgroundthread.BGThreader.addTasksToFront(self.tasks) + + def optionsButtonClicked(self): + options = [] + if xbmc.getCondVisibility('Player.HasAudio + MusicPlayer.HasNext'): + options.append({'key': 'play_next', 'display': T(32325, 'Play Next')}) + + if not options: + return + + choice = dropdown.showDropdown(options, (440, 1020), close_direction='down', pos_is_bottom=True, close_on_playback_ended=True) + if not choice: + return + + if choice['key'] == 'play_next': + xbmc.executebuiltin('PlayerControl(Next)') + + def setProperties(self): + self.setProperty( + 'background', + util.backgroundFromArt(self.playlist.composite, width=self.width, height=self.height) + ) + self.setProperty('playlist.thumb', self.playlist.composite.asTranscodedImageURL(*self.ALBUM_THUMB_DIM)) + self.setProperty('playlist.title', self.playlist.title) + self.setProperty('playlist.duration', util.durationToText(self.playlist.duration.asInt())) + + def updateListItem(self, idx, pi, mli=None): + mli = mli or self.playlistListControl.getListItem(idx) + mli.setLabel(pi.title) + mli.setProperty('track.ID', pi.ratingKey) + mli.setProperty('track.number', str(idx + 1)) + mli.dataSource = pi + + if pi.type == 'track': + self.createTrackListItem(mli, pi) + elif pi.type == 'episode': + self.createEpisodeListItem(mli, pi) + elif pi.type in ('movie', 'clip'): + self.createMovieListItem(mli, pi) + + if pi.type in ('episode', 'movie', 'clip'): + mli.setProperty('progress', util.getProgressImage(mli.dataSource)) + + return mli + + def createTrackListItem(self, mli, track): + mli.setLabel2(u'{0} / {1}'.format(track.grandparentTitle, track.parentTitle)) + mli.setThumbnailImage(track.defaultThumb.asTranscodedImageURL(*self.LI_SQUARE_THUMB_DIM)) + mli.setProperty('track.duration', util.simplifiedTimeDisplay(track.duration.asInt())) + + def createEpisodeListItem(self, mli, episode): + label2 = u'{0} \u2022 {1}'.format( + episode.grandparentTitle, u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), episode.parentIndex, T(32311, 'E'), episode.index) + ) + mli.setLabel2(label2) + mli.setThumbnailImage(episode.thumb.asTranscodedImageURL(*self.LI_AR16X9_THUMB_DIM)) + mli.setProperty('track.duration', util.durationToShortText(episode.duration.asInt())) + mli.setProperty('video', '1') + mli.setProperty('watched', episode.isWatched and '1' or '') + + def createMovieListItem(self, mli, movie): + mli.setLabel(movie.defaultTitle) + mli.setLabel2(movie.year) + mli.setThumbnailImage(movie.art.asTranscodedImageURL(*self.LI_AR16X9_THUMB_DIM)) + mli.setProperty('track.duration', util.durationToShortText(movie.duration.asInt())) + mli.setProperty('video', '1') + mli.setProperty('watched', movie.isWatched and '1' or '') + + @busy.dialog() + def fillPlaylist(self): + total = self.playlist.leafCount.asInt() + + # leafCount is clamped to 6 when coming from Home/PlaylistsHub + actualPlaylistLength = len(self.playlist.items()) + + if total < len(self.playlist): + total = actualPlaylistLength + + endoffirst = min(PLAYLIST_INITIAL_SIZE, PLAYLIST_PAGE_SIZE, total) + items = [self.updateListItem(i, pi, kodigui.ManagedListItem()) for i, pi in enumerate(self.playlist.extend(0, endoffirst))] + + items += [kodigui.ManagedListItem() for i in range(total - endoffirst)] + + self.playlistListControl.reset() + self.playlistListControl.addItems(items) + + if total <= min(PLAYLIST_INITIAL_SIZE, PLAYLIST_PAGE_SIZE): + return + + for start in range(endoffirst, total, PLAYLIST_PAGE_SIZE): + if util.MONITOR.abortRequested(): + break + self.tasks.add(ChunkRequestTask().setup(start, PLAYLIST_PAGE_SIZE)) + + backgroundthread.BGThreader.addTasksToFront(self.tasks) + + def chunkCallback(self, items, start): + for i, pi in enumerate(items): + if self.isPlaying or not self.isOpen or util.MONITOR.abortRequested(): + break + + idx = start + i + self.updateListItem(idx, pi) diff --git a/script.plexmod/lib/windows/playlists.py b/script.plexmod/lib/windows/playlists.py new file mode 100644 index 0000000000..12d22bb1fa --- /dev/null +++ b/script.plexmod/lib/windows/playlists.py @@ -0,0 +1,138 @@ +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import kodigui + +from . import busy +from . import playlist +from . import windowutils +from . import search + +from lib import util +from lib import colors + +from plexnet import plexapp + + +class PlaylistsWindow(kodigui.ControlledWindow, windowutils.UtilMixin): + xmlFile = 'script-plex-playlists.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + THUMB_DIMS = { + 'audio': { + 'item.thumb': util.scaleResolution(270, 270) + }, + 'video': { + 'item.thumb': util.scaleResolution(610, 344) + } + } + + AUDIO_PL_LIST_ID = 101 + VIDEO_PL_LIST_ID = 301 + + OPTIONS_GROUP_ID = 200 + + HOME_BUTTON_ID = 201 + SEARCH_BUTTON_ID = 202 + PLAYER_STATUS_BUTTON_ID = 204 + + def __init__(self, *args, **kwargs): + kodigui.ControlledWindow.__init__(self, *args, **kwargs) + self.exitCommand = None + + def onFirstInit(self): + self.audioPLListControl = kodigui.ManagedControlList(self, self.AUDIO_PL_LIST_ID, 5) + self.videoPLListControl = kodigui.ManagedControlList(self, self.VIDEO_PL_LIST_ID, 5) + + self.fill() + if self.audioPLListControl.size(): + self.setFocusId(self.AUDIO_PL_LIST_ID) + else: + self.setFocusId(self.VIDEO_PL_LIST_ID) + + def onAction(self, action): + try: + if action == xbmcgui.ACTION_CONTEXT_MENU: + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)): + self.setFocusId(self.OPTIONS_GROUP_ID) + return + # elif action in(xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_CONTEXT_MENU): + # if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)): + # self.setFocusId(self.OPTIONS_GROUP_ID) + # return + + except: + util.ERROR() + + kodigui.ControlledWindow.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.HOME_BUTTON_ID: + self.goHome() + elif controlID == self.AUDIO_PL_LIST_ID: + self.playlistListClicked(self.audioPLListControl) + elif controlID == self.VIDEO_PL_LIST_ID: + self.playlistListClicked(self.videoPLListControl) + elif controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() + elif controlID == self.SEARCH_BUTTON_ID: + self.searchButtonClicked() + + def searchButtonClicked(self): + self.processCommand(search.dialog(self)) + + def playlistListClicked(self, list_control): + mli = list_control.getSelectedItem() + if not mli: + return + + self.openWindow(playlist.PlaylistWindow, playlist=mli.dataSource) + + def createListItem(self, obj): + dimensions = self.THUMB_DIMS.get(obj.playlistType) + + if not dimensions: + return + + w, h = dimensions['item.thumb'] + + if obj.playlistType == 'audio': + thumb = obj.buildComposite(width=w, height=h, media='thumb') + else: + thumb = obj.buildComposite(width=w, height=h, media='art') + + mli = kodigui.ManagedListItem( + obj.title or '', + util.durationToText(obj.duration.asInt()), + # thumbnailImage=obj.composite.asTranscodedImageURL(*self.THUMB_DIMS[obj.playlistType]['item.thumb']), + thumbnailImage=thumb, + data_source=obj + ) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/{0}.png'.format(obj.playlistType == 'audio' and 'music' or 'movie')) + + return mli + + @busy.dialog() + def fill(self): + items = { + 'audio': [], + 'video': [] + } + playlists = plexapp.SERVERMANAGER.selectedServer.playlists() + + self.setProperty( + 'background', + util.backgroundFromArt(playlists[0].composite, width=self.width, height=self.height) + ) + + for pl in playlists: + mli = self.createListItem(pl) + if mli: + items[pl.playlistType].append(mli) + + self.audioPLListControl.addItems(items['audio']) + self.videoPLListControl.addItems(items['video']) diff --git a/script.plexmod/lib/windows/preplay.py b/script.plexmod/lib/windows/preplay.py new file mode 100644 index 0000000000..5b8228b36d --- /dev/null +++ b/script.plexmod/lib/windows/preplay.py @@ -0,0 +1,720 @@ +from __future__ import absolute_import + +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import kodigui + +from . import busy +from . import opener +from . import info +from . import videoplayer +from . import playersettings +from . import search +from . import dropdown +from . import windowutils +from . import optionsdialog +from . import preplayutils +from . import pagination + +from plexnet import plexplayer, media + +from lib import util +from lib import metadata + +from lib.util import T + + +VIDEO_RELOAD_KW = dict(includeExtras=1, includeExtrasCount=10, includeChapters=1, includeReviews=1) + + +class RelatedPaginator(pagination.BaseRelatedPaginator): + def getData(self, offset, amount): + return self.parentWindow.video.getRelated(offset=offset, limit=amount) + + +class PrePlayWindow(kodigui.ControlledWindow, windowutils.UtilMixin): + xmlFile = 'script-plex-pre_play.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + THUMB_POSTER_DIM = util.scaleResolution(347, 518) + RELATED_DIM = util.scaleResolution(268, 397) + EXTRA_DIM = util.scaleResolution(329, 185) + ROLES_DIM = util.scaleResolution(334, 334) + PREVIEW_DIM = util.scaleResolution(343, 193) + + ROLES_LIST_ID = 400 + REVIEWS_LIST_ID = 401 + EXTRA_LIST_ID = 402 + RELATED_LIST_ID = 403 + + OPTIONS_GROUP_ID = 200 + PROGRESS_IMAGE_ID = 250 + + HOME_BUTTON_ID = 201 + SEARCH_BUTTON_ID = 202 + + INFO_BUTTON_ID = 304 + PLAY_BUTTON_ID = 302 + TRAILER_BUTTON_ID = 303 + SETTINGS_BUTTON_ID = 305 + OPTIONS_BUTTON_ID = 306 + MEDIA_BUTTON_ID = 307 + + PLAYER_STATUS_BUTTON_ID = 204 + + def __init__(self, *args, **kwargs): + kodigui.ControlledWindow.__init__(self, *args, **kwargs) + self.video = kwargs.get('video') + self.parentList = kwargs.get('parent_list') + self.videos = None + self.exitCommand = None + self.trailer = None + self.lastFocusID = None + self.lastNonOptionsFocusID = None + self.initialized = False + self.relatedPaginator = None + + def doClose(self): + self.relatedPaginator = None + kodigui.ControlledWindow.doClose(self) + + def onFirstInit(self): + self.extraListControl = kodigui.ManagedControlList(self, self.EXTRA_LIST_ID, 5) + self.relatedListControl = kodigui.ManagedControlList(self, self.RELATED_LIST_ID, 5) + self.rolesListControl = kodigui.ManagedControlList(self, self.ROLES_LIST_ID, 5) + self.reviewsListControl = kodigui.ManagedControlList(self, self.REVIEWS_LIST_ID, 5) + + self.progressImageControl = self.getControl(self.PROGRESS_IMAGE_ID) + self.setup() + self.initialized = True + + def doAutoPlay(self): + # First reload the video to get all the other info + self.video.reload(checkFiles=1, **VIDEO_RELOAD_KW) + return self.playVideo() + + @busy.dialog() + def onReInit(self): + self.initialized = False + if util.getSetting("slow_connection", False): + self.progressImageControl.setWidth(1) + self.setProperty('remainingTime', T(32914, "Loading")) + self.video.reload(checkFiles=1, fromMediaChoice=self.video.mediaChoice is not None, **VIDEO_RELOAD_KW) + self.refreshInfo(from_reinit=True) + self.initialized = True + + def refreshInfo(self, from_reinit=False): + oldFocusId = self.getFocusId() + + util.setGlobalProperty('hide.resume', '' if self.video.viewOffset.asInt() else '1') + # skip setting background when coming from reinit (other window) if we've focused something other than main + self.setInfo(skip_bg=from_reinit and not (self.PLAY_BUTTON_ID <= oldFocusId <= self.MEDIA_BUTTON_ID)) + self.fillRelated() + xbmc.sleep(100) + + if oldFocusId == self.PLAY_BUTTON_ID: + self.focusPlayButton() + + def onAction(self, action): + try: + controlID = self.getFocusId() + + if not controlID and self.lastFocusID and not action == xbmcgui.ACTION_MOUSE_MOVE: + self.setFocusId(self.lastFocusID) + + if action == xbmcgui.ACTION_CONTEXT_MENU: + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)): + self.lastNonOptionsFocusID = self.lastFocusID + self.setFocusId(self.OPTIONS_GROUP_ID) + return + else: + if self.lastNonOptionsFocusID: + self.setFocusId(self.lastNonOptionsFocusID) + self.lastNonOptionsFocusID = None + return + + elif action == xbmcgui.ACTION_NAV_BACK: + if (not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format( + self.OPTIONS_GROUP_ID)) or not controlID) and \ + not util.advancedSettings.fastBack: + if self.getProperty('on.extras'): + self.setFocusId(self.OPTIONS_GROUP_ID) + return + + elif action == xbmcgui.ACTION_LAST_PAGE and xbmc.getCondVisibility('ControlGroup(300).HasFocus(0)'): + next(self) + elif action == xbmcgui.ACTION_NEXT_ITEM: + self.setFocusId(300) + next(self) + elif action == xbmcgui.ACTION_FIRST_PAGE and xbmc.getCondVisibility('ControlGroup(300).HasFocus(0)'): + self.prev() + elif action == xbmcgui.ACTION_PREV_ITEM: + self.setFocusId(300) + self.prev() + + elif action == xbmcgui.ACTION_MOVE_UP and controlID in (self.REVIEWS_LIST_ID, + self.ROLES_LIST_ID, + self.EXTRA_LIST_ID): + self.updateBackgroundFrom(self.video) + + if controlID == self.RELATED_LIST_ID: + if self.relatedPaginator.boundaryHit: + self.relatedPaginator.paginate() + return + elif action in (xbmcgui.ACTION_MOVE_LEFT, xbmcgui.ACTION_MOVE_RIGHT): + self.updateBackgroundFrom(self.relatedListControl.getSelectedItem().dataSource) + except: + util.ERROR() + + kodigui.ControlledWindow.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.HOME_BUTTON_ID: + self.goHome() + elif controlID == self.EXTRA_LIST_ID: + self.openItem(self.extraListControl) + elif controlID == self.RELATED_LIST_ID: + self.openItem(self.relatedListControl) + elif controlID == self.ROLES_LIST_ID: + self.roleClicked() + elif controlID == self.PLAY_BUTTON_ID: + self.playVideo() + elif controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() + elif controlID == self.INFO_BUTTON_ID: + self.infoButtonClicked() + elif controlID == self.SETTINGS_BUTTON_ID: + self.settingsButtonClicked() + elif controlID == self.TRAILER_BUTTON_ID: + self.openItem(item=self.trailer) + elif controlID == self.OPTIONS_BUTTON_ID: + self.optionsButtonClicked() + elif controlID == self.MEDIA_BUTTON_ID: + self.mediaButtonClicked() + elif controlID == self.SEARCH_BUTTON_ID: + self.searchButtonClicked() + + def onFocus(self, controlID): + self.lastFocusID = controlID + + if 399 < controlID < 500: + self.setProperty('hub.focus', str(controlID - 400)) + + if controlID == self.RELATED_LIST_ID: + self.updateBackgroundFrom(self.relatedListControl.getSelectedItem().dataSource) + + if xbmc.getCondVisibility('ControlGroup(50).HasFocus(0) + ControlGroup(300).HasFocus(0)'): + self.setProperty('on.extras', '') + elif xbmc.getCondVisibility('ControlGroup(50).HasFocus(0) + !ControlGroup(300).HasFocus(0)'): + self.setProperty('on.extras', '1') + + def searchButtonClicked(self): + self.processCommand(search.dialog(self, section_id=self.video.getLibrarySectionId() or None)) + + def settingsButtonClicked(self): + if not self.video.mediaChoice: + playerObject = plexplayer.PlexPlayer(self.video) + playerObject.build() + playersettings.showDialog(video=self.video, non_playback=True) + self.setAudioAndSubtitleInfo() + + def infoButtonClicked(self): + opener.handleOpen( + info.InfoWindow, + title=self.video.defaultTitle, + sub_title=self.getProperty('info'), + thumb=self.video.type == 'episode' and self.video.thumb or self.video.defaultThumb, + thumb_fallback='script.plex/thumb_fallbacks/{0}.png'.format(self.video.type == 'episode' and 'show' or 'movie'), + info=self.video.summary, + background=self.getProperty('background'), + is_16x9=self.video.type == 'episode', + video=self.video + ) + + def optionsButtonClicked(self): + options = [] + + inProgress = self.video.viewOffset.asInt() + if not self.video.isWatched or inProgress: + options.append({'key': 'mark_watched', 'display': T(32319, 'Mark Played')}) + if self.video.isWatched or inProgress: + options.append({'key': 'mark_unwatched', 'display': T(32318, 'Mark Unplayed')}) + + options.append(dropdown.SEPARATOR) + + if self.video.type == 'episode': + options.append({'key': 'to_season', 'display': T(32400, 'Go to Season')}) + options.append({'key': 'to_show', 'display': T(32323, 'Go to Show')}) + + if self.video.type in ('episode', 'movie'): + options.append({'key': 'to_section', 'display': T(32324, u'Go to {0}').format(self.video.getLibrarySectionTitle())}) + + if self.video.server.allowsMediaDeletion: + options.append({'key': 'delete', 'display': T(32322, 'Delete')}) + # if xbmc.getCondVisibility('Player.HasAudio') and self.section.TYPE == 'artist': + # options.append({'key': 'add_to_queue', 'display': 'Add To Queue'}) + + # if False: + # options.append({'key': 'add_to_playlist', 'display': 'Add To Playlist'}) + posy = 880 + if not util.getGlobalProperty('hide.resume'): + posy += 106 + if self.getProperty('trailer.button'): + posy += 106 + choice = dropdown.showDropdown(options, (posy, 618), close_direction='left') + if not choice: + return + + if choice['key'] == 'play_next': + xbmc.executebuiltin('PlayerControl(Next)') + elif choice['key'] == 'mark_watched': + self.video.markWatched(**VIDEO_RELOAD_KW) + self.refreshInfo() + util.MONITOR.watchStatusChanged() + elif choice['key'] == 'mark_unwatched': + self.video.markUnwatched(**VIDEO_RELOAD_KW) + self.refreshInfo() + util.MONITOR.watchStatusChanged() + elif choice['key'] == 'to_season': + self.processCommand(opener.open(self.video.parentRatingKey)) + elif choice['key'] == 'to_show': + self.processCommand(opener.open(self.video.grandparentRatingKey)) + elif choice['key'] == 'to_section': + self.goHome(self.video.getLibrarySectionId()) + elif choice['key'] == 'delete': + self.delete() + + def mediaButtonClicked(self): + options = [] + for media in self.video.media: + ind = '' + if self.video.mediaChoice and media.id == self.video.mediaChoice.media.id: + ind = 'script.plex/home/device/check.png' + options.append({'key': media, 'display': media.versionString(), 'indicator': ind}) + choice = dropdown.showDropdown(options, header=T(32450, 'Choose Version'), with_indicator=True) + if not choice: + return False + + for media in self.video.media: + media.set('selected', '') + + self.video.setMediaChoice(choice['key']) + choice['key'].set('selected', 1) + self.setInfo() + + def delete(self): + button = optionsdialog.show( + T(32326, 'Really delete?'), + T(32327, 'Are you sure you really want to delete this media?'), + T(32328, 'Yes'), + T(32329, 'No') + ) + + if button != 0: + return + + if self._delete(): + self.doClose() + else: + util.messageDialog(T(32330, 'Message'), T(32331, 'There was a problem while attempting to delete the media.')) + + @busy.dialog() + def _delete(self): + success = self.video.delete() + util.LOG('Media DELETE: {0} - {1}'.format(self.video, success and 'SUCCESS' or 'FAILED')) + return success + + def roleClicked(self): + mli = self.rolesListControl.getSelectedItem() + if not mli: + return + + sectionRoles = busy.widthDialog(mli.dataSource.sectionRoles, '') + + if not sectionRoles: + util.DEBUG_LOG('No sections found for actor') + return + + if len(sectionRoles) > 1: + x, y = self.getRoleItemDDPosition() + + options = [{'role': r, 'display': r.reasonTitle} for r in sectionRoles] + choice = dropdown.showDropdown(options, (x, y), pos_is_bottom=True, close_direction='bottom') + + if not choice: + return + + role = choice['role'] + else: + role = sectionRoles[0] + + if util.advancedSettings.dialogFlickerFix: + with busy.BusyContext(): + xbmc.sleep(100) + xbmc.sleep(650) + self.processCommand(opener.open(role)) + + def getVideos(self): + if not self.videos: + if self.video.TYPE == 'episode': + self.videos = self.video.show().episodes() + + if not self.videos: + return False + + return True + + def next(self): + if not self._next(): + return + self.setup() + + __next__ = next + + @busy.dialog() + def _next(self): + if self.parentList: + mli = self.parentList.getListItemByDataSource(self.video) + if not mli: + return False + + pos = mli.pos() + 1 + if not self.parentList.positionIsValid(pos): + pos = 0 + + self.video = self.parentList.getListItem(pos).dataSource + else: + if not self.getVideos(): + return False + + if self.video not in self.videos: + return False + + pos = self.videos.index(self.video) + pos += 1 + if pos >= len(self.videos): + pos = 0 + + self.video = self.videos[pos] + + return True + + def prev(self): + if not self._prev(): + return + self.setup() + + @busy.dialog() + def _prev(self): + if self.parentList: + mli = self.parentList.getListItemByDataSource(self.video) + if not mli: + return False + + pos = mli.pos() - 1 + if pos < 0: + pos = self.parentList.size() - 1 + + self.video = self.parentList.getListItem(pos).dataSource + else: + if not self.getVideos(): + return False + + if self.video not in self.videos: + return False + + pos = self.videos.index(self.video) + pos -= 1 + if pos < 0: + pos = len(self.videos) - 1 + + self.video = self.videos[pos] + + return True + + def getRoleItemDDPosition(self): + y = 200 + if xbmc.getCondVisibility('Control.IsVisible(500)'): + y += 360 + if xbmc.getCondVisibility('Control.IsVisible(501)'): + y += 520 + if xbmc.getCondVisibility('!String.IsEmpty(Window.Property(on.extras))'): + y -= 300 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),0) + Control.IsVisible(500)'): + y -= 500 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),1) + Control.IsVisible(501)'): + y -= 500 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),2) + Control.IsVisible(502)'): + y -= 500 + + focus = int(xbmc.getInfoLabel('Container(400).Position')) + + x = ((focus + 1) * 304) - 100 + return x, y + + def playVideo(self): + if not self.video.available(): + util.messageDialog(T(32312, 'Unavailable'), T(32313, 'This item is currently unavailable.')) + return + + resume = False + if self.video.viewOffset.asInt(): + choice = dropdown.showDropdown( + options=[ + {'key': 'resume', 'display': T(32429, 'Resume from {0}').format(util.timeDisplay(self.video.viewOffset.asInt()).lstrip('0').lstrip(':'))}, + {'key': 'play', 'display': T(32317, 'Play from beginning')} + ], + pos=(660, 441), + close_direction='none', + set_dropdown_prop=False, + header=T(32314, 'In Progress') + ) + + if not choice: + return + + if choice['key'] == 'resume': + resume = True + + self.processCommand(videoplayer.play(video=self.video, resume=resume)) + return True + + def openItem(self, control=None, item=None): + if not item: + mli = control.getSelectedItem() + if not mli: + return + item = mli.dataSource + + self.processCommand(opener.open(item)) + + def focusPlayButton(self): + try: + if not self.getFocusId() == self.PLAY_BUTTON_ID: + self.setFocusId(self.PLAY_BUTTON_ID) + except (SystemError, RuntimeError): + self.setFocusId(self.PLAY_BUTTON_ID) + + @busy.dialog() + def setup(self): + self.focusPlayButton() + + util.DEBUG_LOG('PrePlay: Showing video info: {0}'.format(self.video)) + if self.video.type == 'episode': + self.setProperty('preview.yes', '1') + elif self.video.type == 'movie': + self.setProperty('preview.no', '1') + + self.video.reload(checkFiles=1, **VIDEO_RELOAD_KW) + try: + self.relatedPaginator = RelatedPaginator(self.relatedListControl, leaf_count=int(self.video.relatedCount), + parent_window=self) + except ValueError: + raise util.NoDataException + + self.setInfo() + self.setBoolProperty("initialized", True) + hasRoles = self.fillRoles() + hasReviews = self.fillReviews() + hasExtras = self.fillExtras() + self.fillRelated(hasRoles and not hasExtras and not hasReviews) + + def setInfo(self, skip_bg=False): + if not skip_bg: + self.updateBackgroundFrom(self.video) + self.setProperty('title', self.video.title) + self.setProperty('duration', util.durationToText(self.video.duration.asInt())) + self.setProperty('summary', self.video.summary.strip().replace('\t', ' ')) + self.setProperty('unwatched', not self.video.isWatched and '1' or '') + + directors = u' / '.join([d.tag for d in self.video.directors()][:5]) + directorsLabel = len(self.video.directors) > 1 and T(32401, u'DIRECTORS').upper() or T(32383, u'DIRECTOR').upper() + self.setProperty('directors', directors and u'{0} {1}'.format(directorsLabel, directors) or '') + + if self.video.type == 'episode': + self.setProperty('content.rating', '') + self.setProperty('thumb', self.video.defaultThumb.asTranscodedImageURL(*self.THUMB_POSTER_DIM)) + self.setProperty('preview', self.video.thumb.asTranscodedImageURL(*self.PREVIEW_DIM)) + self.setProperty('info', u'{0} {1} {2} {3}'.format(T(32303, 'Season'), self.video.parentIndex, T(32304, 'Episode'), self.video.index)) + self.setProperty('date', util.cleanLeadingZeros(self.video.originallyAvailableAt.asDatetime('%B %d, %Y'))) + + writers = u' / '.join([w.tag for w in self.video.writers()][:5]) + writersLabel = len(self.video.writers) > 1 and T(32403, u'WRITERS').upper() or T(32402, u'WRITER').upper() + self.setProperty('writers', writers and u'{0} {1}'.format(writersLabel, writers) or '') + self.setProperty('related.header', T(32306, 'Related Shows')) + elif self.video.type == 'movie': + self.setProperty('title', self.video.defaultTitle) + self.setProperty('preview', '') + self.setProperty('thumb', self.video.thumb.asTranscodedImageURL(*self.THUMB_POSTER_DIM)) + genres = u' / '.join([g.tag for g in self.video.genres()][:3]) + self.setProperty('info', genres) + self.setProperty('date', self.video.year) + self.setProperty('content.rating', self.video.contentRating.split('/', 1)[-1]) + + cast = u' / '.join([r.tag for r in self.video.roles()][:5]) + castLabel = 'CAST' + self.setProperty('writers', cast and u'{0} {1}'.format(castLabel, cast) or '') + self.setProperty('related.header', T(32404, 'Related Movies')) + + self.setProperty('video.res', self.video.resolutionString()) + self.setProperty('audio.codec', self.video.audioCodecString()) + self.setProperty('video.codec', self.video.videoCodecString()) + self.setProperty('video.rendering', self.video.videoCodecRendering) + self.setProperty('audio.channels', self.video.audioChannelsString(metadata.apiTranslate)) + self.setBoolProperty('media.multiple', len(list(filter(lambda x: x.isAccessible(), self.video.media()))) > 1) + + self.setProperties(('rating.stars', 'rating', 'rating.image', 'rating2', 'rating2.image'), '') + if self.video.userRating: + stars = str(int(round((self.video.userRating.asFloat() / 10) * 5))) + self.setProperty('rating.stars', stars) + # elif self.video.rating: + # stars = str(int(round((self.video.rating.asFloat() / 10) * 5))) + # self.setProperty('rating.stars', stars) + + if self.video.ratingImage: + rating = self.video.rating + audienceRating = self.video.audienceRating + if self.video.ratingImage.startswith('rottentomatoes:'): + rating = '{0}%'.format(int(rating.asFloat() * 10)) + if audienceRating: + audienceRating = '{0}%'.format(int(audienceRating.asFloat() * 10)) + + self.setProperty('rating', rating) + self.setProperty('rating.image', 'script.plex/ratings/{0}.png'.format(self.video.ratingImage.replace('://', '/'))) + if self.video.audienceRatingImage: + self.setProperty('rating2', audienceRating) + self.setProperty('rating2.image', 'script.plex/ratings/{0}.png'.format(self.video.audienceRatingImage.replace('://', '/'))) + else: + self.setProperty('rating', self.video.rating) + + self.setAudioAndSubtitleInfo() + + self.setProperty('unavailable', all(not v.isAccessible() for v in self.video.media()) and '1' or '') + + if self.video.viewOffset.asInt(): + width = self.video.viewOffset.asInt() and (1 + int((self.video.viewOffset.asInt() / self.video.duration.asFloat()) * self.width)) or 1 + self.progressImageControl.setWidth(width) + else: + self.progressImageControl.setWidth(1) + + if self.video.viewOffset.asInt(): + self.setProperty('remainingTime', T(33615, "{time} left").format(time=self.video.remainingTimeString)) + else: + self.setProperty('remainingTime', '') + + def setAudioAndSubtitleInfo(self): + sas = self.video.selectedAudioStream() + self.setProperty('audio', sas and sas.getTitle(metadata.apiTranslate) or T(32309, 'None')) + + sss = self.video.selectedSubtitleStream( + forced_subtitles_override=util.getSetting("forced_subtitles_override", False)) + if sss: + if len(self.video.subtitleStreams) > 1: + self.setProperty( + 'subtitles', u'{0} \u2022 {1} {2}'.format(sss.getTitle(metadata.apiTranslate), len(self.video.subtitleStreams) - 1, T(32307, 'More')) + ) + else: + self.setProperty('subtitles', sss.getTitle(metadata.apiTranslate)) + else: + if self.video.subtitleStreams: + self.setProperty('subtitles', u'{0} \u2022 {1} {2}'.format(T(32309, 'None'), len(self.video.subtitleStreams), T(32308, 'Available'))) + else: + self.setProperty('subtitles', T(32309, u'None')) + + def createListItem(self, obj): + mli = kodigui.ManagedListItem(obj.title or '', thumbnailImage=obj.thumb.asTranscodedImageURL(*self.EXTRA_DIM), data_source=obj) + return mli + + def fillExtras(self, has_prev=False): + items = [] + idx = 0 + + if not self.video.extras: + self.extraListControl.reset() + return False + + for extra in self.video.extras(): + if not self.trailer and extra.extraType.asInt() == media.METADATA_RELATED_TRAILER: + self.trailer = extra + self.setProperty('trailer.button', '1') + continue + + mli = self.createListItem(extra) + if mli: + mli.setProperty('index', str(idx)) + mli.setProperty( + 'thumb.fallback', 'script.plex/thumb_fallbacks/{0}.png'.format(extra.type in ('show', 'season', 'episode') and 'show' or 'movie') + ) + items.append(mli) + idx += 1 + + if not items: + return False + + self.extraListControl.reset() + self.extraListControl.addItems(items) + + self.setProperty('divider.{0}'.format(self.EXTRA_LIST_ID), has_prev and '1' or '') + + return True + + def fillRelated(self, has_prev=False): + if not self.relatedPaginator.leafCount: + self.relatedListControl.reset() + return False + + items = self.relatedPaginator.paginate() + + if not items: + return False + + self.setProperty('divider.{0}'.format(self.RELATED_LIST_ID), has_prev and '1' or '') + + return True + + def fillRoles(self, has_prev=False): + items = [] + idx = 0 + + if not self.video.roles: + self.rolesListControl.reset() + return False + + for role in self.video.roles(): + mli = kodigui.ManagedListItem(role.tag, role.role, thumbnailImage=role.thumb.asTranscodedImageURL(*self.ROLES_DIM), data_source=role) + mli.setProperty('index', str(idx)) + items.append(mli) + idx += 1 + + if not items: + return False + + self.rolesListControl.reset() + self.rolesListControl.addItems(items) + return True + + def fillReviews(self, has_prev=False): + items = [] + idx = 0 + + if not self.video.reviews: + self.reviewsListControl.reset() + return False + + for review in self.video.reviews(): + mli = kodigui.ManagedListItem(review.source, review.tag, thumbnailImage=review.ratingImage()) + mli.setProperty('index', str(idx)) + mli.setProperty('text', review.text) + items.append(mli) + idx += 1 + + if not items: + return False + + self.reviewsListControl.reset() + self.reviewsListControl.addItems(items) + return True diff --git a/script.plexmod/lib/windows/preplayutils.py b/script.plexmod/lib/windows/preplayutils.py new file mode 100644 index 0000000000..7d000622fe --- /dev/null +++ b/script.plexmod/lib/windows/preplayutils.py @@ -0,0 +1,35 @@ +from __future__ import absolute_import +from . import dropdown + +from lib.util import T + + +def chooseVersion(video): + if len(video.media) > 1: + options = [] + for media in video.media: + ind = '' + if video.mediaChoice and media.id == video.mediaChoice.media.id: + ind = 'script.plex/home/device/check.png' + options.append({'key': media, 'display': media.versionString(), 'indicator': ind}) + choice = dropdown.showDropdown(options, header=T(32450, 'Choose Version'), with_indicator=True) + if not choice: + return False + + for media in video.media: + media.set('selected', '') + + video.setMediaChoice(choice['key']) + choice['key'].set('selected', 1) + + return True + + +def resetVersion(video): + if len(video.media) < 2: + return + + for media in video.media: + media.set('selected', '') + + video.media[0].set('selected', 1) diff --git a/script.plexmod/lib/windows/search.py b/script.plexmod/lib/windows/search.py new file mode 100644 index 0000000000..2b4e2998c7 --- /dev/null +++ b/script.plexmod/lib/windows/search.py @@ -0,0 +1,435 @@ +from __future__ import absolute_import +import time +import threading + +from kodi_six import xbmcgui, xbmc + +from . import kodigui +from . import opener +from . import windowutils + +from lib import util +from lib.kodijsonrpc import rpc + +from plexnet import plexapp + +class SearchDialog(kodigui.BaseDialog, windowutils.UtilMixin): + xmlFile = 'script-plex-search.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + LETTERS = 'abcdefghijklmnopqrstuvwxyz0123456789 ' + SECTION_BUTTONS = { + 901: 'all', + 902: 'movie', + 903: 'show', + 904: 'artist', + 905: 'photo' + } + + EDIT_CONTROL_ID = 650 + BUTTON_A_ID = 1001 + + HUB_POSTER_00 = 2100 + HUB_SQUARE_01 = 2101 + HUB_AR16X9_02 = 2102 + HUB_CIRCLE_03 = 2103 + HUB_POSTER_04 = 2104 + HUB_SQUARE_05 = 2105 + HUB_AR16X9_06 = 2106 + HUB_CIRCLE_07 = 2107 + HUB_POSTER_08 = 2108 + HUB_SQUARE_09 = 2109 + HUB_AR16X9_10 = 2110 + HUB_CIRCLE_11 = 2111 + HUB_POSTER_12 = 2112 + HUB_SQUARE_13 = 2113 + HUB_AR16X9_14 = 2114 + HUB_CIRCLE_15 = 2115 + HUB_POSTER_16 = 2116 + HUB_SQUARE_17 = 2117 + HUB_AR16X9_18 = 2118 + HUB_CIRCLE_19 = 2119 + HUB_POSTER_20 = 2120 + HUB_SQUARE_21 = 2121 + HUB_AR16X9_22 = 2122 + HUB_CIRCLE_23 = 2123 + HUB_POSTER_24 = 2124 + HUB_SQUARE_25 = 2125 + HUB_AR16X9_26 = 2126 + HUB_CIRCLE_27 = 2127 + HUB_POSTER_28 = 2128 + HUB_SQUARE_29 = 2129 + HUB_AR16X9_30 = 2130 + HUB_CIRCLE_31 = 2131 + HUB_POSTER_32 = 2132 + HUB_SQUARE_33 = 2133 + HUB_AR16X9_34 = 2134 + HUB_CIRCLE_35 = 2135 + HUB_POSTER_36 = 2136 + HUB_SQUARE_37 = 2137 + HUB_AR16X9_38 = 2138 + HUB_CIRCLE_39 = 2139 + HUB_POSTER_40 = 2140 + HUB_SQUARE_41 = 2141 + HUB_AR16X9_42 = 2142 + HUB_CIRCLE_43 = 2143 + HUB_POSTER_44 = 2144 + HUB_SQUARE_45 = 2145 + HUB_AR16X9_46 = 2146 + HUB_CIRCLE_47 = 2147 + + HUBMAP = { + 'track': {'type': 'square'}, + 'episode': {'type': 'ar16x9'}, + 'movie': {'type': 'poster'}, + 'show': {'type': 'poster'}, + 'artist': {'type': 'square'}, + 'album': {'type': 'square'}, + 'photoalbum': {'type': 'square'}, + 'photo': {'type': 'square'}, + 'actor': {'type': 'circle'}, + 'director': {'type': 'circle'}, + 'genre': {'type': 'circle'}, + 'playlist': {'type': 'square'}, + } + + SECTION_TYPE_MAP = { + '1': {'thumb': 'script.plex/section_type/movie.png'}, # Movie + '2': {'thumb': 'script.plex/section_type/show.png'}, # Show + '3': {'thumb': 'script.plex/section_type/show.png'}, # Season + '4': {'thumb': 'script.plex/section_type/show.png'}, # Episode + '8': {'thumb': 'script.plex/section_type/music.png'}, # Artist + '9': {'thumb': 'script.plex/section_type/music.png'}, # Album + '10': {'thumb': 'script.plex/section_type/music.png'}, # Track + } + + def __init__(self, *args, **kwargs): + kodigui.BaseDialog.__init__(self, *args, **kwargs) + windowutils.UtilMixin.__init__(self) + self.parentWindow = kwargs.get('parent_window') + self.sectionID = kwargs.get('section_id') + self.resultsThread = None + self.updateResultsTimeout = 0 + self.isActive = True + self.useKodiKbd = util.getSetting('search_use_kodi_kbd', False) + + def onFirstInit(self): + self.hubControls = ( + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_00, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_01, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_02, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_03, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_04, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_05, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_06, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_07, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_08, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_09, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_10, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_11, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_12, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_13, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_14, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_15, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_16, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_17, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_18, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_19, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_20, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_21, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_22, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_23, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_24, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_25, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_26, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_27, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_28, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_29, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_30, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_31, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_32, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_33, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_34, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_35, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_36, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_37, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_38, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_39, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_40, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_41, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_42, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_43, 5) + }, + { + 'poster': kodigui.ManagedControlList(self, self.HUB_POSTER_44, 5), + 'square': kodigui.ManagedControlList(self, self.HUB_SQUARE_45, 5), + 'ar16x9': kodigui.ManagedControlList(self, self.HUB_AR16X9_46, 5), + 'circle': kodigui.ManagedControlList(self, self.HUB_CIRCLE_47, 5) + }, + ) + + self.edit = kodigui.SafeControlEdit(self.EDIT_CONTROL_ID, 651, self, key_callback=self.updateFromEdit, + grab_focus=True) + self.edit.setCompatibleMode(rpc.Application.GetProperties(properties=["version"])["version"]["major"] < 17) + if self.useKodiKbd: + self.setProperty('hide.kbd', '1') + self.setFocusId(self.EDIT_CONTROL_ID) + xbmc.executebuiltin('Action(Select,{0})'.format(self._winID)) + else: + self.setFocusId(self.BUTTON_A_ID) + self.setProperty('search.section', 'all') + self.updateQuery() + + def onAction(self, action): + try: + if action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): + self.isActive = False + except: + util.ERROR() + + kodigui.BaseDialog.onAction(self, action) + + def onClick(self, controlID): + if 1000 < controlID < 1037: + self.letterClicked(controlID) + elif controlID in self.SECTION_BUTTONS: + self.sectionClicked(controlID) + elif controlID == 951: + self.deleteClicked() + elif controlID == 952: + self.letterClicked(1037) + elif controlID == 953: + self.clearClicked() + elif 2099 < controlID < 2200: + self.hubItemClicked(controlID) + + def onFocus(self, controlID): + if 2099 < controlID < 2200: + self.setProperty('hub.focus', str(controlID - 2099)) + + def updateFromEdit(self, actionID, oldVal, newVal): + if actionID == xbmcgui.ACTION_PREVIOUS_MENU: + self.isActive = False + self.doClose() + return + + self.updateQuery() + + def updateQuery(self): + self.updateResults() + + def updateResults(self): + self.updateResultsTimeout = time.time() + 1 + if not self.resultsThread or not self.resultsThread.is_alive(): + self.resultsThread = threading.Thread(target=self._updateResults, name='search.update') + self.resultsThread.start() + + def _updateResults(self): + while time.time() < self.updateResultsTimeout and not util.MONITOR.waitForAbort(0.1): + pass + + self._reallyUpdateResults() + + def _reallyUpdateResults(self): + query = self.edit.getText() + if query: + with self.propertyContext('searching'): + hubs = plexapp.SERVERMANAGER.selectedServer.hubs(count=10, search_query=query, section=self.sectionID) + self.showHubs(hubs) + else: + self.clearHubs() + + def sectionClicked(self, controlID): + section = self.SECTION_BUTTONS[controlID] + old = self.getProperty('search.section') + self.setProperty('search.section', section) + if old != section: + self.updateResults() + + def letterClicked(self, controlID): + letter = self.LETTERS[controlID - 1001] + self.edit.append(letter) + self.updateQuery() + + def deleteClicked(self): + self.edit.delete() + self.updateQuery() + + def clearClicked(self): + self.edit.setText('') + self.updateQuery() + + def hubItemClicked(self, hubControlID): + for controls in self.hubControls: + for control in controls.values(): + if control.controlID == hubControlID: + break + else: + continue + break + else: + return + + mli = control.getSelectedItem() + if not mli: + return + + hubItem = mli.dataSource + if hubItem.TYPE == 'playlist' and not hubItem.exists(): # Workaround for server bug + util.messageDialog('No Access', 'Playlist not accessible by this user.') + util.DEBUG_LOG('Search: Playlist does not exist - probably wrong user') + return + + self.doClose() + try: + command = opener.open(hubItem) + + if not hubItem.exists(): + control.removeManagedItem(mli) + + self.processCommand(command) + finally: + if not self.exitCommand: + self.show() + else: + self.isActive = False + + def createListItem(self, hubItem): + if hubItem.TYPE in ('Genre', 'Director', 'Role'): + if hubItem.TYPE == 'Genre': + thumb = (self.SECTION_TYPE_MAP.get(hubItem.librarySectionType) or {}).get('thumb', '') + mli = kodigui.ManagedListItem(hubItem.tag, hubItem.reasonTitle, thumbnailImage=thumb, data_source=hubItem) + mli.setProperty('thumb.fallback', thumb) + else: + mli = kodigui.ManagedListItem( + hubItem.tag, hubItem.reasonTitle, thumbnailImage=hubItem.get('thumb').asTranscodedImageURL(256, 256), data_source=hubItem + ) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/role.png') + else: + if hubItem.TYPE == 'playlist': + mli = kodigui.ManagedListItem(hubItem.tag, thumbnailImage=hubItem.get('composite').asTranscodedImageURL(256, 256), data_source=hubItem) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/{0}.png'.format(hubItem.playlistType == 'audio' and 'music' or 'movie')) + elif hubItem.TYPE == 'photodirectory': + mli = kodigui.ManagedListItem(hubItem.title, thumbnailImage=hubItem.get('composite').asTranscodedImageURL(256, 256), data_source=hubItem) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/photo.png') + else: + mli = kodigui.ManagedListItem(hubItem.title, thumbnailImage=hubItem.get('thumb').asTranscodedImageURL(256, 256), data_source=hubItem) + if hubItem.TYPE in ('movie', 'clip'): + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/movie.png') + elif hubItem.TYPE in ('artist', 'album', 'track'): + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/music.png') + elif hubItem.TYPE in ('show', 'season', 'episode'): + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/show.png') + elif hubItem.TYPE == 'photo': + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/photo.png') + + return mli + + def showHubs(self, hubs): + self.clearHubs() + self.opaqueBackground(on=False) + + allowed = None + if self.getProperty('search.section') == 'movie': + allowed = ('movie',) + elif self.getProperty('search.section') == 'show': + allowed = ('show', 'season', 'episode') + elif self.getProperty('search.section') == 'artist': + allowed = ('artist', 'album', 'track') + elif self.getProperty('search.section') == 'photo': + allowed = ('photo', 'photodirectory') + + controlID = None + i = 0 + for h in hubs: + if allowed and h.type not in allowed: + continue + + if h.size.asInt() > 0: + self.opaqueBackground() + cid = self.showHub(h, i) + controlID = controlID or cid + i += 1 + + if controlID: + self.setProperty('no.results', '') + else: + self.setProperty('no.results', '1') + + def showHub(self, hub, idx): + util.DEBUG_LOG('Showing search hub: {0} at {1}'.format(hub.type, idx)) + info = self.HUBMAP.get(hub.type) + if not info: + util.DEBUG_LOG('Unhandled hub type: {0}'.format(hub.type)) + return + + itemListControl = self.hubControls[idx][info['type']] + if itemListControl is None: + util.DEBUG_LOG('No control defined') + return + + self.setProperty('hub.{0}'.format(itemListControl.controlID), hub.title) + + items = [] + for hubItem in hub.items: + mli = self.createListItem(hubItem) + items.append(mli) + + itemListControl.reset() + itemListControl.addItems(items) + + return itemListControl.controlID + + def clearHubs(self): + self.opaqueBackground(on=False) + self.setProperty('no.results', '') + for controls in self.hubControls: + for control in controls.values(): + if control: + control.reset() + self.setProperty('hub.focus', '') + + def opaqueBackground(self, on=True): + self.parentWindow.setProperty('search.dialog.hasresults', on and '1' or '') + + def wait(self): + while self.isActive and not util.MONITOR.waitForAbort(0.1): + pass + + +def dialog(parent_window, section_id=None): + parent_window.setProperty('search.dialog.hasresults', '') + with parent_window.propertyContext('search.dialog'): + try: + w = SearchDialog.open(parent_window=parent_window, section_id=section_id) + w.wait() + command = w.exitCommand or '' + del w + return command + finally: + parent_window.setProperty('search.dialog.hasresults', '') diff --git a/script.plexmod/lib/windows/seekdialog.py b/script.plexmod/lib/windows/seekdialog.py new file mode 100644 index 0000000000..f5d566743b --- /dev/null +++ b/script.plexmod/lib/windows/seekdialog.py @@ -0,0 +1,2204 @@ +from __future__ import absolute_import +import re +import time +import threading +import math + +from kodi_six import xbmc +from kodi_six import xbmcgui +from collections import OrderedDict + +from . import kodigui +from . import playersettings +from . import dropdown +from . import busy +from plexnet import plexapp + +from lib import util +from plexnet.videosession import VideoSessionInfo, ATTRIBUTE_TYPES as SESSION_ATTRIBUTE_TYPES +from plexnet.exceptions import ServerNotOwned, NotFound +from plexnet.signalsmixin import SignalsMixin + +from lib.kodijsonrpc import builtin + +from lib.util import T +from six.moves import range + +KEY_MOVE_SET = frozenset( + ( + xbmcgui.ACTION_MOVE_LEFT, + xbmcgui.ACTION_MOVE_RIGHT, + xbmcgui.ACTION_MOVE_UP, + xbmcgui.ACTION_MOVE_DOWN + ) +) + +KEY_STEP_SEEK_SET = frozenset( + ( + xbmcgui.ACTION_MOVE_LEFT, + xbmcgui.ACTION_MOVE_RIGHT, + xbmcgui.ACTION_STEP_FORWARD, + xbmcgui.ACTION_STEP_BACK + ) +) + +MARKERS = OrderedDict([ + ("intro", { + "marker": None, + "name": T(32495, 'Skip intro'), + "autoSkipName": T(32800, 'Skipping intro'), + "overrideStartOff": None, + "countdown": None, + + # attrs + "markerAutoSkip": "autoSkipIntro", + "markerAutoSkipped": False, + "markerAutoSkipShownTimer": "_introSkipShownStarted", + "markerSkipBtnTimeout": "skipIntroButtonTimeout", + }), + ("credits", { + "marker": None, + "name": T(32496, 'Skip credits'), + "autoSkipName": T(32801, 'Skipping credits'), + "overrideStartOff": None, + "countdown": None, + + "markerAutoSkip": "autoSkipCredits", + "markerAutoSkipped": False, + "markerAutoSkipShownTimer": "_creditsSkipShownStarted", + "markerSkipBtnTimeout": "skipCreditsButtonTimeout" + }) +]) + +FINAL_MARKER_NEGOFF = 5000 +MARKER_SHOW_NEGOFF = 3000 +MARKER_OFF = 500 +MARKER_CHAPTER_OVERLAP_THRES = 30000 # 30 seconds + + +class SeekDialog(kodigui.BaseDialog): + """ + fixme: This is a convoluted mess. + """ + + xmlFile = 'script-plex-seek_dialog.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + MAIN_BUTTON_ID = 100 + SEEK_IMAGE_ID = 200 + POSITION_IMAGE_ID = 201 + SELECTION_INDICATOR = 202 + SELECTION_INDICATOR_GROUP = 203 + SELECTION_INDICATOR_IMAGE = 204 + SELECTION_INDICATOR_TEXT = 205 + CACHE_IMAGE_ID = 206 + BIF_IMAGE_ID = 300 + SEEK_IMAGE_WIDTH = 1920 + + REPEAT_BUTTON_ID = 401 + SHUFFLE_BUTTON_ID = 402 + SETTINGS_BUTTON_ID = 403 + PREV_BUTTON_ID = 404 + SKIP_BACK_BUTTON_ID = 405 + PLAY_PAUSE_BUTTON_ID = 406 + STOP_BUTTON_ID = 407 + SKIP_FORWARD_BUTTON_ID = 408 + NEXT_BUTTON_ID = 409 + PLAYLIST_BUTTON_ID = 410 + OPTIONS_BUTTON_ID = 411 + SUBTITLE_BUTTON_ID = 412 + + BIG_SEEK_GROUP_ID = 500 + BIG_SEEK_LIST_ID = 501 + + SKIP_MARKER_BUTTON_ID = 791 + NO_OSD_BUTTON_ID = 800 + + BAR_X = 0 + BAR_Y = 921 + BAR_RIGHT = 1920 + BAR_BOTTOM = 969 + + NAVBAR_BTN_SIZE = 60 + + HIDE_DELAY = 4 # This uses the Cron tick so is +/- 1 second accurate + OSD_HIDE_ANIMATION_DURATION = 0.2 + SKIP_STEPS = {"negative": [-10000], "positive": [30000]} + + def __init__(self, *args, **kwargs): + kodigui.BaseDialog.__init__(self, *args, **kwargs) + + # fixme: heyo, there's a lot of disorder in here. + self.handler = kwargs.get('handler') + self.initialVideoSettings = {} + self.initialAudioStream = None + self.initialSubtitleStream = None + self.bifURL = None + self.baseURL = None + self.hasBif = bool(self.bifURL) + self.baseOffset = 0 + self._duration = 0 + self.offset = 0 + self.selectedOffset = 0 + self.bigSeekOffset = 0 + self.bigSeekChanged = False # attention, with chapters this can become an integer for the True state + self.title = '' + self.title2 = '' + self.fromSeek = 0 + self.initialized = False + self.playlistDialog = None + self.timeout = None + self.autoSeekTimeout = None + self.hasDialog = False + self.lastFocusID = None + self.previousFocusID = None + self.playlistDialogVisible = False + self.forceNextTimeAsChapter = False + self.showChapters = False + self._seeking = False + self._applyingSeek = False + self._seekingWithoutOSD = False + self._delayedSeekThread = None + self._delayedSeekTimeout = 0 + self._osdHideAnimationTimeout = 0 + self._osdHideFast = False + self._hideDelay = self.HIDE_DELAY + self._autoSeekDelay = util.advancedSettings.autoSeekDelay + self._atSkipStep = -1 + self._lastSkipDirection = None + self._forcedLastSkipAmount = None + self._navigatedViaMarkerOrChapter = False + self._lastAction = None + self.lastTimelineResponse = None + self._ignoreInput = False + self._ignoreTick = False + self._abortBufferWait = False + + self._videoBelowOneHour = False + self.timeFmtKodi = util.timeFormatKN + self.waitingForBuffer = False + self.lastSubtitleNavAction = "forward" + self.subtitleButtonLeft = 0 + self.ldTimer = True #util.advancedSettings.lowDriftTimer + self.timeKeeper = None + self.timeKeeperTime = None + self.idleTime = None + self.stopPlaybackOnIdle = util.getSetting('player_stop_on_idle', 0) + self.isDirectPlay = True + self.isTranscoded = False + + # optimize + self._enableMarkerSkip = plexapp.ACCOUNT.hasPlexPass() + self.markers = None + self.chapters = None + self._introSkipShownStarted = None + self._creditsSkipShownStarted = None + self._currentMarker = None + self.skipSteps = self.SKIP_STEPS + self.useAutoSeek = util.advancedSettings.autoSeek + self.useDynamicStepsForTimeline = util.advancedSettings.dynamicTimelineSeek + + self.bingeMode = False + self.autoSkipIntro = False + self.autoSkipCredits = False + self.showIntroSkipEarly = False + + self.skipIntroButtonTimeout = util.advancedSettings.skipIntroButtonTimeout + self.skipCreditsButtonTimeout = util.advancedSettings.skipCreditsButtonTimeout + self.showItemEndsInfo = util.advancedSettings.showMediaEndsInfo + self.showItemEndsLabel = util.advancedSettings.showMediaEndsLabel + + self.player.video.server.on("np:timelineResponse", self.timelineResponseCallback) + + if util.kodiSkipSteps and util.advancedSettings.kodiSkipStepping: + self.skipSteps = {"negative": [], "positive": []} + for step in util.kodiSkipSteps: + key = "negative" if step < 0 else "positive" + self.skipSteps[key].append(step * 1000) + + self.skipSteps["negative"].reverse() + + try: + seconds = int(xbmc.getInfoLabel("Skin.String(SkinHelper.AutoCloseVideoOSD)")) + if seconds > 0: + self._hideDelay = seconds + except ValueError: + pass + + @property + def player(self): + return self.handler.player + + def timelineResponseCallback(self, **kwargs): + response = kwargs.get("response") + self.lastTimelineResponse = response.getBodyXml() + + def resetTimeout(self): + self.timeout = time.time() + self._hideDelay + + def resetAutoSeekTimer(self, value="not_set"): + self.autoSeekTimeout = value if value != "not_set" else time.time() + self._autoSeekDelay + + def resetSeeking(self): + self._seeking = False + self._seekingWithoutOSD = False + self._delayedSeekTimeout = None + self._applyingSeek = False + self.bigSeekChanged = False + self.selectedOffset = None + self.forceNextTimeAsChapter = False + self._navigatedViaMarkerOrChapter = False + self.setProperty('show.chapters', '') + self.setProperty('button.seek', '') + self.setProperty('marker.countdown', '') + self.resetAutoSeekTimer(None) + self.resetSkipSteps() + + def resetMarkerStates(self): + self.setProperty('show.markerSkip', '') + self.setProperty('show.markerSkip_OSDOnly', '') + self.setProperty('marker.autoSkip', '') + self.setProperty('skipMarkerName', '') + + self._introSkipShownStarted = None + self._introAutoSkipped = False + self._creditsSkipShownStarted = None + self._currentMarker = None + self._creditsAutoSkipped = False + self.markers = None + + @property + def DPPlayerOffset(self): + if self.isDirectPlay and self.handler.player and self.handler.player.playerObject: + return self.handler.player.playerObject.startOffset * 1000 + return 0 + + def trueOffset(self): + if self.isDirectPlay: + return self.DPPlayerOffset + self.offset + else: + return self.baseOffset + self.offset + + @property + def markers(self): + # fixme: fix transcoded marker skip + if not self._enableMarkerSkip: + return None + + if not self._markers and hasattr(self.handler.player.video, "markers"): + markers = [] + + for marker in self.handler.player.video.markers: + if marker.type in MARKERS: + m = MARKERS[marker.type].copy() + m["marker"] = marker + m["marker_type"] = marker.type + markers.append(m) + + self._markers = markers + + return self._markers + + @markers.setter + def markers(self, val): + self._markers = val + + def onFirstInit(self): + try: + self._onFirstInit() + except RuntimeError: + util.ERROR(hide_tb=True) + self.started = False + + def _onFirstInit(self): + util.DEBUG_LOG("SeekDialog: onFirstInit") + self.resetTimeout() + self.setProperty('skipMarkerName', T(32495, 'Skip intro')) + self.bigSeekHideTimer = kodigui.PropertyTimer(self._winID, 0.5, 'hide.bigseek') + + if self.handler.playlist: + self.handler.playlist.on('change', self.updateProperties) + + self.seekbarControl = self.getControl(self.SEEK_IMAGE_ID) + self.positionControl = self.getControl(self.POSITION_IMAGE_ID) + self.cacheControl = self.getControl(self.CACHE_IMAGE_ID) + self.bifImageControl = self.getControl(self.BIF_IMAGE_ID) + self.selectionIndicator = self.getControl(self.SELECTION_INDICATOR) + self.selectionIndicatorImage = self.getControl(self.SELECTION_INDICATOR_IMAGE) + self.selectionIndicatorText = self.getControl(self.SELECTION_INDICATOR_TEXT) + self.selectionIndicatorGroup = self.getControl(self.SELECTION_INDICATOR_GROUP) + self.selectionBox = self.getControl(203) + self.bigSeekControl = kodigui.ManagedControlList(self, self.BIG_SEEK_LIST_ID, 12) + self.bigSeekGroupControl = self.getControl(self.BIG_SEEK_GROUP_ID) + self.initialized = True + + showQuickSubs = util.getSetting('subtitle_downloads', False) + showRepeat = util.getSetting('video_show_repeat', False) + showFfwdRwd = util.getSetting('video_show_ffwdrwd', False) + showShuffle = util.getSetting('video_show_shuffle', False) + self.setBoolProperty('nav.quick_subtitles', showQuickSubs) + self.setBoolProperty('nav.repeat', showRepeat) + self.setBoolProperty('nav.ffwdrwd', showFfwdRwd) + self.setBoolProperty('nav.shuffle', showShuffle) + + if showQuickSubs: + self.subtitleButtonLeft += self.NAVBAR_BTN_SIZE * len( + list(x for x in (showRepeat, showFfwdRwd, showShuffle) if not x)) + + self.updateProperties() + self.updateChapters() + self.videoSettingsHaveChanged() + self.update() + + def onReInit(self): + util.DEBUG_LOG("SeekDialog: onReInit") + self.lastTimelineResponse = None + self._lastAction = None + self._ignoreTick = False + self.waitingForBuffer = False + self._abortBufferWait = False + + self.resetTimeout() + self.resetSeeking() + self.updateProperties() + self.updateChapters() + self.videoSettingsHaveChanged() + self.updateProgress() + + def setup(self, duration, meta, offset=0, bif_url=None, title='', title2='', chapters=None, keepMarkerDef=False): + """ + this is called by our handler and occurs earlier than onFirstInit. + """ + util.DEBUG_LOG("SeekDialog: setup, keepMarkerDef={}".format(keepMarkerDef)) + self.title = title + self.title2 = title2 + self.chapters = chapters or [] + self.isDirectPlay = not meta.isTranscoded + self.isTranscoded = not self.isDirectPlay + self.showChapters = util.getUserSetting('show_chapters', True) and ( + bool(chapters) or (util.getUserSetting('virtual_chapters', True) and bool(self.markers))) + self.setProperty('video.title', title) + self.setProperty('is.show', (self.player.video.type == 'episode') and '1' or '') + self.setProperty('has.playlist', self.handler.playlist and '1' or '') + self.setProperty('shuffled', (self.handler.playlist and self.handler.playlist.isShuffled) and '1' or '') + self.setProperty('has.chapters', self.showChapters and '1' or '') + self.setProperty('show.buffer', (util.advancedSettings.playerShowBuffer and self.isDirectPlay) and '1' or '') + + self.killTimeKeeper() + + navPlaylist = util.getSetting('video_show_playlist', 'eponly') + self.setBoolProperty('nav.playlist', (navPlaylist == "eponly" and self.player.video.type == 'episode') or + navPlaylist == "always") + + if not self.getProperty('nav.playlist'): + self.subtitleButtonLeft += self.NAVBAR_BTN_SIZE + + navPrevNext = util.getSetting('video_show_prevnext', 'eponly') + self.setBoolProperty('nav.prevnext', (navPrevNext == "eponly" and self.player.video.type == 'episode') or + navPrevNext == "always") + + if not self.getProperty('nav.prevnext'): + self.subtitleButtonLeft += self.NAVBAR_BTN_SIZE + + try: + if self.player.video.type == 'episode': + pbs = self.player.video.playbackSettings + util.DEBUG_LOG("Playback settings for {}: {}".format(self.player.video.ratingKey, pbs)) + + self.bingeMode = pbs.binge_mode + self.handler.inBingeMode = self.bingeMode + + # don't auto skip intro when on binge mode on the first episode of a season + firstEp = self.player.video.index == '1' + + if self.isDirectPlay or util.getUserSetting('auto_skip_in_transcode', True): + self.autoSkipIntro = (self.bingeMode and not firstEp) or pbs.auto_skip_intro + self.autoSkipCredits = self.bingeMode or pbs.auto_skip_credits + + self.showIntroSkipEarly = self.bingeMode or pbs.show_intro_skip_early + + # in transcoded scenarios, when seeking, keep previous marker states, as the video restarts + if not keepMarkerDef: + self.resetMarkerStates() + except IndexError: + self.doClose(delete=True) + raise util.NoDataException + self.baseOffset = offset + self.offset = 0 + self.idleTime = None + self.lastSubtitleNavAction = "forward" + self._duration = duration + self._videoBelowOneHour = duration / 3600000 < 1 + if self._videoBelowOneHour: + self.timeFmtKodi = self.timeFmtKodi.replace("hh:", "") + self._ignoreTick = False + self._ignoreInput = False + if not self.showChapters: + self.bifURL = bif_url + self.hasBif = bool(self.bifURL) + + if self.hasBif: + self.baseURL = re.sub('/\d+\?', '/{0}?', self.bifURL) + self.update() + + def update(self, offset=None, from_seek=False): + if from_seek: + self.fromSeek = time.time() + else: + if time.time() - self.fromSeek > 0.5: + self.fromSeek = 0 + + if offset is not None: + self.offset = offset + self.selectedOffset = self.trueOffset() + + self.updateProgress() + + def onAction(self, action): + if xbmc.getCondVisibility('Window.IsActive(selectdialog)'): + if self.doKodiSelectDialogHack(action): + return + + try: + self.resetTimeout() + + controlID = self.getFocusId() + self.idleTime = None + + lastAction = self._lastAction + self._lastAction = currentAction = (action.getId(), controlID) + + cancelActions = (xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_STOP) + + if not self._ignoreInput: + if action.getId() in KEY_MOVE_SET: + self.setProperty('mouse.mode', '') + if not controlID: + self.setBigSeekShift() + self.setFocusId(400) + return + elif action == xbmcgui.ACTION_MOUSE_MOVE: + self.setProperty('mouse.mode', '1') + + if controlID in (self.MAIN_BUTTON_ID, self.NO_OSD_BUTTON_ID): + if action == xbmcgui.ACTION_MOUSE_LEFT_CLICK: + if self.getProperty('mouse.mode') != '1': + self.setProperty('mouse.mode', '1') + + self.seekMouse(action, without_osd=controlID == self.NO_OSD_BUTTON_ID) + return + elif action == xbmcgui.ACTION_MOUSE_MOVE: + self.seekMouse(action, without_osd=controlID == self.NO_OSD_BUTTON_ID, preview=True) + return + + if action in (xbmcgui.ACTION_PAUSE, xbmcgui.ACTION_PLAYER_PLAY, xbmcgui.ACTION_PLAYER_PLAYPAUSE) and \ + self.player.playState == self.player.STATE_PLAYING: + self.hideOSD() + + passThroughMain = False + if controlID == self.SKIP_MARKER_BUTTON_ID: + if action == xbmcgui.ACTION_SELECT_ITEM: + markerDef = self._currentMarker + if markerDef["marker"]: + marker = markerDef["marker"] + final = getattr(marker, "final", False) + + markerOff = 0 + if marker.type == "credits" and final: + # offset final marker seek so we can trigger postPlay + markerOff = FINAL_MARKER_NEGOFF + + util.DEBUG_LOG('MarkerSkip: Skipping marker {}'.format(markerDef["marker"])) + self.setProperty('show.markerSkip', '') + self.setProperty('show.markerSkip_OSDOnly', '') + self.doSeek(math.ceil(float(marker.endTimeOffset)) - markerOff) + self.hideOSD(skipMarkerFocus=True) + + if marker.type == "credits" and not final: + # non-final marker + setattr(self, markerDef["markerAutoSkipShownTimer"], None) + self.resetAutoSeekTimer(None) + + return + elif action == xbmcgui.ACTION_MOVE_DOWN: + self.setProperty('show.markerSkip_OSDOnly', '1') + self.showOSD() + elif action in (xbmcgui.ACTION_MOVE_RIGHT, xbmcgui.ACTION_STEP_FORWARD, xbmcgui.ACTION_MOVE_LEFT, + xbmcgui.ACTION_STEP_BACK): + # allow no-OSD-seeking with intro skip button shown + passThroughMain = True + elif action == xbmcgui.ACTION_MOVE_UP and self.osdVisible() and self.showChapters: + self.setProperty('show.chapters', '1') + self.setFocusId(self.BIG_SEEK_LIST_ID) + return + + if controlID == self.MAIN_BUTTON_ID: + # we're seeking from the timeline with the OSD open - do an actual timeline seek + if not self._seeking: + self.selectedOffset = self.trueOffset() + + if action in (xbmcgui.ACTION_MOVE_RIGHT, xbmcgui.ACTION_STEP_FORWARD): + if self.useDynamicStepsForTimeline: + return self.skipForward() + return self.seekByOffset(10000, auto_seek=self.useAutoSeek) + + elif action in (xbmcgui.ACTION_MOVE_LEFT, xbmcgui.ACTION_STEP_BACK): + if self.useDynamicStepsForTimeline: + return self.skipBack() + return self.seekByOffset(-10000, auto_seek=self.useAutoSeek) + + elif action == xbmcgui.ACTION_MOVE_UP: + if self.getProperty('show.markerSkip') or self.getProperty('show.markerSkip_OSDOnly'): + # pressed up on player controls, then up on MAIN BUTTON; focus marker button + if currentAction == lastAction: + self.setFocusId(self.SKIP_MARKER_BUTTON_ID) + return + elif self.showChapters: + self.setProperty('show.chapters', '1') + + elif action == xbmcgui.ACTION_MOVE_DOWN: + if self.previousFocusID == self.BIG_SEEK_LIST_ID and ( + self.getProperty('show.markerSkip') or self.getProperty('show.markerSkip_OSDOnly')): + self.setFocusId(self.SKIP_MARKER_BUTTON_ID) + self.setProperty('show.chapters', '') + + self.updateBigSeek() + + # elif action == xbmcgui.ACTION_MOVE_UP: + # self.seekForward(60000) + # elif action == xbmcgui.ACTION_MOVE_DOWN: + # self.seekBack(60000) + + # don't auto-apply the currently selected seek when pressing down + elif controlID == self.PLAY_PAUSE_BUTTON_ID and self.previousFocusID == self.MAIN_BUTTON_ID \ + and action == xbmcgui.ACTION_MOVE_DOWN: + self.resetSeeking() + + elif controlID == self.NO_OSD_BUTTON_ID or passThroughMain: + if action in (xbmcgui.ACTION_MOVE_RIGHT, xbmcgui.ACTION_MOVE_LEFT): + # we're seeking from the timeline, with the OSD closed; act as we're skipping + if not self._seeking: + self.selectedOffset = self.trueOffset() + + if action == xbmcgui.ACTION_MOVE_RIGHT: + self.skipForward(without_osd=True) + + else: + self.skipBack(without_osd=True) + if action in (xbmcgui.ACTION_MOVE_UP, xbmcgui.ACTION_MOVE_DOWN): + # we're seeking from the timeline, with the OSD closed; act as we're skipping + if not self._seeking: + self.selectedOffset = self.trueOffset() + + if self.skipChapter(forward=(action == xbmcgui.ACTION_MOVE_UP), without_osd=True): + return + + if action in ( + xbmcgui.ACTION_MOVE_UP, + xbmcgui.ACTION_MOVE_DOWN, + xbmcgui.ACTION_BIG_STEP_FORWARD, + xbmcgui.ACTION_BIG_STEP_BACK + ) and not self._seekingWithoutOSD: + self.selectedOffset = self.trueOffset() + self.setBigSeekShift() + self.updateProgress() + self.showOSD() + + elif action.getButtonCode() == 61519: + if self.getProperty('show.PPI'): + self.hidePPIDialog() + else: + self.showPPIDialog() + return + + elif controlID == self.BIG_SEEK_LIST_ID: + if action in (xbmcgui.ACTION_MOVE_RIGHT, xbmcgui.ACTION_BIG_STEP_FORWARD): + return self.updateBigSeek(changed=True) + elif action in (xbmcgui.ACTION_MOVE_LEFT, xbmcgui.ACTION_BIG_STEP_BACK): + return self.updateBigSeek(changed=True) + + elif action == xbmcgui.ACTION_MOVE_DOWN: + if self.getProperty('show.markerSkip'): + self.setProperty('show.chapters', '') + self.setFocusId(self.SKIP_MARKER_BUTTON_ID) + + if action.getButtonCode() == 61516: + self.cycleSubtitles() + elif action.getButtonCode() == 61524: + self.toggleSubtitles() + elif action.getButtonCode() == 323714: + # Alt-left + builtin.PlayerControl('tempodown') + elif action.getButtonCode() == 323715: + # Alt-right + builtin.PlayerControl('tempoup') + elif action == xbmcgui.ACTION_NEXT_ITEM: + self.handler.ignoreTimelines = True + self._ignoreTick = True + self.killTimeKeeper() + self.handler.next() + elif action == xbmcgui.ACTION_PREV_ITEM: + self.handler.ignoreTimelines = True + self._ignoreTick = True + self.killTimeKeeper() + self.handler.prev() + + if action in cancelActions + (xbmcgui.ACTION_SELECT_ITEM,): + if self.getProperty('show.PPI') and action in cancelActions: + self.hidePPIDialog() + self.hideOSD() + return + + # immediate marker timer actions + if self.countingDownMarker and \ + (self.getProperty('show.markerSkip') or self.getProperty('show.markerSkip_OSDOnly')): + + if controlID != self.BIG_SEEK_LIST_ID and \ + (util.advancedSettings.skipMarkerTimerCancel + or util.advancedSettings.skipMarkerTimerImmediate): + if util.advancedSettings.skipMarkerTimerCancel and \ + action in (xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK): + self.displayMarkers(cancelTimer=True) + + elif util.advancedSettings.skipMarkerTimerImmediate \ + and action == xbmcgui.ACTION_SELECT_ITEM: + self.displayMarkers(immediate=True) + self.hideOSD(skipMarkerFocus=True) + return + + if action in cancelActions: + if self.waitingForBuffer: + self._abortBufferWait = True + self.waitingForBuffer = False + return + + if self._seeking and not self._ignoreInput: + self.resetSeeking() + self.updateCurrent() + self.updateProgress() + if self.osdVisible(): + self.hideOSD() + return + + if action in (xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK): + if self._osdHideAnimationTimeout: + if self._osdHideAnimationTimeout >= time.time(): + return + else: + self._osdHideAnimationTimeout = None + + if self.osdVisible(): + self.hideOSD() + else: + self.stop() + return + except: + util.ERROR() + + kodigui.BaseDialog.onAction(self, action) + + def doKodiSelectDialogHack(self, action): + command = { + xbmcgui.ACTION_MOVE_UP: "Up", + xbmcgui.ACTION_MOVE_DOWN: "Down", + xbmcgui.ACTION_MOVE_LEFT: "Right", # Not sure if these are actually reversed or something else is up here + xbmcgui.ACTION_MOVE_RIGHT: "Left", + xbmcgui.ACTION_SELECT_ITEM: "Select", + xbmcgui.ACTION_PREVIOUS_MENU: "Back", + xbmcgui.ACTION_NAV_BACK: "Back" + }.get(action.getId()) + + if command is not None: + xbmc.executebuiltin('Action({0},selectdialog)'.format(command)) + return True + + return False + + def onFocus(self, controlID): + lastFocusID = self.lastFocusID + self.previousFocusID = self.lastFocusID + self.lastFocusID = controlID + if controlID == self.MAIN_BUTTON_ID: + # when seeking via ENTER/CLICK on chapters, coming directly from bigSeekSelected, don't assume we've + # already seeked. bigSeekSelected sets self.selectedOffset + if not self.showChapters: + self.selectedOffset = self.trueOffset() + + if lastFocusID == self.BIG_SEEK_LIST_ID and self.bigSeekChanged: + self.updateBigSeek(changed=True) + + # in case of chapter mode, bigSeekChanged holds our chapter's offset + offset = self.bigSeekChanged if self.showChapters else self.selectedOffset + self.updateProgress(set_to_current=False, offset=offset) + + # immediately seek bigSeek after click + self._performSeek(offset=offset) + self.hideOSD(skipMarkerFocus=True) + + else: + self.setBigSeekShift() + self.updateProgress() + + elif controlID == self.BIG_SEEK_LIST_ID: + self.setBigSeekShift() + self.updateBigSeek(changed=False) + + elif xbmc.getCondVisibility('ControlGroup(400).HasFocus(0)'): + self.selectedOffset = self.trueOffset() + self.updateProgress() + + def onClick(self, controlID): + if self._ignoreInput: + return + + if controlID in (self.MAIN_BUTTON_ID, self.NO_OSD_BUTTON_ID): + # only react to click events on our main areas if we're not in mouse mode, otherwise mouse seeking is + # handled by onAction + if self.getProperty('mouse.mode') != '1': + if controlID == self.MAIN_BUTTON_ID: + self.resetAutoSeekTimer(None) + self.doSeek() + elif controlID == self.NO_OSD_BUTTON_ID: + if not self._seeking: + # we might be reacting to an immediate marker skip while showing a marker with timeout; + # in that case, don't show the OSD + if not self._currentMarker or not util.advancedSettings.skipMarkerTimerImmediate or \ + self._currentMarker["countdown"] is None: + self.showOSD() + else: + # currently seeking without the OSD, apply the seek + self.doSeek() + elif controlID == self.PLAY_PAUSE_BUTTON_ID \ + and self.player.playState == self.player.STATE_PLAYING \ + and self.osdVisible(): + self.hideOSD() + elif controlID == self.STOP_BUTTON_ID: + self.stop() + elif controlID == self.SETTINGS_BUTTON_ID: + self.handleDialog(self.showSettings) + elif controlID == self.REPEAT_BUTTON_ID: + self.repeatButtonClicked() + elif controlID == self.SHUFFLE_BUTTON_ID: + self.shuffleButtonClicked() + elif controlID == self.PREV_BUTTON_ID: + self.handler.ignoreTimelines = True + self._ignoreTick = True + self.handler.prev() + elif controlID == self.NEXT_BUTTON_ID: + if not self.handler.queuingNext: + self.handler.ignoreTimelines = True + self.handler.queuingNext = True + self._ignoreTick = True + self._ignoreInput = True + self.killTimeKeeper() + next(self.handler) + return + elif controlID == self.PLAYLIST_BUTTON_ID: + self.showPlaylistDialog() + elif controlID == self.OPTIONS_BUTTON_ID: + self.handleDialog(self.optionsButtonClicked) + elif controlID == self.SUBTITLE_BUTTON_ID: + self.handleDialog(self.subtitleButtonClicked) + elif controlID == self.BIG_SEEK_LIST_ID: + self.bigSeekSelected() + elif controlID == self.SKIP_BACK_BUTTON_ID: + self.skipBack() + elif controlID == self.SKIP_FORWARD_BUTTON_ID: + self.skipForward() + + def stop(self): + self._ignoreTick = True + self.doClose() + # self.handler.onSeekAborted() + if self.bingeMode: + self.handler.stoppedInBingeMode = True + self.handler.player.stop() + + def doClose(self, delete=False): + if self.handler.playlist: + self.handler.playlist.off('change', self.updateProperties) + + try: + if self.playlistDialog: + self.playlistDialog.doClose() + if delete: + del self.playlistDialog + self.playlistDialog = None + util.garbageCollect() + + self.killTimeKeeper() + finally: + kodigui.BaseDialog.doClose(self) + + def showPPIDialog(self): + for attrib in SESSION_ATTRIBUTE_TYPES.values(): + self.setProperty('ppi.%s' % attrib.label, "") + + self.setProperty('show.PPI', '1') + self.setProperty('ppi.Status', 'Loading ...') + + def getVideoSession(currentVideo): + return currentVideo.server.findVideoSession(currentVideo.settings.getGlobal("clientIdentifier"), + currentVideo.ratingKey) + + if util.KODI_BUILD_NUMBER < 2090821: + try: + cache = int(xbmc.getInfoLabel('Player.ProgressCache')) - int(xbmc.getInfoLabel('Player.Progress')) + self.setProperty('ppi.Buffered', str(cache)) + except: + pass + + while not self.player.started: + util.MONITOR.waitForAbort(0.1) + + info = None + currentVideo = self.player.video + try: + videoSession = None + elapsed = 0 + while not videoSession: + if elapsed > 10: + raise NotFound + + videoSession = getVideoSession(currentVideo) + if videoSession: + break + + util.MONITOR.waitForAbort(1) + elapsed += 1 + + # fill attributes + info = VideoSessionInfo(videoSession, currentVideo) + + except ServerNotOwned: + # timeline response data fallback + elapsed = 0 + try: + while not self.lastTimelineResponse: + if elapsed > 10: + raise NotFound + + util.MONITOR.waitForAbort(0.1) + elapsed += 0.1 + + info = VideoSessionInfo(None, currentVideo, incompleteSessionData=self.lastTimelineResponse) + except NotFound: + self.setProperty('ppi.Status', 'Info not available (data not found)') + + except: + util.ERROR() + + except NotFound: + self.setProperty('ppi.Status', 'Info not available (session not found)') + + except: + util.ERROR() + + if info: + self.setProperty('ppi.Status', '') + for attrib in info.attributes.values(): + self.setProperty('ppi.%s' % attrib.label, attrib.value) + + def hidePPIDialog(self): + self.setProperty('show.PPI', '') + + def resetSkipSteps(self): + self._forcedLastSkipAmount = None + self._atSkipStep = -1 + self._lastSkipDirection = None + + def determineSkipStep(self, direction): + stepCount = len(self.skipSteps[direction]) + + # shortcut for simple skipping + if stepCount == 1: + return self.skipSteps[direction][0] + + use_direction = direction + + # kodi-style skip steps + + # when the direction changes, we either use the skip steps of the other direction, or walk backwards in the + # current skip step list + if self._lastSkipDirection != direction: + if self._atSkipStep == -1 or self._lastSkipDirection is None: + self._atSkipStep = 0 + self._lastSkipDirection = direction + self._forcedLastSkipAmount = None + step = self.skipSteps[use_direction][0] + + else: + # we're reversing the current direction + use_direction = self._lastSkipDirection + + # use the inverse value of the current skip step + step = self.skipSteps[use_direction][min(self._atSkipStep, len(self.skipSteps[use_direction]) - 1)] * -1 + + # we've hit a boundary, reverse the difference of the last skip step in relation to the boundary + if self._forcedLastSkipAmount is not None: + step = self._forcedLastSkipAmount * -1 + self._forcedLastSkipAmount = None + + # walk back one step + self._atSkipStep -= 1 + else: + # no reversal of any kind was requested and we've not hit any boundary, use the next skip step + if self._forcedLastSkipAmount is None: + self._atSkipStep += 1 + step = self.skipSteps[use_direction][min(self._atSkipStep, stepCount - 1)] + + else: + # we've hit a timeline boundary and haven't reversed yet. Don't do any further skipping + return + + return step + + def skipChapter(self, forward=True, without_osd=False): + lastSelectedOffset = self.selectedOffset + util.DEBUG_LOG('chapter skipping from {0} with forward {1}'.format(lastSelectedOffset, forward)) + if forward: + nextChapters = [c for c in self.chapters if c.startTime() > lastSelectedOffset] + util.DEBUG_LOG('Found {0} chapters among {1}'.format(len(nextChapters), len(self.chapters))) + if len(nextChapters) == 0: + return False + chapter = nextChapters[0] + else: + startTimeLimit = lastSelectedOffset - 2000 + if startTimeLimit < 0: + startTimeLimit = 0 + lastChapters = [c for c in self.chapters if c.startTime() <= startTimeLimit] + util.DEBUG_LOG('Found {0} chapters among {1}'.format(len(lastChapters), len(self.chapters))) + if len(lastChapters) == 0: + return False + chapter = lastChapters[-1] + + if chapter.tag: + util.DEBUG_LOG('Skipping to chapter: {}'.format(chapter.tag)) + self.forceNextTimeAsChapter = chapter.tag + + util.DEBUG_LOG('New start time is {0}'.format(chapter.startTime())) + self.skipByOffset(chapter.startTime() - lastSelectedOffset, without_osd=without_osd) + return True + + def skipForward(self, without_osd=False): + self.skipByStep("positive", without_osd) + + def skipBack(self, without_osd=False): + self.skipByStep("negative", without_osd) + + def skipByStep(self, direction="positive", without_osd=False): + step = self.determineSkipStep(direction) + self.skipByOffset(step, without_osd) + + def skipByOffset(self, offset, without_osd=False): + if self.countingDownMarker: + self.displayMarkers(cancelTimer=True) + + if offset is not None: + if not self.seekByOffset(offset, without_osd=without_osd): + return + + if self.useAutoSeek: + self.delayedSeek() + else: + self.setProperty('button.seek', '1') + + def delayedSeek(self): + self.setProperty('button.seek', '1') + delay = self._autoSeekDelay + + if delay > 0: + self._delayedSeekTimeout = time.time() + delay + + if not self._delayedSeekThread or not self._delayedSeekThread.is_alive(): + self._delayedSeekThread = threading.Thread(target=self._delayedSeek) + self._delayedSeekThread.start() + else: + # Do seek now + self._performSeek() + self.resetSeeking() + + def _delayedSeek(self): + try: + while not util.MONITOR.waitForAbort(0.1): + if not self._delayedSeekTimeout or time.time() > self._delayedSeekTimeout: + break + + if not util.MONITOR.abortRequested() and self._delayedSeekTimeout is not None: + self._performSeek() + except: + util.ERROR() + + def _performSeek(self, offset=None): + self._lastSkipDirection = None + self._forcedLastSkipAmount = None + self.doSeek(offset=offset) + + def handleDialog(self, func): + self.hasDialog = True + + try: + func() + finally: + self.resetTimeout() + self.hasDialog = False + + def videoSettingsHaveChanged(self): + changed = False + if ( + self.player.video.settings.prefOverrides != self.initialVideoSettings or + self.player.video.selectedAudioStream() != self.initialAudioStream + ): + self.initialVideoSettings = dict(self.player.video.settings.prefOverrides) + self.initialAudioStream = self.player.video.selectedAudioStream() + changed = True + + sss = self.player.video.selectedSubtitleStream() + if sss != self.initialSubtitleStream: + self.initialSubtitleStream = sss + if changed or self.isTranscoded: + return True + else: + return 'SUBTITLE' + + return changed + + def repeatButtonClicked(self): + pl = self.handler.playlist + + if pl: + if pl.isRepeatOne: + pl.setRepeat(False, one=False) + self.updateProperties() + elif pl.isRepeat: + pl.setRepeat(False, one=True) + pl.refresh(force=True) + else: + pl.setRepeat(True) + pl.refresh(force=True) + else: + xbmc.executebuiltin('PlayerControl(Repeat)') + + def shuffleButtonClicked(self): + if self.handler.playlist: + self.handler.playlist.setShuffle() + + def optionsButtonClicked(self): # Button currently commented out. + pass + # options = [] + + # options.append({'key': 'kodi_video', 'display': 'Video Options'}) + # options.append({'key': 'kodi_audio', 'display': 'Audio Options'}) + + # choice = dropdown.showDropdown(options, (1360, 1060), close_direction='down', pos_is_bottom=True, close_on_playback_ended=True) + + # if not choice: + # return + + # if choice['key'] == 'kodi_video': + # xbmc.executebuiltin('ActivateWindow(OSDVideoSettings)') + # elif choice['key'] == 'kodi_audio': + # xbmc.executebuiltin('ActivateWindow(OSDAudioSettings)') + + def subtitleButtonClicked(self): + options = [] + + options.append({'key': 'download', 'display': T(32405, 'Download Subtitles')}) + + # select "enable" by default + selectIndex = 1 + if self.lastSubtitleNavAction == "download": + selectIndex = 0 + + if self.player.video.hasSubtitles: + if self.player.video.hasSubtitle: + options.append({'key': 'delay', 'display': T(32406, 'Subtitle Delay')}) + + # select "disable" if we only have one subtitle + selectIndex = 2 + if self.lastSubtitleNavAction == "delay": + selectIndex = 1 + elif self.lastSubtitleNavAction == "download": + selectIndex = 0 + + if len(self.player.video.subtitleStreams) > 1: + options.append({'key': 'prev', 'display': T(32930, 'Previous Subtitle')}) + options.append({'key': 'next', 'display': T(32407, 'Next Subtitle')}) + + # select "next subtitle" if we already have subs active + selectIndex = 3 + + # select "prev subtitle" if we've last cycled backwards + if self.lastSubtitleNavAction == "backward": + selectIndex = 2 + elif self.lastSubtitleNavAction == "delay": + selectIndex = 1 + elif self.lastSubtitleNavAction == "download": + selectIndex = 0 + + options.append( + { + 'key': 'enable', + 'display': + xbmc.getCondVisibility('VideoPlayer.SubtitlesEnabled') and self.player.video.hasSubtitle and + T(32408, 'Disable Subtitles') or T(32409, 'Enable Subtitles') + } + ) + + # cheap and inaccurate approach to move the dropdown to the left based on how many buttons the user has hidden + choice = dropdown.showDropdown(options, (1360 - self.subtitleButtonLeft, 1060), close_direction='down', pos_is_bottom=True, + close_on_playback_ended=True, select_index=selectIndex) + + if not choice: + return + + if choice['key'] == 'download': + self.hideOSD() + if self.handler and self.handler.player and self.handler.player.playerObject \ + and util.getSetting('calculate_oshash', False): + meta = self.handler.player.playerObject.metadata + oss_hash = util.getOpenSubtitlesHash(meta.size, meta.streamUrls[0]) + if oss_hash: + util.DEBUG_LOG("OpenSubtitles hash: %s" % oss_hash) + util.setGlobalProperty("current_oshash", oss_hash, base='videoinfo.{0}') + else: + util.setGlobalProperty("current_oshash", '', base='videoinfo.{0}') + self.lastSubtitleNavAction = "download" + builtin.ActivateWindow('SubtitleSearch') + elif choice['key'] == 'delay': + self.hideOSD() + self.lastSubtitleNavAction = "delay" + builtin.Action('SubtitleDelay') + elif choice['key'] == 'next': + self.cycleSubtitles() + self.lastSubtitleNavAction = "forward" + elif choice['key'] == 'prev': + self.cycleSubtitles(forward=False) + self.lastSubtitleNavAction = "backward" + elif choice['key'] == 'enable': + enabled = self.toggleSubtitles() + self.lastSubtitleNavAction = "forward" + + def toggleSubtitles(self): + """ + Used for subtitle toggling from button press or subtitle toggle menu + """ + if xbmc.getCondVisibility('VideoPlayer.SubtitlesEnabled') and self.player.video.hasSubtitle: + self.disableSubtitles() + return False + else: + self.cycleSubtitles() + return True + + def disableSubtitles(self): + self.player.video.disableSubtitles() + self.setSubtitles() + + def cycleSubtitles(self, forward=True): + """ + Selects the first subtitle or the next one + """ + stream = self.player.video.cycleSubtitles(forward=forward) + self.setSubtitles(honor_forced_subtitles_override=False) + util.showNotification(str(stream), time_ms=1500, header=util.T(32396, "Subtitles")) + + def setSubtitles(self, do_sleep=False, honor_forced_subtitles_override=False): + self.handler.setSubtitles(do_sleep=do_sleep, honor_forced_subtitles_override=honor_forced_subtitles_override) + if self.player.video.current_subtitle_is_embedded: + # this is an embedded stream, seek back a second after setting the subtitle due to long standing kodi + # issue: https://github.com/xbmc/xbmc/issues/21086 + util.DEBUG_LOG("Switching embedded subtitle stream, seeking due to Kodi issue #21086") + + # true offset can be 0, which might lead to an infinite loop, seek to 100ms at least. + self.doSeek(max(self.trueOffset() - 100, 100)) + + def showSettings(self): + with self.propertyContext('settings.visible'): + playersettings.showDialog(self.player.video, via_osd=True, parent=self) + + changed = self.videoSettingsHaveChanged() + + if self.player.playState == self.player.STATE_PLAYING: + self._osdHideFast = True + + if changed == 'SUBTITLE': + self.setSubtitles(do_sleep=False) + self.lastSubtitleNavAction = "forward" + + elif changed: + self.doSeek(self.trueOffset(), settings_changed=True) + + def setBigSeekShift(self): + closest = None + if self.selectedOffset is None: + return + + for mli in self.bigSeekControl: + if mli.dataSource > self.selectedOffset: + break + closest = mli + if not closest: + return + + self.bigSeekOffset = self.selectedOffset - closest.dataSource + pxOffset = int(self.bigSeekOffset / float(self.duration) * 1920) + + if not self.showChapters: + self.bigSeekGroupControl.setPosition(-8 + pxOffset, 917) + self.bigSeekControl.selectItem(closest.pos()) + + self._seeking = True + # xbmc.sleep(100) + + def updateBigSeek(self, changed=False): + if changed and not self.showChapters: + self.bigSeekChanged = True + self.selectedOffset = self.bigSeekControl.getSelectedItem().dataSource + self.bigSeekOffset + self.updateProgress(set_to_current=False) + elif self.showChapters: + # when hovering chapters, show its corresponding time on the timeline, but don't act like we're seeking + self.updateProgress(set_to_current=False, offset=self.bigSeekControl.getSelectedItem().dataSource, + onlyTimeIndicator=True) + self.resetSkipSteps() + + def bigSeekSelected(self): + # this gets called when a click action happened on the bigSeek, defer the actual action to onFocus + # by setFocusId(MAIN) + + self.bigSeekChanged = True + if self.showChapters: + self.resetAutoSeekTimer(None) + self._navigatedViaMarkerOrChapter = True + + sel = self.bigSeekControl.getSelectedItem() + if self.bigSeekControl.isLastItem(sel): + self.selectedOffset = sel.dataSource - FINAL_MARKER_NEGOFF + else: + self.selectedOffset = sel.dataSource + MARKER_OFF + + # the onFocus action might take a couple of ms and might be overridden by onAction, store separately + self.bigSeekChanged = self.selectedOffset + + self.setFocusId(self.MAIN_BUTTON_ID) + + def updateProperties(self, **kwargs): + if not self.started: + return + + if self.fromSeek: + self.setFocusId(self.MAIN_BUTTON_ID) + self.fromSeek = 0 + + self.setProperty('has.bif', self.bifURL and '1' or '') + self.setProperty('video.title', self.title) + self.setProperty('video.title2', self.title2) + self.setProperty('is.show', (self.player.video.type == 'episode') and '1' or '') + self.setProperty('media.show_ends', self.showItemEndsInfo and '1' or '') + self.setProperty('time.ends_label', self.showItemEndsLabel and (util.T(32543, 'Ends at')) or '') + + if self.isDirectPlay: + self.setProperty('time.fmt', self.timeFmtKodi) + self.setProperty('time.fmt.ends', util.timeFormatKN.replace(":ss", "")) + + self.setBoolProperty('direct.play', self.isDirectPlay) + + if not self.getProperty('nav.playlist') and self.getProperty('nav.quick_subtitles'): + # offset the subtitle button + self.getControl(self.SUBTITLE_BUTTON_ID).setPosition(30, 0) + + if not self.getProperty('nav.prevnext'): + if self.getProperty('nav.ffwdrwd'): + self.getControl(self.SKIP_BACK_BUTTON_ID).setPosition(30, 0) + + pq = self.handler.playlist + if pq: + self.setProperty('has.playlist', '1') + self.setProperty('pq.isRemote', pq.isRemote and '1' or '') + self.setProperty('pq.hasnext', pq.hasNext() and '1' or '') + self.setProperty('pq.hasprev', pq.hasPrev() and '1' or '') + self.setProperty('pq.repeat', pq.isRepeat and '1' or '') + self.setProperty('pq.repeat.one', pq.isRepeatOne and '1' or '') + self.setProperty('pq.shuffled', pq.isShuffled and '1' or '') + else: + self.setProperties(('pq.isRemote', 'pq.hasnext', 'pq.hasprev', 'pq.repeat', 'pq.shuffled', 'has.playlist'), + '') + + self.updateCurrent() + + def updateChapters(self): + items = [] + + # replace bigSeek with chapters or markers if possible + if self.showChapters: + chaps = [] + chapOffsets = [] + if self.chapters: + self.setProperty('chapters.label', T(33605, 'Video Chapters').upper()) + for index, chapter in enumerate(self.chapters): + thumb = chapter.thumb and chapter.thumb.asTranscodedImageURL( + *PlaylistDialog.LI_AR16X9_THUMB_DIM) or None + # mli = kodigui.ManagedListItem(data_source=chapter.startTime(), + # thumbnailImage=thumb, + # label=chapter.tag or T(33607, 'Chapter {}').format(index + 1)) + # items.append(mli) + st = chapter.startTime() + chapOffsets.append(st) + chaps.append((st, thumb, chapter.tag or T(33607, 'Chapter {}').format(index + 1))) + + # fake chapters by using markers + if util.getSetting('virtual_chapters', True) and self.markers: + if not self.chapters: + self.setProperty('chapters.label', T(33606, 'Virtual Chapters').upper()) + else: + self.setProperty('chapters.label', T(33634, 'Combined Chapters').upper()) + creditsCounter = 0 + preparedMarkers = [] + for markerDef in self.markers: + marker = markerDef["marker"] + if marker: + if markerDef["marker_type"] == "intro": + preparedMarkers.append((int(marker.startTimeOffset), T(33608, "Intro"), False)) + preparedMarkers.append((int(marker.endTimeOffset), T(33610, "Main"), False)) + + elif markerDef["marker_type"] == "credits": + creditsCounter += 1 + if creditsCounter > 1 and getattr(marker, "final", False): + label = T(33635, "Final Credits") + else: + label = T(33609, "Credits") + "{}" + preparedMarkers.append((int(marker.startTimeOffset), label, True)) + + # add staggered virtual markers + preparedMarkers.append((int(self.duration * 0.25), "25 %", False)) + preparedMarkers.append((int(self.duration * 0.50), "50 %", False)) + preparedMarkers.append((int(self.duration * 0.75), "75 %", False)) + + credCnt = 1 + for offset, label, credits in sorted(preparedMarkers): + # filter intersections + skipMarker = False + for cOffset in chapOffsets: + if offset - MARKER_CHAPTER_OVERLAP_THRES <= cOffset <= offset + MARKER_CHAPTER_OVERLAP_THRES: + skipMarker = True + break + + # skip marker if we're overlapping with any chapter + if skipMarker: + continue + + chaps.append((offset, self.handler.player.playerObject.getBifUrl(offset), + label.format(" #{}".format(credCnt) if credits and creditsCounter > 1 else ""))) + + if credits: + credCnt += 1 + + for offset, thumb, label in sorted(chaps): + mli = kodigui.ManagedListItem(data_source=offset, thumbnailImage=thumb, label=label) + items.append(mli) + + else: + div = int(self.duration / 12) + for x in range(12): + offset = div * x + items.append(kodigui.ManagedListItem(data_source=offset)) + + # we might've been reinizialized by the handler and have had markers/chapters before. reset height and + # positioning of the bigSeekControl + self.bigSeekControl.control.setHeight(16) + self.bigSeekControl.control.setPosition(self.bigSeekControl.getX(), 0) + + self.bigSeekControl.reset() + self.bigSeekControl.addItems(items) + + if self.showChapters: + # adjust height and positioning of bigSeekControl to accomodate chapters + self.bigSeekControl.control.setHeight(160) + self.bigSeekControl.control.setPosition(self.bigSeekControl.getX(), -126) + + def updateCurrent(self, update_position_control=True, atOffset=None): + ratio = self.trueOffset() / float(self.duration) + + if update_position_control: + w = int(ratio * self.SEEK_IMAGE_WIDTH) + self.positionControl.setWidth(w) + + # update cache/buffer bar + if util.advancedSettings.playerShowBuffer and self.isDirectPlay and util.KODI_VERSION_MAJOR > 18: + cache_w = int(xbmc.getInfoLabel("Player.ProgressCache")) * self.SEEK_IMAGE_WIDTH // 100 + self.cacheControl.setWidth(cache_w) + + if self.isTranscoded: + to = atOffset if atOffset is not None else self.trueOffset() + self.setProperty('time.current', util.timeDisplay(to, cutHour=self._videoBelowOneHour)) + self.setProperty('time.left', + util.timeDisplay(self.duration - to, cutHour=self._videoBelowOneHour)) + + _fmt = util.timeFormat.replace(":%S", "") + + val = time.strftime(_fmt, time.localtime(time.time() + ((self.duration - to) / 1000))) + if not util.padHour and val[0] == "0" and val[1] != ":": + val = val[1:] + + self.setProperty('time.end', val) + + def doSeek(self, offset=None, settings_changed=False): + self._applyingSeek = True + self._ignoreInput = settings_changed + offset = self.selectedOffset if offset is None else offset + + if self.countingDownMarker: + self.displayMarkers(cancelTimer=True) + + self.resetSkipSteps() + self.updateProgress(offset=offset) + + try: + self.handler.seek(offset, settings_changed=settings_changed) + finally: + self.resetSeeking() + + def seekByOffset(self, offset, auto_seek=False, without_osd=False): + """ + Sets the selected offset and updates the progress bar to visually represent the current seek + :param offset: offset to seek to + :param auto_seek: whether to automatically seek to :offset: after a certain amount of time + :param without_osd: indicates whether this seek was done with or without OSD + :return: + """ + if self.selectedOffset is None: + self.selectedOffset = self.offset + lastSelectedOffset = self.selectedOffset + # If we are seeking forward and already past 5 seconds from end, don't seek at all + if lastSelectedOffset > self.duration - 5000 and offset > 0: + return False + + self._seeking = True + self._seekingWithoutOSD = without_osd + self.selectedOffset += offset + # Don't skip past 5 seconds from end + if self.selectedOffset > self.duration - 5000: + # offset = +100, at = 80000, duration = 80007, realoffset = 2 + self._forcedLastSkipAmount = self.duration - 5000 - lastSelectedOffset + self.selectedOffset = self.duration - 5000 + # Don't skip back past 1 (0 is handled specially so seeking to 0 will not do a seek) + elif self.selectedOffset < 1: + # offset = -100, at = 5, realat = -95, realoffset = 1 - 5 = -4 + self._forcedLastSkipAmount = 1 - lastSelectedOffset + self.selectedOffset = 1 + + self.updateProgress(set_to_current=False) + self.setBigSeekShift() + if auto_seek: + self.resetAutoSeekTimer() + self.bigSeekHideTimer.reset() + return True + + def seekMouse(self, action, without_osd=False, preview=False): + x = self.mouseXTrans(action.getAmount1()) + y = self.mouseYTrans(action.getAmount2()) + if not (self.BAR_Y <= y <= self.BAR_BOTTOM): + return + + if not (self.BAR_X <= x <= self.BAR_RIGHT): + return + + self._seeking = True + self._seekingWithoutOSD = without_osd + + self.selectedOffset = int((x - self.BAR_X) / float(self.SEEK_IMAGE_WIDTH) * self.duration) + if not preview: + self.doSeek() + if not xbmc.getCondVisibility('Window.IsActive(videoosd) | Player.Rewinding | Player.Forwarding'): + self.hideOSD() + else: + self.updateProgress(set_to_current=False) + self.setProperty('button.seek', '1') + + def getCurrentMarkerDef(self, offset=None): + """ + Show intro/credits skip button at current time + """ + + if not self.markers: + return + + off = offset if offset is not None else self.trueOffset() + + for markerDef in self.markers: + marker = markerDef["marker"] + if marker: + startTimeOffset = int(marker.startTimeOffset) + + # show intro skip early? (only if intro is during the first X minutes) + if self.showIntroSkipEarly and markerDef["marker_type"] == "intro" and \ + startTimeOffset <= util.advancedSettings.skipIntroButtonShowEarlyThreshold1 * 1000: + startTimeOffset = 0 + markerDef["overrideStartOff"] = 0 + + markerEndNegoff = FINAL_MARKER_NEGOFF if getattr(markerDef["marker"], "final", False) else 0 + + if startTimeOffset - MARKER_SHOW_NEGOFF <= off < int(marker.endTimeOffset) - markerEndNegoff: + + return markerDef + + + @property + def duration(self): + try: + return self._duration or int(self.handler.player.getTotalTime() * 1000) + except RuntimeError: # Not playing + return 1 + + def updateProgress(self, set_to_current=True, offset=None, onlyTimeIndicator=False): + """ + Updates the progress bars (seek and position) and the currently-selected-time-label for the current position or + seek state on the timeline. + :param set_to_current: if True, sets both the position bar and the seek bar to the currently selected position, + otherwise we're in seek mode, whereas one of both bars move relatively to the currently + selected position depending on the direction of the seek + :return: None + """ + if not self.initialized: + return + + offset = offset if offset is not None else \ + self.selectedOffset if self.selectedOffset is not None else self.trueOffset() + ratio = offset / float(self.duration) + w = int(ratio * self.SEEK_IMAGE_WIDTH) + + current_w = int(self.offset / float(self.duration) * self.SEEK_IMAGE_WIDTH) + + bifx = (w - int(ratio * 324)) + self.BAR_X + # bifx = w + self.selectionIndicator.setPosition(w, 896) + if w < 51: + self.selectionBox.setPosition(-50 + (50 - w), 0) + elif w > 1869: + self.selectionBox.setPosition(-100 + (1920 - w), 0) + else: + self.selectionBox.setPosition(-50, 0) + + if self.forceNextTimeAsChapter: + self.setProperty('time.selection', self.forceNextTimeAsChapter) + + # fixme: might be superfluous + self.selectionIndicatorImage.setWidth(self.selectionIndicatorText.getWidth()) + self.forceNextTimeAsChapter = False + else: + self.setProperty('time.selection', util.simplifiedTimeDisplay(offset)) + self.selectionIndicatorImage.setWidth(101) + + if onlyTimeIndicator: + return + + if self.hasBif: + self.setProperty('bif.image', self.handler.player.playerObject.getBifUrl(offset)) + self.bifImageControl.setPosition(bifx, 752) + + self.seekbarControl.setPosition(0, self.seekbarControl.getPosition()[1]) + if set_to_current: + self.seekbarControl.setWidth(w) + self.positionControl.setWidth(w) + else: + # we're seeking + if not self.selectedOffset: + return + + # current seek position below current offset? set the position bar's width to the current position of the + # seek and the seek bar to the current position of the video, to visually indicate the backwards-seeking + if self.selectedOffset < self.offset: + self.positionControl.setWidth(current_w) + self.seekbarControl.setWidth(w) + + # current seek position ahead of current offset? set the position bar's width to the current position of the + # video and the seek bar to the current position of the seek, to visually indicate the forwards-seeking + elif self.selectedOffset > self.offset: + self.seekbarControl.setPosition(current_w, self.seekbarControl.getPosition()[1]) + self.seekbarControl.setWidth(w - current_w) + # we may have "shortened" the width before, by seeking negatively, reset the position bar's width to + # the current video's position if that's the case + if self.positionControl.getWidth() < current_w: + self.positionControl.setWidth(current_w) + + else: + self.seekbarControl.setWidth(w) + self.positionControl.setWidth(w) + + def waitForBuffer(self): + # current filesize in bytes + size = float(self.handler.player.video.mediaChoice.part.size) + + # current buffer fill percentage + currentBufferPerc = int(xbmc.getInfoLabel("Player.ProgressCache")) - int(xbmc.getInfoLabel("Player.Progress")) + + # configured buffer size + bufferBytes = util.kcm.memorySize * 1024 * 1024 + + # wait for the full buffer or for 10% of the file at max + # a full buffer is typically 30% of the configured cache value + sensibleBufferPerc = min(bufferBytes / size * 100.0 / 2.8, 10) + + # can wait for buffer? + # we're relying on integer based percentages coming from kodi's internal ProgressCache. + # with a typical device buffer of 20-160 MB, this might be less than 1% of available buffer based on the playing + # media item. If we're below that value, wait for a defined amount of time instead of being smart. + if sensibleBufferPerc >= 1.0: + if currentBufferPerc < sensibleBufferPerc: + # pause + wasPlaying = False + if self.player.playState == self.player.STATE_PLAYING: + util.DEBUG_LOG("SeekDialog.buffer: Waiting for buffer to reach {} (is: {}), pausing" + .format(sensibleBufferPerc, currentBufferPerc)) + self.player.pause() + wasPlaying = True + + waitedFor = 0 + waitMax = util.advancedSettings.bufferWaitMax + waitExceeded = False + self.waitingForBuffer = True + self.showOSD(focusButton=False) + with busy.BusyClosableMsgContext() as bc: + # check for the buffer fill-state every 200ms + # this may be canceled by the usual actions; + # depending on who receives the cancel action, _abortBufferWait might be set by our onAction + # or by the busy window via the context manager + while not self._abortBufferWait and not bc.shouldClose and waitedFor < waitMax and \ + (int(xbmc.getInfoLabel("Player.ProgressCache")) - + int(xbmc.getInfoLabel("Player.Progress"))) < sensibleBufferPerc: + curBuf = int(xbmc.getInfoLabel("Player.ProgressCache")) - \ + int(xbmc.getInfoLabel("Player.Progress")) + + bc.setMessage("Buffer: {} %".format(int(curBuf / sensibleBufferPerc * 100))) + + xbmc.sleep(200) + waitedFor += 0.2 + + # report buffer state every 10 seconds + if int(waitedFor) > 0 and int(waitedFor) % 10 == 0: + util.DEBUG_LOG("SeekDialog.buffer: " + "Buffer filled {}/{}".format(curBuf, sensibleBufferPerc)) + + # buffer wait canceled via busy window + if bc.shouldClose: + self._abortBufferWait = True + + # buffer timed out + if waitedFor >= waitMax: + waitExceeded = True + + self.waitingForBuffer = False + + if waitExceeded or self._abortBufferWait: + if not self._abortBufferWait: + util.showNotification(util.T(32917, "Couldn't fill buffer in time ({}s)").format(waitMax), + header="Buffer") + self.stop() + return True + + if self.player.playState == self.player.STATE_PAUSED and wasPlaying: + # resume + util.DEBUG_LOG("SeekDialog.buffer: Buffer filled, resuming") + self.player.pause() + return True + else: + util.DEBUG_LOG("SeekDialog.buffer: Buffer already filled, not waiting for buffer") + + else: + wait = util.advancedSettings.bufferInsufficientWait + util.DEBUG_LOG("SeekDialog.buffer: Buffer is too small for us to see, waiting {} seconds".format(wait)) + self.waitingForBuffer = True + + wasPlaying = False + if self.player.playState == self.player.STATE_PLAYING: + self.player.pause() + wasPlaying = True + + with busy.BusyClosableMsgContext() as bc: + bc.setMessage("Buffering") + util.MONITOR.waitForAbort(wait) + self.waitingForBuffer = False + if self.player.playState == self.player.STATE_PAUSED and wasPlaying: + self.player.pause() + return True + + def onPlayBackResumed(self): + util.DEBUG_LOG("SeekDialog: OnPlaybackResumed") + if self._ignoreInput: + self._ignoreInput = False + + self.idleTime = None + self.ldTimer and self.syncTimeKeeper() + + def onAVChange(self): + util.DEBUG_LOG("SeekDialog: OnAVChange: DPO: {0}, offset: {1}".format(self.DPPlayerOffset, self.offset)) + + # wait for buffer if we're not expecting a seek + if not self.handler.seekOnStart and util.getSetting("slow_connection", False) and not self.waitingForBuffer: + # fixme: not sure why this is necessary, but something breaks when playing back a next item from playback + # that doesn't have a seek value. Adding a slight delay here fixes that. Timing issue? + xbmc.sleep(100) + self.tick(waitForBuffer=True) + return + + def onAVStarted(self): + util.DEBUG_LOG("SeekDialog: OnAVStarted: DPO: {0}, offset: {1}".format(self.DPPlayerOffset, self.offset)) + if self._ignoreInput: + self._ignoreInput = False + + self.ldTimer and self.syncTimeKeeper() + + def onPlayBackStarted(self): + util.DEBUG_LOG("SeekDialog: OnPlaybackStarted") + if self._ignoreInput: + self._ignoreInput = False + + self.ldTimer and self.syncTimeKeeper() + + def onPlayBackPaused(self): + util.DEBUG_LOG("SeekDialog: OnPlaybackPaused") + self.idleTime = time.time() + + def onPlayBackSeek(self, stime, offset): + util.DEBUG_LOG("SeekDialog: OnPlaybackSeek: {0}, {1}".format(stime, offset)) + self.idleTime = None + self.ldTimer and self.syncTimeKeeper() + + def onPlayBackStopped(self): + util.DEBUG_LOG("SeekDialog: OnPlayBackStopped") + self.killTimeKeeper() + + def onPlayBackEnded(self): + util.DEBUG_LOG("SeekDialog: OnPlayBackEnded") + self.killTimeKeeper() + + def onPlayBackFailed(self): + util.DEBUG_LOG("SeekDialog: OnPlayBackFailed") + self.killTimeKeeper() + + def syncTimeKeeper(self): + if not not self.handler.player.playerObject: + return + + self.timeKeeperTime = self.trueOffset()#int(self.handler.player.getTime() * 1000) + if not self.timeKeeper: + self.timeKeeper = plexapp.util.RepeatingCounterTimer(1.0, self.onTimeKeeperCallback) + self.onTimeKeeperCallback(tick=False) + self.timeKeeper.reset() + + def killTimeKeeper(self): + if self.timeKeeper: + try: + self.timeKeeper.cancel() + self.timeKeeper.join() + self.timeKeeper = None + except: + util.ERROR("Couldn't stop timeKeeper") + + def onTimeKeeperCallback(self, tick=True): + """ + called by playbackTimer periodically, sets playback time/ends in UI + """ + # we might be a little early on slower systems + if not self.started or not self.handler.player.playerObject: + return + + if self.stopPlaybackOnIdle: + if self.idleTime and time.time() - self.idleTime >= self.stopPlaybackOnIdle: + util.LOG("Player has been idle for {}s, stopping.".format(int(time.time() - self.idleTime))) + self.handler.player.stopAndWait() + return + + if not self.idleTime and xbmc.getCondVisibility('Player.Paused'): + self.idleTime = time.time() + + if tick and xbmc.getCondVisibility('Player.HasVideo + Player.Playing'): + self.timeKeeperTime += 1000 + + # Update buffer state in PPI if open and old Kodi version + if util.KODI_BUILD_NUMBER < 2090821 and self.getProperty('show.PPI'): + try: + cache = int(xbmc.getInfoLabel('Player.ProgressCache')) - int(xbmc.getInfoLabel('Player.Progress')) + self.setProperty('ppi.Buffered', str(cache)) + except: + pass + + # Only updateCurrent when not in DirectPlay mode. Otherwise the Kodi time functions will be used by the skin. + if self.isDirectPlay: + return + + self.updateCurrent( + update_position_control=not self._seeking and not self._applyingSeek, atOffset=self.timeKeeperTime) + + @property + def countingDownMarker(self): + return self._currentMarker and \ + self._currentMarker["countdown"] is not None and \ + self._currentMarker["countdown"] > 0 + + def displayMarkers(self, cancelTimer=False, immediate=False, onlyReturnIntroMD=False, setSkipped=False, + offset=None): + # intro/credits marker display logic + markerDef = self.getCurrentMarkerDef(offset=offset) + + if not markerDef: + # no marker to display, hide it + self.setProperty('show.markerSkip', '') + self.setProperty('show.markerSkip_OSDOnly', '') + + # this might be counter intuitive, but self._currentMarker is a reference to a dict + if self._currentMarker: + self._currentMarker["countdown"] = None + self._currentMarker = None + return False + + # getCurrentMarkerDef might have overridden the startTimeOffset, use that + startTimeOff = markerDef["overrideStartOff"] if markerDef["overrideStartOff"] is not None else \ + int(markerDef["marker"].startTimeOffset) + + markerAutoSkip = getattr(self, markerDef["markerAutoSkip"]) + markerAutoSkipped = markerDef["markerAutoSkipped"] + + sTOffWThres = startTimeOff + util.advancedSettings.autoSkipOffset * 1000 + + # we just want to return an early marker if we want to autoSkip it, so we can tell the handler to seekOnStart + if onlyReturnIntroMD and markerDef["marker_type"] == "intro" and markerAutoSkip: + if startTimeOff == 0 and not markerDef["markerAutoSkipped"]: + if setSkipped: + markerDef["markerAutoSkipped"] = True + return int(markerDef["marker"].endTimeOffset) + 1000 + return False + + if cancelTimer and self.countingDownMarker: + self._currentMarker["countdown"] = None + markerDef["markerAutoSkipped"] = True + setattr(self, markerDef["markerAutoSkipShownTimer"], None) + self.setProperty('show.markerSkip', '') + return False + + autoSkippingNow = markerDef \ + and markerAutoSkip \ + and not markerAutoSkipped \ + and not self._navigatedViaMarkerOrChapter \ + and (markerDef["countdown"] == 0 or startTimeOff == 0 or immediate) + # and (startTimeOff == 0 or sTOffWThres <= self.offset) \ + + # auto skip marker + # delay marker autoskip by autoSkipOffset to avoid cutting off content at the expense of being + # slightly too late + if autoSkippingNow: + markerDef["markerAutoSkipped"] = True + setattr(self, markerDef["markerAutoSkipShownTimer"], None) + self.setProperty('show.markerSkip', '') + self.setProperty('show.markerSkip_OSDOnly', '') + self.resetAutoSeekTimer(None) + final = getattr(markerDef["marker"], "final", False) + markerDef["countdown"] = None + + if final: + # final marker is _not_ at the end of video, seek and do nothing + if int(markerDef["marker"].endTimeOffset) < self.duration - FINAL_MARKER_NEGOFF: + target = int(markerDef["marker"].endTimeOffset) + util.DEBUG_LOG( + "MarkerAutoSkip: Skipping final marker, its endTime is too early, " + "though, seeking and playing back") + self.doSeek(target) + return False + + # tell plex we've arrived at the end of the video, playing back + self.handler.updateNowPlaying(True, state=self.player.STATE_STOPPED, time=self.duration - 1000) + + # go to next video immediately if on bingeMode + if self.handler.playlist and self.handler.playlist.hasNext() and self.bingeMode: + if not self.handler.queuingNext: + # skip final marker + util.DEBUG_LOG("MarkerAutoSkip: Skipping final marker, going to next video") + self.handler.ignoreTimelines = True + self.handler.queuingNext = True + self._ignoreTick = True + self._ignoreInput = True + self.killTimeKeeper() + self.player.stop() + return True + else: + util.DEBUG_LOG("MarkerAutoSkip: Skipping final marker, stopping") + self.stop() + return False + + util.DEBUG_LOG('MarkerAutoSkip: Skipping marker {}'.format(markerDef["marker"])) + self.doSeek(int(markerDef["marker"].endTimeOffset) + 1000) + return True + + # got a marker, display logic + # hide marker into OSD after a timeout + timer = getattr(self, markerDef["markerAutoSkipShownTimer"]) + + if timer is None or self.player.playState == self.player.STATE_PAUSED: + setattr(self, markerDef["markerAutoSkipShownTimer"], time.time()) + + else: + if timer + getattr(self, markerDef["markerSkipBtnTimeout"]) <= time.time(): + self.setProperty('show.markerSkip_OSDOnly', '1') + else: + self.setProperty('show.markerSkip_OSDOnly', '') + + # no marker auto skip or not yet auto skipped, normal display + if not markerAutoSkip or (markerAutoSkip and not markerAutoSkipped): + self.setProperty('show.markerSkip', '1') + # marker auto skip and already skipped - hide in OSD + elif markerAutoSkip and markerAutoSkipped: + self.setProperty('show.markerSkip_OSDOnly', '1') + + # set marker name, count down + if markerAutoSkip and not markerAutoSkipped: + if markerDef["countdown"] is None: + # reset countdown on new marker + if not self._currentMarker or self._currentMarker != markerDef or markerDef["countdown"] is None: + # fixme: round might not be right here, but who cares + markerDef["countdown"] = int(max(round((sTOffWThres - self.trueOffset()) / 1000.0) + 1, 1)) + + if self.player.playState == self.player.STATE_PLAYING and not self.osdVisible(): + markerDef["countdown"] -= 1 + + self.setProperty('marker.countdown', '1') + + if markerDef["countdown"] > 0: + markerName = "{} ({})".format(markerDef["autoSkipName"], markerDef["countdown"]) + else: + markerName = markerDef["autoSkipName"] + else: + markerName = markerDef["name"] + self.setProperty('skipMarkerName', markerName) + + # store current marker + self._currentMarker = markerDef + + # focus marker if OSD is hidden, last focus wasn't the marker button and we're not auto skipping this marker + if not self.osdVisible() and self.lastFocusID != self.SKIP_MARKER_BUTTON_ID and \ + not self.getProperty('show.markerSkip_OSDOnly') and self.getProperty('show.markerSkip') \ + and not markerAutoSkip: + self.setFocusId(self.SKIP_MARKER_BUTTON_ID) + + def tick(self, offset=None, waitForBuffer=False): + """ + Called ~1/s; can be wildly inaccurate. + """ + if waitForBuffer: + cont = self.waitForBuffer() + if not cont: + return + + if not self.initialized or self._ignoreTick: + return + + # invisibly sync low-drift timer to current playback every X seconds, as Player.getTime() can be wildly off + if self.ldTimer and not self.osdVisible() and self.timeKeeper and self.timeKeeper.ticks >= 60: + self.syncTimeKeeper() + + cancelTick = False + # don't auto skip while we're initializing and waiting for the handler to seek on start + if offset is None and not self.handler.seekOnStart: + cancelTick = self.displayMarkers() + + if cancelTick: + return + + if xbmc.getCondVisibility('Window.IsActive(busydialog) + !Player.Caching'): + util.DEBUG_LOG('SeekDialog: Possible stuck busy dialog - closing') + xbmc.executebuiltin('Dialog.Close(busydialog,1)') + + if not self.hasDialog and not self.playlistDialogVisible and self.osdVisible(): + if time.time() > self.timeout and not self._osdHideFast: + if not xbmc.getCondVisibility('Window.IsActive(videoosd) | Player.Rewinding | Player.Forwarding'): + self.hideOSD() + + # try insta-hiding the OSDs when playback was requested + elif self._osdHideFast: + xbmc.executebuiltin('Dialog.Close(videoosd,true)') + xbmc.executebuiltin('Dialog.Close(seekbar,true)') + if not xbmc.getCondVisibility('Window.IsActive(videoosd) | Player.Rewinding | Player.Forwarding'): + self.hideOSD() + + self._osdHideFast = False + + try: + self.offset = offset or int(self.handler.player.getTime() * 1000) + except RuntimeError: # Playback has stopped + self.resetSeeking() + return + + if offset or (self.autoSeekTimeout and time.time() >= self.autoSeekTimeout and + self.offset != self.selectedOffset): + self.resetAutoSeekTimer(None) + #off = offset is not None and offset or None + #self.doSeek(off) + self.doSeek() + return True + + if self.isDirectPlay or not self.ldTimer: + self.updateCurrent(update_position_control=not self._seeking and not self._applyingSeek) + + @property + def playlistDialogVisible(self): + return self._playlistDialogVisible + + @playlistDialogVisible.setter + def playlistDialogVisible(self, value): + self._playlistDialogVisible = value + self.setProperty('playlist.visible', '1' if value else '') + + def showPlaylistDialog(self): + if not self.playlistDialog: + self.playlistDialog = PlaylistDialog.create(show=False, handler=self.handler) + + self.playlistDialogVisible = True + self.playlistDialog.doModal() + self.resetTimeout() + self.playlistDialogVisible = False + + def osdVisible(self): + return xbmc.getCondVisibility('Control.IsVisible(801)') + + def showOSD(self, focusButton=True): + self.setProperty('show.OSD', '1') + xbmc.executebuiltin('Dialog.Close(videoosd,true)') + if xbmc.getCondVisibility('Player.showinfo'): + xbmc.executebuiltin('Action(Info)') + + if focusButton: + self.setFocusId(self.PLAY_PAUSE_BUTTON_ID) + + def hideOSD(self, skipMarkerFocus=False, closing=False): + self.setProperty('show.OSD', '') + if closing: + return + + self.setFocusId(self.NO_OSD_BUTTON_ID) + if not skipMarkerFocus and self.getCurrentMarkerDef() and not self.getProperty('show.markerSkip_OSDOnly'): + self.setFocusId(self.SKIP_MARKER_BUTTON_ID) + + self.resetSeeking() + self._osdHideAnimationTimeout = time.time() + self.OSD_HIDE_ANIMATION_DURATION + + self._osdHideFast = False + if self.playlistDialog: + self.playlistDialog.doClose() + self.playlistDialogVisible = False + + +class PlaylistDialog(kodigui.BaseDialog): + xmlFile = 'script-plex-video_current_playlist.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + LI_AR16X9_THUMB_DIM = (178, 100) + LI_SQUARE_THUMB_DIM = (100, 100) + + PLAYLIST_LIST_ID = 101 + + def __init__(self, *args, **kwargs): + kodigui.BaseDialog.__init__(self, *args, **kwargs) + self.handler = kwargs.get('handler') + self.playlist = self.handler.playlist + + def onFirstInit(self): + self.handler.player.on('playlist.changed', self.playQueueCallback) + self.handler.player.on('session.ended', self.sessionEnded) + self.playlistListControl = kodigui.ManagedControlList(self, self.PLAYLIST_LIST_ID, 6) + self.fillPlaylist() + self.updatePlayingItem() + self.setFocusId(self.PLAYLIST_LIST_ID) + + def onClick(self, controlID): + if controlID == self.PLAYLIST_LIST_ID: + self.playlistListClicked() + + def playlistListClicked(self): + mli = self.playlistListControl.getSelectedItem() + if not mli: + return + self.handler.playAt(mli.pos()) + self.updatePlayingItem() + + def sessionEnded(self, **kwargs): + util.DEBUG_LOG('Video OSD: Session ended - closing') + self.doClose() + + def createListItem(self, pi): + if pi.type == 'episode': + return self.createEpisodeListItem(pi) + elif pi.type in ('movie', 'clip'): + return self.createMovieListItem(pi) + + def createEpisodeListItem(self, episode): + label2 = u'{0} \u2022 {1}'.format( + episode.grandparentTitle, + u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), episode.parentIndex, T(32311, 'E'), episode.index) + ) + mli = kodigui.ManagedListItem(episode.title, label2, + thumbnailImage=episode.thumb.asTranscodedImageURL(*self.LI_AR16X9_THUMB_DIM), + data_source=episode) + mli.setProperty('track.duration', util.durationToShortText(episode.duration.asInt())) + mli.setProperty('video', '1') + mli.setProperty('watched', episode.isWatched and '1' or '') + return mli + + def createMovieListItem(self, movie): + mli = kodigui.ManagedListItem(movie.title, movie.year, + thumbnailImage=movie.art.asTranscodedImageURL(*self.LI_AR16X9_THUMB_DIM), + data_source=movie) + mli.setProperty('track.duration', util.durationToShortText(movie.duration.asInt())) + mli.setProperty('video', '1') + mli.setProperty('watched', movie.isWatched and '1' or '') + return mli + + def playQueueCallback(self, **kwargs): + mli = self.playlistListControl.getSelectedItem() + pi = mli.dataSource + plexID = pi['comment'].split(':', 1)[0] + viewPos = self.playlistListControl.getViewPosition() + + self.fillPlaylist() + + for ni in self.playlistListControl: + if ni.dataSource['comment'].split(':', 1)[0] == plexID: + self.playlistListControl.selectItem(ni.pos()) + break + + xbmc.sleep(100) + + newViewPos = self.playlistListControl.getViewPosition() + if viewPos != newViewPos: + diff = newViewPos - viewPos + self.playlistListControl.shiftView(diff, True) + + def updatePlayingItem(self): + playing = self.handler.player.video.ratingKey + selectIndex = None + for (index, mli) in enumerate(self.playlistListControl): + isMLI = mli.dataSource.ratingKey == playing + mli.setProperty('playing', isMLI and '1' or '') + if isMLI: + selectIndex = index + + if selectIndex is not None: + xbmc.executebuiltin('Control.SetFocus({0}, {1})'.format(self.PLAYLIST_LIST_ID, selectIndex)) + + def fillPlaylist(self): + items = [] + idx = 1 + for pi in self.playlist.items(): + mli = self.createListItem(pi) + if mli: + mli.setProperty('track.number', str(idx)) + items.append(mli) + idx += 1 + + self.playlistListControl.reset() + self.playlistListControl.addItems(items) diff --git a/script.plexmod/lib/windows/settings.py b/script.plexmod/lib/windows/settings.py new file mode 100644 index 0000000000..66e1c220e5 --- /dev/null +++ b/script.plexmod/lib/windows/settings.py @@ -0,0 +1,836 @@ +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcgui +from kodi_six import xbmcvfs +from . import kodigui +from . import windowutils + +from lib import util +from lib.util import T + +import plexnet +import sys + + +class Setting(object): + type = None + ID = None + label = None + desc = None + default = None + userAware = False + + def translate(self, val): + return str(val) + + def get(self): + return util.getSetting(self.ID, self.default) + + def set(self, val): + old = self.get() + setRet = util.setSetting(self.ID, val) + if old != val: + util.DEBUG_LOG('Setting: {0} - changed from [{1}] to [{2}]'.format(self.ID, old, val)) + plexnet.util.APP.trigger('change:{0}'.format(self.ID), value=val) + return setRet + + def valueLabel(self): + return self.translate(self.get()) + + def __repr__(self): + return ''.format(self.ID, self.get()) + + +class BasicSetting(Setting): + def __init__(self, ID, label, default, desc=''): + self.ID = ID + self.label = label + self.default = default + self.desc = desc + + def description(self, desc): + self.desc = desc + return self + + +class ListSetting(BasicSetting): + type = 'LIST' + options = () + + def translate(self, val): + return self.options[len(self.options) - 1 - val] + + def optionLabels(self): + return self.options + + def optionIndex(self): + return len(self.options) - 1 - self.get() + + def set(self, val): + BasicSetting.set(self, len(self.options) - 1 - val) + + +class QualitySetting(ListSetting): + options = ( + T(32001), + T(32002), + T(32003), + T(32004), + T(32005), + T(32006), + T(32007), + T(32008), + T(32009), + T(32010), + T(32011), + T(32012), + T(32013), + T(32014), + ) + + +class ThemeMusicSetting(ListSetting): + options = [ + T(32481), + ] + [T(32482) % {"percentage": 10+i} for i in range(0, 100, 10)] + + +class PlayedThresholdSetting(ListSetting): + options = ['{} %'.format(perc) for perc in range(70, 100, 5)] + + +class BoolSetting(BasicSetting): + type = 'BOOL' + + +class BoolUserSetting(BoolSetting): + """ + A user-aware BoolSetting + """ + userAware = True + + @property + def userAwareID(self): + return '{}.{}'.format(self.ID, plexnet.plexapp.ACCOUNT.ID) + + def get(self): + return util.getSetting(self.userAwareID, self.default) + + def set(self, val): + old = self.get() + if old != val: + util.DEBUG_LOG('Setting: {0} - changed from [{1}] to [{2}]'.format(self.userAwareID, old, val)) + plexnet.util.APP.trigger('change:{0}'.format(self.ID), key=self.userAwareID, value=val, skey=self.ID) + return util.setSetting(self.userAwareID, val) + + +class OptionsSetting(BasicSetting): + type = 'OPTIONS' + + def __init__(self, ID, label, default, options): + BasicSetting.__init__(self, ID, label, default) + self.options = options + + def translate(self, val): + for ID, label in self.options: + if ID == val: + return label + + def optionLabels(self): + return [o[1] for o in self.options] + + def optionIndex(self): + val = self.get() + for i, o in enumerate(self.options): + if val == o[0]: + return i + + return 0 + + +class BufferSetting(OptionsSetting): + def get(self): + return util.kcm.memorySize + + def set(self, val): + old = self.get() + if old != val: + util.DEBUG_LOG('Setting: {0} - changed from [{1}] to [{2}]'.format(self.ID, old, val)) + plexnet.util.APP.trigger('change:{0}'.format(self.ID), value=val) + + util.kcm.write(memorySize=val) + + +class ReadFactorSetting(OptionsSetting): + def get(self): + return util.kcm.readFactor + + def set(self, val): + old = self.get() + if old != val: + util.DEBUG_LOG('Setting: {0} - changed from [{1}] to [{2}]'.format(self.ID, old, val)) + plexnet.util.APP.trigger('change:{0}'.format(self.ID), value=val) + + util.kcm.write(readFactor=val) + + +class InfoSetting(BasicSetting): + type = 'INFO' + + def __init__(self, ID, label, info): + BasicSetting.__init__(self, ID, label, None) + self.info = info + + def valueLabel(self): + return self.info + + +class PlatformSetting(InfoSetting): + def __init__(self): + InfoSetting.__init__(self, None, None, None) + self.ID = 'platfom_version' + self.label = T(32410, 'Platform Version') + + def valueLabel(self): + plat = None + try: + if sys.version_info[0] >= 3: + from lib import distro + dist = distro.linux_distribution() + if dist and len(dist) > 1: + plat = u'{0} {1}'.format(dist[0], dist[1]) + else: + import platform + dist = platform. dist() + if dist and len(dist) > 1: + plat = u'{0} {1}'.format(dist[0], dist[1]) + else: + plat = platform.platform() + plat = u'{0} {1}'.format(plat[0], '.'.join(plat[1].split('.', 2)[:2])) + except: + util.ERROR() + + plat = plat.strip() + + if not plat: + if xbmc.getCondVisibility('System.Platform.Android'): + plat = 'Android' + elif xbmc.getCondVisibility('System.Platform.OSX'): + plat = 'OSX' + elif xbmc.getCondVisibility('System.Platform.Darwin'): + plat = 'Darwin' + elif xbmc.getCondVisibility('System.Platform.Linux.RaspberryPi'): + plat = 'Linux (RPi)' + elif xbmc.getCondVisibility('System.Platform.Linux'): + plat = 'Linux' + elif xbmc.getCondVisibility('System.Platform.Windows'): + plat = 'Windows' + + return plat or T(32411, 'Unknown') + + +class ServerVersionSetting(InfoSetting): + def valueLabel(self): + if not plexnet.plexapp.SERVERMANAGER.selectedServer: + return '' + + return plexnet.plexapp.SERVERMANAGER.selectedServer.rawVersion or '' + + +class IPSetting(BasicSetting): + type = 'IP' + + +class IntegerSetting(BasicSetting): + type = 'INTEGER' + + +class Settings(object): + SETTINGS = { + 'main': ( + T(32000, 'Main'), ( + BoolSetting( + 'auto_signin', T(32038, 'Automatically Sign In'), False + ).description( + T(32100, 'Skip user selection and pin entry on startup.') + ), + BoolSetting( + 'speedy_home_hubs2', T(33503, 'Use alternative hubs refresh'), False + ).description( + T( + 33504, + "Refreshes all hubs for all libraries after an item's watch-state has changed, instead of " + "only those likely affected. Use this if you find a hub that doesn't update properly." + ) + ), + BoolSetting( + 'search_use_kodi_kbd', T(32955, 'Use Kodi keyboard for searching'), False + ), + ThemeMusicSetting('theme_music', T(32480, 'Theme music'), 5), + PlayedThresholdSetting('played_threshold', T(33501, 'Video played threshold'), 1).description( + T( + 33502, + "Set this to the same value as your Plex server (Settings>Library>Video played threshold) to av" + "oid certain pitfalls, Default: 90 %" + ) + ) + ) + ), + 'video': ( + T(32053, 'Video'), ( + QualitySetting('local_quality', T(32020, 'Local Quality'), 13), + QualitySetting('remote_quality', T(32021, 'Remote Quality'), 13), + QualitySetting('online_quality', T(32022, 'Online Quality'), 13), + BoolSetting('playback_directplay', T(32025, 'Allow Direct Play'), True), + BoolSetting('playback_remux', T(32026, 'Allow Direct Stream'), True), + BoolSetting('allow_4k', T(32036, 'Allow 4K'), True).description( + T(32102, 'Enable this if your hardware can handle 4K playback. Disable it to force transcoding.') + ), + BoolSetting('allow_hevc', T(32037, 'Allow HEVC (h265)'), True).description( + T(32103, 'Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding.') + ) + ) + ), + 'audio': ( + T(32931, 'Audio/Subtitles'), ( + BoolSetting('audio_clamp_to_orig', T(32058, 'Never exceed original audio codec'), True).description( + T(32059, 'When transcoding audio, never exceed the original audio bitrate or channel ' + 'count on the same codec.') + ), + BoolSetting('audio_channels_kodi', T(32060, 'Use Kodi audio channels'), + False).description( + T(32061, 'When transcoding audio, target the audio channels set in Kodi.') + ), + OptionsSetting( + 'audio_force_ac3_cond', + T(32062, 'Transcode audio to AC3'), + 'never', + ( + ('never', T(32033, 'Never')), + ('always', T(32028, 'Always')), + ('2', '2.1+'), + ('5', '5.1+'), + ) + ).description( + T(32063, 'Transcode audio to AC3 in certain conditions (useful for passthrough).') + ), + BoolSetting('audio_ac3dts', T(32064, 'Treat DTS like AC3'), + True).description( + T(32065, 'When force AC3 settings are enabled, treat DTS the same as AC3 ' + '(useful for Optical passthrough)') + ), + OptionsSetting( + 'burn_subtitles', + T(32031, 'Burn-in Subtitles'), + 'auto', + (('auto', T(32030, 'Auto')), ('image', T(32029, 'Only Image Formats')), + ('always', T(32028, 'Always'))) + ), + BoolSetting('burn_ssa', T(32944, 'Burn-in SSA subtitles'), + True).description( + T(32945, 'When Direct Streaming instruct the Plex Server to burn in SSA/ASS subtitles (thus ' + 'transcoding the video stream). If disabled it will not touch the video stream, but ' + 'will convert the subtitle to unstyled text.') + ), + BoolSetting('forced_subtitles_override', T(32941, 'Forced subtitles fix'), + False).description( + T(32493, 'When a media file has a forced/foreign subtitle for a subtitle-enabled language, the Plex' + ' Media Server preselects it. This behaviour is usually not necessary and not configurable' + '. This setting fixes that by ignoring the PMSs decision and selecting the same language ' + 'without a forced flag if possible.') + ), + BoolSetting('calculate_oshash', T(32958, 'Calculate OpenSubtitles.com hash'), + False).description( + T(32959, '') + ), + ) + ), + 'player': ( + T(32940, 'Player UI'), ( + BoolSetting('subtitle_downloads', T(32932, 'Show subtitle quick-actions button'), False).description( + T(32939, 'Only applies to video player UI')), + BoolSetting('video_show_ffwdrwd', T(32933, 'Show FFWD/RWD buttons'), False).description( + T(32939, 'Only applies to video player UI')), + BoolSetting('video_show_repeat', T(32934, 'Show repeat button'), False).description( + T(32939, 'Only applies to video player UI')), + BoolSetting('video_show_shuffle', T(32935, 'Show shuffle button'), False).description( + T(32939, 'Only applies to video player UI')), + OptionsSetting( + 'video_show_playlist', T(32936, 'Show playlist button'), 'eponly', + ( + ('always', T(32035, 'Always')), ('eponly', T(32938, 'Only for Episodes')), + ('never', T(32033, 'Never')) + ) + ).description(T(32939, 'Only applies to video player UI')), + OptionsSetting( + 'video_show_prevnext', T(32937, 'Show prev/next button'), 'eponly', + ( + ('always', T(32035, 'Always')), ('eponly', T(32938, 'Only for Episodes')), + ('never', T(32033, 'Never')) + ) + ).description(T(32939, 'Only applies to video player UI')), + ) + ), + 'player_user': ( + T(32631, 'Playback (user-specific)'), ( + BoolUserSetting( + 'post_play_auto', T(32039, 'Post Play Auto Play'), True + ).description( + T( + 32101, + "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatical" + "ly be played after a 15 second delay." + ) + ), + BoolUserSetting( + 'binge_mode', T(33618, 'TV binge-viewing mode'), False + ).description( + T(33619, 'Automatically skips episode intros, credits and tries to skip episode recaps. Doesn\'t ' + 'skip the intro of the first episode of a season.\n\nCan be disabled/enabled per TV show.') + ), + BoolUserSetting( + 'auto_skip_intro', T(32522, 'Automatically Skip Intro'), False + ).description( + T(32523, 'Automatically skip intros if available. Doesn\'t override enabled binge mode.') + ), + BoolUserSetting( + 'auto_skip_credits', T(32526, 'Auto Skip Credits'), False + ).description( + T(32527, 'Automatically skip credits if available. Doesn\'t override enabled binge mode.') + ), + BoolUserSetting( + 'show_intro_skip_early', T(33505, 'Show intro skip button early'), False + ).description( + T(33506, 'Show the intro skip button from the start of a video with an intro marker. The auto-skipp' + 'ing setting applies. Doesn\'t override enabled binge mode.') + ), + BoolUserSetting( + 'auto_skip_in_transcode', T(32948, 'Allow auto-skip when transcoding'), True + ).description( + T(32949, 'When transcoding/DirectStreaming, allow auto-skip functionality.') + ), + BoolUserSetting( + 'show_chapters', T(33601, 'Show video chapters'), True + ).description( + T(33602, 'If available, show video chapters from the video-file instead of the ' + 'timeline-big-seek-steps.') + ), + BoolUserSetting( + 'virtual_chapters', T(33603, 'Use virtual chapters'), True + ).description( + T(33604, 'When the above is enabled and no video chapters are available, simulate them by using the' + ' markers identified by the Plex Server (Intro, Credits).') + ), + ) + ), + 'network': ( + T(33624, 'Network'), ( + OptionsSetting( + 'allow_insecure', T(32032), 'never', + (('never', T(32033)), ('same_network', T(32034)), ('always', T(32035))) + ).description( + T(32104, 'When to connect to servers with no secure connections...') + ), + BoolSetting('smart_discover_local', T(33625, 'Smart LAN/local server discovery'), True) + .description( + T(33626, "Checks whether servers returned from Plex.tv are actually local/in your LAN. " + "For specific setups (e.g. Docker) Plex.tv might not properly detect a local " + "server.\n\nNOTE: Only works on Kodi 19 or above." + ) + ), + BoolSetting('prefer_local', T(33627, 'Prefer LAN/local servers over security'), False) + .description( + T(33628, "Prioritizes local connections over secure ones. Needs the proper setting in \"Allow " + "Insecure Connections\" and the Plex Server's \"Secure connections\" at \"Preferred\". " + "Can be used to enforce manual servers." + ) + ), + BoolSetting('gdm_discovery', T(32042, 'Server Discovery (GDM)'), False), + IPSetting('manual_ip_0', T(32044, 'Connection 1 IP'), ''), + IntegerSetting('manual_port_0', T(32045, 'Connection 1 Port'), 32400), + IPSetting('manual_ip_1', T(32046, 'Connection 2 IP'), ''), + IntegerSetting('manual_port_1', T(32047, 'Connection 2 Port'), 32400), + ) + ), + 'system': ( + T(33600, 'System'), ( + + BoolSetting('kiosk.mode', T(32043, 'Start Plex On Kodi Startup'), False), + BufferSetting('cache_size', + T(33613, 'Kodi Buffer Size (MB)'), + 20, + [(mem, '{} MB'.format(mem)) for mem in util.kcm.viableOptions]) + .description( + '{}{}'.format(T(33614, 'stub1').format( + util.kcm.free, util.kcm.recMax), + '' if util.kcm.useModernAPI else ' '+T(32954, 'stub2')) + ), + ReadFactorSetting('readfactor', + T(32922, 'Kodi Cache Readfactor'), + 4, + [(rf, str(rf)) for rf in util.kcm.readFactorOpts]) + .description( + T(32923, 'Sets the Kodi cache readfactor value. Default: {0}, recommended: {1}.' + 'With "Slow connection" enabled this will be set to {2}, as otherwise the cache doesn\'t' + 'fill fast/aggressively enough.').format(util.kcm.defRF, + "{}-{}".format(*util.kcm.recRFRange), + util.kcm.defRFSM) + ), + BoolSetting( + 'slow_connection', T(32915, 'Slow connection'), False + ).description("Use with a wonky/slow connection, e.g. in a hotel room. Adjusts the UI to visually " + "wait for item refreshes and waits for the buffer to fill when starting playback."), + OptionsSetting( + 'action_on_sleep', + T(32700, 'Action on Sleep event'), + 'none', + (('none', T(32702, 'Nothing')), ('stop', T(32703, 'Stop playback')), + ('quit', T(32704, 'Quit Kodi')), ('reboot', T(32426, 'Reboot')), + ('shutdown', T(32423, 'Shutdown')), + ('hibernate', T(32425, 'Hibernate')), ('suspend', T(32424, 'Suspend')), + ('cecstandby', T(32705, 'CEC Standby')), ('logoff', T(32421, 'Sign Out'))) + ).description(T(32701, 'When Kodi receives a sleep event from the system, run the following action.')), + OptionsSetting( + 'player_stop_on_idle', + T(32946, 'Stop video playback on idle after'), + 0, + ((0, T(32033, 'Never')), (30, '30s'), (60, '1m'), (120, '2m'), (300, '5m'), (600, '10m'), + (900, '15m'), (1200, '20m'), (1800, '30m'), (2700, '45m'), (3600, '1h'),) + ), + BoolSetting( + 'player_stop_on_screensaver', T(32947, 'Stop video playback on screensaver'), True + ), + BoolSetting('debug', T(32024, 'Debug Logging'), False), + ) + ), + 'privacy': ( + T(32051, 'Privacy'), + () + ), + 'about': ( + T(32052, 'About'), ( + InfoSetting('addon_version', T(32054, 'Addon Version'), util.ADDON.getAddonInfo('version')), + InfoSetting('kodi_version', T(32055, 'Kodi Version'), xbmc.getInfoLabel('System.BuildVersion')), + PlatformSetting(), + InfoSetting('screen_res', T(32056, 'Screen Resolution'), + xbmc.getInfoLabel('System.ScreenResolution').split('-')[0].strip()), + ServerVersionSetting('server_version', T(32057, 'Current Server Version'), None), + InfoSetting('addon_path', T(33616, 'Addon Path'), util.ADDON.getAddonInfo("path")), + InfoSetting('userdata_path', T(33617, 'Userdata/Profile Path'), + util.translatePath("special://profile")), + ) + ), + } + + SECTION_IDS = ('main', 'video', 'audio', 'player', 'player_user', 'network', 'system', 'about') + + def __getitem__(self, key): + return self.SETTINGS[key] + + +# enable AV1 setting if kodi nexus +if util.KODI_VERSION_MAJOR >= 20: + videoSettings = list(Settings.SETTINGS["video"]) + videoSettings[1] = tuple(list(videoSettings[1]) + [ + BoolSetting('allow_av1', T(32601, 'Allow AV1'), False).description( + T(32602, + 'Enable this if your hardware can handle AV1. Disable it to force transcoding.') + ) + ]) + Settings.SETTINGS["video"] = (videoSettings[0], videoSettings[1]) + + +class SettingsWindow(kodigui.BaseWindow, windowutils.UtilMixin): + xmlFile = 'script-plex-settings.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + SECTION_LIST_ID = 75 + SETTINGS_LIST_ID = 100 + OPTIONS_LIST_ID = 125 + TOP_GROUP_ID = 200 + + CLOSE_BUTTON_ID = 201 + PLAYER_STATUS_BUTTON_ID = 204 + + def onFirstInit(self): + self.settings = Settings() + self.sectionList = kodigui.ManagedControlList(self, self.SECTION_LIST_ID, 6) + self.settingsList = kodigui.ManagedControlList(self, self.SETTINGS_LIST_ID, 6) + self.optionsList = kodigui.ManagedControlList(self, self.OPTIONS_LIST_ID, 6) + + self.setProperty('heading', T(32343, 'Settings')) + self.showSections() + self.setFocusId(75) + self.lastSection = None + self.checkSection() + + def onAction(self, action): + try: + self.checkSection() + controlID = self.getFocusId() + if action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): + if self.getFocusId() == self.OPTIONS_LIST_ID: + self.setFocusId(self.SETTINGS_LIST_ID) + return + # elif not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.TOP_GROUP_ID)): + # self.setFocusId(self.TOP_GROUP_ID) + # return + elif action == xbmcgui.ACTION_MOVE_RIGHT and controlID == 150: + self.editSetting(from_right=True) + except: + util.ERROR() + + kodigui.BaseWindow.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.SECTION_LIST_ID: + self.setFocusId(self.SETTINGS_LIST_ID) + elif controlID == self.SETTINGS_LIST_ID: + self.editSetting() + elif controlID == self.OPTIONS_LIST_ID: + self.changeSetting() + elif controlID == self.CLOSE_BUTTON_ID: + self.doClose() + elif controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() + + def checkSection(self): + mli = self.sectionList.getSelectedItem() + if not mli: + return + + if mli.dataSource == self.lastSection: + return + + self.lastSection = mli.dataSource + self.showSettings(self.lastSection) + self.setProperty('section.about', self.lastSection == 'about' and '1' or '') + util.DEBUG_LOG('Settings: Changed section ({0})'.format(self.lastSection)) + + def showSections(self): + items = [] + for sectionID in self.settings.SECTION_IDS: + label = self.settings[sectionID][0] + item = kodigui.ManagedListItem(label, data_source=sectionID) + items.append(item) + + self.sectionList.addItems(items) + + def showSettings(self, section): + settings = self.settings[section][1] + if not settings: + return self.settingsList.reset() + + items = [] + for setting in settings: + item = kodigui.ManagedListItem(setting.label, setting.type != 'BOOL' and setting.valueLabel() or '', data_source=setting) + item.setProperty('description', setting.desc) + if setting.type == 'BOOL': + item.setProperty('checkbox', '1') + item.setProperty('checkbox.checked', setting.get() and '1' or '') + elif setting.type == 'BUTTON': + item.setProperty('button', '1') + + if setting.userAware: + item.setProperty('useraware', '1') + + items.append(item) + + self.settingsList.reset() + self.settingsList.addItems(items) + + def editSetting(self, from_right=False): + mli = self.settingsList.getSelectedItem() + if not mli: + return + + setting = mli.dataSource + + if setting.type in ('LIST', 'OPTIONS'): + self.fillList(setting) + elif setting.type == 'BOOL' and not from_right: + self.toggleBool(mli, setting) + elif setting.type == 'IP' and not from_right: + self.editIP(mli, setting) + elif setting.type == 'INTEGER' and not from_right: + self.editInteger(mli, setting) + elif setting.type == 'BUTTON': + self.buttonDialog(mli, setting) + + def changeSetting(self): + optionItem = self.optionsList.getSelectedItem() + if not optionItem: + return + + mli = self.settingsList.getSelectedItem() + if not mli: + return + + setting = mli.dataSource + + if setting.type == 'LIST': + setting.set(optionItem.pos()) + mli.setLabel2(setting.valueLabel()) + elif setting.type == 'OPTIONS': + setting.set(optionItem.dataSource) + mli.setLabel2(setting.valueLabel()) + + self.setFocusId(self.SETTINGS_LIST_ID) + + def fillList(self, setting): + items = [] + if setting.type == 'LIST': + for label in setting.optionLabels(): + items.append(kodigui.ManagedListItem(label)) + elif setting.type == 'OPTIONS': + for ID, label in setting.options: + items.append(kodigui.ManagedListItem(label, data_source=ID)) + + self.optionsList.reset() + self.optionsList.addItems(items) + self.optionsList.selectItem(setting.optionIndex()) + self.setFocusId(self.OPTIONS_LIST_ID) + + def toggleBool(self, mli, setting): + setting.set(not setting.get()) + mli.setProperty('checkbox.checked', setting.get() and '1' or '') + + def editIP(self, mli, setting): + current = setting.get() + edit = True + if current: + edit = xbmcgui.Dialog().yesno( + T(32412, 'Edit Or Clear'), + T(32413, 'Edit IP address or clear the current setting?'), + nolabel=T(32414, 'Clear'), + yeslabel=T(32415, 'Edit') + ) + + if edit: + result = xbmcgui.Dialog().input(T(32416, 'Enter IP Address'), current, xbmcgui.INPUT_IPADDRESS) + if not result: + return + else: + result = '' + + setting.set(result) + mli.setLabel2(result) + + def editInteger(self, mli, setting): + result = xbmcgui.Dialog().input(T(32417, 'Enter Port Number'), str(setting.get()), xbmcgui.INPUT_NUMERIC) + if not result: + return + setting.set(int(result)) + mli.setLabel2(result) + + +class SelectDialog(kodigui.BaseDialog, util.CronReceiver): + xmlFile = 'script-plex-settings_select_dialog.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + OPTIONS_LIST_ID = 100 + + def __init__(self, *args, **kwargs): + kodigui.BaseDialog.__init__(self, *args, **kwargs) + self.heading = kwargs.get('heading') + self.options = kwargs.get('options') + self.choice = None + + def onFirstInit(self): + self.optionsList = kodigui.ManagedControlList(self, self.OPTIONS_LIST_ID, 8) + self.setProperty('heading', self.heading) + self.showOptions() + util.CRON.registerReceiver(self) + + def onAction(self, action): + try: + if not xbmc.getCondVisibility('Player.HasMedia'): + self.doClose() + return + except: + util.ERROR() + + kodigui.BaseDialog.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.OPTIONS_LIST_ID: + self.setChoice() + + def onClosed(self): + util.CRON.cancelReceiver(self) + + def tick(self): + if not xbmc.getCondVisibility('Player.HasMedia'): + self.doClose() + return + + def setChoice(self): + mli = self.optionsList.getSelectedItem() + if not mli: + return + + self.choice = self.options[self.optionsList.getSelectedPosition()][0] + self.doClose() + + def showOptions(self): + items = [] + for o in self.options: + item = kodigui.ManagedListItem(o[1], data_source=o[0]) + items.append(item) + + self.optionsList.reset() + self.optionsList.addItems(items) + + self.setFocusId(self.OPTIONS_LIST_ID) + + +def showOptionsDialog(heading, options): + w = SelectDialog.open(heading=heading, options=options) + choice = w.choice + del w + return choice + + +def showAudioDialog(video): + options = [(s, s.getTitle()) for s in video.audioStreams] + choice = showOptionsDialog(T(32048, 'Audio'), options) + if choice is None: + return + + video.selectStream(choice) + + +def showSubtitlesDialog(video): + options = [(s, s.getTitle()) for s in video.subtitleStreams] + options.insert(0, (plexnet.plexstream.NoneStream(), 'None')) + choice = showOptionsDialog(T(32396, 'Subtitles'), options) + if choice is None: + return + + video.selectStream(choice) + + +def showQualityDialog(video): + options = [(13 - i, T(l)) for (i, l) in enumerate((32001, 32002, 32003, 32004, 32005, 32006, 32007, 32008, 32009, + 32010, 32011))] + + choice = showOptionsDialog(T(32397, 'Quality'), options) + if choice is None: + return + + video.settings.setPrefOverride('local_quality', choice) + video.settings.setPrefOverride('remote_quality', choice) + video.settings.setPrefOverride('online_quality', choice) + + +def openWindow(): + w = SettingsWindow.open() + del w diff --git a/script.plexmod/lib/windows/signin.py b/script.plexmod/lib/windows/signin.py new file mode 100644 index 0000000000..444933662d --- /dev/null +++ b/script.plexmod/lib/windows/signin.py @@ -0,0 +1,146 @@ +from __future__ import absolute_import +from kodi_six import xbmcgui +from . import kodigui +from lib import util + + +class Background(kodigui.BaseWindow): + xmlFile = 'script-plex-signin_background.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + +class SignInMessage(kodigui.BaseWindow): + xmlFile = 'script-plex-signin_blank.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + SCREEN_BUTTON_ID = 100 + + def __init__(self, *args, **kwargs): + self.message = kwargs.get('message') + kodigui.BaseWindow.__init__(self, *args, **kwargs) + + def onFirstInit(self): + self.setProperty('message', self.message) + + def onClick(self, controlID): + if controlID == self.SCREEN_BUTTON_ID: + self.doClose() + + +class SignInPlexPass(kodigui.BaseWindow): + xmlFile = 'script-plex-plex_pass.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + RETRY_BUTTON_ID = 100 + + def __init__(self, *args, **kwargs): + self.retry = False + kodigui.BaseWindow.__init__(self, *args, **kwargs) + + def onAction(self, action): + if action == xbmcgui.ACTION_SELECT_ITEM: + self.retry = True + self.doClose() + + def onClick(self, controlID): + if controlID == self.RETRY_BUTTON_ID: + self.retry = True + self.doClose() + + +class PreSignInWindow(kodigui.BaseWindow): + xmlFile = 'script-plex-pre_signin.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + SIGNIN_BUTTON_ID = 100 + + def __init__(self, *args, **kwargs): + self.doSignin = False + kodigui.BaseWindow.__init__(self, *args, **kwargs) + + def onFirstInit(self): + self.signinButton = self.getControl(self.SIGNIN_BUTTON_ID) + + def onAction(self, action): + if action == xbmcgui.ACTION_SELECT_ITEM: + self.doSignin = True + self.doClose() + + def onClick(self, controlID): + if controlID == self.SIGNIN_BUTTON_ID: + self.doSignin = True + self.doClose() + + +class PinLoginWindow(kodigui.BaseWindow): + xmlFile = 'script-plex-pin_login.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + def __init__(self, *args, **kwargs): + self.abort = False + kodigui.BaseWindow.__init__(self, *args, **kwargs) + + def setPin(self, pin): + self.setProperty('pin.image.0', 'script.plex/sign_in/digits/{0}.png'.format(pin[0].upper())) + self.setProperty('pin.image.1', 'script.plex/sign_in/digits/{0}.png'.format(pin[1].upper())) + self.setProperty('pin.image.2', 'script.plex/sign_in/digits/{0}.png'.format(pin[2].upper())) + self.setProperty('pin.image.3', 'script.plex/sign_in/digits/{0}.png'.format(pin[3].upper())) + + def setLinking(self): + self.setProperty('linking', '1') + self.setProperty('pin.image.0', '') + self.setProperty('pin.image.1', '') + self.setProperty('pin.image.2', '') + self.setProperty('pin.image.3', '') + + def onAction(self, action): + try: + if action == xbmcgui.ACTION_NAV_BACK or action == xbmcgui.ACTION_PREVIOUS_MENU: + self.abort = True + except: + util.ERROR() + + kodigui.BaseWindow.onAction(self, action) + + +class ExpiredWindow(kodigui.BaseWindow): + xmlFile = 'script-plex-refresh_code.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + REFRESH_BUTTON_ID = 100 + + def __init__(self, *args, **kwargs): + self.refresh = False + kodigui.BaseWindow.__init__(self, *args, **kwargs) + + def onFirstInit(self): + self.refreshButton = self.getControl(self.REFRESH_BUTTON_ID) + + def onClick(self, controlID): + if controlID == self.REFRESH_BUTTON_ID: + self.refresh = True + self.doClose() diff --git a/script.plexmod/lib/windows/slidehshow.py b/script.plexmod/lib/windows/slidehshow.py new file mode 100644 index 0000000000..d25f8b670b --- /dev/null +++ b/script.plexmod/lib/windows/slidehshow.py @@ -0,0 +1,108 @@ +import time +import random + +from . import kodigui + +from lib import util +from plexnet import plexapp + +class Slideshow(kodigui.BaseWindow, util.CronReceiver): + xmlFile = 'script-plex-slideshow.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + TIME_BETWEEN_IMAGES = 15 + TIME_HIDE_TITLE_IN_QUIZ = 5 + TIME_DISPLAY_MOVE = 60 + + CONTROL_INFO_GROUP = 100 + + def __init__(self, *args, **kwargs): + kodigui.BaseWindow.__init__(self, *args, **kwargs) + self.timeBetweenImages = self.TIME_BETWEEN_IMAGES + self.timeBetweenDisplayMove = self.TIME_DISPLAY_MOVE + self.timeTitleIsHidden = self.TIME_HIDE_TITLE_IN_QUIZ + self.quizMode = util.advancedSettings.screensaverQuiz + self.initialized = False + + def onFirstInit(self): + self.setProperty('clock', '') + self.setProperty('title', '') + self.setProperty('thumb', '') + self.setProperty('align', '0') + + self.infoGroupControl = self.getControl(self.CONTROL_INFO_GROUP) + + util.CRON.registerReceiver(self) + self.timeFormat = util.timeFormat.replace(":%S", "") + self.lastTime = '' + self.displayPosition = 0 + self.changeTime = time.time() - 1 + self.displayMoveTime = time.time() + self.timeBetweenDisplayMove + self.revealTitleTime = None + + self.selectedServer = plexapp.SERVERMANAGER.selectedServer + self.index = -1 + self.images = [] + + self.initialized = True + + def tick(self): + if not self.initialized: + return + + currentTime = time.time() + timestr = time.strftime(self.timeFormat, time.localtime(currentTime)) + if not util.padHour and timestr[0] == "0" and timestr[1] != ":": + timestr = timestr[1:] + + if currentTime > self.changeTime: + nextIndex = self.index + 1 + + if nextIndex >= len(self.images): + if self.selectedServer != None: + self.images = self.selectedServer.library.randomArts(); + util.DEBUG_LOG('[SS] Fetched {0} items'.format(len(self.images))) + nextIndex = 0 + + if len(self.images) == 0: + title = 'No Images' + url = '' + else: + image = self.images[nextIndex] + title = image.get('title') + key = image.get('key') + url = self.selectedServer.getImageTranscodeURL(key, self.width, self.height) + if not self.quizMode: + self.setProperty('title', title) + else: + self.setProperty('title', '') + self.quizTitle = title + self.revealTitleTime = currentTime + self.timeTitleIsHidden + self.setProperty('thumb', url) + + self.index = nextIndex + self.changeTime = time.time() + self.timeBetweenImages + + if self.revealTitleTime != None and currentTime > self.revealTitleTime: + self.setProperty('title', self.quizTitle) + self.revealTitleTime = None + + if currentTime > self.displayMoveTime: + oldDisplayPosition = self.displayPosition + self.displayPosition = (oldDisplayPosition + random.randint(1, 3)) % 4 + + if (oldDisplayPosition&2) != (self.displayPosition&2): + self.setProperty('align', str((self.displayPosition&2)>>1)) + + if (oldDisplayPosition&1) != (self.displayPosition&1): + newY = self.height - self.infoGroupControl.getY() - self.infoGroupControl.getHeight() + self.infoGroupControl.setPosition(self.infoGroupControl.getX(), newY) + + self.displayMoveTime = currentTime + self.timeBetweenDisplayMove + + if timestr != self.lastTime: + self.setProperty('clock', timestr) \ No newline at end of file diff --git a/script.plexmod/lib/windows/subitems.py b/script.plexmod/lib/windows/subitems.py new file mode 100644 index 0000000000..13204429b6 --- /dev/null +++ b/script.plexmod/lib/windows/subitems.py @@ -0,0 +1,647 @@ +from __future__ import absolute_import +import gc + +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import kodigui + +from lib import colors +from lib import util +from lib import metadata +from lib import player + +from plexnet import playlist +from plexnet.util import INTERFACE + +from . import busy +from . import episodes +from . import tracks +from . import opener +from . import info +from . import musicplayer +from . import videoplayer +from . import dropdown +from . import windowutils +from . import search +from . import pagination +from . import playbacksettings + +from lib.util import T +from .mixins import SeasonsMixin + + +class RelatedPaginator(pagination.BaseRelatedPaginator): + def getData(self, offset, amount): + return self.parentWindow.mediaItem.getRelated(offset=offset, limit=amount) + + +class ShowWindow(kodigui.ControlledWindow, windowutils.UtilMixin, SeasonsMixin, playbacksettings.PlaybackSettingsMixin): + xmlFile = 'script-plex-seasons.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + EXTRA_DIM = util.scaleResolution(329, 185) + RELATED_DIM = util.scaleResolution(268, 397) + ROLES_DIM = util.scaleResolution(334, 334) + + SUB_ITEM_LIST_ID = 400 + + EXTRA_LIST_ID = 401 + RELATED_LIST_ID = 402 + ROLES_LIST_ID = 403 + + OPTIONS_GROUP_ID = 200 + + HOME_BUTTON_ID = 201 + SEARCH_BUTTON_ID = 202 + PLAYER_STATUS_BUTTON_ID = 204 + + PROGRESS_IMAGE_ID = 250 + + INFO_BUTTON_ID = 301 + PLAY_BUTTON_ID = 302 + SHUFFLE_BUTTON_ID = 303 + OPTIONS_BUTTON_ID = 304 + + def __init__(self, *args, **kwargs): + kodigui.ControlledWindow.__init__(self, *args, **kwargs) + self.mediaItem = kwargs.get('media_item') + self.parentList = kwargs.get('parent_list') + self.cameFrom = kwargs.get('came_from') + self.mediaItems = None + self.exitCommand = None + self.lastFocusID = None + self.lastNonOptionsFocusID = None + self.initialized = False + self.relatedPaginator = None + + def doClose(self): + self.relatedPaginator = None + kodigui.ControlledWindow.doClose(self) + + def onFirstInit(self): + self.subItemListControl = kodigui.ManagedControlList(self, self.SUB_ITEM_LIST_ID, 5) + self.extraListControl = kodigui.ManagedControlList(self, self.EXTRA_LIST_ID, 5) + self.relatedListControl = kodigui.ManagedControlList(self, self.RELATED_LIST_ID, 5) + self.rolesListControl = kodigui.ManagedControlList(self, self.ROLES_LIST_ID, 5) + self.progressImageControl = self.getControl(self.PROGRESS_IMAGE_ID) + + self.setup() + self.initialized = True + + self.setFocusId(self.PLAY_BUTTON_ID) + + def onInit(self): + super(ShowWindow, self).onInit() + if self.mediaItem.theme and (not self.cameFrom or self.cameFrom != self.mediaItem.ratingKey) \ + and not util.getSetting("slow_connection", False): + self.cameFrom = self.mediaItem.ratingKey + volume = self.mediaItem.settings.getThemeMusicValue() + if volume > 0: + player.PLAYER.playBackgroundMusic(self.mediaItem.theme.asURL(True), volume, + self.mediaItem.ratingKey) + + def setup(self): + self.mediaItem.reload(includeExtras=1, includeExtrasCount=10) + + self.relatedPaginator = RelatedPaginator(self.relatedListControl, leaf_count=int(self.mediaItem.relatedCount), + parent_window=self) + + self.updateProperties() + self.setBoolProperty("initialized", True) + self.fill() + hasPrev = self.fillExtras() + hasPrev = self.fillRelated(hasPrev) + self.fillRoles(hasPrev) + + def updateProperties(self): + self.setProperty('title', self.mediaItem.title) + self.setProperty('summary', self.mediaItem.summary) + self.setProperty('thumb', self.mediaItem.defaultThumb.asTranscodedImageURL(*self.THUMB_DIMS[self.mediaItem.type]['main.thumb'])) + self.updateBackgroundFrom(self.mediaItem) + self.setProperty('duration', util.durationToText(self.mediaItem.fixedDuration())) + self.setProperty('info', '') + self.setProperty('date', self.mediaItem.year) + + self.setProperty('extras.header', T(32305, 'Extras')) + self.setProperty('related.header', T(32306, 'Related Shows')) + + if self.mediaItem.creator: + self.setProperty('directors', u'{0} {1}'.format(T(32418, 'Creator').upper(), self.mediaItem.creator)) + elif self.mediaItem.studio: + self.setProperty('directors', u'{0} {1}'.format(T(32386, 'Studio').upper(), self.mediaItem.studio)) + + cast = u' / '.join([r.tag for r in self.mediaItem.roles()][:5]) + castLabel = T(32419, 'Cast').upper() + self.setProperty('writers', cast and u'{0} {1}'.format(castLabel, cast) or '') + + genres = self.mediaItem.genres() + self.setProperty('info', genres and (u' / '.join([g.tag for g in genres][:3])) or '') + + self.setProperties(('rating.stars', 'rating', 'rating.image', 'rating2', 'rating2.image'), '') + + if self.mediaItem.userRating: + stars = str(int(round((self.mediaItem.userRating.asFloat() / 10) * 5))) + self.setProperty('rating.stars', stars) + + if self.mediaItem.ratingImage: + rating = self.mediaItem.rating + audienceRating = self.mediaItem.audienceRating + if self.mediaItem.ratingImage.startswith('rottentomatoes:'): + rating = '{0}%'.format(int(rating.asFloat() * 10)) + if audienceRating: + audienceRating = '{0}%'.format(int(audienceRating.asFloat() * 10)) + + self.setProperty('rating', rating) + self.setProperty('rating.image', 'script.plex/ratings/{0}.png'.format(self.mediaItem.ratingImage.replace('://', '/'))) + if self.mediaItem.audienceRatingImage: + self.setProperty('rating2', audienceRating) + self.setProperty('rating2.image', 'script.plex/ratings/{0}.png'.format(self.mediaItem.audienceRatingImage.replace('://', '/'))) + else: + self.setProperty('rating', self.mediaItem.rating) + + sas = self.mediaItem.selectedAudioStream() + self.setProperty('audio', sas and sas.getTitle() or 'None') + + sss = self.mediaItem.selectedSubtitleStream( + forced_subtitles_override=util.getSetting("forced_subtitles_override", False)) + self.setProperty('subtitles', sss and sss.getTitle() or 'None') + + leafcount = self.mediaItem.leafCount.asFloat() + if leafcount: + width = (int((self.mediaItem.viewedLeafCount.asInt() / leafcount) * self.width)) or 1 + self.progressImageControl.setWidth(width) + + def onAction(self, action): + try: + controlID = self.getFocusId() + + if not controlID and self.lastFocusID and not action == xbmcgui.ACTION_MOUSE_MOVE: + self.setFocusId(self.lastFocusID) + + if action == xbmcgui.ACTION_CONTEXT_MENU: + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)): + self.lastNonOptionsFocusID = self.lastFocusID + self.setFocusId(self.OPTIONS_GROUP_ID) + return + else: + if self.lastNonOptionsFocusID: + self.setFocusId(self.lastNonOptionsFocusID) + self.lastNonOptionsFocusID = None + return + + elif action in(xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_CONTEXT_MENU): + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format( + self.OPTIONS_GROUP_ID)) and \ + (not util.advancedSettings.fastBack or action == xbmcgui.ACTION_CONTEXT_MENU): + if self.getProperty('on.extras'): + self.setFocusId(self.OPTIONS_GROUP_ID) + return + + if action == xbmcgui.ACTION_LAST_PAGE and xbmc.getCondVisibility('ControlGroup(300).HasFocus(0)'): + next(self) + elif action == xbmcgui.ACTION_NEXT_ITEM: + self.setFocusId(300) + next(self) + elif action == xbmcgui.ACTION_FIRST_PAGE and xbmc.getCondVisibility('ControlGroup(300).HasFocus(0)'): + self.prev() + elif action == xbmcgui.ACTION_PREV_ITEM: + self.setFocusId(300) + self.prev() + + if action == xbmcgui.ACTION_MOVE_UP and (controlID == self.SUB_ITEM_LIST_ID or + self.INFO_BUTTON_ID <= controlID <= self.OPTIONS_BUTTON_ID): + self.updateBackgroundFrom(self.mediaItem) + + if controlID == self.RELATED_LIST_ID: + if self.relatedPaginator.boundaryHit: + self.relatedPaginator.paginate() + return + elif action in (xbmcgui.ACTION_MOVE_LEFT, xbmcgui.ACTION_MOVE_RIGHT): + self.updateBackgroundFrom(self.relatedListControl.getSelectedItem().dataSource) + + except: + util.ERROR() + + kodigui.ControlledWindow.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.HOME_BUTTON_ID: + self.goHome() + elif controlID == self.SUB_ITEM_LIST_ID: + self.subItemListClicked() + elif controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() + elif controlID == self.EXTRA_LIST_ID: + self.openItem(self.extraListControl) + elif controlID == self.RELATED_LIST_ID: + self.openItem(self.relatedListControl) + elif controlID == self.ROLES_LIST_ID: + self.roleClicked() + elif controlID == self.INFO_BUTTON_ID: + self.infoButtonClicked() + elif controlID == self.PLAY_BUTTON_ID: + self.playButtonClicked() + elif controlID == self.SHUFFLE_BUTTON_ID: + self.shuffleButtonClicked() + elif controlID == self.OPTIONS_BUTTON_ID: + self.optionsButtonClicked() + elif controlID == self.SEARCH_BUTTON_ID: + self.searchButtonClicked() + + def onFocus(self, controlID): + self.lastFocusID = controlID + + if 399 < controlID < 500: + self.setProperty('hub.focus', str(controlID - 400)) + + if controlID == self.RELATED_LIST_ID: + self.updateBackgroundFrom(self.relatedListControl.getSelectedItem().dataSource) + + if xbmc.getCondVisibility('ControlGroup(50).HasFocus(0) + ControlGroup(300).HasFocus(0)'): + self.setProperty('on.extras', '') + elif xbmc.getCondVisibility('ControlGroup(50).HasFocus(0) + !ControlGroup(300).HasFocus(0)'): + self.setProperty('on.extras', '1') + + if player.PLAYER.bgmPlaying and player.PLAYER.handler.currentlyPlaying != self.mediaItem.ratingKey: + player.PLAYER.stopAndWait() + + def getMediaItems(self): + return False + + def next(self): + if not self._next(): + return + self.setup() + + __next__ = next + + @busy.dialog() + def _next(self): + if self.parentList: + mli = self.parentList.getListItemByDataSource(self.mediaItem) + if not mli: + return False + + pos = mli.pos() + 1 + if not self.parentList.positionIsValid(pos): + pos = 0 + + self.mediaItem = self.parentList.getListItem(pos).dataSource + else: + if not self.getMediaItems(): + return False + + if self.mediaItem not in self.mediaItems: + return False + + pos = self.mediaItems.index(self.mediaItem) + pos += 1 + if pos >= len(self.mediaItems): + pos = 0 + + self.mediaItem = self.mediaItems[pos] + + return True + + def prev(self): + if not self._prev(): + return + self.setup() + + @busy.dialog() + def _prev(self): + if self.parentList: + mli = self.parentList.getListItemByDataSource(self.mediaItem) + if not mli: + return False + + pos = mli.pos() - 1 + if pos < 0: + pos = self.parentList.size() - 1 + + self.mediaItem = self.parentList.getListItem(pos).dataSource + else: + if not self.getMediaItems(): + return False + + if self.mediaItem not in self.mediaItems: + return False + + pos = self.mediaItems.index(self.mediaItem) + pos -= 1 + if pos < 0: + pos = len(self.mediaItems) - 1 + + self.mediaItem = self.mediaItems[pos] + + return True + + def searchButtonClicked(self): + self.processCommand(search.dialog(self, section_id=self.mediaItem.getLibrarySectionId() or None)) + + def openItem(self, control=None, item=None): + if not item: + mli = control.getSelectedItem() + if not mli: + return + item = mli.dataSource + + self.processCommand(opener.open(item)) + + def subItemListClicked(self): + mli = self.subItemListControl.getSelectedItem() + if not mli: + return + + update = False + + w = None + if self.mediaItem.type == 'show': + w = episodes.EpisodesWindow.open(season=mli.dataSource, show=self.mediaItem, parent_list=self.subItemListControl) + update = True + elif self.mediaItem.type == 'artist': + w = tracks.AlbumWindow.open(album=mli.dataSource, parent_list=self.subItemListControl) + + if not mli: + return + + if not mli.dataSource.exists(): + self.subItemListControl.removeItem(mli.pos()) + + if not self.subItemListControl.size(): + self.closeWithCommand(w.exitCommand) + del w + gc.collect(2) + return + + if update: + mli.setProperty('unwatched.count', not mli.dataSource.isWatched and str(mli.dataSource.unViewedLeafCount) or '') + self.mediaItem.reload(includeRelated=1, includeRelatedCount=10, includeExtras=1, includeExtrasCount=10) + self.updateProperties() + + try: + self.processCommand(w.exitCommand) + finally: + del w + gc.collect(2) + + def infoButtonClicked(self): + fallback = 'script.plex/thumb_fallbacks/{0}.png'.format(self.mediaItem.type == 'show' and 'show' or 'music') + genres = u' / '.join([g.tag for g in util.removeDups(self.mediaItem.genres())][:6]) + + w = info.InfoWindow.open( + title=self.mediaItem.title, + sub_title=genres, + thumb=self.mediaItem.defaultThumb, + thumb_fallback=fallback, + info=self.mediaItem.summary, + background=self.getProperty('background'), + is_square=bool(isinstance(self, ArtistWindow)), + video=self.mediaItem + ) + del w + util.garbageCollect() + + def playButtonClicked(self, shuffle=False): + items = self.mediaItem.all() + pl = playlist.LocalPlaylist(items, self.mediaItem.getServer()) + resume = False + if not shuffle and self.mediaItem.type == 'show': + resume = self.getPlaylistResume(pl, items, self.mediaItem.title) + if resume is None: + return + + pl.shuffle(shuffle, first=True) + videoplayer.play(play_queue=pl, resume=resume) + + def shuffleButtonClicked(self): + self.playButtonClicked(shuffle=True) + + def optionsButtonClicked(self): + options = [] + oldBingeModeValue = None + if xbmc.getCondVisibility('Player.HasAudio + MusicPlayer.HasNext'): + options.append({'key': 'play_next', 'display': 'Play Next'}) + + if self.mediaItem.type != 'artist': + if self.mediaItem.isWatched: + options.append({'key': 'mark_unwatched', 'display': T(32318, 'Mark Unplayed')}) + else: + options.append({'key': 'mark_watched', 'display': T(32319, 'Mark Played')}) + + if self.mediaItem.type == "show": + if options: + options.append(dropdown.SEPARATOR) + + options.append({'key': 'playback_settings', 'display': T(32925, 'Playback Settings')}) + + # if xbmc.getCondVisibility('Player.HasAudio') and self.section.TYPE == 'artist': + # options.append({'key': 'add_to_queue', 'display': 'Add To Queue'}) + + # if False: + # options.append({'key': 'add_to_playlist', 'display': 'Add To Playlist'}) + + options.append(dropdown.SEPARATOR) + + options.append({'key': 'to_section', 'display': u'Go to {0}'.format(self.mediaItem.getLibrarySectionTitle())}) + pos = (880, 618) + + choice = dropdown.showDropdown(options, pos, close_direction='left') + if not choice: + return + + if choice['key'] == 'play_next': + xbmc.executebuiltin('PlayerControl(Next)') + elif choice['key'] == 'mark_watched': + self.mediaItem.markWatched() + self.updateItems() + self.updateProperties() + util.MONITOR.watchStatusChanged() + elif choice['key'] == 'mark_unwatched': + self.mediaItem.markUnwatched() + self.updateItems() + self.updateProperties() + util.MONITOR.watchStatusChanged() + elif choice['key'] == 'to_section': + self.goHome(self.mediaItem.getLibrarySectionId()) + elif choice['key'] == 'playback_settings': + self.playbackSettings(self.mediaItem, pos, False) + + def roleClicked(self): + mli = self.rolesListControl.getSelectedItem() + if not mli: + return + + sectionRoles = busy.widthDialog(mli.dataSource.sectionRoles, '') + + if not sectionRoles: + util.DEBUG_LOG('No sections found for actor') + return + + if len(sectionRoles) > 1: + x, y = self.getRoleItemDDPosition() + + options = [{'role': r, 'display': r.reasonTitle} for r in sectionRoles] + choice = dropdown.showDropdown(options, (x, y), pos_is_bottom=True, close_direction='bottom') + + if not choice: + return + + role = choice['role'] + else: + role = sectionRoles[0] + + self.processCommand(opener.open(role)) + + def getRoleItemDDPosition(self): + y = 980 + if xbmc.getCondVisibility('Control.IsVisible(500)'): + y += 360 + if xbmc.getCondVisibility('Control.IsVisible(501)'): + y += 360 + if xbmc.getCondVisibility('Control.IsVisible(502)'): + y += 520 + if xbmc.getCondVisibility('!String.IsEmpty(Window.Property(on.extras))'): + y -= 300 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),0) + Control.IsVisible(500)'): + y -= 500 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),1) + Control.IsVisible(501)'): + y -= 360 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),1) + Control.IsVisible(502)'): + y -= 500 + + focus = int(xbmc.getInfoLabel('Container(403).Position')) + + x = ((focus + 1) * 304) - 100 + return x, y + + def updateItems(self): + self.fill(update=True) + + def createListItem(self, obj): + mli = kodigui.ManagedListItem( + obj.title or '', + thumbnailImage=obj.defaultThumb.asTranscodedImageURL(*self.THUMB_DIMS[self.mediaItem.type]['item.thumb']), + data_source=obj + ) + return mli + + @busy.dialog() + def fill(self, update=False): + self.fillSeasons(self.mediaItem, update=update) + + def fillExtras(self): + items = [] + idx = 0 + + if not self.mediaItem.extras: + self.extraListControl.reset() + return False + + for extra in self.mediaItem.extras(): + mli = kodigui.ManagedListItem( + extra.title or '', + metadata.EXTRA_MAP.get(extra.extraType.asInt(), ''), + thumbnailImage=extra.thumb.asTranscodedImageURL(*self.EXTRA_DIM), + data_source=extra + ) + + if mli: + mli.setProperty('index', str(idx)) + mli.setProperty( + 'thumb.fallback', 'script.plex/thumb_fallbacks/{0}.png'.format(extra.type in ('show', 'season', 'episode') and 'show' or 'movie') + ) + items.append(mli) + idx += 1 + + if not items: + return False + + self.extraListControl.reset() + self.extraListControl.addItems(items) + return True + + def fillRelated(self, has_prev=False): + if not self.relatedPaginator.leafCount: + self.relatedListControl.reset() + return has_prev + + self.setProperty('divider.{0}'.format(self.RELATED_LIST_ID), has_prev and '1' or '') + + items = self.relatedPaginator.paginate() + + if not items: + return False + + return True + + def fillRoles(self, has_prev=False): + items = [] + idx = 0 + if not self.mediaItem.roles: + self.rolesListControl.reset() + return has_prev + + self.setProperty('divider.{0}'.format(self.ROLES_LIST_ID), has_prev and '1' or '') + + for role in self.mediaItem.roles(): + mli = kodigui.ManagedListItem(role.tag, role.role, thumbnailImage=role.thumb.asTranscodedImageURL(*self.ROLES_DIM), data_source=role) + mli.setProperty('index', str(idx)) + items.append(mli) + idx += 1 + + self.rolesListControl.reset() + self.rolesListControl.addItems(items) + return True + + +class ArtistWindow(ShowWindow): + xmlFile = 'script-plex-artist.xml' + + SUB_ITEM_LIST_ID = 101 + + def onFirstInit(self): + self.subItemListControl = kodigui.ManagedControlList(self, self.SUB_ITEM_LIST_ID, 5) + + self.setup() + + self.setFocusId(self.PLAY_BUTTON_ID) + + def setup(self): + self.updateProperties() + self.fill() + + def playButtonClicked(self, shuffle=False): + pl = playlist.LocalPlaylist(self.mediaItem.all(), self.mediaItem.getServer(), self.mediaItem) + pl.startShuffled = shuffle + w = musicplayer.MusicPlayerWindow.open(track=pl.current(), playlist=pl) + del w + + def updateProperties(self): + self.setProperty('summary', self.mediaItem.summary) + self.setProperty('thumb', self.mediaItem.defaultThumb.asTranscodedImageURL(*self.THUMB_DIMS[self.mediaItem.type]['main.thumb'])) + self.updateBackgroundFrom(self.mediaItem) + + @busy.dialog() + def fill(self): + self.mediaItem.reload(includeRelated=1, includeRelatedCount=10, includeExtras=1, includeExtrasCount=10) + self.setProperty('artist.title', self.mediaItem.title) + genres = u' / '.join([g.tag for g in util.removeDups(self.mediaItem.genres())][:6]) + self.setProperty('artist.genre', genres) + items = [] + idx = 0 + for album in sorted(self.mediaItem.albums(), key=lambda x: x.year): + mli = self.createListItem(album) + if mli: + mli.setProperty('index', str(idx)) + mli.setProperty('year', album.year) + mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/music.png') + items.append(mli) + idx += 1 + + self.subItemListControl.reset() + self.subItemListControl.addItems(items) diff --git a/script.plexmod/lib/windows/tracks.py b/script.plexmod/lib/windows/tracks.py new file mode 100644 index 0000000000..90dc430436 --- /dev/null +++ b/script.plexmod/lib/windows/tracks.py @@ -0,0 +1,348 @@ +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcgui +from . import kodigui + +from lib import colors +from lib import util + +from plexnet import playlist + +from . import busy +from . import musicplayer +from . import dropdown +from . import windowutils +from . import opener +from . import search + +from lib.util import T + + +class AlbumWindow(kodigui.ControlledWindow, windowutils.UtilMixin): + xmlFile = 'script-plex-album.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + THUMB_AR16X9_DIM = util.scaleResolution(178, 100) + THUMB_SQUARE_DIM = util.scaleResolution(630, 630) + + TRACKS_LIST_ID = 101 + LIST_OPTIONS_BUTTON_ID = 111 + + OPTIONS_GROUP_ID = 200 + + HOME_BUTTON_ID = 201 + SEARCH_BUTTON_ID = 202 + PLAYER_STATUS_BUTTON_ID = 204 + + PLAY_BUTTON_ID = 301 + SHUFFLE_BUTTON_ID = 302 + OPTIONS_BUTTON_ID = 303 + + def __init__(self, *args, **kwargs): + kodigui.ControlledWindow.__init__(self, *args, **kwargs) + self.album = kwargs.get('album') + self.parentList = kwargs.get('parentList') + self.albums = None + self.exitCommand = None + + def onFirstInit(self): + self.trackListControl = kodigui.ManagedControlList(self, self.TRACKS_LIST_ID, 5) + + self.setup() + self.setFocusId(self.TRACKS_LIST_ID) + try: + self.checkForHeaderFocus(xbmcgui.ACTION_MOVE_DOWN) + except AttributeError: + raise util.NoDataException + + def setup(self): + self.updateProperties() + self.fillTracks() + + def onAction(self, action): + controlID = self.getFocusId() + try: + if action == xbmcgui.ACTION_LAST_PAGE and xbmc.getCondVisibility('ControlGroup(300).HasFocus(0)'): + self.next() + elif action == xbmcgui.ACTION_NEXT_ITEM: + self.next() + elif action == xbmcgui.ACTION_FIRST_PAGE and xbmc.getCondVisibility('ControlGroup(300).HasFocus(0)'): + self.prev() + elif action == xbmcgui.ACTION_PREV_ITEM: + self.prev() + + if controlID == self.TRACKS_LIST_ID: + self.checkForHeaderFocus(action) + if controlID == self.LIST_OPTIONS_BUTTON_ID and self.checkOptionsAction(action): + return + elif action == xbmcgui.ACTION_CONTEXT_MENU: + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)): + self.setFocusId(self.OPTIONS_GROUP_ID) + return + # elif action in(xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_CONTEXT_MENU): + # if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)): + # self.setFocusId(self.OPTIONS_GROUP_ID) + # return + except: + util.ERROR() + + kodigui.ControlledWindow.onAction(self, action) + + def checkOptionsAction(self, action): + if action == xbmcgui.ACTION_MOVE_UP: + mli = self.trackListControl.getSelectedItem() + if not mli: + return False + pos = mli.pos() - 1 + if self.trackListControl.positionIsValid(pos): + self.setFocusId(self.TRACKS_LIST_ID) + self.trackListControl.selectItem(pos) + return True + elif action == xbmcgui.ACTION_MOVE_DOWN: + mli = self.trackListControl.getSelectedItem() + if not mli: + return False + pos = mli.pos() + 1 + if self.trackListControl.positionIsValid(pos): + self.setFocusId(self.TRACKS_LIST_ID) + self.trackListControl.selectItem(pos) + return True + + return False + + def onClick(self, controlID): + if controlID == self.HOME_BUTTON_ID: + self.goHome() + elif controlID == self.TRACKS_LIST_ID: + self.trackPanelClicked() + elif controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() + elif controlID == self.PLAY_BUTTON_ID: + self.playButtonClicked() + elif controlID == self.SHUFFLE_BUTTON_ID: + self.shuffleButtonClicked() + elif controlID == self.OPTIONS_BUTTON_ID: + self.optionsButtonClicked() + elif controlID == self.LIST_OPTIONS_BUTTON_ID: + mli = self.trackListControl.getSelectedItem() + if mli: + self.optionsButtonClicked(mli) + elif controlID == self.SEARCH_BUTTON_ID: + self.searchButtonClicked() + + def getAlbums(self): + if not self.albums: + self.albums = self.album.artist().albums() + + if not self.albums: + return False + + return True + + def next(self): + if not self._next(): + return + self.setup() + + @busy.dialog() + def _next(self): + if self.parentList: + mli = self.parentList.getListItemByDataSource(self.album) + if not mli: + return False + + pos = mli.pos() + 1 + if not self.parentList.positionIsValid(pos): + pos = 0 + + self.album = self.parentList.getListItem(pos).dataSource + else: + if not self.getAlbums(): + return False + + if self.album not in self.albums: + return False + + pos = self.albums.index(self.album) + pos += 1 + if pos >= len(self.albums): + pos = 0 + + self.album = self.albums[pos] + + return True + + def prev(self): + if not self._prev(): + return + self.setup() + + @busy.dialog() + def _prev(self): + if self.parentList: + mli = self.parentList.getListItemByDataSource(self.album) + if not mli: + return False + + pos = mli.pos() - 1 + if pos < 0: + pos = self.parentList.size() - 1 + + self.album = self.parentList.getListItem(pos).dataSource + else: + if not self.getAlbums(): + return False + + if self.album not in self.albums: + return False + + pos = self.albums.index(self.album) + pos -= 1 + if pos < 0: + pos = len(self.albums) - 1 + + self.album = self.albums[pos] + + return True + + def searchButtonClicked(self): + self.processCommand(search.dialog(self, section_id=self.album.getLibrarySectionId() or None)) + + def shuffleButtonClicked(self): + self.playButtonClicked(shuffle=True) + + def optionsButtonClicked(self, item=None): + options = [] + + if item: + if item.dataSource.isWatched: + options.append({'key': 'mark_unwatched', 'display': T(32318, 'Mark Unplayed')}) + else: + options.append({'key': 'mark_watched', 'display': T(32319, 'Mark Played')}) + + # if False: + # options.append({'key': 'add_to_playlist', 'display': '[COLOR FF808080]Add To Playlist[/COLOR]'}) + else: + if xbmc.getCondVisibility('Player.HasAudio + MusicPlayer.HasNext'): + options.append({'key': 'play_next', 'display': T(32325, 'Play Next')}) + + # if xbmc.getCondVisibility('Player.HasAudio') and self.section.TYPE == 'artist': + # options.append({'key': 'add_to_queue', 'display': 'Add To Queue'}) + + if options: + options.append(dropdown.SEPARATOR) + + options.append({'key': 'to_artist', 'display': T(32301, 'Go to Artist')}) + options.append({'key': 'to_section', 'display': T(32302, u'Go to {0}').format(self.album.getLibrarySectionTitle())}) + + pos = (460, 1106) + bottom = True + setDropdownProp = False + if item: + viewPos = self.trackListControl.getViewPosition() + if viewPos > 6: + pos = (1490, 312 + (viewPos * 100)) + bottom = True + else: + pos = (1490, 167 + (viewPos * 100)) + bottom = False + setDropdownProp = True + choice = dropdown.showDropdown(options, pos, pos_is_bottom=bottom, close_direction='right', set_dropdown_prop=setDropdownProp) + if not choice: + return + + if choice['key'] == 'play_next': + xbmc.executebuiltin('PlayerControl(Next)') + elif choice['key'] == 'mark_watched': + media = item and item.dataSource or self.album + media.markWatched() + self.updateItems(item) + util.MONITOR.watchStatusChanged() + elif choice['key'] == 'mark_unwatched': + media = item and item.dataSource or self.album + media.markUnwatched() + self.updateItems(item) + util.MONITOR.watchStatusChanged() + elif choice['key'] == 'to_artist': + self.processCommand(opener.open(self.album.parentRatingKey)) + elif choice['key'] == 'to_section': + self.goHome(self.album.getLibrarySectionId()) + + def checkForHeaderFocus(self, action): + if action in (xbmcgui.ACTION_MOVE_UP, xbmcgui.ACTION_PAGE_UP): + if self.trackListControl.getSelectedItem().getProperty('is.header'): + xbmc.executebuiltin('Action(up)') + if action in (xbmcgui.ACTION_MOVE_DOWN, xbmcgui.ACTION_PAGE_DOWN, xbmcgui.ACTION_MOVE_LEFT, xbmcgui.ACTION_MOVE_RIGHT): + if self.trackListControl.getSelectedItem().getProperty('is.header'): + xbmc.executebuiltin('Action(down)') + + def updateItems(self, item=None): + if item: + self.album.reload() + item.setProperty('watched', item.dataSource.isWatched and '1' or '') + else: + self.fillTracks() + + def playButtonClicked(self, shuffle=False): + pl = playlist.LocalPlaylist(self.album.all(), self.album.getServer()) + pl.startShuffled = shuffle + self.openWindow(musicplayer.MusicPlayerWindow, track=pl.current(), playlist=pl) + + def trackPanelClicked(self): + mli = self.trackListControl.getSelectedItem() + if not mli: + return + + self.openWindow(musicplayer.MusicPlayerWindow, track=mli.dataSource, album=self.album) + + def updateProperties(self): + self.setProperty( + 'background', + util.backgroundFromArt(self.album.art, width=self.width, height=self.height) + ) + self.setProperty('album.thumb', self.album.thumb.asTranscodedImageURL(*self.THUMB_SQUARE_DIM)) + self.setProperty('artist.title', self.album.parentTitle or '') + self.setProperty('album.title', self.album.title) + + def createListItem(self, obj): + mli = kodigui.ManagedListItem(obj.title, data_source=obj) + mli.setProperty('track.number', str(obj.index) or '') + mli.setProperty('track.duration', util.simplifiedTimeDisplay(obj.duration.asInt())) + return mli + + #@busy.dialog() + def fillTracks(self): + items = [] + idx = 0 + multiDisc = 0 + + for track in self.album.tracks(): + disc = track.parentIndex.asInt() + if disc > 1: + if not multiDisc: + items.insert(0, kodigui.ManagedListItem(u'{0} 1'.format(T(32420, 'Disc').upper()), properties={'is.header': '1'})) + + if disc != multiDisc: + items[-1].setProperty('is.footer', '1') + multiDisc = disc + items.append(kodigui.ManagedListItem('{0} {1}'.format(T(32420, 'Disc').upper(), disc), properties={'is.header': '1'})) + + mli = self.createListItem(track) + if mli: + mli.setProperty('track.ID', track.ratingKey) + mli.setProperty('index', str(idx)) + mli.setProperty('artist', self.album.parentTitle) + mli.setProperty('disc', str(disc)) + mli.setProperty('album', self.album.title) + mli.setProperty('number', '{0:0>2}'.format(track.index)) + items.append(mli) + idx += 1 + + if items: + items[-1].setProperty('is.footer', '1') + + self.trackListControl.replaceItems(items) diff --git a/script.plexmod/lib/windows/userselect.py b/script.plexmod/lib/windows/userselect.py new file mode 100644 index 0000000000..c659276a9f --- /dev/null +++ b/script.plexmod/lib/windows/userselect.py @@ -0,0 +1,234 @@ +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcgui + +from . import kodigui +from . import dropdown +from . import busy + +from lib import util, image, backgroundthread +from plexnet import plexapp + +from lib.util import T + + +class UserThumbTask(backgroundthread.Task): + def setup(self, users, callback): + self.users = users + self.callback = callback + return self + + def run(self): + for user in self.users: + if self.isCanceled(): + return + + thumb, back = image.getImage(user.thumb, user.id) + self.callback(user, thumb, back) + + +class UserSelectWindow(kodigui.BaseWindow): + xmlFile = 'script-plex-user_select.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + USER_LIST_ID = 101 + PIN_ENTRY_GROUP_ID = 400 + SHUTDOWN_BUTTON_ID = 500 + + def __init__(self, *args, **kwargs): + self.task = None + self.selected = False + kodigui.BaseWindow.__init__(self, *args, **kwargs) + + def onFirstInit(self): + self.userList = kodigui.ManagedControlList(self, self.USER_LIST_ID, 6) + + self.start() + + def onAction(self, action): + try: + ID = action.getId() + if 57 < ID < 68: + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.PIN_ENTRY_GROUP_ID)): + item = self.userList.getSelectedItem() + if not item.dataSource.isProtected: + return + self.setFocusId(self.PIN_ENTRY_GROUP_ID) + self.pinEntryClicked(ID + 142) + return + elif 142 <= ID <= 149: # JumpSMS action + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.PIN_ENTRY_GROUP_ID)): + item = self.userList.getSelectedItem() + if not item.dataSource.isProtected: + return + self.setFocusId(self.PIN_ENTRY_GROUP_ID) + self.pinEntryClicked(ID + 60) + return + elif ID in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_BACKSPACE): + item = self.userList.getSelectedItem() + if xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.PIN_ENTRY_GROUP_ID)): + if item.getProperty('editing.pin'): + self.pinEntryClicked(211) + else: + self.setFocusId(self.USER_LIST_ID) + return + # return to selected user + self.selected = 'cancel' + self.doClose() + return + except: + util.ERROR() + + kodigui.BaseWindow.onAction(self, action) + + def onClick(self, controlID): + if controlID == self.USER_LIST_ID: + item = self.userList.getSelectedItem() + if item.dataSource.isProtected: + self.setFocusId(self.PIN_ENTRY_GROUP_ID) + else: + self.userSelected(item) + elif 200 < controlID < 212: + self.pinEntryClicked(controlID) + elif controlID == self.SHUTDOWN_BUTTON_ID: + self.shutdownClicked() + + def onFocus(self, controlID): + if controlID == self.USER_LIST_ID: + item = self.userList.getSelectedItem() + item.setProperty('editing.pin', '') + + def userThumbCallback(self, user, thumb, back): + item = self.userList.getListItemByDataSource(user) + if item: + item.setThumbnailImage(thumb) + item.setProperty('back.image', back) + + def start(self): + self.setProperty('busy', '1') + try: + users = plexapp.ACCOUNT.homeUsers + + items = [] + selectIndex = None + for idx, user in enumerate(users): + # thumb, back = image.getImage(user.thumb, user.id) + # mli = kodigui.ManagedListItem(user.title, thumbnailImage=thumb, data_source=user) + mli = kodigui.ManagedListItem(user.title, user.title[0].upper(), data_source=user) + mli.setProperty('pin', user.title) + # mli.setProperty('back.image', back) + mli.setProperty('protected', user.isProtected and '1' or '') + mli.setProperty('admin', user.isAdmin and '1' or '') + + if plexapp.ACCOUNT.ID == user.id: + selectIndex = idx + + items.append(mli) + + self.userList.addItems(items) + + self.task = UserThumbTask().setup(users, self.userThumbCallback) + backgroundthread.BGThreader.addTask(self.task) + + self.setFocusId(self.USER_LIST_ID) + + if selectIndex is not None: + self.userList.setSelectedItemByPos(selectIndex) + + self.setProperty('initialized', '1') + finally: + self.setProperty('busy', '') + + def shutdownClicked(self): + options = [] + options.append({'key': 'sign_out', 'display': T(32421, 'Sign Out')}) + options.append({'key': 'exit', 'display': T(32422, 'Exit')}) + if util.getSetting('kiosk.mode', False): + if xbmc.getCondVisibility('System.CanPowerDown'): + options.append({'key': 'shutdown', 'display': T(32423, 'Shutdown')}) + if xbmc.getCondVisibility('System.CanSuspend'): + options.append({'key': 'suspend', 'display': T(32424, 'Suspend')}) + if xbmc.getCondVisibility('System.CanHibernate'): + options.append({'key': 'hibernate', 'display': T(32425, 'Hibernate')}) + if xbmc.getCondVisibility('System.CanReboot'): + options.append({'key': 'reboot', 'display': T(32426, 'Reboot')}) + + with self.propertyContext('dropdown'): + choice = dropdown.showDropdown(options, (60, 101)) + if not choice: + return + + if choice['key'] == 'sign_out': + self.selected = 'signout' + self.doClose() + elif choice['key'] == 'exit': + self.doClose() + elif choice['key'] == 'shutdown': + xbmc.executebuiltin('Powerdown()') + elif choice['key'] == 'suspend': + xbmc.executebuiltin('Suspend()') + elif choice['key'] == 'hibernate': + xbmc.executebuiltin('Hibernate()') + elif choice['key'] == 'reboot': + xbmc.executebuiltin('Reset()') + + def pinEntryClicked(self, controlID): + item = self.userList.getSelectedItem() + if item.getProperty('editing.pin'): + pin = item.getProperty('editing.pin') + else: + pin = '' + + if len(pin) > 3: + return + + if controlID < 210: + pin += str(controlID - 200) + elif controlID == 210: + pin += '0' + elif controlID == 211: + pin = pin[:-1] + + if pin: + item.setProperty('pin', ' '.join(list(u"\u2022" * len(pin)))) + item.setProperty('editing.pin', pin) + if len(pin) > 3: + self.userSelected(item, pin) + else: + item.setProperty('pin', item.dataSource.title) + item.setProperty('editing.pin', '') + + @busy.dialog() + def userSelected(self, item, pin=None): + user = item.dataSource + # xbmc.sleep(500) + util.DEBUG_LOG('Home user selected: {0}'.format(user)) + + from lib import plex + with plex.CallbackEvent(plexapp.util.APP, 'account:response') as e: + if plexapp.ACCOUNT.switchHomeUser(user.id, pin) and plexapp.ACCOUNT.switchUser: + util.DEBUG_LOG('Waiting for user change...') + else: + e.close() + item.setProperty('pin', item.dataSource.title) + item.setProperty('editing.pin', '') + util.messageDialog(T(32427, 'Failed'), T(32926, 'Wrong pin entered!')) + return + + self.selected = True + self.doClose() + + def finished(self): + if self.task: + self.task.cancel() + + +def start(): + w = UserSelectWindow.open() + selected = w.selected + del w + return selected diff --git a/script.plexmod/lib/windows/videoplayer.py b/script.plexmod/lib/windows/videoplayer.py new file mode 100644 index 0000000000..0e36426cd7 --- /dev/null +++ b/script.plexmod/lib/windows/videoplayer.py @@ -0,0 +1,596 @@ +from __future__ import absolute_import +import time +import threading +import math + +from kodi_six import xbmc +from kodi_six import xbmcgui + +from . import kodigui +from . import windowutils +from . import opener +from . import busy +from . import search +from . import dropdown +from . import pagination + +from lib import util +from lib import player +from lib import colors + +from lib.util import T + + +PASSOUT_PROTECTION_DURATION_SECONDS = 7200 +PASSOUT_LAST_VIDEO_DURATION_MILLIS = 1200000 + + +class RelatedPaginator(pagination.BaseRelatedPaginator): + def readyForPaging(self): + return self.parentWindow.postPlayInitialized + + def getData(self, offset, amount): + return (self.parentWindow.prev or self.parentWindow.next).getRelated(offset=offset, limit=amount) + + +class OnDeckPaginator(pagination.MCLPaginator): + def readyForPaging(self): + return self.parentWindow.postPlayInitialized + + thumbFallback = lambda self, rel: 'script.plex/thumb_fallbacks/{0}.png'.format( + rel.type in ('show', 'season', 'episode') and 'show' or 'movie') + + def prepareListItem(self, data, mli): + mli.setProperty('progress', util.getProgressImage(mli.dataSource)) + mli.setProperty('unwatched', not mli.dataSource.isWatched and '1' or '') + + if data.type in 'episode': + mli.setLabel2( + u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), data.parentIndex, T(32311, 'E'), data.index)) + else: + mli.setLabel2(data.year) + + def createListItem(self, ondeck): + title = ondeck.grandparentTitle or ondeck.title + if ondeck.type == 'episode': + thumb = ondeck.thumb.asTranscodedImageURL(*self.parentWindow.ONDECK_DIM) + else: + thumb = ondeck.defaultArt.asTranscodedImageURL(*self.parentWindow.ONDECK_DIM) + + mli = kodigui.ManagedListItem(title or '', thumbnailImage=thumb, data_source=ondeck) + if mli: + return mli + + def getData(self, offset, amount): + return (self.parentWindow.prev or self.parentWindow.next).sectionOnDeck(offset=offset, limit=amount) + + +class VideoPlayerWindow(kodigui.ControlledWindow, windowutils.UtilMixin): + xmlFile = 'script-plex-video_player.xml' + path = util.ADDON.getAddonInfo('path') + theme = 'Main' + res = '1080i' + width = 1920 + height = 1080 + + NEXT_DIM = util.scaleResolution(537, 303) + PREV_DIM = util.scaleResolution(462, 259) + ONDECK_DIM = util.scaleResolution(329, 185) + RELATED_DIM = util.scaleResolution(268, 397) + ROLES_DIM = util.scaleResolution(334, 334) + + OPTIONS_GROUP_ID = 200 + + PREV_BUTTON_ID = 101 + NEXT_BUTTON_ID = 102 + + ONDECK_LIST_ID = 400 + RELATED_LIST_ID = 401 + ROLES_LIST_ID = 403 + + HOME_BUTTON_ID = 201 + SEARCH_BUTTON_ID = 202 + + PLAYER_STATUS_BUTTON_ID = 204 + + def __init__(self, *args, **kwargs): + kodigui.ControlledWindow.__init__(self, *args, **kwargs) + windowutils.UtilMixin.__init__(self) + self.playQueue = kwargs.get('play_queue') + self.video = kwargs.get('video') + self.resume = bool(kwargs.get('resume')) + + self.postPlayMode = False + self.prev = None + self.playlist = None + self.handler = None + self.next = None + self.videos = None + self.trailer = None + self.aborted = True + self.timeout = None + self.passoutProtection = 0 + self.postPlayInitialized = False + self.relatedPaginator = None + self.onDeckPaginator = None + self.lastFocusID = None + self.lastNonOptionsFocusID = None + self.playBackStarted = False + + def doClose(self): + util.DEBUG_LOG('VideoPlayerWindow: Closing') + self.timeout = None + self.relatedPaginator = None + self.onDeckPaginator = None + kodigui.ControlledWindow.doClose(self) + player.PLAYER.handler.sessionEnded() + + def onFirstInit(self): + player.PLAYER.on('session.ended', self.sessionEnded) + player.PLAYER.on('av.started', self.playerPlaybackStarted) + player.PLAYER.on('post.play', self.postPlay) + player.PLAYER.on('change.background', self.changeBackground) + + self.onDeckListControl = kodigui.ManagedControlList(self, self.ONDECK_LIST_ID, 5) + self.relatedListControl = kodigui.ManagedControlList(self, self.RELATED_LIST_ID, 5) + self.rolesListControl = kodigui.ManagedControlList(self, self.ROLES_LIST_ID, 5) + + util.DEBUG_LOG('VideoPlayerWindow: Starting session (ID: {0})'.format(id(self))) + self.resetPassoutProtection() + self.play(resume=self.resume) + + def onReInit(self): + self.setBackground() + + def onAction(self, action): + try: + if self.postPlayMode: + controlID = self.getFocusId() + + self.cancelTimer() + self.resetPassoutProtection() + if action in(xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_CONTEXT_MENU): + if not xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)): + if not util.advancedSettings.fastBack or action == xbmcgui.ACTION_CONTEXT_MENU: + self.lastNonOptionsFocusID = self.lastFocusID + self.setFocusId(self.OPTIONS_GROUP_ID) + return + else: + if self.lastNonOptionsFocusID and action == xbmcgui.ACTION_CONTEXT_MENU: + self.setFocusId(self.lastNonOptionsFocusID) + self.lastNonOptionsFocusID = None + return + + if action in(xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): + self.doClose() + return + + if action in (xbmcgui.ACTION_NEXT_ITEM, xbmcgui.ACTION_PLAYER_PLAY): + self.playVideo() + elif action == xbmcgui.ACTION_PREV_ITEM: + self.playVideo(prev=True) + elif action == xbmcgui.ACTION_STOP: + self.doClose() + + if controlID == self.RELATED_LIST_ID: + if self.relatedPaginator.boundaryHit: + self.relatedPaginator.paginate() + return + + elif controlID == self.ONDECK_LIST_ID: + if self.onDeckPaginator.boundaryHit: + self.onDeckPaginator.paginate() + return + except: + util.ERROR() + + kodigui.ControlledWindow.onAction(self, action) + + def playerPlaybackStarted(self, *args, **kwargs): + self.playBackStarted = True + + def onClick(self, controlID): + if not self.postPlayMode: + return + + timeoutCanceled = False + if util.advancedSettings.postplayCancel: + timeoutCanceled = bool(self.timeout) + self.cancelTimer() + + if controlID == self.HOME_BUTTON_ID: + self.goHome() + elif controlID == self.ONDECK_LIST_ID: + self.openItem(self.onDeckListControl) + elif controlID == self.RELATED_LIST_ID: + self.openItem(self.relatedListControl) + elif controlID == self.ROLES_LIST_ID: + self.roleClicked() + elif controlID == self.PREV_BUTTON_ID: + self.playVideo(prev=True) + elif controlID == self.NEXT_BUTTON_ID: + if not timeoutCanceled: + self.playVideo() + elif controlID == self.PLAYER_STATUS_BUTTON_ID: + self.showAudioPlayer() + elif controlID == self.SEARCH_BUTTON_ID: + self.searchButtonClicked() + + def onFocus(self, controlID): + if not self.postPlayMode: + return + + self.lastFocusID = controlID + + if 399 < controlID < 500: + self.setProperty('hub.focus', str(controlID - 400)) + else: + self.setProperty('hub.focus', '') + + if xbmc.getCondVisibility('Control.HasFocus(101) | Control.HasFocus(102) | ControlGroup(200).HasFocus(0)'): + self.setProperty('on.extras', '') + elif xbmc.getCondVisibility('ControlGroup(60).HasFocus(0)'): + self.setProperty('on.extras', '1') + + def searchButtonClicked(self): + self.processCommand(search.dialog(self, section_id=self.prev.getLibrarySectionId() or None)) + + def roleClicked(self): + mli = self.rolesListControl.getSelectedItem() + if not mli: + return + + sectionRoles = busy.widthDialog(mli.dataSource.sectionRoles, '') + + if not sectionRoles: + util.DEBUG_LOG('No sections found for actor') + return + + if len(sectionRoles) > 1: + x, y = self.getRoleItemDDPosition() + + options = [{'role': r, 'display': r.reasonTitle} for r in sectionRoles] + choice = dropdown.showDropdown(options, (x, y), pos_is_bottom=True, close_direction='bottom') + + if not choice: + return + + role = choice['role'] + else: + role = sectionRoles[0] + + self.processCommand(opener.open(role)) + + def getRoleItemDDPosition(self): + y = 1000 + if xbmc.getCondVisibility('Control.IsVisible(500)'): + y += 360 + if xbmc.getCondVisibility('Control.IsVisible(501)'): + y += 520 + if xbmc.getCondVisibility('!String.IsEmpty(Window.Property(on.extras))'): + y -= 300 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),0) + Control.IsVisible(500)'): + y -= 500 + if xbmc.getCondVisibility('Integer.IsGreater(Window.Property(hub.focus),1) + Control.IsVisible(501)'): + y -= 500 + + focus = int(xbmc.getInfoLabel('Container(403).Position')) + + x = ((focus + 1) * 304) - 100 + return x, y + + def setBackground(self): + video = self.video if self.video else self.playQueue.current() + self.windowSetBackground(video.defaultArt.asTranscodedImageURL(1920, 1080, opacity=60, + background=colors.noAlpha.Background)) + + def changeBackground(self, url, **kwargs): + self.windowSetBackground(url) + + def sessionEnded(self, session_id=None, **kwargs): + if session_id != id(self): + util.DEBUG_LOG('VideoPlayerWindow: Ignoring session end (ID: {0} - SessionID: {1})'.format(id(self), session_id)) + return + + util.DEBUG_LOG('VideoPlayerWindow: Session ended - closing (ID: {0})'.format(id(self))) + self.doClose() + + def play(self, resume=False, handler=None): + self.hidePostPlay() + + self.setBackground() + if self.playQueue: + player.PLAYER.playVideoPlaylist(self.playQueue, resume=self.resume, session_id=id(self), handler=handler) + elif self.video: + player.PLAYER.playVideo(self.video, resume=self.resume, force_update=True, session_id=id(self), handler=handler) + + def openItem(self, control=None, item=None): + if not item: + mli = control.getSelectedItem() + if not mli: + return + item = mli.dataSource + + self.processCommand(opener.open(item)) + + def showPostPlay(self): + self.postPlayMode = True + self.setProperty('post.play', '1') + + def hidePostPlay(self): + self.postPlayMode = False + self.setProperty('post.play', '') + self.setProperties(( + 'post.play.background', + 'info.title', + 'info.duration', + 'info.summary', + 'info.date', + 'next.thumb', + 'next.title', + 'next.subtitle', + 'prev.thumb', + 'prev.title', + 'prev.subtitle', + 'related.header', + 'has.next' + ), '') + + self.onDeckListControl.reset() + self.relatedListControl.reset() + self.rolesListControl.reset() + + @busy.dialog() + def postPlay(self, video=None, playlist=None, handler=None, stoppedInBingeMode=False, **kwargs): + util.DEBUG_LOG('VideoPlayer: Starting post-play') + self.showPostPlay() + self.prev = video + self.playlist = playlist + self.handler = handler + + self.getHubs() + + self.setProperty( + 'thumb.fallback', 'script.plex/thumb_fallbacks/{0}.png'.format(self.prev.type in ('show', 'season', 'episode') and 'show' or 'movie') + ) + + util.DEBUG_LOG('PostPlay: Showing video info') + if self.next: + self.next.reload(includeExtras=1, includeExtrasCount=10) + + self.relatedPaginator = RelatedPaginator(self.relatedListControl, + leaf_count=int((self.prev or self.next).relatedCount), + parent_window=self) + + vid = self.prev or self.next + if vid.sectionOnDeckCount: + self.onDeckPaginator = OnDeckPaginator(self.onDeckListControl, + leaf_count=int(vid.sectionOnDeckCount), + parent_window=self) + + self.setInfo() + self.fillOnDeck() + hasPrev = self.fillRelated() + self.fillRoles(hasPrev) + + if not stoppedInBingeMode: + self.startTimer() + + if self.next: + self.setFocusId(self.NEXT_BUTTON_ID) + else: + self.setFocusId(self.PREV_BUTTON_ID) + self.postPlayInitialized = True + + def resetPassoutProtection(self): + self.passoutProtection = time.time() + PASSOUT_PROTECTION_DURATION_SECONDS + + def startTimer(self): + if not util.getUserSetting('post_play_auto', True): + util.DEBUG_LOG('Post play auto-play disabled') + return + + if not self.next: + return + + if time.time() > self.passoutProtection and self.prev.duration.asInt() > PASSOUT_LAST_VIDEO_DURATION_MILLIS: + util.DEBUG_LOG('Post play auto-play skipped: Passout protection') + return + else: + millis = (self.passoutProtection - time.time()) * 1000 + util.DEBUG_LOG('Post play auto-play: Passout protection in {0}'.format(util.durationToShortText(millis))) + + self.timeout = time.time() + abs(util.advancedSettings.postplayTimeout) + util.DEBUG_LOG('Starting post-play timer until: %i' % self.timeout) + threading.Thread(target=self.countdown).start() + + def cancelTimer(self): + if self.timeout is not None: + util.DEBUG_LOG('Canceling post-play timer') + + self.timeout = None + self.setProperty('countdown', '') + + def countdown(self): + while self.timeout and not util.MONITOR.waitForAbort(0.1): + now = time.time() + if self.timeout and now > self.timeout: + self.timeout = None + self.setProperty('countdown', '') + util.DEBUG_LOG('Post-play timer finished') + # This works. The direct method caused the OSD to be broken, possibly because it was triggered from another thread? + # That was the only real difference I could see between the direct method and the user actually clicking the button. + xbmc.executebuiltin('SendClick(,{0})'.format(self.NEXT_BUTTON_ID)) + # Direct method, causes issues with OSD + # self.playVideo() + break + elif self.timeout is not None: + cd = min(abs(util.advancedSettings.postplayTimeout-1), int((self.timeout or now) - now)) + base = 15 / float(util.advancedSettings.postplayTimeout-1) + self.setProperty('countdown', str(int(math.ceil(base*cd)))) + + def getHubs(self): + try: + self.hubs = self.prev.postPlay() + except: + util.ERROR("No data - disconnected?", notify=True, time_ms=5000) + self.doClose() + return + + self.next = None + + if self.playlist: + if self.prev != self.playlist.current(): + self.next = self.playlist.current() + else: + if self.prev.type == 'episode' and 'tv.upnext' in self.hubs: + self.next = self.hubs['tv.upnext'].items[-1] + + if self.next: + self.setProperty('has.next', '1') + + def setInfo(self): + if self.next: + self.setProperty( + 'post.play.background', + util.backgroundFromArt(self.next.art, width=self.width, height=self.height) + ) + self.setProperty('info.title', self.next.title) + self.setProperty('info.duration', util.durationToText(self.next.duration.asInt())) + self.setProperty('info.summary', self.next.summary) + + if self.prev: + self.setProperty( + 'post.play.background', + util.backgroundFromArt(self.prev.art, width=self.width, height=self.height) + ) + self.setProperty('prev.info.title', self.prev.title) + self.setProperty('prev.info.duration', util.durationToText(self.prev.duration.asInt())) + self.setProperty('prev.info.summary', self.prev.summary) + + if self.prev.type == 'episode': + self.setProperty('related.header', T(32306, 'Related Shows')) + if self.next: + self.setProperty('next.thumb', self.next.thumb.asTranscodedImageURL(*self.NEXT_DIM)) + self.setProperty('info.date', util.cleanLeadingZeros(self.next.originallyAvailableAt.asDatetime('%B %d, %Y'))) + + self.setProperty('next.title', self.next.grandparentTitle) + self.setProperty( + 'next.subtitle', u'{0} {1} \u2022 {2} {3}'.format(T(32303, 'Season'), self.next.parentIndex, T(32304, 'Episode'), self.next.index) + ) + if self.prev: + self.setProperty('prev.thumb', self.prev.thumb.asTranscodedImageURL(*self.PREV_DIM)) + self.setProperty('prev.title', self.prev.grandparentTitle) + self.setProperty( + 'prev.subtitle', u'{0} {1} \u2022 {2} {3}'.format(T(32303, 'Season'), self.prev.parentIndex, T(32304, 'Episode'), self.prev.index) + ) + self.setProperty('prev.info.date', util.cleanLeadingZeros(self.prev.originallyAvailableAt.asDatetime('%B %d, %Y'))) + elif self.prev.type == 'movie': + self.setProperty('related.header', T(32404, 'Related Movies')) + if self.next: + self.setProperty('next.thumb', self.next.defaultArt.asTranscodedImageURL(*self.NEXT_DIM)) + self.setProperty('info.date', self.next.year) + + self.setProperty('next.title', self.next.title) + self.setProperty('next.subtitle', self.next.year) + if self.prev: + self.setProperty('prev.thumb', self.prev.defaultArt.asTranscodedImageURL(*self.PREV_DIM)) + self.setProperty('prev.title', self.prev.title) + self.setProperty('prev.subtitle', self.prev.year) + self.setProperty('prev.info.date', self.prev.year) + + def fillOnDeck(self): + if not self.onDeckPaginator: + return False + + if not self.onDeckPaginator.leafCount: + self.onDeckPaginator.reset() + return False + + items = self.onDeckPaginator.paginate() + + if not items: + return False + + return True + + def fillRelated(self, has_prev=False): + if not self.relatedPaginator.leafCount: + self.relatedListControl.reset() + return False + + items = self.relatedPaginator.paginate() + + if not items: + return False + + self.setProperty('divider.{0}'.format(self.RELATED_LIST_ID), has_prev and '1' or '') + return True + + def fillRoles(self, has_prev=False): + items = [] + idx = 0 + + video = self.next if self.next else self.prev + + if not video.roles: + self.rolesListControl.reset() + return False + + for role in video.roles(): + mli = kodigui.ManagedListItem(role.tag, role.role, thumbnailImage=role.thumb.asTranscodedImageURL(*self.ROLES_DIM), data_source=role) + mli.setProperty('index', str(idx)) + items.append(mli) + idx += 1 + + if not items: + return False + + self.setProperty('divider.{0}'.format(self.ROLES_LIST_ID), has_prev and '1' or '') + + self.rolesListControl.reset() + self.rolesListControl.addItems(items) + return True + + def playVideo(self, prev=False): + self.cancelTimer() + try: + if not self.next and self.playlist: + if prev: + self.playlist.prev() + self.aborted = False + self.playQueue = self.playlist + self.video = None + self.play(handler=self.handler) + else: + video = self.next + if prev: + video = self.prev + + if not video: + util.DEBUG_LOG('Trying to play next video with no next video available') + self.video = None + return + + self.playQueue = None + self.video = video + self.play(handler=self.handler) + except: + util.ERROR() + + +def play(video=None, play_queue=None, resume=False): + try: + w = VideoPlayerWindow.open(video=video, play_queue=play_queue, resume=resume) + except util.NoDataException: + raise + finally: + player.PLAYER.off('session.ended', w.sessionEnded) + player.PLAYER.off('post.play', w.postPlay) + player.PLAYER.off('av.started', w.playerPlaybackStarted) + player.PLAYER.off('change.background', w.changeBackground) + player.PLAYER.reset() + command = w.exitCommand + del w + util.garbageCollect() + return command diff --git a/script.plexmod/lib/windows/windowutils.py b/script.plexmod/lib/windows/windowutils.py new file mode 100644 index 0000000000..9914d8c879 --- /dev/null +++ b/script.plexmod/lib/windows/windowutils.py @@ -0,0 +1,84 @@ +from __future__ import absolute_import +from lib import util +from . import opener +from . import dropdown + +from lib.util import T + + +HOME = None + + +class UtilMixin(): + def __init__(self): + self.exitCommand = None + + def goHome(self, section=None): + HOME.show() + if section: + self.closeWithCommand('HOME:{0}'.format(section)) + else: + self.closeWithCommand('HOME') + + def openItem(self, obj): + self.processCommand(opener.open(obj)) + + def openWindow(self, window_class, **kwargs): + self.processCommand(opener.handleOpen(window_class, **kwargs)) + + def processCommand(self, command): + if command and command.startswith('HOME'): + self.exitCommand = command + self.doClose() + elif command and command == "NODATA": + raise util.NoDataException + + def closeWithCommand(self, command): + self.exitCommand = command + self.doClose() + + def showAudioPlayer(self, **kwargs): + from . import musicplayer + self.processCommand(opener.handleOpen(musicplayer.MusicPlayerWindow, **kwargs)) + + def getPlaylistResume(self, pl, items, title): + resume = False + watched = False + for i in items: + if (watched and not i.isWatched) or i.get('viewOffset').asInt(): + if i.get('viewOffset'): + choice = dropdown.showDropdown( + options=[ + {'key': 'resume', 'display': T(32429, 'Resume from {0}').format(util.timeDisplay(i.viewOffset.asInt()).lstrip('0').lstrip(':'))}, + {'key': 'play', 'display': T(32317, 'Play from beginning')} + ], + pos=(660, 441), + close_direction='none', + set_dropdown_prop=False, + header=u'{0} - {1}{2} \u2022 {3}{4}'.format(title, T(32310, 'S'), i.parentIndex, T(32311, 'E'), i.index) + ) + + if not choice: + return None + + if choice['key'] == 'resume': + resume = True + + pl.setCurrent(i) + break + elif i.isWatched: + watched = True + else: + break + + return resume + + +def shutdownHome(): + global HOME + if HOME: + HOME._shuttingDown = True + HOME.shutdown() + del HOME + HOME = None + HOME diff --git a/script.plexmod/plugin.py b/script.plexmod/plugin.py new file mode 100644 index 0000000000..6e2eec66e2 --- /dev/null +++ b/script.plexmod/plugin.py @@ -0,0 +1,75 @@ +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcplugin +from kodi_six import xbmcgui +import sys +import base64 +from lib import _included_packages, plex, util +from plexnet import audio, plexplayer, plexapp +from plexnet import util as plexnetUtil + +HANDLE = int(sys.argv[1]) + +BASE_LOG = util.LOG + + +def LOG(msg): + BASE_LOG('(plugin) - {0}'.format(plexnetUtil.cleanToken(msg))) + + +util.LOG = LOG + + +def playTrack(track): + track.reload() + apobj = plexplayer.PlexAudioPlayer(track) + url = apobj.build()['url'] + url = util.addURLParams(url, { + 'X-Plex-Client-Profile-Name': 'Generic', + 'X-Plex-Client-Identifier': plexapp.util.INTERFACE.getGlobal('clientIdentifier') + }) + LOG('Playing URL: {0}'.format(url)) + + return xbmcgui.ListItem(path=url) + + +def playVideo(video): + return None + + +def play(data): + try: + from plexnet import plexobjects + + plexObject = plexobjects.PlexObject.deSerialize(base64.urlsafe_b64decode(data.encode('utf-8'))) + + if plexObject.type == 'track': + listitem = playTrack(plexObject) + elif plexObject.type in ('episode', 'movie', 'clip'): + listitem = playVideo(plexObject) + except: + util.ERROR() + xbmcplugin.setResolvedUrl(HANDLE, False, None) + return + + xbmcplugin.setResolvedUrl(HANDLE, True, listitem) + + +def main(): + try: + if len(sys.argv) < 3: + return + + path = sys.argv[0].split('/', 3)[-1] + data = sys.argv[2].lstrip('?') + + if path == 'play': + play(data) + else: # This is a hack since it's both a plugin and a script. My Addons and Shortcuts otherwise can't launch the add-on + xbmc.executebuiltin('Action(back)') # This sometimes works to back out of the plugin directory display + xbmc.executebuiltin('RunScript(script.plexmod)') + except: + util.ERROR() + + +main() diff --git a/script.plexmod/pm4k_cache_template.xml b/script.plexmod/pm4k_cache_template.xml new file mode 100644 index 0000000000..82ad94e327 --- /dev/null +++ b/script.plexmod/pm4k_cache_template.xml @@ -0,0 +1,5 @@ + + 1 + {memorysize} + {readfactor} + \ No newline at end of file diff --git a/script.plexmod/resources/language/resource.language.cs_cz/strings.po b/script.plexmod/resources/language/resource.language.cs_cz/strings.po new file mode 100644 index 0000000000..189e635a4b --- /dev/null +++ b/script.plexmod/resources/language/resource.language.cs_cz/strings.po @@ -0,0 +1,927 @@ +# XBMC Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2013-12-12 22:56+0000\n" +"PO-Revision-Date: 2017-02-04 14:36+0100\n" +"Language-Team: LANGUAGE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: cs\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Last-Translator: Michal Kuncl \n" +"X-Generator: Poedit 2.0beta2\n" + +msgctxt "#32000" +msgid "Main" +msgstr "Hlavní" + +msgctxt "#32001" +msgid "Original" +msgstr "Originální" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "20 Mb/s 1080p" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "12 Mb/s 1080p" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "10 Mb/s 1080p" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "8 Mb/s 1080p" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "4 Mb/s 720p" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "3 Mb/s 720p" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "2 Mb/s 720p" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "1.5 Mb/s 480p" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "720 kb/s" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "320 kb/s" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "208 kb/s" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "96 kb/s" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "64 kb/s" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "Místní kvalita" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "Vzdálená kvalita" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "Online kvalita" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "Formát překódování" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "Ladící záznamy" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "Povolit přímé přehrávání" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "Povolit přímé streamování" + +msgctxt "#32027" +msgid "Force" +msgstr "Vynutit" + +msgctxt "#32028" +msgid "Always" +msgstr "Vždy" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "Pouze obrázkové formáty" + +msgctxt "#32030" +msgid "Auto" +msgstr "Automaticky" + +msgctxt "#32031" +msgid "Burn Subtitles (Direct Play Only)" +msgstr "Vpálit titulky (pouze přímá přehrávání)" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "Povolit nezabezpečené připojení" + +msgctxt "#32033" +msgid "Never" +msgstr "Nikdy" + +msgctxt "#32034" +msgid "On Same network" +msgstr "Pouze na stejné síti" + +msgctxt "#32035" +msgid "Always" +msgstr "Vždy" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "Povolit 4K" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "Povolit HEVC (H265)" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "Automaticky přihlašovat" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "Automatické přehrání po skončení" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "Povolit stahování titulků" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "Povolit stahování titulků" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "Objevení serveru (GDM)" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "Spustit plex při spuštění Kodi" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "IP připojení 1" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "Port připojení 1" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "IP připojení 2" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "Port připojení 2" + +msgctxt "#32048" +msgid "Audio" +msgstr "Audio" + +msgctxt "#32049" +msgid "Advanced" +msgstr "Rozšířené" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "Ruční servery" + +msgctxt "#32051" +msgid "Privacy" +msgstr "Soukromí" + +msgctxt "#32052" +msgid "About" +msgstr "O doplňku" + +msgctxt "#32053" +msgid "Video" +msgstr "Video" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "Verze doplňku" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Verze Kodi" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "Rozlišení obrazovky" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "Verze serveru" + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "Při spuštění přeskočit výběr uživatele a zadávání pinu." + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "Pokud povolíte, po zkončení přehrávání se automaticky přehraje položka ze seznamu 'Následující' po prodlevě 15 sekund." + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "Povolte pokud váš hardware zvládne přehrávat 4K videa. Zakázáním vynutíte překódování." + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "Povolte pokud váš hardware zvládne přehrávat formát HEVC/H265. Zakázáním vynutíte překódování." + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "Kdy se připojovat k serverům přes nezabezpečené připojení.[CR][CR]* [B]Nikdy[/B]: Nepoužívat nezabezpečená připojení[CR]* [B]Na stejné síti[/B]: Povolte pokud jste na stejné síti jako server[CR]* [B]Vždy[/B]: Povolí na stejné síti a při vzdálených připojeních" + +msgctxt "#32201" +msgid "Trailer" +msgstr "Ukázka" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "Smazaná scéna" + +msgctxt "#32203" +msgid "Interview" +msgstr "Rozhovor" + +msgctxt "#32204" +msgid "Music Video" +msgstr "Videoklip" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "Ze zákulisí" + +msgctxt "#32206" +msgid "Scene" +msgstr "Scéna" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "Živý videoklip" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "Videoklip s textem" + +msgctxt "#32209" +msgid "Concert" +msgstr "Koncert" + +msgctxt "#32210" +msgid "Featurette" +msgstr "" + +msgctxt "#32211" +msgid "Short" +msgstr "Krátký film" + +msgctxt "#32212" +msgid "Other" +msgstr "Jiný" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "Přejít na album" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "Přejít na interpreta" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "Přejít na {0}" + +msgctxt "#32303" +msgid "Season" +msgstr "Sezóna" + +msgctxt "#32304" +msgid "Episode" +msgstr "Epizoda" + +msgctxt "#32305" +msgid "Extras" +msgstr "Extra" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "Podobné seriály" + +msgctxt "#32307" +msgid "More" +msgstr "Více" + +msgctxt "#32308" +msgid "Available" +msgstr "K dispozici" + +msgctxt "#32309" +msgid "None" +msgstr "Žádné" + +msgctxt "#32310" +msgid "S" +msgstr "" + +msgctxt "#32311" +msgid "E" +msgstr "" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "Není k dispozici" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "Tato položka momentálně není k dispozici" + +msgctxt "#32314" +msgid "In Progress" +msgstr "Rozkoukané" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "Pokračovat v přehrávání?" + +msgctxt "#32316" +msgid "Resume" +msgstr "Pokračovat" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "Přehrát od začátku" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "Označit jako neshlédnuté" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "Označit jako shlédnuté" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "Označit sezónu jako neshlédnutou" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "Označit sezónu jako shlédnutou" + +msgctxt "#32322" +msgid "Delete" +msgstr "Smazat" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "Přejít na seriál" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "Přejít na {0}" + +msgctxt "#32325" +msgid "Play Next" +msgstr "Přehrát další" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "Opravdu smazat?" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "Opravdu chcete smazat tyto média?" + +msgctxt "#32328" +msgid "Yes" +msgstr "Ano" + +msgctxt "#32329" +msgid "No" +msgstr "Ne" + +msgctxt "#32330" +msgid "Message" +msgstr "Zpráva" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "Při mazání média se vyskytla chyba." + +msgctxt "#32332" +msgid "Home" +msgstr "Domů" + +msgctxt "#32333" +msgid "Playlists" +msgstr "Playlisty" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "Potvrdit odchod" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "Opravdu chcete odejít z Plexu?" + +msgctxt "#32336" +msgid "Exit" +msgstr "Odejít" + +msgctxt "#32337" +msgid "Cancel" +msgstr "Zrušit" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "Nenalezeny žádné servery" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "Server je nedostupný" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "Probíhají zkoušky připojení. Prosím počkejte." + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "Server je nedostupný. Prosím přihlašte se ke svému serveru a zkontrolujte připojení." + +msgctxt "#32342" +msgid "Switch User" +msgstr "Přepnout uživatele" + +msgctxt "#32343" +msgid "Settings" +msgstr "Nastavení" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "Odhlásit" + +msgctxt "#32345" +msgid "All" +msgstr "Všechno" + +msgctxt "#32346" +msgid "By Name" +msgstr "Podle názvu" + +msgctxt "#32347" +msgid "artists" +msgstr "interpreti" + +msgctxt "#32348" +msgid "movies" +msgstr "filmy" + +msgctxt "#32349" +msgid "photos" +msgstr "fotky" + +msgctxt "#32350" +msgid "shows" +msgstr "seriály" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "Podle data přidání" + +msgctxt "#32352" +msgid "Date Added" +msgstr "Datum přidání" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "Podle data vydání" + +msgctxt "#32354" +msgid "Release Date" +msgstr "Datum vydání" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "Podle data shlédnutí" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "Datum shlédnutí" + +msgctxt "#32357" +msgid "By Name" +msgstr "Podle názvu" + +msgctxt "#32358" +msgid "Name" +msgstr "Název" + +msgctxt "#32359" +msgid "By Rating" +msgstr "Podle hodnocení" + +msgctxt "#32360" +msgid "Rating" +msgstr "Hodnocení" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "Podle rozlišení" + +msgctxt "#32362" +msgid "Resolution" +msgstr "Rozlišení" + +msgctxt "#32363" +msgid "By Duration" +msgstr "Podle délky" + +msgctxt "#32364" +msgid "Duration" +msgstr "Délka" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "Podle prvního vysílání" + +msgctxt "#32366" +msgid "First Aired" +msgstr "První vysílání" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "Podle neshlédnutí" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "Neshlédnuté" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "Podle data přehrání" + +msgctxt "#32370" +msgid "Date Played" +msgstr "Datum přehrání" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "Podle počtu přehrání" + +msgctxt "#32372" +msgid "Play Count" +msgstr "Počet přehrání" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "Podle data pořízení" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "Datum pořízení" + +msgctxt "#32375" +msgid "No filters available" +msgstr "Filtry nejsou k dispozici" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "Odstranit filtr" + +msgctxt "#32377" +msgid "Year" +msgstr "Rok" + +msgctxt "#32378" +msgid "Decade" +msgstr "Desetiletí" + +msgctxt "#32379" +msgid "Genre" +msgstr "Žánr" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "Hodnocení obsahu" + +msgctxt "#32381" +msgid "Network" +msgstr "Stanice" + +msgctxt "#32382" +msgid "Collection" +msgstr "Kolekce" + +msgctxt "#32383" +msgid "Director" +msgstr "Režie" + +msgctxt "#32384" +msgid "Actor" +msgstr "Herci" + +msgctxt "#32385" +msgid "Country" +msgstr "Země" + +msgctxt "#32386" +msgid "Studio" +msgstr "Studio" + +msgctxt "#32387" +msgid "Labels" +msgstr "Popisky" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "Výrobce kamery" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "Model kamery" + +msgctxt "#32390" +msgid "Aperture" +msgstr "Clona" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "Rychlost závěrky" + +msgctxt "#32392" +msgid "Lens" +msgstr "Čočka" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "Seriály" + +msgctxt "#32394" +msgid "Music" +msgstr "Hudba" + +msgctxt "#32395" +msgid "Audio" +msgstr "Zvuková stopa" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "Titulky" + +msgctxt "#32397" +msgid "Quality" +msgstr "Kvalita" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "Video nastavení Kodi" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "Audio nastavení Kodi" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "Přejít na sezónu" + +msgctxt "#32401" +msgid "Directors" +msgstr "Režiséři" + +msgctxt "#32402" +msgid "Writer" +msgstr "Autor" + +msgctxt "#32403" +msgid "Writers" +msgstr "Autoři" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "Podobné filmy" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "Stáhnout titulky" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "Zpoždění titulků" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "Další titulky" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "Vypnout titulky" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "Zapnout titulky" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "Verze platformy" + +msgctxt "#32411" +msgid "Unknown" +msgstr "Neznámá" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "Upravit nebo smazat" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "Upravit IP adresu nebo smazat nastavení?" + +msgctxt "#32414" +msgid "Clear" +msgstr "Smazat" + +msgctxt "#32415" +msgid "Edit" +msgstr "Upravit" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "Zadejte IP adresu" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "Zadejte číslo portu" + +msgctxt "#32418" +msgid "Creator" +msgstr "Tvůrce" + +msgctxt "#32419" +msgid "Cast" +msgstr "Hrají" + +msgctxt "#32420" +msgid "Disc" +msgstr "Disk" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "Odhlásit" + +msgctxt "#32422" +msgid "Exit" +msgstr "Odejít" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "Vypnout" + +msgctxt "#32424" +msgid "Suspend" +msgstr "Uspat" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "Hibernovat" + +msgctxt "#32426" +msgid "Reboot" +msgstr "Restartovat" + +msgctxt "#32427" +msgid "Failed" +msgstr "Neuspělo" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "Přihlášení neuspělo!" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "Pokračovat od {0}" + +msgctxt "#32430" +msgid "Discovery" +msgstr "Objevit" + +msgctxt "#32431" +msgid "Search" +msgstr "Vyhledat" + +msgctxt "#32432" +msgid "Space" +msgstr "Mezera" + +msgctxt "#32433" +msgid "Clear" +msgstr "Smazat" + +msgctxt "#32434" +msgid "Searching..." +msgstr "Vyhledávám..." + +msgctxt "#32435" +msgid "No Results" +msgstr "Žádné výsledky" + +msgctxt "#32436" +msgid "Paused" +msgstr "Pozastaveno" + +msgctxt "#32437" +msgid "Welcome" +msgstr "Vítáme vás" + +msgctxt "#32438" +msgid "Previous" +msgstr "Předchozí" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "Přehrávám další" + +msgctxt "#32440" +msgid "On Deck" +msgstr "Aktuální" + +msgctxt "#32441" +msgid "Unknown" +msgstr "Neznámý" + +msgctxt "#32442" +msgid "Embedded" +msgstr "Vestavěné" + +msgctxt "#32443" +msgid "Forced" +msgstr "Vynucené" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "Text skladby" + +msgctxt "#32445" +msgid "Mono" +msgstr "Mono" + +msgctxt "#32446" +msgid "Stereo" +msgstr "Stereo" + +msgctxt "#32447" +msgid "None" +msgstr "Žádné" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "Přehrávání neuspělo!" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "Nemohu se připojit k plex.tv[CR]Zkontrolujte připojení k internetu a zkuste to znovu." + +msgctxt "#32450" +msgid "Choose Version" +msgstr "Zvolte verzi" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "Přehrávám verzi..." + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "V této knihovně není žádný obsah" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "Prosím přidejte obsah a nebo zkontrolujte, že je povolené nastavení 'přidat na nástěnku'." + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "Pro tento filtr není k dispozici žádný obsah" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "Prosím změňte nebo odstraňte filtr" + +msgctxt "#32456" +msgid "Offline Mode" +msgstr "Režim offline" + +msgctxt "#32457" +msgid "Sign In" +msgstr "Přihlásit" diff --git a/script.plexmod/resources/language/resource.language.de_de/strings.po b/script.plexmod/resources/language/resource.language.de_de/strings.po new file mode 100644 index 0000000000..b50c731b50 --- /dev/null +++ b/script.plexmod/resources/language/resource.language.de_de/strings.po @@ -0,0 +1,1946 @@ +msgid "" +msgstr "" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: POEditor.com\n" +"Project-Id-Version: PM4K\n" +"Language: de\n" + +#: +msgctxt "#32000" +msgid "Main" +msgstr "Allgemein" + +#: +msgctxt "#32001" +msgid "Original" +msgstr "Original" + +#: +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "20 Mbit/s 1080p" + +#: +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "12 Mbit/s 1080p" + +#: +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "10 Mbit/s 1080p" + +#: +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "8 Mbit/s 1080p" + +#: +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "4 Mbit/s 720p" + +#: +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "3 Mbit/s 720p" + +#: +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "2 Mbit/s 720p" + +#: +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "1.5 Mbit/s 480p" + +#: +msgctxt "#32010" +msgid "720 kbps" +msgstr "720 kbit/s" + +#: +msgctxt "#32011" +msgid "320 kbps" +msgstr "320 kbit/s" + +#: +msgctxt "#32012" +msgid "208 kbps" +msgstr "208 kbit/s" + +#: +msgctxt "#32013" +msgid "96 kbps" +msgstr "96 kbit/s" + +#: +msgctxt "#32014" +msgid "64 kbps" +msgstr "64 kbit/s" + +#: +msgctxt "#32020" +msgid "Local Quality" +msgstr "Qualität für lokale Geräte" + +#: +msgctxt "#32021" +msgid "Remote Quality" +msgstr "Qualität für entfernte Geräte" + +#: +msgctxt "#32022" +msgid "Online Quality" +msgstr "Online Qualität" + +#: +msgctxt "#32023" +msgid "Transcode Format" +msgstr "Transkodierungsformat" + +#: +msgctxt "#32024" +msgid "Debug Logging" +msgstr "Debug-Protokollierung" + +#: +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "Direkte Wiedergabe erlauben" + +#: +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "Direktes streamen erlauben" + +#: +msgctxt "#32027" +msgid "Force" +msgstr "Erzwingen" + +#: +msgctxt "#32028" +msgid "Always" +msgstr "Immer" + +#: +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "nur Bildformate" + +#: +msgctxt "#32030" +msgid "Auto" +msgstr "Automatisch" + +#: +msgctxt "#32031" +msgid "Burn-in Subtitles" +msgstr "Untertitel einbrennen" + +#: +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "Unsichere Verbindung erlauben" + +#: +msgctxt "#32033" +msgid "Never" +msgstr "Nie" + +#: +msgctxt "#32034" +msgid "On Same network" +msgstr "Im selben Netzwerk" + +#: +msgctxt "#32035" +msgid "Always" +msgstr "Immer" + +#: +msgctxt "#32036" +msgid "Allow 4K" +msgstr "4K erlauben" + +#: +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "HEVC erlauben (H265)" + +#: +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "Automatisch anmelden" + +#: +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "Automatisch nächsten Titel abspielen" + +#: +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "Untertitel download aktivieren" + +#: +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "Untertitel download aktivieren" + +#: +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "Server Erkennung (GDM)" + +#: +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "Plex mit Kodi starten" + +#: +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "Verbindung 1 IP" + +#: +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "Verbindung 1 Port" + +#: +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "Verbindung 2 IP" + +#: +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "Verbindung 2 Port" + +#: +msgctxt "#32048" +msgid "Audio" +msgstr "Ton" + +#: +msgctxt "#32049" +msgid "Advanced" +msgstr "Erweitert" + +#: +msgctxt "#32050" +msgid "Manual Servers" +msgstr "Manuelle Server" + +#: +msgctxt "#32051" +msgid "Privacy" +msgstr "Datenschutz" + +#: +msgctxt "#32052" +msgid "About" +msgstr "Über" + +#: +msgctxt "#32053" +msgid "Video" +msgstr "Video" + +#: +msgctxt "#32054" +msgid "Addon Version" +msgstr "Erweiterung Version" + +#: +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Kodi Version" + +#: +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "Bilschirmauflösung" + +#: +msgctxt "#32057" +msgid "Current Server Version" +msgstr "Aktuelle Server Version" + +#: +msgctxt "#32058" +msgid "Never exceed original audio codec" +msgstr "Niemals den ursprünglichen Audio-Codec überschreiten" + +#: +msgctxt "#32059" +msgid "When transcoding audio, never exceed the original audio bitrate or channel count on the same codec." +msgstr "Bei der Transkodierung von Audio niemals die ursprüngliche Audio-Bitrate oder die Anzahl der Kanäle mit demselben Codec überschreiten." + +#: +msgctxt "#32060" +msgid "Use Kodi audio channels" +msgstr "Kodi-Audiokanäle verwenden" + +#: +msgctxt "#32061" +msgid "When transcoding audio, target the audio channels set in Kodi." +msgstr "Beim Transkodieren von Audio werden die in Kodi eingestellten Audiokanäle verwendet." + +#: +msgctxt "#32062" +msgid "Transcode audio to AC3" +msgstr "Transkodiere Ton zu AC3" + +#: +msgctxt "#32063" +msgid "Transcode audio to AC3 in certain conditions (useful for passthrough)." +msgstr "Transkodiere Ton zu AC3 in bestimmten Umständen (nützlich für Passthrough)" + +#: +msgctxt "#32064" +msgid "Treat DTS like AC3" +msgstr "DTS wie AC3 behandeln" + +#: +msgctxt "#32065" +msgid "When any of the force AC3 settings are enabled, treat DTS the same as AC3 (useful for Optical passthrough)" +msgstr "Wenn einer der AC3 Optionen aktiviert ist, wird DTS wie AC3 behandelt (nützlich für Optical Passthrough)" + + +msgctxt "#32066" +msgid "Force audio to AC3" +msgstr "Audio immer als AC3 erzwingen" + + +msgctxt "#32067" +msgid "Only force multichannel audio to AC3" +msgstr "Nur Mehrkanal-Audio als AC3 erzwingen" + +#: +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "Benutzerauswahl und Pin-Eingabe beim Start überspringen." + +#: +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "Falls aktiviert wird, sofern verfügbar, nachdem die Wiedergabe endet ein 'nächster Titel' automatisch nach 15 Sekunden gestartet." + +#: +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "Aktiviert 4K Wiedergabe per Hardware. Deaktivierung erzwingt Transcodierung." + +#: +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "Aktiviert HEVC/H265 Wiedergabe per Hardware. Deaktivierung erzwingt Transcodierung." + +#: +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "Wann soll zu Servern ohne 'sichere Verbindung' verbunden werden[CR]* [B]Nie[/B]: Niemals unsicher zu eine Server verbinden.[CR]* [B]Im selben Netzwerk[/B]: Im selben Netzwerk erlauben[CR]* [B]Immer[/B]: Im selben Netzwerk und bei entfernter Verbindung erlauben" + +#: +msgctxt "#32201" +msgid "Trailer" +msgstr "Trailer" + +#: +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "Entfernte Szene" + +#: +msgctxt "#32203" +msgid "Interview" +msgstr "Interview" + +#: +msgctxt "#32204" +msgid "Music Video" +msgstr "Musik-Video" + +#: +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "Hinter den Kulissen" + +#: +msgctxt "#32206" +msgid "Scene" +msgstr "Szene" + +#: +msgctxt "#32207" +msgid "Live Music Video" +msgstr "Live Musikvideo" + +#: +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "Musikvideo mit Lyrics" + +#: +msgctxt "#32209" +msgid "Concert" +msgstr "Konzert" + +#: +msgctxt "#32210" +msgid "Featurette" +msgstr "Featurette" + +#: +msgctxt "#32211" +msgid "Short" +msgstr "Kurzfilm" + +#: +msgctxt "#32212" +msgid "Other" +msgstr "Sonstige" + +#: +msgctxt "#32300" +msgid "Go to Album" +msgstr "Gehe zu Album" + +#: +msgctxt "#32301" +msgid "Go to Artist" +msgstr "Gehe zu Künstler(in)" + +#: +msgctxt "#32302" +msgid "Go to {0}" +msgstr "Gehe zu {0}" + +#: +msgctxt "#32303" +msgid "Season" +msgstr "Staffel" + +#: +msgctxt "#32304" +msgid "Episode" +msgstr "Folge" + +#: +msgctxt "#32305" +msgid "Extras" +msgstr "Extras" + +#: +msgctxt "#32306" +msgid "Related Shows" +msgstr "Ähnliche Serien" + +#: +msgctxt "#32307" +msgid "More" +msgstr "Film" + +#: +msgctxt "#32308" +msgid "Available" +msgstr "Verfügbar" + +#: +msgctxt "#32309" +msgid "None" +msgstr "Ohne" + +#: +msgctxt "#32310" +msgid "S" +msgstr "S" + +#: +msgctxt "#32311" +msgid "E" +msgstr "E" + +#: +msgctxt "#32312" +msgid "Unavailable" +msgstr "Nicht verfügbar" + +#: +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "Dieser Eintrag ist aktuell nicht verfügbar." + +#: +msgctxt "#32314" +msgid "In Progress" +msgstr "in Bearbeitung" + +#: +msgctxt "#32315" +msgid "Resume playback?" +msgstr "Wiedergabe fortsetzen?" + +#: +msgctxt "#32316" +msgid "Resume" +msgstr "Fortsetzen" + +#: +msgctxt "#32317" +msgid "Play from beginning" +msgstr "Von vorne wiedergeben" + +#: +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "Als ungesehen markieren" + +#: +msgctxt "#32319" +msgid "Mark Played" +msgstr "Als gesehen markieren" + +#: +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "Staffel als ungesehen markieren" + +#: +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "Staffel als gesehen markieren" + +#: +msgctxt "#32322" +msgid "Delete" +msgstr "Löschen" + +#: +msgctxt "#32323" +msgid "Go To Show" +msgstr "Gehe zu Serie" + +#: +msgctxt "#32324" +msgid "Go To {0}" +msgstr "Gehe zu {0}" + +#: +msgctxt "#32325" +msgid "Play Next" +msgstr "Nächster Titel" + +#: +msgctxt "#32326" +msgid "Really Delete?" +msgstr "Wirklich löschen?" + +#: +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "Soll diese Mediandatei wirklich gelöscht werden?" + +#: +msgctxt "#32328" +msgid "Yes" +msgstr "Ja" + +#: +msgctxt "#32329" +msgid "No" +msgstr "Nein" + +#: +msgctxt "#32330" +msgid "Message" +msgstr "Nachricht" + +#: +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "Es gab einen Fehler beim Löschversuch dieser Mediendatei." + +#: +msgctxt "#32332" +msgid "Home" +msgstr "Start" + +#: +msgctxt "#32333" +msgid "Playlists" +msgstr "Wiedergabelisten" + +#: +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "Beenden bestätigen" + +#: +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "Bereit um Plex zu beenden?" + +#: +msgctxt "#32336" +msgid "Exit" +msgstr "Beenden" + +#: +msgctxt "#32337" +msgid "Cancel" +msgstr "Abbrechen" + +#: +msgctxt "#32338" +msgid "No Servers Found" +msgstr "Keine Server gefunden" + +#: +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "Server ist nicht erreichbar" + +#: +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "Verbindungstests laufen. Bitte warten." + +#: +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "Der Server ist nicht erreichbar. Bitte einloggen und Verbindung prüfen." + +#: +msgctxt "#32342" +msgid "Switch User" +msgstr "Benutzer wechseln" + +#: +msgctxt "#32343" +msgid "Settings" +msgstr "Einstellungen" + +#: +msgctxt "#32344" +msgid "Sign Out" +msgstr "Abmelden" + +#: +msgctxt "#32345" +msgid "All" +msgstr "Alle" + +#: +msgctxt "#32346" +msgid "By Name" +msgstr "Nach Name" + +#: +msgctxt "#32347" +msgid "Artists" +msgstr "Künstler" + +#: +msgctxt "#32348" +msgid "Movies" +msgstr "Filme" + +#: +msgctxt "#32349" +msgid "photos" +msgstr "Fotos" + +#: +msgctxt "#32350" +msgid "Shows" +msgstr "Serien" + +#: +msgctxt "#32351" +msgid "By Date Added" +msgstr "Nach 'Hinzugefügt am'" + +#: +msgctxt "#32352" +msgid "Date Added" +msgstr "Hinzugefügt am" + +#: +msgctxt "#32353" +msgid "By Release Date" +msgstr "Nach Erscheinungsdatum" + +#: +msgctxt "#32354" +msgid "Release Date" +msgstr "Erscheinungsdatum" + +#: +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "Nach 'Gesehen am'" + +#: +msgctxt "#32356" +msgid "Date Viewed" +msgstr "Gesehen am" + +#: +msgctxt "#32357" +msgid "By Name" +msgstr "Nach Name" + +#: +msgctxt "#32358" +msgid "Name" +msgstr "Name" + +#: +msgctxt "#32359" +msgid "By Rating" +msgstr "Nach Bewertung" + +#: +msgctxt "#32360" +msgid "Rating" +msgstr "Bewertung" + +#: +msgctxt "#32361" +msgid "By Resolution" +msgstr "Nach Auflösung" + +#: +msgctxt "#32362" +msgid "Resolution" +msgstr "Auflösung" + +#: +msgctxt "#32363" +msgid "By Duration" +msgstr "Nach Dauer" + +#: +msgctxt "#32364" +msgid "Duration" +msgstr "Dauer" + +#: +msgctxt "#32365" +msgid "By First Aired" +msgstr "Nach Erstausstrahlung" + +#: +msgctxt "#32366" +msgid "First Aired" +msgstr "Erstausstrahlung" + +#: +msgctxt "#32367" +msgid "By Unplayed" +msgstr "Nach Ungesehen" + +#: +msgctxt "#32368" +msgid "Unplayed" +msgstr "Ungesehen" + +#: +msgctxt "#32369" +msgid "By Date Played" +msgstr "Nach 'Abgespielt am'" + +#: +msgctxt "#32370" +msgid "Date Played" +msgstr "Abgespielt am" + +#: +msgctxt "#32371" +msgid "By Play Count" +msgstr "Nach Wiedergabe-Zähler" + +#: +msgctxt "#32372" +msgid "Play Count" +msgstr "Wiedergabe-Zähler" + +#: +msgctxt "#32373" +msgid "By Date Taken" +msgstr "Nach Aufnahmedatum" + +#: +msgctxt "#32374" +msgid "Date Taken" +msgstr "Aufnahmedatum" + +#: +msgctxt "#32375" +msgid "No filters available" +msgstr "Keine Filter verfügbar" + +#: +msgctxt "#32376" +msgid "Clear Filter" +msgstr "Filter bereinigen" + +#: +msgctxt "#32377" +msgid "Year" +msgstr "Jahr" + +#: +msgctxt "#32378" +msgid "Decade" +msgstr "Jahrzent" + +#: +msgctxt "#32379" +msgid "Genre" +msgstr "Genre" + +#: +msgctxt "#32380" +msgid "Content Rating" +msgstr "Jugendfreigabe" + +#: +msgctxt "#32381" +msgid "Network" +msgstr "Netzwerk" + +#: +msgctxt "#32382" +msgid "Collection" +msgstr "Sammlung" + +#: +msgctxt "#32383" +msgid "Director" +msgstr "Regisseur(in)" + +#: +msgctxt "#32384" +msgid "Actor" +msgstr "Schauspieler(in)" + +#: +msgctxt "#32385" +msgid "Country" +msgstr "Land" + +#: +msgctxt "#32386" +msgid "Studio" +msgstr "Studio" + +#: +msgctxt "#32387" +msgid "Labels" +msgstr "Labels" + +#: +msgctxt "#32388" +msgid "Camera Make" +msgstr "Kamerahersteller" + +#: +msgctxt "#32389" +msgid "Camera Model" +msgstr "Kameramodell" + +#: +msgctxt "#32390" +msgid "Aperture" +msgstr "Blendenöffnung" + +#: +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "Verschlusszeit" + +#: +msgctxt "#32392" +msgid "Lens" +msgstr "Linse" + +#: +msgctxt "#32393" +msgid "TV Shows" +msgstr "Fernsehserien" + +#: +msgctxt "#32394" +msgid "Music" +msgstr "Musik" + +#: +msgctxt "#32395" +msgid "Audio" +msgstr "Ton" + +#: +msgctxt "#32396" +msgid "Subtitles" +msgstr "Untertitel" + +#: +msgctxt "#32397" +msgid "Quality" +msgstr "Qualität" + +#: +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "Kodi Bild Einstellungen" + +#: +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "Kodi Ton Einstellungen" + +#: +msgctxt "#32400" +msgid "Go To Season" +msgstr "Gehe zu Staffel" + +#: +msgctxt "#32401" +msgid "Directors" +msgstr "Regisseure" + +#: +msgctxt "#32402" +msgid "Writer" +msgstr "Autor(in)" + +#: +msgctxt "#32403" +msgid "Writers" +msgstr "Autoren" + +#: +msgctxt "#32404" +msgid "Related Movies" +msgstr "Ähnliche Filme" + +#: +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "Untertitel downloaden" + +#: +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "Untertitel Verzögerung" + +#: +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "Nächster Untertitel" + +#: +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "Untertitel deaktiviren" + +#: +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "Untertitel aktivieren" + +#: +msgctxt "#32410" +msgid "Platform Version" +msgstr "Platform Version" + +#: +msgctxt "#32411" +msgid "Unknown" +msgstr "Unbekannt" + +#: +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "Bearbeiten oder bereinigen" + +#: +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "IP Adresse bearbeiten oder die aktuellen Einstellungen bereinigen?" + +#: +msgctxt "#32414" +msgid "Clear" +msgstr "Bereinigen" + +#: +msgctxt "#32415" +msgid "Edit" +msgstr "Ändern" + +#: +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "IP Adresse eingeben" + +#: +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "Port Nummer eingeben" + +#: +msgctxt "#32418" +msgid "Creator" +msgstr "Urheber(in)" + +#: +msgctxt "#32419" +msgid "Cast" +msgstr "Besetzung" + +#: +msgctxt "#32420" +msgid "Disc" +msgstr "Disk" + +#: +msgctxt "#32421" +msgid "Sign Out" +msgstr "Abmelden" + +#: +msgctxt "#32422" +msgid "Exit" +msgstr "Beenden" + +#: +msgctxt "#32423" +msgid "Shutdown" +msgstr "Herunterfahren" + +#: +msgctxt "#32424" +msgid "Suspend" +msgstr "Energie sparen" + +#: +msgctxt "#32425" +msgid "Hibernate" +msgstr "Ruhezustand" + +#: +msgctxt "#32426" +msgid "Reboot" +msgstr "Neustart" + +#: +msgctxt "#32427" +msgid "Failed" +msgstr "Fehlgeschlagen" + +#: +msgctxt "#32428" +msgid "Login failed!" +msgstr "Anmeldung fehlgeschlagen!" + +#: +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "Fortsetzen ab {0}" + +#: +msgctxt "#32430" +msgid "Discovery" +msgstr "Entdecken" + +#: +msgctxt "#32431" +msgid "Search" +msgstr "Suche" + +#: +msgctxt "#32432" +msgid "Space" +msgstr "Leerzeichen" + +#: +msgctxt "#32433" +msgid "Clear" +msgstr "Bereinigen" + +#: +msgctxt "#32434" +msgid "Searching..." +msgstr "Suche..." + +#: +msgctxt "#32435" +msgid "No Results" +msgstr "Keine Ergebnisse" + +#: +msgctxt "#32436" +msgid "Paused" +msgstr "Pausiert" + +#: +msgctxt "#32437" +msgid "Welcome" +msgstr "Willkommen" + +#: +msgctxt "#32438" +msgid "Previous" +msgstr "Vorheriger Titel" + +#: +msgctxt "#32439" +msgid "Playing Next" +msgstr "Nächster Titel" + +#: +msgctxt "#32440" +msgid "On Deck" +msgstr "Aktuell" + +#: +msgctxt "#32441" +msgid "Unknown" +msgstr "Unbekannt" + +#: +msgctxt "#32442" +msgid "Embedded" +msgstr "Eingebettet" + +#: +msgctxt "#32443" +msgid "Forced" +msgstr "Zwangsuntertitel" + +#: +msgctxt "#32444" +msgid "Lyrics" +msgstr "Lyrics" + +#: +msgctxt "#32445" +msgid "Mono" +msgstr "Mono" + +#: +msgctxt "#32446" +msgid "Stereo" +msgstr "Stereo" + +#: +msgctxt "#32447" +msgid "None" +msgstr "Nichts" + +#: +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "Wiedergabe fehlgeschlagen!" + +#: +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "Keine Verbindung zu plex.tv[CR]Internetverbindung prüfen und erneut versuchen." + +#: +msgctxt "#32450" +msgid "Choose Version" +msgstr "Version auswählen" + +#: +msgctxt "#32451" +msgid "Play Version..." +msgstr "Version abspielen..." + +#: +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "In dieser Bibliothek ist nichts vorhanden" + +#: +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "Bitte Inhalte ergänzen und/oder prüfen ob 'In Dashboard anzeigen' aktiv ist." + +#: +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "Mit diesem Filter ist kein Inhalt verfügbar" + +#: +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "Bitte aktuellen Filter ändern oder entfernen" + +#: +msgctxt "#32456" +msgid "Show" +msgstr "Serie" + +#: +msgctxt "#32457" +msgid "By Show" +msgstr "Nach Serie" + +#: +msgctxt "#32458" +msgid "Episodes" +msgstr "Episoden" + +#: +msgctxt "#32459" +msgid "Offline Mode" +msgstr "Offline-Modus" + +#: +msgctxt "#32460" +msgid "Sign In" +msgstr "Anmelden" + +#: +msgctxt "#32461" +msgid "Albums" +msgstr "Alben" + +#: +msgctxt "#32462" +msgid "Artist" +msgstr "Künstler(in)" + +#: +msgctxt "#32463" +msgid "By Artist" +msgstr "Nach Künstler(in)" + +#: +msgctxt "#32464" +msgid "Player" +msgstr "Wiedergabe" + +#: +msgctxt "#32465" +msgid "Use skip step settings from Kodi" +msgstr "Skip-Schritte-Einstellung von Kodi benutzen" + +#: +msgctxt "#32466" +msgid "Automatically seek selected position after a delay" +msgstr "Automatisch verzögert zur ausgewählten Position springen" + +#: +msgctxt "#32467" +msgid "User Interface" +msgstr "Benutzeroberfläche" + +#: +msgctxt "#32468" +msgid "Show dynamic background art" +msgstr "Dynamische Hintergrundbilder aktivieren" + +#: +msgctxt "#32469" +msgid "Background art blur amount" +msgstr "Unschärfe der Hintergrundbilder" + +#: +msgctxt "#32470" +msgid "Background art opacity" +msgstr "Deckkraft der Hintergrundbilder" + +#: +msgctxt "#32471" +msgid "Use Plex/Kodi steps for timeline" +msgstr "Plex/Kodi-Skip-Schritte für die Zeitachse verwenden" + +#: +msgctxt "#32480" +msgid "Theme music" +msgstr "Titelmusik" + +#: +msgctxt "#32481" +msgid "Off" +msgstr "Aus" + +#: +msgctxt "#32482" +msgid "%(percentage)s %%" +msgstr "%(percentage)s %%" + +#: +msgctxt "#32483" +msgid "Hide Stream Info" +msgstr "Stream Info nicht anzeigen" + +#: +msgctxt "#32484" +msgid "Show Stream Info" +msgstr "Stream Info anzeigen" + +#: +msgctxt "#32485" +msgid "Go back instantly with the previous menu action in scrolled views" +msgstr "Mit der Previous-Menu-Aktion In gescrollten Ansichten sofort zurückgehen" + +#: +msgctxt "#32487" +msgid "Seek Delay" +msgstr "Vorspulverzögerung" + +#: +msgctxt "#32488" +msgid "Screensaver" +msgstr "Bildschirmschoner" + +#: +msgctxt "#32489" +msgid "Quiz Mode" +msgstr "Quiz-Modus" + +#: +msgctxt "#32490" +msgid "Collections" +msgstr "Sammlungen" + +#: +msgctxt "#32491" +msgid "Folders" +msgstr "Ordner" + +#: +msgctxt "#32492" +msgid "Kodi Subtitle Settings" +msgstr "Kodi Untertitel-Einstellungen" + +#: +msgctxt "#32493" +msgid "When a media file has a forced/foreign subtitle for a subtitle-enabled language, the Plex Media Server preselects it. This behaviour is usually not necessary and not configurable. This setting fixes that by ignoring the PMSs decision and selecting the same language without a forced flag if possible." +msgstr "Hat eine Mediendatei erzwungenge Untertitel für eine Sprache, bei der Untertitel erwünscht sind, wählt der Plex Media Server diesen standardmäßig aus. Das Verhalten ist normalerweise unerwünscht und nicht konfigurierbar. Diese Einstellung behebt das Problem, indem versucht wird, einen Untertitel der selben Sprache ohne Erzwungen-Markierung zu wählen." + +#: +msgctxt "#32495" +msgid "Skip intro" +msgstr "Intro überspringen" + +#: +msgctxt "#32496" +msgid "Skip credits" +msgstr "Abspann überspringen" + +#: +msgctxt "#32500" +msgid "Always show post-play screen (even for short videos)" +msgstr "Immer den Nachwiedergabe-Bildschirm anzeigen (auch bei kurzen Videos)" + +#: +msgctxt "#32501" +msgid "Time-to-wait between videos on post-play" +msgstr "Wartezeit zwischen Videos bei Nachwiedergabe" + +#: +msgctxt "#32505" +msgid "Visit media in video playlist instead of playing it" +msgstr "Medien in der Video-Wiedergabeliste anzeigen, anstatt sie abzuspielen" + +#: +msgctxt "#32521" +msgid "Skip Intro Button Timeout" +msgstr "Zeitlimit für die Schaltfläche Intro überspringen" + +#: +msgctxt "#32522" +msgid "Automatically Skip Intro" +msgstr "Intro automatisch überspringen" + +#: +msgctxt "#32523" +msgid "Automatically skip intros if available." +msgstr "Automatisches Überspringen von Intros, falls vorhanden. Überschreibt aktivierten Binge-Modus nicht." + +#: +msgctxt "#32524" +msgid "Set how long the skip intro button shows for." +msgstr "Festlegen, wie lange die Schaltfläche zum Überspringen des Intros angezeigt werden soll." + +#: +msgctxt "#32525" +msgid "Skip Credits Button Timeout" +msgstr "Zeitlimit für die Schaltfläche Abspann überspringen" + +#: +msgctxt "#32526" +msgid "Automatically Skip Credits" +msgstr "Automatisches Überspringen von Abspann" + +#: +msgctxt "#32527" +msgid "Automatically skip credits if available." +msgstr "Automatisches Überspringen von Abspann, falls vorhanden. Überschreibt aktivierten Binge-Modus nicht." + +#: +msgctxt "#32528" +msgid "Set how long the skip credits button shows for." +msgstr "Festlegen, wie lange die Schaltfläche zum Überspringen des Abspann angezeigt werden soll." + +#: +msgctxt "#32540" +msgid "Show when the current video will end in player" +msgstr "Im Player anzeigen, wann das aktuelle Video endet" + +#: +msgctxt "#32541" +msgid "Shows time left and at which time the media will end." +msgstr "Zeigt im Player an, wann und zu welchem Zeitpunkt das aktuelle Video endet." + +#: +msgctxt "#32542" +msgid "Show \"Ends at\" label for the end-time as well" +msgstr "\"Endet um\"-Label für die Endzeit auch anzeigen" + +#: +msgctxt "#32543" +msgid "Ends at" +msgstr "Endet um" + +#: +msgctxt "#32601" +msgid "Allow AV1" +msgstr "AV1 zulassen" + +#: +msgctxt "#32602" +msgid "Enable this if your hardware can handle AV1. Disable it to force transcoding." +msgstr "Diese Option aktivieren, wenn die Hardware AV1 verarbeiten kann. Deaktivieren, um die Transkodierung zu erzwingen." + +#: +msgctxt "#33101" +msgid "By Audience Rating" +msgstr "Nach Zuschauerwertung" + +#: +msgctxt "#33102" +msgid "Audience Rating" +msgstr "Zuschauerwertung" + +#: +msgctxt "#33103" +msgid "By my Rating" +msgstr "Nach meiner Bewertung" + +#: +msgctxt "#33104" +msgid "My Rating" +msgstr "Meine Bewertung" + +#: +msgctxt "#33105" +msgid "By Content Rating" +msgstr "Nach Inhaltsbewertung" + +#: +msgctxt "#33106" +msgid "Content Rating" +msgstr "Inhaltsbewertung" + +#: +msgctxt "#33107" +msgid "By Critic Rating" +msgstr "Nach kritischer Bewertung" + +#: +msgctxt "#33108" +msgid "Critic Rating" +msgstr "Kritikerwertung" + +#: +msgctxt "#33200" +msgid "Background Color" +msgstr "Hintergrundfarbe" + +#: +msgctxt "#33201" +msgid "Specify solid Background Color instead of using media images" +msgstr "Hintergrundfarbe anstatt Bilder verwenden" + +#: +msgctxt "#33400" +msgid "Use old compatibility profile" +msgstr "Altes Kompatibilitätsprofil verwenden" + +#: +msgctxt "#33401" +msgid "Uses the Chrome client profile instead of the custom one. Might fix rare issues with 3D playback." +msgstr "Benutzt das alte Chrome Client-Profil anstatt des angepassten. Könnte seltene Fehler beim Abspielen von 3D-Inhalten verhindern." + +#: +msgctxt "#32348" +msgid "movies" +msgstr "Filme" + +#: +msgctxt "#32466" +msgid "Automatically seek to the selected timeline position after a second" +msgstr "Nach Verzögerung automatisch zur aktuell gewählten Position springen" + +msgctxt "#33501" +msgid "Video played threshold" +msgstr "Video-abgespielt-Grenzwert" + +msgctxt "#33502" +msgid "Set this to the same value as your Plex server (Settings>Library>Video played threshold) to avoid certain pitfalls, Default: 90 %" +msgstr "Auf dem selben wert wie im Plex server setzen (Einstellungen>Mediathek>Video played threshold) um bestimmte Fehler zu umgehen, Standardwert: 90 %" + +msgctxt "#33503" +msgid "Use alternative hubs refresh" +msgstr "Alternative Aktualisierung der Hubs" + +msgctxt "#33504" +msgid "Refreshes all hubs for all libraries after an item's watch-state has changed, instead of only those likely affected. Use this if you find a hub that doesn't update properly." +msgstr "Aktualisiert alle Hubs aller Bibliotheken, anstatt nur die, die möglicherweise zutreffend sind, nachdem sich der Abspielstatus eines Items geändert hat. Benutzen, wenn sich ein Hub nicht aktualisiert." + +msgctxt "#33505" +msgid "Show intro skip button early" +msgstr "Intro überspringen früher anzeigen" + +msgctxt "#33506" +msgid "Show the intro skip button from the start of a video with an intro marker. The auto-skipping setting applies." +msgstr "Zeige den Intro-Überspringen-Knopf von Anfang an. Die Automatische-Intro-Überspringen-Einstellung wird angewandt. Überschreibt aktivierten Binge-Modus nicht." + +msgctxt "#33507" +msgid "Enabled" +msgstr "Aktiviert" + +msgctxt "#33508" +msgid "Disabled" +msgstr "Deaktiviert" + +msgctxt "#33509" +msgid "Early intro skip threshold (default: < 60s/1m)" +msgstr "Frühes Intro-Überspringen Grenzwert (default: < 60s/1m)" + +msgctxt "#33510" +msgid "When showing the intro skip button early, only do so if the intro starts within the first X seconds." +msgstr "Wenn der Into-Überspringen-Knopf früher angezeigt werden soll, nur anzeigen, wenn das Intro innerhalb der ersten X Sekunden startet." + +msgctxt "#33600" +msgid "System" +msgstr "System" + +msgctxt "#33601" +msgid "Show video chapters" +msgstr "Video-Kapitel anzeigen" + +msgctxt "#33602" +msgid "If available, show video chapters from the video-file instead of the timeline-big-seek-steps." +msgstr "Wenn verfügbar, Video-Kapitel aus der Video-Datei anstatt der Zeitleiste-Big-Seek-Schritte anzeigen." + +msgctxt "#33603" +msgid "Use virtual chapters" +msgstr "Virtuelle Kapitel verwenden" + +msgctxt "#33604" +msgid "When the above is enabled and no video chapters are available, simulate them by using the markers identified by the Plex Server (Intro, Credits)." +msgstr "Wenn die obrige aktiviert ist und keine Video-Kapitel verfügbar sind, virtuelle Kapitel aus den Plex Server Markern (Intro, Abspann) erzeugen." + +msgctxt "#33605" +msgid "Video Chapters" +msgstr "Video-Kapitel" + +msgctxt "#33606" +msgid "Virtual Chapters" +msgstr "Virtuelle Kapitel" + +msgctxt "#33607" +msgid "Chapter {}" +msgstr "Kapitel {}" + +msgctxt "#33608" +msgid "Intro" +msgstr "Intro" + +msgctxt "#33609" +msgid "Credits" +msgstr "Abspann" + +msgctxt "#33610" +msgid "Main" +msgstr "Haupt" + +msgctxt "#33611" +msgid "Chapters" +msgstr "Kapitel" + +msgctxt "#33612" +msgid "Markers" +msgstr "Markierungen" + +msgctxt "#33613" +msgid "Kodi Buffer Size (MB)" +msgstr "Kodi Puffergröße (MB)" + +msgctxt "#33614" +msgid "Set the Kodi Cache/Buffer size. Free: {} MB, Recommended: ~100 MB, Recommended max: {} MB, Default: 20 MB." +msgstr "Setzt die Kodi Cache/Puffer Größe. Frei: {} MB, empfohlen: ~100 MB, empfohlenes Max.: {} MB, Default: 20 MB." + +msgctxt "#33615" +msgid "{time} left" +msgstr "{time} übrig" + +msgctxt "#33616" +msgid "Addon Path" +msgstr "Addon-Pfad" + +msgctxt "#33617" +msgid "Userdata/Profile Path" +msgstr "Benutzerdaten-/Profilpfad" + +msgctxt "#33618" +msgid "TV binge-viewing mode" +msgstr "TV Binge-Viewing-Modus" + +msgctxt "#33619" +msgid "Automatically skips episode intros, credits and tries to skip episode recaps. Doesn\'t skip the intro of the first episode of a season.\n\nCan be disabled/enabled per TV show." +msgstr "Überspringt automatisch Intros und Abspänne von Episoden und versucht Recaps zu vermeiden. Überspringt das Intro der ersten Episode einer Staffel nicht." + +msgctxt "#33620" +msgid "Plex requests timeout (seconds)" +msgstr "Plex HTTP Zeitlimit (Sekunden)" + +msgctxt "#33621" +msgid "Set the (async and connection) timeout value of the Python requests library in seconds. Default: 5 seconds" +msgstr "Setzt das Zeitlimit für die Python Requests Bibliothek bei asynchronen Verbindungen und Verbindungsanfragen. Default: 5 Sekunden" + +msgctxt "#33622" +msgid "LAN reachability timeout (ms)" +msgstr "LAN-Erreichbarkeits-Zeitlimit (ms)" + +msgctxt "#33623" +msgid "When checking for Server-in-LAN reachability, use this timeout. Default: 10ms" +msgstr "Wenn die lokale Serververbindung im LAN überprüft wird, benutze dieses Zeitlimit. Default: 10ms" + +msgctxt "#33624" +msgid "Network" +msgstr "Netzwerk" + +msgctxt "#33625" +msgid "Smart LAN/local server discovery" +msgstr "Smartes LAN/lokale Server-Auffinden" + +msgctxt "#33626" +msgid "Checks whether servers returned from Plex.tv are actually local/in your LAN. For specific setups (e.g. Docker) Plex.tv might not properly detect a local server.\n\nNOTE: Only works on Kodi 19 or above." +msgstr "Überprüft, ob von Plex.tv zurückgegebene Server tatsächlich lokal/in Deinem LAN sind. Für bestimmte Setups (z. B. Docker) könnte Plex.tv einen lokalen Servern nicht als solchen entdecken.\n\nACHTUNG: Funktioniert nur unter Kodi 19 oder neuer." + +msgctxt "#33627" +msgid "Prefer LAN/local servers over security" +msgstr "LAN/lokale Server bevorzugen" + +msgctxt "#33628" +msgid "Prioritizes local connections over secure ones. Needs the proper setting in \"Allow Insecure Connections\" and the Plex Server's \"Secure connections\" at \"Preferred\". Can be used to enforce manual servers." +msgstr "Priorisiert lokale Verbindungen über sichere. Benötigt die korrekte Einstellung in \"Unsichere Verbindung erlauben\" und die Plex Server Einstellung \"Sichere Verbindungen\" auf \"Bevorzugt\". Kann verwendet werden um manuelle Server zu forcieren." + +msgctxt "#33629" +msgid "Auto-skip intro/credits offset" +msgstr "Auto-Überspringen-Versatz" + +msgctxt "#33630" +msgid "Intro/credits markers might be a little early in Plex. When auto skipping add (or subtract) this many seconds from the marker. This avoids cutting off content, while possibly skipping the marker a little late." +msgstr "Intro-/Abspann-Markierungen können ein wenig früh erscheinen in Plex. Wenn diese automatisch übersprungen werden sollen, addiere (oder subtrahiere) diese Menge an Sekunden. Das verhindert das verfrühte Abschneiden von Inhalten, kann aber zu etwas verspätetem Springen führen." + +msgctxt "#32631" +msgid "Playback (user-specific)" +msgstr "Wiedergabe (benutzerspezifisch)" + +msgctxt "#33632" +msgid "Server connectivity check timeout (seconds)" +msgstr "Server Konnektivitätscheck-Timeout (Sekunden)" + +msgctxt "#33633" +msgid "Set the maximum amount of time a server connection has to answer a connectivity request. Default: 2.5" +msgstr "Setzt die maximale Zeit, in der eine Serververbindung antworten muss. Voreinstellung: 2.5" + +msgctxt "#33634" +msgid "Combined Chapters" +msgstr "Kombinierte Kapitel" + +msgctxt "#33635" +msgid "Final Credits" +msgstr "Finaler Abspann" + +msgctxt "#32700" +msgid "Action on Sleep event" +msgstr "Aktion bei Sleep-Ereignis" + +msgctxt "#32701" +msgid "When Kodi receives a sleep event from the system, run the following action." +msgstr "Wenn Kodi ein Sleep-Ereignis vom System erhält, folgende Aktion ausführen." + +msgctxt "#32702" +msgid "Nothing" +msgstr "Nichts" + +msgctxt "#32703" +msgid "Stop playback" +msgstr "Abspielen stoppen" + +msgctxt "#32704" +msgid "Quit Kodi" +msgstr "Kodi beenden" + +msgctxt "#32705" +msgid "CEC Standby" +msgstr "CEC Standby" + +msgctxt "#32800" +msgid "Skipping intro" +msgstr "Überspringe Intro" + +msgctxt "#32801" +msgid "Skipping credits" +msgstr "Überspringe Abspann" + +msgctxt "#32900" +msgid "While playing back an item and seeking on the seekbar, automatically seek to the selected position after a delay instead of having to confirm the selection." +msgstr "Wird während des Abspielens die Position auf der Zeitleiste verändert, automatisch nach einer Verzögerung auf die gewählte Position springen, ohne diese bestätigen zu müssen." + +msgctxt "#32901" +msgid "Seek delay in seconds." +msgstr "Sprungverzögerung in Sekunden." + +msgctxt "#32902" +msgid "Kodi has its own skip step settings. Try to use them if they're configured instead of the default ones." +msgstr "Kodi besitzt seine eigenen Sprungeinstellungen. Versuche diese anstatt der standardmäßigen zu verwenden, sollten sie konfiguriert sein." + +msgctxt "#32903" +msgid "Use the above for seeking on the timeline as well." +msgstr "Benutze die obrige Einstellung auch für die Zeitleiste." + +msgctxt "#32904" +msgid "In seconds." +msgstr "In Sekunden." + +msgctxt "#32905" +msgid "Cancel post-play timer by pressing OK/SELECT" +msgstr "Post-Play Timer durch OK/AUSWAHL abbrechen" + +msgctxt "#32906" +msgid "Cancel skip marker timer with BACK" +msgstr "Markierung überspringen durch Zurück-Taste abbrechen" + +msgctxt "#32907" +msgid "When auto-skipping a marker, allow cancelling the timer by pressing BACK." +msgstr "Wenn eine Markierung mit einem Zeitgeber automatisch übersprungen wird, durch Zurück-Taste abbrechen." + +msgctxt "#32908" +msgid "Immediately skip marker with OK/SELECT" +msgstr "Markierung sofort überspringen mit OK/AUSWAHL" + +msgctxt "#32909" +msgid "When auto-skipping a marker with a timer, allow skipping immediately by pressing OK/SELECT." +msgstr "Wenn eine Markierung mit einem Zeitgeber automatisch übersprungen wird, durch OK/AUSWAHL-Taste sofort überspringen." + +msgctxt "#32912" +msgid "Show buffer-state on timeline" +msgstr "Zeige Puffer-Stand auf Zeitachse" + +msgctxt "#32913" +msgid "Shows the current Kodi buffer/cache state on the video player timeline." +msgstr "Zeigt den aktuellen Kodi Puffer/Cache-Stand auf der Videoplayer Zeitachse." + +msgctxt "#32914" +msgid "Loading" +msgstr "Lädt" + +msgctxt "#32915" +msgid "Slow connection" +msgstr "Langsame Verbindung" + +msgctxt "#32916" +msgid "Use with a wonky/slow connection, e.g. in a hotel room. Adjusts the UI to visually wait for item refreshes and waits for the buffer to fill when starting playback. Automatically sets readfactor=20, requires Kodi restart." +msgstr "Bei langsamer Verbindung benutzen, z.B. im Hotel. Passt die Oberfläche visuell an um auf Media Auffrischungen zu warten und füllt den Kodi Puffer vor dem Abspielen. Setzt automatisch Kodi Cache readfactor=20, benötigt einen Kodi Neustart." + +msgctxt "#32917" +msgid "Couldn't fill buffer in time ({}s)" +msgstr "Konnte den Puffer nicht schnell genug füllen ({} Sek.)" + +msgctxt "#32918" +msgid "Buffer wait timeout (seconds)" +msgstr "Puffer-Wartezeit (Sekunden)" + +msgctxt "#32919" +msgid "When slow connection is enabled in the addon, wait this long for the buffer to fill. Default: 120 s" +msgstr "Wenn Langsame Verbindung im Addon aktiviert ist, warte so lange bis der Puffer gefüllt ist. Voreinstellung: 120 Sek." + +msgctxt "#32920" +msgid "Insufficient buffer wait (seconds)" +msgstr "Ungenügender Puffer Wartezeit (Sekunden)" + +msgctxt "#32921" +msgid "When slow connection is enabled in the addon and the configured cache/buffer isn't big enough for us to determine its fill state, wait this long when starting playback. Default: 10 s" +msgstr "Wenn \"Langsame Verbindung\" im Addon aktiviert ist und der konfigurierte Puffer/Cache nicht groß genug ist, um seinen Füllstand zu ermitteln, wird so lange gewartet, bevor die Wiedergabe gestartet wird. Voreinstellung: 10 Sek." + +msgctxt "#32922" +msgid "Kodi Cache Readfactor" +msgstr "Kodi Puffer Readfactor" + +msgctxt "#32923" +msgid "Sets the Kodi cache readfactor value. Default: {0}, recommended: {1}. With \"Slow connection\" enabled this will be set to {2}, as otherwise the cache doesn't fill fast/aggressively enough." +msgstr "Setzt den Kodi Cache/Puffer readfactor Wert. Standard: {0}, Empfohlen: {1}. Bei aktivem \"Langsame Verbindung\" wird dies automatisch auf {2} gesetzt, da ansonsten der Cache nicht schnell/agressiv genug gefüllt wird." + +msgctxt "#32924" +msgid "Minimize" +msgstr "Minimieren" + +msgctxt "#32925" +msgid "Playback Settings" +msgstr "Abspieleinstell." + +msgctxt "#32926" +msgid "Wrong pin entered!" +msgstr "Falsche PIN eingegeben!" + +msgctxt "#32927" +msgid "Use episode thumbnails in continue hub" +msgstr "Vorschaubild für Episoden im Fortsetzen-Hub verwenden" + +msgctxt "#32928" +msgid "Instead of using media artwork, use thumbnails for episodes in the continue hub on the home screen if available." +msgstr "Verwende Vorschaubilder anstatt Media-Artwork für Episoden im Fortsetzen-Hub auf der Start-Ansicht." + +msgctxt "#32929" +msgid "Use legacy background fallback image" +msgstr "Veraltetes Ausweich-Hintergrundbild verwenden" + +msgctxt "#32930" +msgid "Previous Subtitle" +msgstr "Vorheriger Untertitel" + +msgctxt "#32931" +msgid "Audio/Subtitles" +msgstr "Audio/Untertitel" + +msgctxt "#32932" +msgid "Show subtitle quick-actions button" +msgstr "Zeige Untertitel-Schnellaktionen-Knopf" + +msgctxt "#32933" +msgid "Show FFWD/RWD buttons" +msgstr "Zeige Vorspulen-Zurückspulen-Knopf" + +msgctxt "#32934" +msgid "Show repeat button" +msgstr "Zeige Wiederholen-Knopf" + +msgctxt "#32935" +msgid "Show shuffle button" +msgstr "Zeige Zufällige-Wiedergabe-Knopf" + +msgctxt "#32936" +msgid "Show playlist button" +msgstr "Zeige Wiedergabeliste-Knopf" + +msgctxt "#32937" +msgid "Show prev/next button" +msgstr "Zeige Vorheriger/Nächster-Knopf" + +msgctxt "#32938" +msgid "Only for Episodes" +msgstr "Nur bei Episoden" + +msgctxt "#32939" +msgid "Only applies to video player UI" +msgstr "Gilt nur für die Video Abspieloberfläche" + +msgctxt "#32940" +msgid "Player UI" +msgstr "Abspieloberfläche" + +msgctxt "#32941" +msgid "Forced subtitles fix" +msgstr "Erzwungene Untertitel beheben" + +msgctxt "#32942" +msgid "Other seasons" +msgstr "Weitere Staffeln" + +msgctxt "#32943" +msgid "Crossfade dynamic background art" +msgstr "Dynamische Hintergrundbilder überblenden" + +msgctxt "#32944" +msgid "Burn-in SSA subtitles (DirectStream)" +msgstr "SSA-Untertitel einbrennen (DirectStream)" + +msgctxt "#32945" +msgid "When Direct Streaming instruct the Plex Server to burn in SSA/ASS subtitles (thus transcoding the video stream). If disabled it will not touch the video stream, but will convert the subtitle to unstyled text." +msgstr "Wird Direct Streaming verwendet, den Plex Server dazu bringen, SSA/ASS-Untertitel einzubrennen (also den Video Stream zu transcoden). Wenn deaktiviert, wird dieser den Video Stream nicht anfassen, jedoch den Untertitel als reinen Text anzeigen." + +msgctxt "#32946" +msgid "Stop video playback on idle after" +msgstr "Bei Inaktivität Video stoppen nach" + +msgctxt "#32947" +msgid "Stop video playback on screensaver" +msgstr "Video stoppen bei Bildschirmschoner" + +msgctxt "#32948" +msgid "Allow auto-skip when transcoding" +msgstr "Überspringen beim Transkodieren erlauben" + +msgctxt "#32949" +msgid "When transcoding/DirectStreaming, allow auto-skip functionality." +msgstr "Beim Transkodieren/DirectStream die automatische Überspringen-Funktionalität erlauben." + +msgctxt "#32950" +msgid "Use extended title for subtitles" +msgstr "Erweiterten Titel für Untertitel verwenden" + +msgctxt "#32951" +msgid "When displaying subtitles use the extendedDisplayTitle Plex exposes." +msgstr "Verwende erweiterte Namen wenn Untertitelnamen angezeigt werden." + +msgctxt "#32952" +msgid "Dialog-Flackern beheben" +msgstr "" + +msgctxt "#32953" +msgid "Reviews" +msgstr "Kritik" + +msgctxt "#32954" +msgid "Needs Kodi restart. WARNING: This will overwrite advancedsettings.xml!\n\nTo customize other cache/network-related values, copy \"script.plexmod/pm4k_cache_template.xml\" to profile folder and edit it to your liking. (See About section for the file paths)" +msgstr "Benötigt Kodi Neustart. ACHTUNG: Überschreibt advancedsettings.xml!\n\nUm weitere Cache-/Netzwerkbezogene Werte zu ändern, kopiere \"script.plexmod/pm4k_cache_template.xml\" in den Profilordner und editiere sie. (Für die Dateipfade schaue in die Über-Sektion)" + +msgctxt "#32955" +msgid "Use Kodi keyboard for searching" +msgstr "Kodi-Tastatur bei der Suche verwenden" + +msgctxt "#32956" +msgid "Poster resolution scaling %" +msgstr "Poster Auflösungsskalierung %" + +msgctxt "#32957" +msgid "In percent. Scales the resolution of all posters/thumbnails for better image quality. May impact PMS/PM4K performance, will increase the cache usage accordingly. Recommended: 200-300 % for big screens if your hardware can handle it. Needs addon restart." +msgstr "In Prozent. Skaliert die Auflösung aller Poster/Vorschaubilder für bessere Bildqualität. Kann die PMS/PM4K Performance beeinflussen, wird die Cache-Nutzung dementsprechend erhöhen. Empfohlen: 200-300 % für große Bildschirme, wenn die Hardware damit umgehen kann. Benötigt Addon-Neustart." + +msgctxt "#32958" +msgid "Calculate OpenSubtitles.com hash" +msgstr "OpenSubtitles.com Prüfsumme berechnen" + +msgctxt "#32959" +msgid "When opening the subtitle download feature, automatically calculate the OpenSubtitles.com hash for the given file. Can improve search results, downloads 2*64 KB of the video file to calculate the hash." +msgstr "Beim Öffnen der Untertitel-Herunterladen-Funktion die Prüfsumme der Datei für OpenSubtitles.com automatisch berechnen. Kann die Suchergebnisse verbessern, lädt 2*64 KB der Videodatei herunter um die Prüfsumme zu berechnen." diff --git a/script.plexmod/resources/language/resource.language.en_gb/strings.po b/script.plexmod/resources/language/resource.language.en_gb/strings.po new file mode 100644 index 0000000000..62f5ebd930 --- /dev/null +++ b/script.plexmod/resources/language/resource.language.en_gb/strings.po @@ -0,0 +1,1647 @@ +# XBMC Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2013-12-12 22:56+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +msgctxt "#32000" +msgid "Main" +msgstr "" + +msgctxt "#32001" +msgid "Original" +msgstr "" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "" + +msgctxt "#32027" +msgid "Force" +msgstr "" + +msgctxt "#32028" +msgid "Always" +msgstr "" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "" + +msgctxt "#32030" +msgid "Auto" +msgstr "" + +msgctxt "#32031" +msgid "Burn-in Subtitles" +msgstr "" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "" + +msgctxt "#32033" +msgid "Never" +msgstr "" + +msgctxt "#32034" +msgid "On Same network" +msgstr "" + +msgctxt "#32035" +msgid "Always" +msgstr "" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "" + +msgctxt "#32048" +msgid "Audio" +msgstr "" + +msgctxt "#32049" +msgid "Advanced" +msgstr "" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "" + +msgctxt "#32051" +msgid "Privacy" +msgstr "" + +msgctxt "#32052" +msgid "About" +msgstr "" + +msgctxt "#32053" +msgid "Video" +msgstr "" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "" + +msgctxt "#32058" +msgid "Never exceed original audio codec" +msgstr "" + +msgctxt "#32059" +msgid "When transcoding audio, never exceed the original audio bitrate or channel count on the same codec." +msgstr "" + +msgctxt "#32060" +msgid "Use Kodi audio channels" +msgstr "" + +msgctxt "#32061" +msgid "When transcoding audio, target the audio channels set in Kodi." +msgstr "" + +msgctxt "#32062" +msgid "Transcode audio to AC3" +msgstr "" + +msgctxt "#32063" +msgid "Transcode audio to AC3 in certain conditions (useful for passthrough)." +msgstr "" + +msgctxt "#32064" +msgid "Treat DTS like AC3" +msgstr "" + +msgctxt "#32065" +msgid "When any of the force AC3 settings are enabled, treat DTS the same as AC3 (useful for Optical passthrough)" +msgstr "" + +msgctxt "#32066" +msgid "Force audio to AC3" +msgstr "" + +msgctxt "#32067" +msgid "Only force multichannel audio to AC3" +msgstr "" + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "" + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "" + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "" + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "" + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "" + +msgctxt "#32201" +msgid "Trailer" +msgstr "" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "" + +msgctxt "#32203" +msgid "Interview" +msgstr "" + +msgctxt "#32204" +msgid "Music Video" +msgstr "" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "" + +msgctxt "#32206" +msgid "Scene" +msgstr "" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "" + +msgctxt "#32209" +msgid "Concert" +msgstr "" + +msgctxt "#32210" +msgid "Featurette" +msgstr "" + +msgctxt "#32211" +msgid "Short" +msgstr "" + +msgctxt "#32212" +msgid "Other" +msgstr "" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "" + +msgctxt "#32303" +msgid "Season" +msgstr "" + +msgctxt "#32304" +msgid "Episode" +msgstr "" + +msgctxt "#32305" +msgid "Extras" +msgstr "" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "" + +msgctxt "#32307" +msgid "More" +msgstr "" + +msgctxt "#32308" +msgid "Available" +msgstr "" + +msgctxt "#32309" +msgid "None" +msgstr "" + +msgctxt "#32310" +msgid "S" +msgstr "" + +msgctxt "#32311" +msgid "E" +msgstr "" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "" + +msgctxt "#32314" +msgid "In Progress" +msgstr "" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "" + +msgctxt "#32316" +msgid "Resume" +msgstr "" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "" + +msgctxt "#32322" +msgid "Delete" +msgstr "" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "" + +msgctxt "#32325" +msgid "Play Next" +msgstr "" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "" + +msgctxt "#32328" +msgid "Yes" +msgstr "" + +msgctxt "#32329" +msgid "No" +msgstr "" + +msgctxt "#32330" +msgid "Message" +msgstr "" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "" + +msgctxt "#32332" +msgid "Home" +msgstr "" + +msgctxt "#32333" +msgid "Playlists" +msgstr "" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "" + +msgctxt "#32336" +msgid "Exit" +msgstr "" + +msgctxt "#32337" +msgid "Cancel" +msgstr "" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "" + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "" + +msgctxt "#32342" +msgid "Switch User" +msgstr "" + +msgctxt "#32343" +msgid "Settings" +msgstr "" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "" + +msgctxt "#32345" +msgid "All" +msgstr "" + +msgctxt "#32346" +msgid "By Name" +msgstr "" + +msgctxt "#32347" +msgid "Artists" +msgstr "" + +msgctxt "#32348" +msgid "Movies" +msgstr "" + +msgctxt "#32349" +msgid "photos" +msgstr "" + +msgctxt "#32350" +msgid "Shows" +msgstr "" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "" + +msgctxt "#32352" +msgid "Date Added" +msgstr "" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "" + +msgctxt "#32354" +msgid "Release Date" +msgstr "" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "" + +msgctxt "#32357" +msgid "By Name" +msgstr "" + +msgctxt "#32358" +msgid "Name" +msgstr "" + +msgctxt "#32359" +msgid "By Rating" +msgstr "" + +msgctxt "#32360" +msgid "Rating" +msgstr "" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "" + +msgctxt "#32362" +msgid "Resolution" +msgstr "" + +msgctxt "#32363" +msgid "By Duration" +msgstr "" + +msgctxt "#32364" +msgid "Duration" +msgstr "" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "" + +msgctxt "#32366" +msgid "First Aired" +msgstr "" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "" + +msgctxt "#32370" +msgid "Date Played" +msgstr "" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "" + +msgctxt "#32372" +msgid "Play Count" +msgstr "" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "" + +msgctxt "#32375" +msgid "No filters available" +msgstr "" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "" + +msgctxt "#32377" +msgid "Year" +msgstr "" + +msgctxt "#32378" +msgid "Decade" +msgstr "" + +msgctxt "#32379" +msgid "Genre" +msgstr "" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "" + +msgctxt "#32381" +msgid "Network" +msgstr "" + +msgctxt "#32382" +msgid "Collection" +msgstr "" + +msgctxt "#32383" +msgid "Director" +msgstr "" + +msgctxt "#32384" +msgid "Actor" +msgstr "" + +msgctxt "#32385" +msgid "Country" +msgstr "" + +msgctxt "#32386" +msgid "Studio" +msgstr "" + +msgctxt "#32387" +msgid "Labels" +msgstr "" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "" + +msgctxt "#32390" +msgid "Aperture" +msgstr "" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "" + +msgctxt "#32392" +msgid "Lens" +msgstr "" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "" + +msgctxt "#32394" +msgid "Music" +msgstr "" + +msgctxt "#32395" +msgid "Audio" +msgstr "" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "" + +msgctxt "#32397" +msgid "Quality" +msgstr "" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "" + +msgctxt "#32401" +msgid "Directors" +msgstr "" + +msgctxt "#32402" +msgid "Writer" +msgstr "" + +msgctxt "#32403" +msgid "Writers" +msgstr "" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "" + +msgctxt "#32411" +msgid "Unknown" +msgstr "" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "" + +msgctxt "#32414" +msgid "Clear" +msgstr "" + +msgctxt "#32415" +msgid "Edit" +msgstr "" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "" + +msgctxt "#32418" +msgid "Creator" +msgstr "" + +msgctxt "#32419" +msgid "Cast" +msgstr "" + +msgctxt "#32420" +msgid "Disc" +msgstr "" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "" + +msgctxt "#32422" +msgid "Exit" +msgstr "" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "" + +msgctxt "#32424" +msgid "Suspend" +msgstr "" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "" + +msgctxt "#32426" +msgid "Reboot" +msgstr "" + +msgctxt "#32427" +msgid "Failed" +msgstr "" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "" + +msgctxt "#32430" +msgid "Discovery" +msgstr "" + +msgctxt "#32431" +msgid "Search" +msgstr "" + +msgctxt "#32432" +msgid "Space" +msgstr "" + +msgctxt "#32433" +msgid "Clear" +msgstr "" + +msgctxt "#32434" +msgid "Searching..." +msgstr "" + +msgctxt "#32435" +msgid "No Results" +msgstr "" + +msgctxt "#32436" +msgid "Paused" +msgstr "" + +msgctxt "#32437" +msgid "Welcome" +msgstr "" + +msgctxt "#32438" +msgid "Previous" +msgstr "" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "" + +msgctxt "#32440" +msgid "On Deck" +msgstr "" + +msgctxt "#32441" +msgid "Unknown" +msgstr "" + +msgctxt "#32442" +msgid "Embedded" +msgstr "" + +msgctxt "#32443" +msgid "Forced" +msgstr "" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "" + +msgctxt "#32445" +msgid "Mono" +msgstr "" + +msgctxt "#32446" +msgid "Stereo" +msgstr "" + +msgctxt "#32447" +msgid "None" +msgstr "" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "" + +msgctxt "#32450" +msgid "Choose Version" +msgstr "" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "" + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "" + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "" + +msgctxt "#32456" +msgid "Show" +msgstr "" + +msgctxt "#32457" +msgid "By Show" +msgstr "" + +msgctxt "#32458" +msgid "Episodes" +msgstr "" + +msgctxt "#32459" +msgid "Offline Mode" +msgstr "" + +msgctxt "#32460" +msgid "Sign In" +msgstr "" + +msgctxt "#32461" +msgid "Albums" +msgstr "" + +msgctxt "#32462" +msgid "Artist" +msgstr "" + +msgctxt "#32463" +msgid "By Artist" +msgstr "" + +msgctxt "#32464" +msgid "Player" +msgstr "" + +msgctxt "#32465" +msgid "Use skip step settings from Kodi" +msgstr "" + +msgctxt "#32466" +msgid "Automatically seek selected position after a delay" +msgstr "" + +msgctxt "#32467" +msgid "User Interface" +msgstr "" + +msgctxt "#32468" +msgid "Show dynamic background art" +msgstr "" + +msgctxt "#32469" +msgid "Background art blur amount" +msgstr "" + +msgctxt "#32470" +msgid "Background art opacity" +msgstr "" + +msgctxt "#32471" +msgid "Use Plex/Kodi steps for timeline" +msgstr "" + +msgctxt "#32480" +msgid "Theme music" +msgstr "" + +msgctxt "#32481" +msgid "Off" +msgstr "" + +msgctxt "#32482" +msgid "%(percentage)s %%" +msgstr "" + +msgctxt "#32483" +msgid "Hide Stream Info" +msgstr "" + +msgctxt "#32484" +msgid "Show Stream Info" +msgstr "" + +msgctxt "#32485" +msgid "Go back instantly with the previous menu action in scrolled views" +msgstr "" + +msgctxt "#32487" +msgid "Seek Delay" +msgstr "" + +msgctxt "#32488" +msgid "Screensaver" +msgstr "" + +msgctxt "#32489" +msgid "Quiz Mode" +msgstr "" + +msgctxt "#32490" +msgid "Collections" +msgstr "" + +msgctxt "#32491" +msgid "Folders" +msgstr "" + +msgctxt "#32492" +msgid "Kodi Subtitle Settings" +msgstr "" + +msgctxt "#32493" +msgid "When a media file has a forced/foreign subtitle for a subtitle-enabled language, the Plex Media Server preselects it. This behaviour is usually not necessary and not configurable. This setting fixes that by ignoring the PMSs decision and selecting the same language without a forced flag if possible." +msgstr "" + +msgctxt "#32495" +msgid "Skip intro" +msgstr "" + +msgctxt "#32496" +msgid "Skip credits" +msgstr "" + + +msgctxt "#32500" +msgid "Always show post-play screen (even for short videos)" +msgstr "" + +msgctxt "#32501" +msgid "Time-to-wait between videos on post-play" +msgstr "" + +msgctxt "#32505" +msgid "Visit media in video playlist instead of playing it" +msgstr "" + +msgctxt "#32521" +msgid "Skip Intro Button Timeout" +msgstr "" + +msgctxt "#32522" +msgid "Automatically Skip Intro" +msgstr "" + +msgctxt "#32523" +msgid "Automatically skip intros if available. Doesn't override enabled binge mode." +msgstr "" + +msgctxt "#32524" +msgid "Set how long the skip intro button shows for." +msgstr "" + +msgctxt "#32525" +msgid "Skip Credits Button Timeout" +msgstr "" + +msgctxt "#32526" +msgid "Automatically Skip Credits" +msgstr "" + +msgctxt "#32527" +msgid "Automatically skip credits if available. Doesn't override enabled binge mode." +msgstr "" + +msgctxt "#32528" +msgid "Set how long the skip credits button shows for." +msgstr "" + +msgctxt "#32540" +msgid "Show when the current video will end in player" +msgstr "" + +msgctxt "#32541" +msgid "Shows time left and at which time the media will end." +msgstr "" + +msgctxt "#32542" +msgid "Show \"Ends at\" label for the end-time as well" +msgstr "" + +msgctxt "#32543" +msgid "Ends at" +msgstr "" + +msgctxt "#32601" +msgid "Allow AV1" +msgstr "" + +msgctxt "#32602" +msgid "Enable this if your hardware can handle AV1. Disable it to force transcoding." +msgstr "" + +msgctxt "#33101" +msgid "By Audience Rating" +msgstr "" + +msgctxt "#33102" +msgid "Audience Rating" +msgstr "" + +msgctxt "#33103" +msgid "By my Rating" +msgstr "" + +msgctxt "#33104" +msgid "My Rating" +msgstr "" + +msgctxt "#33105" +msgid "By Content Rating" +msgstr "" + +msgctxt "#33106" +msgid "Content Rating" +msgstr "" + +msgctxt "#33107" +msgid "By Critic Rating" +msgstr "" + +msgctxt "#33108" +msgid "Critic Rating" +msgstr "" + +msgctxt "#33200" +msgid "Background Color" +msgstr "" + +msgctxt "#33201" +msgid "Specify solid Background Color instead of using media images" +msgstr "" + +msgctxt "#33400" +msgid "Use old compatibility profile" +msgstr "" + +msgctxt "#33401" +msgid "Uses the Chrome client profile instead of the custom one. Might fix rare issues with 3D playback." +msgstr "" + +msgctxt "#33501" +msgid "Video played threshold" +msgstr "" + +msgctxt "#33502" +msgid "Set this to the same value as your Plex server (Settings>Library>Video played threshold) to avoid certain pitfalls, Default: 90 %" +msgstr "" + +msgctxt "#33503" +msgid "Use alternative hubs refresh" +msgstr "" + +msgctxt "#33504" +msgid "Refreshes all hubs for all libraries after an item's watch-state has changed, instead of only those likely affected. Use this if you find a hub that doesn't update properly." +msgstr "" + +msgctxt "#33505" +msgid "Show intro skip button early" +msgstr "" + +msgctxt "#33506" +msgid "Show the intro skip button from the start of a video with an intro marker. The auto-skipping setting applies. Doesn\'t override enabled binge mode." +msgstr "" + +msgctxt "#33507" +msgid "Enabled" +msgstr "" + +msgctxt "#33508" +msgid "Disabled" +msgstr "" + +msgctxt "#33509" +msgid "Early intro skip threshold (default: < 60s/1m)" +msgstr "" + +msgctxt "#33510" +msgid "When showing the intro skip button early, only do so if the intro occurs within the first X seconds." +msgstr "" + +msgctxt "#33600" +msgid "System" +msgstr "" + +msgctxt "#33601" +msgid "Show video chapters" +msgstr "" + +msgctxt "#33602" +msgid "If available, show video chapters from the video-file instead of the timeline-big-seek-steps." +msgstr "" + +msgctxt "#33603" +msgid "Use virtual chapters" +msgstr "" + +msgctxt "#33604" +msgid "When the above is enabled and no video chapters are available, simulate them by using the markers identified by the Plex Server (Intro, Credits)." +msgstr "" + +msgctxt "#33605" +msgid "Video Chapters" +msgstr "" + +msgctxt "#33606" +msgid "Virtual Chapters" +msgstr "" + +msgctxt "#33607" +msgid "Chapter {}" +msgstr "" + +msgctxt "#33608" +msgid "Intro" +msgstr "" + +msgctxt "#33609" +msgid "Credits" +msgstr "" + +msgctxt "#33610" +msgid "Main" +msgstr "" + +msgctxt "#33611" +msgid "Chapters" +msgstr "" + +msgctxt "#33612" +msgid "Markers" +msgstr "" + +msgctxt "#33613" +msgid "Kodi Buffer Size (MB)" +msgstr "" + +msgctxt "#33614" +msgid "Set the Kodi Cache/Buffer size. Free: {} MB, Recommended: ~100 MB, Recommended max: {} MB, Default: 20 MB." +msgstr "" + +msgctxt "#33615" +msgid "{time} left" +msgstr "" + +msgctxt "#33616" +msgid "Addon Path" +msgstr "" + +msgctxt "#33617" +msgid "Userdata/Profile Path" +msgstr "" + +msgctxt "#33618" +msgid "TV binge-viewing mode" +msgstr "" + +msgctxt "#33619" +msgid "Automatically skips episode intros, credits and tries to skip episode recaps. Doesn\'t skip the intro of the first episode of a season.\n\nCan be disabled/enabled per TV show." +msgstr "" + +msgctxt "#33620" +msgid "Plex requests timeout (seconds)" +msgstr "" + +msgctxt "#33621" +msgid "Set the (async and connection) timeout value of the Python requests library in seconds. Default: 5" +msgstr "" + +msgctxt "#33622" +msgid "LAN reachability timeout (ms)" +msgstr "" + +msgctxt "#33623" +msgid "When checking for LAN reachability, use this timeout. Default: 10ms" +msgstr "" + +msgctxt "#33624" +msgid "Network" +msgstr "" + +msgctxt "#33625" +msgid "Smart LAN/local server discovery" +msgstr "" + +msgctxt "#33626" +msgid "Checks whether servers returned from Plex.tv are actually local/in your LAN. For specific setups (e.g. Docker) Plex.tv might not properly detect a local server.\n\nNOTE: Only works on Kodi 19 or above." +msgstr "" + +msgctxt "#33627" +msgid "Prefer LAN/local servers over security" +msgstr "" + +msgctxt "#33628" +msgid "Prioritizes local connections over secure ones. Needs the proper setting in \"Allow Insecure Connections\" and the Plex Server's \"Secure connections\" at \"Preferred\". Can be used to enforce manual servers." +msgstr "" + +msgctxt "#33629" +msgid "Auto-skip intro/credits offset" +msgstr "" + +msgctxt "#33630" +msgid "Intro/credits markers might be a little early in Plex. When auto skipping add (or subtract) this many seconds from the marker. This avoids cutting off content, while possibly skipping the marker a little late." +msgstr "" + +msgctxt "#32631" +msgid "Playback (user-specific)" +msgstr "" + +msgctxt "#33632" +msgid "Server connectivity check timeout (seconds)" +msgstr "" + +msgctxt "#33633" +msgid "Set the maximum amount of time a server connection has to answer a connectivity request. Default: 2.5" +msgstr "" + +msgctxt "#33634" +msgid "Combined Chapters" +msgstr "" + +msgctxt "#33635" +msgid "Final Credits" +msgstr "" + +msgctxt "#32700" +msgid "Action on Sleep event" +msgstr "" + +msgctxt "#32701" +msgid "When Kodi receives a sleep event from the system, run the following action." +msgstr "" + +msgctxt "#32702" +msgid "Nothing" +msgstr "" + +msgctxt "#32703" +msgid "Stop playback" +msgstr "" + +msgctxt "#32704" +msgid "Quit Kodi" +msgstr "" + +msgctxt "#32705" +msgid "CEC Standby" +msgstr "" + +msgctxt "#32800" +msgid "Skipping intro" +msgstr "" + +msgctxt "#32801" +msgid "Skipping credits" +msgstr "" + +msgctxt "#32900" +msgid "While playing back an item and seeking on the seekbar, automatically seek to the selected position after a delay instead of having to confirm the selection." +msgstr "" + +msgctxt "#32901" +msgid "Seek delay in seconds." +msgstr "" + +msgctxt "#32902" +msgid "Kodi has its own skip step settings. Try to use them if they're configured instead of the default ones." +msgstr "" + +msgctxt "#32903" +msgid "Use the above for seeking on the timeline as well." +msgstr "" + +msgctxt "#32904" +msgid "In seconds." +msgstr "" + +msgctxt "#32905" +msgid "Cancel post-play timer by pressing OK/SELECT" +msgstr "" + +msgctxt "#32906" +msgid "Cancel skip marker timer with BACK" +msgstr "" + +msgctxt "#32907" +msgid "When auto-skipping a marker, allow cancelling the timer by pressing BACK." +msgstr "" + +msgctxt "#32908" +msgid "Immediately skip marker with OK/SELECT" +msgstr "" + +msgctxt "#32909" +msgid "When auto-skipping a marker with a timer, allow skipping immediately by pressing OK/SELECT." +msgstr "" + +msgctxt "#32912" +msgid "Show buffer-state on timeline" +msgstr "" + +msgctxt "#32913" +msgid "Shows the current Kodi buffer/cache state on the video player timeline." +msgstr "" + +msgctxt "#32914" +msgid "Loading" +msgstr "" + +msgctxt "#32915" +msgid "Slow connection" +msgstr "" + +msgctxt "#32916" +msgid "Use with a wonky/slow connection, e.g. in a hotel room. Adjusts the UI to visually wait for item refreshes and waits for the buffer to fill when starting playback. Automatically sets readfactor=20, requires Kodi restart." +msgstr "" + +msgctxt "#32917" +msgid "Couldn't fill buffer in time ({}s)" +msgstr "" + +msgctxt "#32918" +msgid "Buffer wait timeout (seconds)" +msgstr "" + +msgctxt "#32919" +msgid "When slow connection is enabled in the addon, wait this long for the buffer to fill. Default: 120 s" +msgstr "" + +msgctxt "#32920" +msgid "Insufficient buffer wait (seconds)" +msgstr "" + +msgctxt "#32921" +msgid "When slow connection is enabled in the addon and the configured buffer isn't big enough for us to determine its fill state, wait this long when starting playback. Default: 10 s" +msgstr "" + +msgctxt "#32922" +msgid "Kodi Cache Readfactor" +msgstr "" + +msgctxt "#32923" +msgid "Sets the Kodi cache readfactor value. Default: {0}, recommended: {1}. With \"Slow connection\" enabled this will be set to {2}, as otherwise the cache doesn't fill fast/aggressively enough." +msgstr "" + +msgctxt "#32924" +msgid "Minimize" +msgstr "" + +msgctxt "#32925" +msgid "Playback Settings" +msgstr "" + +msgctxt "#32926" +msgid "Wrong pin entered!" +msgstr "" + +msgctxt "#32927" +msgid "Use episode thumbnails in continue hub" +msgstr "" + +msgctxt "#32928" +msgid "Instead of using media artwork, use thumbnails for episodes in the continue hub on the home screen if available." +msgstr "" + +msgctxt "#32929" +msgid "Use legacy background fallback image" +msgstr "" + +msgctxt "#32930" +msgid "Previous Subtitle" +msgstr "" + +msgctxt "#32931" +msgid "Audio/Subtitles" +msgstr "" + +msgctxt "#32932" +msgid "Show subtitle quick-actions button" +msgstr "" + +msgctxt "#32933" +msgid "Show FFWD/RWD buttons" +msgstr "" + +msgctxt "#32934" +msgid "Show repeat button" +msgstr "" + +msgctxt "#32935" +msgid "Show shuffle button" +msgstr "" + +msgctxt "#32936" +msgid "Show playlist button" +msgstr "" + +msgctxt "#32937" +msgid "Show prev/next button" +msgstr "" + +msgctxt "#32938" +msgid "Only for Episodes" +msgstr "" + +msgctxt "#32939" +msgid "Only applies to video player UI" +msgstr "" + +msgctxt "#32940" +msgid "Player UI" +msgstr "" + +msgctxt "#32941" +msgid "Forced subtitles fix" +msgstr "" + +msgctxt "#32942" +msgid "Other seasons" +msgstr "" + +msgctxt "#32943" +msgid "Crossfade dynamic background art" +msgstr "" + +msgctxt "#32944" +msgid "Burn-in SSA subtitles (DirectStream)" +msgstr "" + +msgctxt "#32945" +msgid "When Direct Streaming instruct the Plex Server to burn in SSA/ASS subtitles (thus transcoding the video stream). If disabled it will not touch the video stream, but will convert the subtitle to unstyled text." +msgstr "" + +msgctxt "#32946" +msgid "Stop video playback on idle after" +msgstr "" + +msgctxt "#32947" +msgid "Stop video playback on screensaver" +msgstr "" + +msgctxt "#32948" +msgid "Allow auto-skip when transcoding" +msgstr "" + +msgctxt "#32949" +msgid "When transcoding/DirectStreaming, allow auto-skip functionality." +msgstr "" + +msgctxt "#32950" +msgid "Use extended title for subtitles" +msgstr "" + +msgctxt "#32951" +msgid "When displaying subtitles use the extendedDisplayTitle Plex exposes." +msgstr "" + +msgctxt "#32952" +msgid "Dialog flicker fix" +msgstr "" + +msgctxt "#32953" +msgid "Reviews" +msgstr "" + +msgctxt "#32954" +msgid "Needs Kodi restart. WARNING: This will overwrite advancedsettings.xml!\n\nTo customize other cache/network-related values, copy \"script.plexmod/pm4k_cache_template.xml\" to profile folder and edit it to your liking. (See About section for the file paths)" +msgstr "" + +msgctxt "#32955" +msgid "Use Kodi keyboard for searching" +msgstr "" + +msgctxt "#32956" +msgid "Poster resolution scaling %" +msgstr "" + +msgctxt "#32957" +msgid "In percent. Scales the resolution of all posters/thumbnails for better image quality. May impact PMS/PM4K performance, will increase the cache usage accordingly. Recommended: 200-300 % for for big screens if your hardware can handle it. Needs addon restart." +msgstr "" + +msgctxt "#32958" +msgid "Calculate OpenSubtitles.com hash" +msgstr "" + +msgctxt "#32959" +msgid "When opening the subtitle download feature, automatically calculate the OpenSubtitles.com hash for the given file. Can improve search results, downloads 2*64 KB of the video file to calculate the hash." +msgstr "" diff --git a/script.plexmod/resources/language/resource.language.es_es/strings.po b/script.plexmod/resources/language/resource.language.es_es/strings.po new file mode 100644 index 0000000000..b8c6adca8e --- /dev/null +++ b/script.plexmod/resources/language/resource.language.es_es/strings.po @@ -0,0 +1,951 @@ +# XBMC Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2013-12-12 22:56+0000\n" +"PO-Revision-Date: 2020-05-16 10:52+0200\n" +"Language-Team: LANGUAGE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Last-Translator: \n" +"X-Generator: Poedit 2.0.2\n" + +msgctxt "#32000" +msgid "Main" +msgstr "Principal" + +msgctxt "#32001" +msgid "Original" +msgstr "Original" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "20 Mbps 1080p" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "12 Mbps 1080p" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "10 Mbps 1080p" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "8 Mbps 1080p" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "4 Mbps 720p" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "3 Mbps 720p" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "2 Mbps 720p" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "1.5 Mbps 480p" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "720 kbps" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "320 kbps" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "208 kbps" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "96 kbps" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "64 kbps" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "Calidad Local" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "Calidad Remoto" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "Calidad Online" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "Formato transcodificación" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "Log Depuración" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "Permitir Reproducción en Directo" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "Permitir Stream en Directo" + +msgctxt "#32027" +msgid "Force" +msgstr "Forzar" + +msgctxt "#32028" +msgid "Always" +msgstr "Siempre" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "Solo formatos de imagen" + +msgctxt "#32030" +msgid "Auto" +msgstr "Auto" + +msgctxt "#32031" +msgid "Burn Subtitles (Direct Play Only)" +msgstr "Subtítulos (Solo Reproducción Directo)" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "Permetir conexiones inseguras" + +msgctxt "#32033" +msgid "Never" +msgstr "Nunca" + +msgctxt "#32034" +msgid "On Same network" +msgstr "En la misma red" + +msgctxt "#32035" +msgid "Always" +msgstr "Siempre" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "Permitir 4K" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "Permetir HEVC (h265)" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "Accesso automatico" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "Post Play Auto Play" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "Activar la descarga de subtítulos" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "Activar la descarga de subtítulos" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "Detección del Servidor (GDM)" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "Arrancar Plex al iniciar Kodi" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "IP Conexión 1" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "Puerto Conexión 1" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "IP Conexión 2" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "Puerto conexión 2" + +msgctxt "#32048" +msgid "Audio" +msgstr "Audio" + +msgctxt "#32049" +msgid "Advanced" +msgstr "Avanzar" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "Servidores manuales" + +msgctxt "#32051" +msgid "Privacy" +msgstr "Privacidad" + +msgctxt "#32052" +msgid "About" +msgstr "Acerca de" + +msgctxt "#32053" +msgid "Video" +msgstr "Video" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "Versión Add-on" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Versión Kodi" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "Resolución de Pantalla" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "Versión del Servidor" + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "Omitir selección de usuario y PIN al iniciar." + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "Si se activa, cuando acabe la reproducción y 'Siguiente Capítulo' esté disponible, se reproducirá automáticamente a los 15 segundos." + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "Activa esto si se puede reproducir contenido 4K. Desactívalo para forzar la trasncodificación." + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "Activa esto si se puede reproducir HEVC/h265. Desactiva para forzar la trascodificación." + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "Conectar a servidores con conexiones no seguras.[CR][CR]* [B]Nunca[/B]: Nunca conectarse a un servidor de forma no segura[CR]* [B]En la misma red[/B]: Permitir para la misma red[CR]* [B]Siempre[/B]: Permitir para todas las conexiones" + +msgctxt "#32201" +msgid "Trailer" +msgstr "Tráiler" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "Escenas eliminadas" + +msgctxt "#32203" +msgid "Interview" +msgstr "Entrevista" + +msgctxt "#32204" +msgid "Music Video" +msgstr "Video musical" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "Detrás de las escenas" + +msgctxt "#32206" +msgid "Scene" +msgstr "Escena" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "Videos de música en vivo" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "Videos de letras musicales" + +msgctxt "#32209" +msgid "Concert" +msgstr "Conciertos" + +msgctxt "#32210" +msgid "Featurette" +msgstr "Featurette" + +msgctxt "#32211" +msgid "Short" +msgstr "Cortos" + +msgctxt "#32212" +msgid "Other" +msgstr "Otros" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "Ir a Album" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "Ir a Artistas" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "Ir a {0}" + +msgctxt "#32303" +msgid "Season" +msgstr "Temporada" + +msgctxt "#32304" +msgid "Episode" +msgstr "Capítulo" + +msgctxt "#32305" +msgid "Extras" +msgstr "Extras" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "Series relacionadas" + +msgctxt "#32307" +msgid "More" +msgstr "Más" + +msgctxt "#32308" +msgid "Available" +msgstr "Disponible" + +msgctxt "#32309" +msgid "None" +msgstr "Ninguno" + +msgctxt "#32310" +msgid "S" +msgstr "S" + +msgctxt "#32311" +msgid "E" +msgstr "E" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "No disponible" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "Este elemento no está disponible actualmente" + +msgctxt "#32314" +msgid "In Progress" +msgstr "En curso" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "¿Continuar reproducción?" + +msgctxt "#32316" +msgid "Resume" +msgstr "Continuar" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "Reproducir desde el principio" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "Marcar como no visto" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "Marcar como visto" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "Marca la Temporada como no vista" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "Marcar la Temporada como vista" + +msgctxt "#32322" +msgid "Delete" +msgstr "Borrar" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "Ir a la Serie" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "Ir a {0}" + +msgctxt "#32325" +msgid "Play Next" +msgstr "Reproducir el siguiente" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "¿Borrarlo de verdad?" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "¿Seguro que quieres borrar este medio?" + +msgctxt "#32328" +msgid "Yes" +msgstr "Sí" + +msgctxt "#32329" +msgid "No" +msgstr "No" + +msgctxt "#32330" +msgid "Message" +msgstr "Mensaje" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "Hubo un problema al intentar borrar este medio." + +msgctxt "#32332" +msgid "Home" +msgstr "Inicio" + +msgctxt "#32333" +msgid "Playlists" +msgstr "Listas de reproducción" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "Salir realmente" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "¿Listo para salir de Plex?" + +msgctxt "#32336" +msgid "Exit" +msgstr "Salir" + +msgctxt "#32337" +msgid "Cancel" +msgstr "Cancelar" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "Ningún servidor encontrado" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "Servidor no accessible" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "Tests de conexión en curso. Espere por favor." + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "Servidor no accessible. Por favor, comprueba la conexión de tu servidor." + +msgctxt "#32342" +msgid "Switch User" +msgstr "Cambiar usuario" + +msgctxt "#32343" +msgid "Settings" +msgstr "Configuración" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "Desconectar" + +msgctxt "#32345" +msgid "All" +msgstr "Todo" + +msgctxt "#32346" +msgid "By Name" +msgstr "Por Nombre" + +msgctxt "#32347" +msgid "Artists" +msgstr "Artistas" + +msgctxt "#32348" +msgid "movies" +msgstr "películas" + +msgctxt "#32349" +msgid "photos" +msgstr "fotos" + +msgctxt "#32350" +msgid "Shows" +msgstr "Series" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "Por fecha" + +msgctxt "#32352" +msgid "Date Added" +msgstr "Fecha" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "Por fecha de estreno" + +msgctxt "#32354" +msgid "Release Date" +msgstr "Fecha de estreno" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "Por fecha de visionado" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "Fecha de visionado" + +msgctxt "#32357" +msgid "By Name" +msgstr "Por nombre" + +msgctxt "#32358" +msgid "Name" +msgstr "Nombre" + +msgctxt "#32359" +msgid "By Rating" +msgstr "Por valoración" + +msgctxt "#32360" +msgid "Rating" +msgstr "Valoración" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "Por Resolución" + +msgctxt "#32362" +msgid "Resolution" +msgstr "Resolución" + +msgctxt "#32363" +msgid "By Duration" +msgstr "Por Duración" + +msgctxt "#32364" +msgid "Duration" +msgstr "Duración" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "Por primera emisión" + +msgctxt "#32366" +msgid "First Aired" +msgstr "Primera emisión" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "Por No Vistos" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "Non visto" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "Por Fecha de Reproducción" + +msgctxt "#32370" +msgid "Date Played" +msgstr "Fecha de Reproducción" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "Por Número de Reproducciones" + +msgctxt "#32372" +msgid "Play Count" +msgstr "Número de Reproducciones" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "Por Fecha de Captura" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "Fecha de Captura" + +msgctxt "#32375" +msgid "No filters available" +msgstr "Sin filtros disponbles" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "Quitar filtros" + +msgctxt "#32377" +msgid "Year" +msgstr "Año" + +msgctxt "#32378" +msgid "Decade" +msgstr "Década" + +msgctxt "#32379" +msgid "Genre" +msgstr "Género" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "Clasificación por Edad" + +msgctxt "#32381" +msgid "Network" +msgstr "Red" + +msgctxt "#32382" +msgid "Collection" +msgstr "Colección" + +msgctxt "#32383" +msgid "Director" +msgstr "Dirección" + +msgctxt "#32384" +msgid "Actor" +msgstr "Actores" + +msgctxt "#32385" +msgid "Country" +msgstr "País" + +msgctxt "#32386" +msgid "Studio" +msgstr "Estudio" + +msgctxt "#32387" +msgid "Labels" +msgstr "Etiquetas" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "Marca de Cámara" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "Modelo de Cámera" + +msgctxt "#32390" +msgid "Aperture" +msgstr "Apertura" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "Velocidad de apertura" + +msgctxt "#32392" +msgid "Lens" +msgstr "Lente" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "Series de TV" + +msgctxt "#32394" +msgid "Music" +msgstr "Música" + +msgctxt "#32395" +msgid "Audio" +msgstr "Audio" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "Subtítulos" + +msgctxt "#32397" +msgid "Quality" +msgstr "Calidad" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "Configuración de Video de Kodi" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "Configuración de Audio de Kodi" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "Ir a Temporada" + +msgctxt "#32401" +msgid "Directors" +msgstr "Dirección" + +msgctxt "#32402" +msgid "Writer" +msgstr "Autor" + +msgctxt "#32403" +msgid "Writers" +msgstr "Guionistas" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "Películas relacionadas" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "Descargar Subtítulos" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "Retardo en Subtítulos" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "Siguiente Subtítulo" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "Desactivar Subtítulos" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "Activar Subtítulos" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "Versión de la Plataforma" + +msgctxt "#32411" +msgid "Unknown" +msgstr "Desconocido" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "Modificar o Borrar" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "¿Editar la direeción IP o borrar la configuración?" + +msgctxt "#32414" +msgid "Clear" +msgstr "Borrar" + +msgctxt "#32415" +msgid "Edit" +msgstr "Modificar" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "Introduce la Dirección IP" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "Introduce el Puerto" + +msgctxt "#32418" +msgid "Creator" +msgstr "Creador" + +msgctxt "#32419" +msgid "Cast" +msgstr "Elenco" + +msgctxt "#32420" +msgid "Disc" +msgstr "Disco" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "Desconectar" + +msgctxt "#32422" +msgid "Exit" +msgstr "Salir" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "Apagar" + +msgctxt "#32424" +msgid "Suspend" +msgstr "Suspender" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "Hibernar" + +msgctxt "#32426" +msgid "Reboot" +msgstr "Reiniciar" + +msgctxt "#32427" +msgid "Failed" +msgstr "Fallo" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "¡El acceso falló!" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "Continuar desde {0}" + +msgctxt "#32430" +msgid "Discovery" +msgstr "Descubrimiento" + +msgctxt "#32431" +msgid "Search" +msgstr "Búsqueda" + +msgctxt "#32432" +msgid "Space" +msgstr "Espacio" + +msgctxt "#32433" +msgid "Clear" +msgstr "Borrar" + +msgctxt "#32434" +msgid "Searching..." +msgstr "Buscando..." + +msgctxt "#32435" +msgid "No Results" +msgstr "Sin resultados" + +msgctxt "#32436" +msgid "Paused" +msgstr "En Pausa" + +msgctxt "#32437" +msgid "Welcome" +msgstr "Bienvenido" + +msgctxt "#32438" +msgid "Previous" +msgstr "Anterior" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "Reproducir el Siguiente" + +msgctxt "#32440" +msgid "On Deck" +msgstr "En Portada" + +msgctxt "#32441" +msgid "Unknown" +msgstr "Desconocido" + +msgctxt "#32442" +msgid "Embedded" +msgstr "Integrado" + +msgctxt "#32443" +msgid "Forced" +msgstr "Forzado" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "Letras" + +msgctxt "#32445" +msgid "Mono" +msgstr "Mono" + +msgctxt "#32446" +msgid "Stereo" +msgstr "Stereo" + +msgctxt "#32447" +msgid "None" +msgstr "Ninguno" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "¡La reproducción falló!" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "No pude conectarme a plex.tv[CR]Comprueba la conexión y vuelve a intentarlo." + +msgctxt "#32450" +msgid "Choose Version" +msgstr "Elegir una Versión" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "Reproduce un Versión..." + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "No hay contenido disponible en esta bilioteca" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "Por favo, añade contenido y/o comprueba que 'Incluir en el dashboard' esté activado." + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "Sin contenido disponible por este filtro" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "Por favor, cambie o quite el filtro actual" + +msgctxt "#32456" +msgid "Show" +msgstr "Serie" + +msgctxt "#32457" +msgid "By Show" +msgstr "Por Serie" + +msgctxt "#32458" +msgid "Episodes" +msgstr "Capítulo" + +msgctxt "#32459" +msgid "Offline Mode" +msgstr "Modo Offline" + +msgctxt "#32460" +msgid "Sign In" +msgstr "Acceso" + +msgctxt "#32461" +msgid "Albums" +msgstr "Albums" + +msgctxt "#32462" +msgid "Artist" +msgstr "Artista" + +msgctxt "#32463" +msgid "By Artist" +msgstr "Por Artista" diff --git a/script.plexmod/resources/language/resource.language.fr_fr/strings.po b/script.plexmod/resources/language/resource.language.fr_fr/strings.po new file mode 100644 index 0000000000..b4ec81eca1 --- /dev/null +++ b/script.plexmod/resources/language/resource.language.fr_fr/strings.po @@ -0,0 +1,953 @@ +# XBMC Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2013-12-12 22:56+0000\n" +"PO-Revision-Date: 2017-05-29 16:47++0200\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +msgctxt "#32000" +msgid "Main" +msgstr "Main" + +msgctxt "#32001" +msgid "Original" +msgstr "Original" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "20 Mbps 1080p" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "12 Mbps 1080p" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "10 Mbps 1080p" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "8 Mbps 1080p" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "4 Mbps 720p" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "3 Mbps 720p" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "2 Mbps 720p" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "1.5 Mbps 480p" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "720 kbps" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "320 kbps" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "208 kbps" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "96 kbps" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "64 kbps" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "Qualité locale" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "Qualité distante" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "Qualité online" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "Format transcodage" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "Debug Logging" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "Autoriser Direct Play" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "Autoriser Direct Stream" + +msgctxt "#32027" +msgid "Force" +msgstr "Force" + +msgctxt "#32028" +msgid "Always" +msgstr "Toujours" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "Seulement formats d'image" + +msgctxt "#32030" +msgid "Auto" +msgstr "Auto" + +msgctxt "#32031" +msgid "Burn Subtitles (Direct Play Only)" +msgstr "Incruster sous-titres (pour Direct Play)" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "Autoriser connexions non sécurisées" + +msgctxt "#32033" +msgid "Never" +msgstr "Jamais" + +msgctxt "#32034" +msgid "On Same network" +msgstr "Sur le même réseau" + +msgctxt "#32035" +msgid "Always" +msgstr "Toujours" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "Autoriser 4K" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "Autoriser HEVC (h265)" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "Connexion automatique" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "Post Play Auto Play" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "Activer le téléchargement des sous-titres" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "Activer le téléchargement des sous-titres" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "Server Discovery (GDM)" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "Démarrer Plex au démarrage de Kodi" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "Connexion 1 IP" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "Connexion 1 Port" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "Connexion 2 IP" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "Connexion 2 Port" + +msgctxt "#32048" +msgid "Audio" +msgstr "Audio" + +msgctxt "#32049" +msgid "Advanced" +msgstr "Avancée" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "Serveurs manuels" + +msgctxt "#32051" +msgid "Privacy" +msgstr "Privacy" + +msgctxt "#32052" +msgid "About" +msgstr "A propos" + +msgctxt "#32053" +msgid "Video" +msgstr "Video" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "Version de l'addon" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Version de kodi" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "Résolution de l'écran" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "Version actuelle du serveur" + + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "Passer l'écran de sélection de l'utilisateur et du PIN au démarrage" + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "Si actif, à la fin de la lecture, les éléments suivants seront joués après un délai de 15s." + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "Activer cette option si votre hardware est capable de lire la 4K. Désactiver pour forcer le transcodage." + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "Activer cette option si votre hardware est capable de décoder l'HEVC/h265. Désactiver pour forcer le transcodage." + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "Pour se connecter à un serveur via une connexion non sécurisée.[CR][CR]* [B]Attention[/B]: Ne jamais se connecter à un serveur via une connexion son sécurisée[CR]* [B]Sur le même réseau[/B]: Autoriser si même réseau[CR]* [B]Toujours[/B]: Autoriser même réseau et connexions distantes" + + +msgctxt "#32201" +msgid "Trailer" +msgstr "Bande-annonce" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "Supprimer scène" + +msgctxt "#32203" +msgid "Interview" +msgstr "Interview" + +msgctxt "#32204" +msgid "Music Video" +msgstr "Vidéos Musiques" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "Dans les coulisses" + +msgctxt "#32206" +msgid "Scene" +msgstr "Scene" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "Vidéos Musiques Live" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "Paroles vidéos musiques" + +msgctxt "#32209" +msgid "Concert" +msgstr "Concert" + +msgctxt "#32210" +msgid "Featurette" +msgstr "Featurette" + +msgctxt "#32211" +msgid "Short" +msgstr "Courte" + +msgctxt "#32212" +msgid "Other" +msgstr "Autres" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "Voir l'album" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "Voir l'artiste" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "Aller à {0}" + +msgctxt "#32303" +msgid "Season" +msgstr "Saison" + +msgctxt "#32304" +msgid "Episode" +msgstr "Episode" + +msgctxt "#32305" +msgid "Extras" +msgstr "Extras" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "Liens" + +msgctxt "#32307" +msgid "More" +msgstr "Plus" + +msgctxt "#32308" +msgid "Available" +msgstr "Disponible" + +msgctxt "#32309" +msgid "None" +msgstr "Aucun" + +msgctxt "#32310" +msgid "S" +msgstr "S" + +msgctxt "#32311" +msgid "E" +msgstr "E" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "Non disponible" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "Cet élément n'est actuellement pas disponible." + +msgctxt "#32314" +msgid "In Progress" +msgstr "En cours" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "Poursuivre la lecture ?" + +msgctxt "#32316" +msgid "Resume" +msgstr "Resume" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "Lire depuis le début" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "Marquer comme non vu" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "Marquer comme vu" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "Marquer saison comme non vue" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "Marquer saison comme vue" + +msgctxt "#32322" +msgid "Delete" +msgstr "Supprimer" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "Voir le Show" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "Aller à {0}" + +msgctxt "#32325" +msgid "Play Next" +msgstr "Lire le media suivant" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "Supprimer?" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "Etes-vous sûr de vouloir supprimer ce media ?" + +msgctxt "#32328" +msgid "Yes" +msgstr "Oui" + +msgctxt "#32329" +msgid "No" +msgstr "Non" + +msgctxt "#32330" +msgid "Message" +msgstr "Message" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "Erreur : impossible de supprimer le media" + +msgctxt "#32332" +msgid "Home" +msgstr "Home" + +msgctxt "#32333" +msgid "Playlists" +msgstr "Playlists" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "Quitter" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "Souhaitez-vous quitter Plex ?" + +msgctxt "#32336" +msgid "Exit" +msgstr "Quitter" + +msgctxt "#32337" +msgid "Cancel" +msgstr "Annuler" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "Aucun serveur trouvé" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "Serveur non accessible" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "Tests de connexion en cours. Merci de patienter." + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "Serveur non joignable. Merci de vérifier l'accessibilité du serveur." + +msgctxt "#32342" +msgid "Switch User" +msgstr "Changer d'utilisateur" + +msgctxt "#32343" +msgid "Settings" +msgstr "Paramètres" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "Déconnexion" + +msgctxt "#32345" +msgid "All" +msgstr "Tous" + +msgctxt "#32346" +msgid "By Name" +msgstr "Par Nom" + +msgctxt "#32347" +msgid "Artists" +msgstr "Artites" + +msgctxt "#32348" +msgid "movies" +msgstr "films" + +msgctxt "#32349" +msgid "photos" +msgstr "photos" + +msgctxt "#32350" +msgid "Shows" +msgstr "Séries" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "Par date d'ajout" + +msgctxt "#32352" +msgid "Date Added" +msgstr "Date d'ajout" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "Par date de sortie" + +msgctxt "#32354" +msgid "Release Date" +msgstr "Date de sortie" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "Par date de visionnage" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "Date du visionnage" + +msgctxt "#32357" +msgid "By Name" +msgstr "Par nom" + +msgctxt "#32358" +msgid "Name" +msgstr "Nom" + +msgctxt "#32359" +msgid "By Rating" +msgstr "Par note" + +msgctxt "#32360" +msgid "Rating" +msgstr "Note" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "Par qualité" + +msgctxt "#32362" +msgid "Resolution" +msgstr "Qualité" + +msgctxt "#32363" +msgid "By Duration" +msgstr "Par durée" + +msgctxt "#32364" +msgid "Duration" +msgstr "Durée" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "Par première diffusion" + +msgctxt "#32366" +msgid "First Aired" +msgstr "Première diffusion" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "Par non vus" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "Non vus" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "Par date de lecture" + +msgctxt "#32370" +msgid "Date Played" +msgstr "Date de lecture" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "Par nombre de lectures" + +msgctxt "#32372" +msgid "Play Count" +msgstr "Nombre de lectures" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "Par date de prise de vue" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "Date de prise de vue" + +msgctxt "#32375" +msgid "No filters available" +msgstr "Aucuns filtres disponibles" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "Effacer filtres" + +msgctxt "#32377" +msgid "Year" +msgstr "Année" + +msgctxt "#32378" +msgid "Decade" +msgstr "Décennie" + +msgctxt "#32379" +msgid "Genre" +msgstr "Genre" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "Note du contenu" + +msgctxt "#32381" +msgid "Network" +msgstr "Réseau" + +msgctxt "#32382" +msgid "Collection" +msgstr "Collection" + +msgctxt "#32383" +msgid "Director" +msgstr "Réalisateur" + +msgctxt "#32384" +msgid "Actor" +msgstr "Acteur" + +msgctxt "#32385" +msgid "Country" +msgstr "Pays" + +msgctxt "#32386" +msgid "Studio" +msgstr "Studio" + +msgctxt "#32387" +msgid "Labels" +msgstr "Labels" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "Marque appareil photo" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "Modèle caméra" + +msgctxt "#32390" +msgid "Aperture" +msgstr "Aperture" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "Vitesse d'obturation" + +msgctxt "#32392" +msgid "Lens" +msgstr "Lentille" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "Séries TV" + +msgctxt "#32394" +msgid "Music" +msgstr "Musiques" + +msgctxt "#32395" +msgid "Audio" +msgstr "Audio" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "Sous-titres" + +msgctxt "#32397" +msgid "Quality" +msgstr "Qualité" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "Paramètres vidéo Kodi" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "Paramètres audio Kodi" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "Aller à la saison" + +msgctxt "#32401" +msgid "Directors" +msgstr "Réalisateurs" + +msgctxt "#32402" +msgid "Writer" +msgstr "Auteur" + +msgctxt "#32403" +msgid "Writers" +msgstr "Auteurs" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "Films liés" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "Télécharger sous-titres" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "Délai sous-titres" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "Sous-titres suivants" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "Désactiver sous-titres" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "Activer sous-titres" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "Version de la plateforme" + +msgctxt "#32411" +msgid "Unknown" +msgstr "Inconnu" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "Editer ou Effacer" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "Editer adresse IP ou effacer les paramètres actuels ?" + +msgctxt "#32414" +msgid "Clear" +msgstr "Effacer" + +msgctxt "#32415" +msgid "Edit" +msgstr "Editer" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "Saisir adresse IP" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "Saisir le port" + +msgctxt "#32418" +msgid "Creator" +msgstr "Creator" + +msgctxt "#32419" +msgid "Cast" +msgstr "Casting" + +msgctxt "#32420" +msgid "Disc" +msgstr "Disc" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "Déconnexion" + +msgctxt "#32422" +msgid "Exit" +msgstr "Quitter" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "Eteindre" + +msgctxt "#32424" +msgid "Suspend" +msgstr "Veille" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "Veille prolongée" + +msgctxt "#32426" +msgid "Reboot" +msgstr "Redémarrer" + +msgctxt "#32427" +msgid "Failed" +msgstr "Echec" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "Impossible de se connecter" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "Reprendre à {0}" + +msgctxt "#32430" +msgid "Discovery" +msgstr "Recherche" + +msgctxt "#32431" +msgid "Search" +msgstr "Recherche" + +msgctxt "#32432" +msgid "Space" +msgstr "Espace" + +msgctxt "#32433" +msgid "Clear" +msgstr "Effacer" + +msgctxt "#32434" +msgid "Searching..." +msgstr "Recherche en cours..." + +msgctxt "#32435" +msgid "No Results" +msgstr "Aucun résultat" + +msgctxt "#32436" +msgid "Paused" +msgstr "Pause" + +msgctxt "#32437" +msgid "Welcome" +msgstr "Bienvenue" + +msgctxt "#32438" +msgid "Previous" +msgstr "Précédent" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "A regarder ensuite" + +msgctxt "#32440" +msgid "On Deck" +msgstr "Découvrir" + +msgctxt "#32441" +msgid "Unknown" +msgstr "Inconnu" + +msgctxt "#32442" +msgid "Embedded" +msgstr "Intégré" + +msgctxt "#32443" +msgid "Forced" +msgstr "Forcé" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "Parole" + +msgctxt "#32445" +msgid "Mono" +msgstr "Mono" + +msgctxt "#32446" +msgid "Stereo" +msgstr "Stereo" + +msgctxt "#32447" +msgid "None" +msgstr "Aucun" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "Echec de lecture!" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "Impossible de se connecter à plex.tv[CR]Vérifiez votre connexion et réessayez." + +msgctxt "#32450" +msgid "Choose Version" +msgstr "Choisir une version" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "Lire version..." + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "" + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "Aucun contenu disponible dans cette librairie" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "Merci de modifier ou supprimer le filtre courant" + +msgctxt "#32456" +msgid "Show" +msgstr "" + +msgctxt "#32457" +msgid "By Show" +msgstr "" + +msgctxt "#32458" +msgid "Episodes" +msgstr "" + +msgctxt "#32459" +msgid "Offline Mode" +msgstr "Mode Hors-Ligne" + +msgctxt "#32460" +msgid "Sign In" +msgstr "Se connecter" + +msgctxt "#32461" +msgid "Albums" +msgstr "" + +msgctxt "#32462" +msgid "Artist" +msgstr "" + +msgctxt "#32463" +msgid "By Artist" +msgstr "" + diff --git a/script.plexmod/resources/language/resource.language.hu_hu/strings.po b/script.plexmod/resources/language/resource.language.hu_hu/strings.po new file mode 100644 index 0000000000..18410177c1 --- /dev/null +++ b/script.plexmod/resources/language/resource.language.hu_hu/strings.po @@ -0,0 +1,928 @@ +# XBMC Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2013-12-12 22:56+0000\n" +"PO-Revision-Date: 2017-04-21 19:23+0100\n" +"Last-Translator: Norbert Suto \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: hu\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +msgctxt "#32000" +msgid "Main" +msgstr "Főoldal" + +msgctxt "#32001" +msgid "Original" +msgstr "Eredeti" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "20 Mbps 1080p" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "12 Mbps 1080p" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "10 Mbps 1080p" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "8 Mbps 1080p" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "4 Mbps 720p" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "3 Mbps 720p" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "2 Mbps 720p" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "1.5 Mbps 480p" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "720 kbps" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "320 kbps" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "208 kbps" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "96 kbps" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "64 kbps" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "Helyi minőség" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "Távoli minőség" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "Online minőség" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "Átkódolási formátum" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "Hibakeresési naplózás" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "Közvetlen lejátszás engedélyezése" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "Közvetlen adatfolyam engedélyezése" + +msgctxt "#32027" +msgid "Force" +msgstr "Kényszerítés" + +msgctxt "#32028" +msgid "Always" +msgstr "Mindig" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "Csak képformátumok esetében" + +msgctxt "#32030" +msgid "Auto" +msgstr "Automatikus" + +msgctxt "#32031" +msgid "Burn Subtitles (Direct Play Only)" +msgstr "Feliratok égetése (Csak közvetlen lejátszás esetén)" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "Nem biztonságos kapcsolatok engedélyezése" + +msgctxt "#32033" +msgid "Never" +msgstr "Soha" + +msgctxt "#32034" +msgid "On Same network" +msgstr "Ugyanazon a hálózaton" + +msgctxt "#32035" +msgid "Always" +msgstr "Mindig" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "4K engedélyezése" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "HEVC (h265) engedélyezése" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "Automatikus bejelentkezés" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "Post Play Auto Play" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "Felirat letöltés engedélyezése" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "Felirat letöltés engedélyezése" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "Szerver felderítés" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "Indítsa el a Plexet a Kodi indításakor" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "1. Kapcsolat IP" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "1. Kapcsolat Port" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "2. Kapcsolat IP" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "2. Kapcsolat Port" + +msgctxt "#32048" +msgid "Audio" +msgstr "Audió" + +msgctxt "#32049" +msgid "Advanced" +msgstr "Fejlett beállítások" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "Kézi szerverek" + +msgctxt "#32051" +msgid "Privacy" +msgstr "Adatvédelem" + +msgctxt "#32052" +msgid "About" +msgstr "Rólunk" + +msgctxt "#32053" +msgid "Video" +msgstr "Videó" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "Addon verzió" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Kodi verzió" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "Képernyőfelbontás" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "Jelenlegi szerver verzió" + + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "Felhasználó kiválasztás és a PIN kód megadás átugrása indításkor." + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "Ha engedélyezi, akkor a lejátszás befejezése után, amennyiben rendelkezésre áll egy \"következő\" elem, az 15 másodperces késleltetés után automatikusan lejátszásra kerül." + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "Engedélyezze ezt, ha a hardver képes a 4K lejátszásra. Kapcsolja ki, amennyiben kényszeríteni szeretné az átkódolást." + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "Engedélyezze ezt, ha a hardver képes a HEVC/h265 lejátszásra. Kapcsolja ki, amennyiben kényszeríteni szeretné az átkódolást." + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "Mikor kapcsolódhat nem biztonságosan a szerverekhez.[CR][CR]* [B]Soha[/B]: Soha ne kapcsolódjon[CR]* [B]Azonos hálózat[/B]: Azonos hálózat esetén engedélyezze[CR]* [B]Mindig[/B]: Engedélyezze helyi és távoli kapcsolat esetén is" + + +msgctxt "#32201" +msgid "Trailer" +msgstr "Előzetes" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "Törölt jelenet" + +msgctxt "#32203" +msgid "Interview" +msgstr "Interjú" + +msgctxt "#32204" +msgid "Music Video" +msgstr "Videóklip" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "A kulisszák mögött" + +msgctxt "#32206" +msgid "Scene" +msgstr "Jelenet" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "Élő zenei videó" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "Zenei videó dalszöveggel" + +msgctxt "#32209" +msgid "Concert" +msgstr "Koncert" + +msgctxt "#32210" +msgid "Featurette" +msgstr "Kísérő film" + +msgctxt "#32211" +msgid "Short" +msgstr "Rövidfilm" + +msgctxt "#32212" +msgid "Other" +msgstr "Egyéb" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "Ugrás az Albumra" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "Ugrás az előadóra" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "Ugrás ide {0}" + +msgctxt "#32303" +msgid "Season" +msgstr "Évad" + +msgctxt "#32304" +msgid "Episode" +msgstr "Epizód" + +msgctxt "#32305" +msgid "Extras" +msgstr "Extrák" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "Kapcsolódó műsorok" + +msgctxt "#32307" +msgid "More" +msgstr "Egyéb" + +msgctxt "#32308" +msgid "Available" +msgstr "Elérhető" + +msgctxt "#32309" +msgid "None" +msgstr "Nincs" + +msgctxt "#32310" +msgid "S" +msgstr "" + +msgctxt "#32311" +msgid "E" +msgstr "" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "Nem elérhető" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "Ez az elem jelenleg nem érhető el." + +msgctxt "#32314" +msgid "In Progress" +msgstr "Folyamatban" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "Folytatja a lejátszást?" + +msgctxt "#32316" +msgid "Resume" +msgstr "Folytat" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "Lejátszás az elejétől" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "Nem nézettnek jelölés" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "Nézettnek jelölés" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "Az évad nem nézettnek jelölése" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "Az évad nézettnek jelölése" + +msgctxt "#32322" +msgid "Delete" +msgstr "Törlés" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "Ugrás a műsorra" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "Ugrás {0}" + +msgctxt "#32325" +msgid "Play Next" +msgstr "Következő lejátszása" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "Tényleg törli?" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "Biztos benne, hogy törli az alábbi tartalmat?" + +msgctxt "#32328" +msgid "Yes" +msgstr "Igen" + +msgctxt "#32329" +msgid "No" +msgstr "Nem" + +msgctxt "#32330" +msgid "Message" +msgstr "Üzenet" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "Probléma történt a tartalom törlése közben." + +msgctxt "#32332" +msgid "Home" +msgstr "Kezdőoldal" + +msgctxt "#32333" +msgid "Playlists" +msgstr "Lejátszási listák" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "Kilépés megerősítése" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "Készen áll arra, hogy kilépjen a Plexből?" + +msgctxt "#32336" +msgid "Exit" +msgstr "Kilépés" + +msgctxt "#32337" +msgid "Cancel" +msgstr "Mégse" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "Nem található szerver" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "A szerver nem elérhető" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "A kapcsolat tesztelése folyamatban. Kérem várjon." + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "A szerver nem elérhető. Kérem jelentkezzen be a szerverébe és ellenőrizze a hálózati kapcsolatot." + +msgctxt "#32342" +msgid "Switch User" +msgstr "Felhasználóváltás" + +msgctxt "#32343" +msgid "Settings" +msgstr "Beállítások" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "Kijelentkezés" + +msgctxt "#32345" +msgid "All" +msgstr "Összes" + +msgctxt "#32346" +msgid "By Name" +msgstr "Név szerint" + +msgctxt "#32347" +msgid "artists" +msgstr "előadók" + +msgctxt "#32348" +msgid "movies" +msgstr "filmek" + +msgctxt "#32349" +msgid "photos" +msgstr "fényképek" + +msgctxt "#32350" +msgid "shows" +msgstr "műsorok" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "Hozzáadás dátuma szerint" + +msgctxt "#32352" +msgid "Date Added" +msgstr "Dátum szerint" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "Megjelenés dátuma szerint" + +msgctxt "#32354" +msgid "Release Date" +msgstr "Megjelenés dátuma" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "Megtekintés dátuma szerint" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "Megtekintés dátuma" + +msgctxt "#32357" +msgid "By Name" +msgstr "Név szerint" + +msgctxt "#32358" +msgid "Name" +msgstr "Név" + +msgctxt "#32359" +msgid "By Rating" +msgstr "Értékelés szerint" + +msgctxt "#32360" +msgid "Rating" +msgstr "Értékelés" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "Felbontás szerint" + +msgctxt "#32362" +msgid "Resolution" +msgstr "Felbontás" + +msgctxt "#32363" +msgid "By Duration" +msgstr "Időtartam szerint" + +msgctxt "#32364" +msgid "Duration" +msgstr "Időtartam" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "Első sugárzás dátuma szerint" + +msgctxt "#32366" +msgid "First Aired" +msgstr "Első sugárzás dátuma" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "Nem megtekintettek szerint" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "Nem megtekintettek" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "Lejátszás dátuma szerint" + +msgctxt "#32370" +msgid "Date Played" +msgstr "Lejátszás dátuma" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "Lájátszások száma szerint" + +msgctxt "#32372" +msgid "Play Count" +msgstr "Lejátszások száma" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "Készítés dátuma szerint" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "Készítés dátuma" + +msgctxt "#32375" +msgid "No filters available" +msgstr "Nincs elérhető szűrő" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "Szűrők eltávolítása" + +msgctxt "#32377" +msgid "Year" +msgstr "Év" + +msgctxt "#32378" +msgid "Decade" +msgstr "Évtized" + +msgctxt "#32379" +msgid "Genre" +msgstr "Műfaj" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "Értékelés" + +msgctxt "#32381" +msgid "Network" +msgstr "Csatorna" + +msgctxt "#32382" +msgid "Collection" +msgstr "Nyűjtemény" + +msgctxt "#32383" +msgid "Director" +msgstr "Rendező" + +msgctxt "#32384" +msgid "Actor" +msgstr "Színész" + +msgctxt "#32385" +msgid "Country" +msgstr "Ország" + +msgctxt "#32386" +msgid "Studio" +msgstr "Stúdió" + +msgctxt "#32387" +msgid "Labels" +msgstr "Cimkék" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "Fényképezőgép gyártmánya" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "Fényképezőgép Modell" + +msgctxt "#32390" +msgid "Aperture" +msgstr "Rekesz" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "Zár sebesség" + +msgctxt "#32392" +msgid "Lens" +msgstr "Lencsék" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "Sorozatok" + +msgctxt "#32394" +msgid "Music" +msgstr "Zene" + +msgctxt "#32395" +msgid "Audio" +msgstr "Audió" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "Feliratok" + +msgctxt "#32397" +msgid "Quality" +msgstr "Minőség" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "Kodi videó beállitások" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "Kodi audió beállitások" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "Ugrás az évadra" + +msgctxt "#32401" +msgid "Directors" +msgstr "Rendezők" + +msgctxt "#32402" +msgid "Writer" +msgstr "Szerző" + +msgctxt "#32403" +msgid "Writers" +msgstr "Szerzők" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "Kapcsolódó filmek" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "Feliratok letöltése" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "Felirat késleltetés" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "Következő felirat" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "Feliratok letiltása" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "Feliratok engedélyezése" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "Platform verzió" + +msgctxt "#32411" +msgid "Unknown" +msgstr "Ismeretlen" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "Szerkesztés vagy törlés" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "Módosíthatja az IP-címet, vagy törli az aktuális beállítást?" + +msgctxt "#32414" +msgid "Clear" +msgstr "Törlés" + +msgctxt "#32415" +msgid "Edit" +msgstr "Módositás" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "Adja meg az IP-címet" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "Adja meg a port számát" + +msgctxt "#32418" +msgid "Creator" +msgstr "Alkotó" + +msgctxt "#32419" +msgid "Cast" +msgstr "Szereplők" + +msgctxt "#32420" +msgid "Disc" +msgstr "Lemez" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "Kijelentkezés" + +msgctxt "#32422" +msgid "Exit" +msgstr "Kilépés" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "Leállítás" + +msgctxt "#32424" +msgid "Suspend" +msgstr "Felfüggesztés" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "Hibernálás" + +msgctxt "#32426" +msgid "Reboot" +msgstr "Újraindítás" + +msgctxt "#32427" +msgid "Failed" +msgstr "Sikertelen" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "Bejelentkezés sikertelen" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "Folytatás innen {0}" + +msgctxt "#32430" +msgid "Discovery" +msgstr "Felfedezés" + +msgctxt "#32431" +msgid "Search" +msgstr "Keresés" + +msgctxt "#32432" +msgid "Space" +msgstr "Space" + +msgctxt "#32433" +msgid "Clear" +msgstr "Törlés mind" + +msgctxt "#32434" +msgid "Searching..." +msgstr "Keresés..." + +msgctxt "#32435" +msgid "No Results" +msgstr "Nincs találat" + +msgctxt "#32436" +msgid "Paused" +msgstr "Szünetelve" + +msgctxt "#32437" +msgid "Welcome" +msgstr "Üdvözöljük" + +msgctxt "#32438" +msgid "Previous" +msgstr "Előző" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "Következő lejátszása" + +msgctxt "#32440" +msgid "On Deck" +msgstr "Jelenlegi" + +msgctxt "#32441" +msgid "Unknown" +msgstr "Ismeretlen" + +msgctxt "#32442" +msgid "Embedded" +msgstr "Beágyazott" + +msgctxt "#32443" +msgid "Forced" +msgstr "Kényszerített" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "Dalszöveg" + +msgctxt "#32445" +msgid "Mono" +msgstr "Monó" + +msgctxt "#32446" +msgid "Stereo" +msgstr "Sztereó" + +msgctxt "#32447" +msgid "None" +msgstr "Nincs" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "A lejátszás sikertelen!" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "Nem lehet csatlakozni a plex.tv-hez[CR]Ellenőrizze az internetkapcsolatot, és próbálja újra." + +msgctxt "#32450" +msgid "Choose Version" +msgstr "Verzió választása" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "Verzió lejátszása..." + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "Nincs elérhető tartalom ebben a könyvtárban" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "Kérem adjon hozzá tartalmat és/vagy ellenőrizze, hogy a 'Hozzáadás az irányítópulthoz' opció be van kapcsolva" + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "Nincs elérhető tartalom ezzel a szűrővel" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "Kérem változtassa meg, vagy távolítsa el a jelenlegi szűrőt" + +msgctxt "#32456" +msgid "Offline Mode" +msgstr "Offline mód" + +msgctxt "#32457" +msgid "Sign In" +msgstr "Bejelentkezés" diff --git a/script.plexmod/resources/language/resource.language.it_it/strings.po b/script.plexmod/resources/language/resource.language.it_it/strings.po new file mode 100644 index 0000000000..50dee38bce --- /dev/null +++ b/script.plexmod/resources/language/resource.language.it_it/strings.po @@ -0,0 +1,951 @@ +# XBMC Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2013-12-12 22:56+0000\n" +"PO-Revision-Date: 2017-05-25 10:52+0200\n" +"Language-Team: LANGUAGE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Last-Translator: \n" +"X-Generator: Poedit 2.0.2\n" + +msgctxt "#32000" +msgid "Main" +msgstr "Principale" + +msgctxt "#32001" +msgid "Original" +msgstr "Originale" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "20 Mbps 1080p" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "12 Mbps 1080p" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "10 Mbps 1080p" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "8 Mbps 1080p" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "4 Mbps 720p" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "3 Mbps 720p" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "2 Mbps 720p" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "1.5 Mbps 480p" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "720 kbps" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "320 kbps" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "208 kbps" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "96 kbps" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "64 kbps" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "Qualità Locale" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "Qualità Remota" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "Qualità Online" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "Formato transcodifica" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "Log di Debug" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "Permetti Play Diretto" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "Permetti Stream Diretto" + +msgctxt "#32027" +msgid "Force" +msgstr "Forza" + +msgctxt "#32028" +msgid "Always" +msgstr "Sempre" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "Solo formati immagine" + +msgctxt "#32030" +msgid "Auto" +msgstr "Auto" + +msgctxt "#32031" +msgid "Burn Subtitles (Direct Play Only)" +msgstr "Sottotitoli (Solo Play Diretto)" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "Permetti connessioni non sicure" + +msgctxt "#32033" +msgid "Never" +msgstr "Mai" + +msgctxt "#32034" +msgid "On Same network" +msgstr "Sulla stessa rete" + +msgctxt "#32035" +msgid "Always" +msgstr "Sempre" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "Permetti 4K" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "Permetti HEVC (h265)" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "Accesso (Sign In) automatico" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "Post Play Auto Play" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "Abilita il download dei sottotitoli" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "Abilita il download dei sottotitoli" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "Ricerca Server (GDM)" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "Esegui Plex all'avvio di Kodi" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "IP connessione 1" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "Porta connessione 1" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "IP connessione 2" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "Porta connessione 2" + +msgctxt "#32048" +msgid "Audio" +msgstr "Audio" + +msgctxt "#32049" +msgid "Advanced" +msgstr "Avanzate" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "Server manuali" + +msgctxt "#32051" +msgid "Privacy" +msgstr "Privacy" + +msgctxt "#32052" +msgid "About" +msgstr "Circa" + +msgctxt "#32053" +msgid "Video" +msgstr "Video" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "Versione Addon" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Versione Kodi" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "Risoluzione schermo" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "Versione Server attuale" + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "All'avvio salta l'immissione del PIN e la selezione utente." + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "Se abilitato, quando la riproduzione finisce e un 'Titolo Successivo' è disponibile, sarà automaticamente riprodotto dopo un ritardo di 15 secondi." + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "Abilita se il tuo hardware supporta la riproduzione 4K. Disabilita per forzare la trascodifica." + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "Abilita se il tuo hardware supporta HEVC/h265. Disabilita per forzare la trascodifica." + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "Quando connettersi a Server con connessioni non sicure.[CR][CR]* [B]Mai[/B]: Mai connettersi a Server non sicuri[CR]* [B]Sulla stessa Rete[/B]: Permetti se nella stessa Rete[CR]* [B]Sempre[/B]: Permetti sulla stessa Rete e su Reti remote" + +msgctxt "#32201" +msgid "Trailer" +msgstr "Trailer" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "Scene cancellate" + +msgctxt "#32203" +msgid "Interview" +msgstr "Intervista" + +msgctxt "#32204" +msgid "Music Video" +msgstr "Video musicali" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "Dietro le scene" + +msgctxt "#32206" +msgid "Scene" +msgstr "Scena" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "Video musicali dal vivo" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "Testi video musicali" + +msgctxt "#32209" +msgid "Concert" +msgstr "Concerto" + +msgctxt "#32210" +msgid "Featurette" +msgstr "Featurette" + +msgctxt "#32211" +msgid "Short" +msgstr "Corto" + +msgctxt "#32212" +msgid "Other" +msgstr "Altro" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "Vai all'Album" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "Vai all'Artista" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "Vai a {0}" + +msgctxt "#32303" +msgid "Season" +msgstr "Stagione" + +msgctxt "#32304" +msgid "Episode" +msgstr "Episodio" + +msgctxt "#32305" +msgid "Extras" +msgstr "Extras" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "Serie correlate" + +msgctxt "#32307" +msgid "More" +msgstr "Più" + +msgctxt "#32308" +msgid "Available" +msgstr "Disponibile" + +msgctxt "#32309" +msgid "None" +msgstr "Nessuno" + +msgctxt "#32310" +msgid "S" +msgstr "S" + +msgctxt "#32311" +msgid "E" +msgstr "E" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "Non disponibile" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "Questo elemento non è al momento diponibile" + +msgctxt "#32314" +msgid "In Progress" +msgstr "In Corso" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "Riprendere la riproduzione?" + +msgctxt "#32316" +msgid "Resume" +msgstr "Riprendi" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "Riproduci dall'inizio" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "Marca come non visto" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "Marca come visto" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "Marca la Stagione come non vista" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "Marca la Stagione come vista" + +msgctxt "#32322" +msgid "Delete" +msgstr "Cancellato" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "Vai alla Serie" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "Vai a {0}" + +msgctxt "#32325" +msgid "Play Next" +msgstr "Riproduci il titolo succesivo" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "Cancellare veramente?" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "Sei sucuro che vuoi davvero cancellare questo media?" + +msgctxt "#32328" +msgid "Yes" +msgstr "Sì" + +msgctxt "#32329" +msgid "No" +msgstr "No" + +msgctxt "#32330" +msgid "Message" +msgstr "Messaggio" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "C'è stato un problema nella cancellazione del media." + +msgctxt "#32332" +msgid "Home" +msgstr "Home" + +msgctxt "#32333" +msgid "Playlists" +msgstr "Playlists" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "Conferma Uscita" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "Sei pronto per uscire da Plex?" + +msgctxt "#32336" +msgid "Exit" +msgstr "Esci" + +msgctxt "#32337" +msgid "Cancel" +msgstr "Cancella" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "Nessun Server trovato" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "Server non accessibile" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "Test di connessione in corso. Per favore attenti." + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "Server non accessibile. Per favore fai il sign in nel Server a controlla la connessione." + +msgctxt "#32342" +msgid "Switch User" +msgstr "Cambia utente" + +msgctxt "#32343" +msgid "Settings" +msgstr "Impostazioni" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "Esci (Sign Out)" + +msgctxt "#32345" +msgid "All" +msgstr "Tutto" + +msgctxt "#32346" +msgid "By Name" +msgstr "Per Nome" + +msgctxt "#32347" +msgid "Artists" +msgstr "Artisti" + +msgctxt "#32348" +msgid "movies" +msgstr "film" + +msgctxt "#32349" +msgid "photos" +msgstr "foto" + +msgctxt "#32350" +msgid "Shows" +msgstr "Serie" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "Per data di aggiunta" + +msgctxt "#32352" +msgid "Date Added" +msgstr "Data di aggiunta" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "Per data di uscita" + +msgctxt "#32354" +msgid "Release Date" +msgstr "Data di uscita" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "Per data di già visto" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "Data di già visto" + +msgctxt "#32357" +msgid "By Name" +msgstr "Per nome" + +msgctxt "#32358" +msgid "Name" +msgstr "Nome" + +msgctxt "#32359" +msgid "By Rating" +msgstr "Per Valutazione" + +msgctxt "#32360" +msgid "Rating" +msgstr "Valutazione" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "Per Risoluzione" + +msgctxt "#32362" +msgid "Resolution" +msgstr "Risoluzione" + +msgctxt "#32363" +msgid "By Duration" +msgstr "Per Durata" + +msgctxt "#32364" +msgid "Duration" +msgstr "Durata" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "Per prima trasmissione" + +msgctxt "#32366" +msgid "First Aired" +msgstr "Prima trasmissione" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "Per Non visto" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "Non visto" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "Per data di riproduzione" + +msgctxt "#32370" +msgid "Date Played" +msgstr "Data di riproduzione" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "Per numero di volte riprodotto" + +msgctxt "#32372" +msgid "Play Count" +msgstr "Numero di volte riprodotto" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "Per data di ripresa" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "Data di ripresa" + +msgctxt "#32375" +msgid "No filters available" +msgstr "Nussun filtro disponibile" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "Pulisci i filtri" + +msgctxt "#32377" +msgid "Year" +msgstr "Anno" + +msgctxt "#32378" +msgid "Decade" +msgstr "Decennio" + +msgctxt "#32379" +msgid "Genre" +msgstr "Genere" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "Classificazione dei contenuti" + +msgctxt "#32381" +msgid "Network" +msgstr "Rete" + +msgctxt "#32382" +msgid "Collection" +msgstr "Collezione" + +msgctxt "#32383" +msgid "Director" +msgstr "Regista" + +msgctxt "#32384" +msgid "Actor" +msgstr "Attore" + +msgctxt "#32385" +msgid "Country" +msgstr "Nazione" + +msgctxt "#32386" +msgid "Studio" +msgstr "Studio" + +msgctxt "#32387" +msgid "Labels" +msgstr "Etichette" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "Marca camera" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "Modello camera" + +msgctxt "#32390" +msgid "Aperture" +msgstr "Apertura" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "Velocità di scatto" + +msgctxt "#32392" +msgid "Lens" +msgstr "Lenti" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "Serie televisive" + +msgctxt "#32394" +msgid "Music" +msgstr "Musica" + +msgctxt "#32395" +msgid "Audio" +msgstr "Audio" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "Sottotitoli" + +msgctxt "#32397" +msgid "Quality" +msgstr "Qualità" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "Impostazioni Video di Kodi" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "Impostazioni Audio di Kodi" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "Vai alla Stagione" + +msgctxt "#32401" +msgid "Directors" +msgstr "Registi" + +msgctxt "#32402" +msgid "Writer" +msgstr "Autore" + +msgctxt "#32403" +msgid "Writers" +msgstr "Autori" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "Film correlati" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "Scarica Sottotitoli" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "Ritardo Sottotitolo" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "Sottotitolo successivo" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "Disabilita sottotitoli" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "Abilita Sottotitoli" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "Versione piattaforma" + +msgctxt "#32411" +msgid "Unknown" +msgstr "Sconosciuto" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "Modifica o Cancella" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "Modificare l'indirizzo IP o cancellare le impostazioni correnti?" + +msgctxt "#32414" +msgid "Clear" +msgstr "Cancella" + +msgctxt "#32415" +msgid "Edit" +msgstr "Modifica" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "Inserisci l'indirizzo IP" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "Inserisci il numero della Porta" + +msgctxt "#32418" +msgid "Creator" +msgstr "Creatore" + +msgctxt "#32419" +msgid "Cast" +msgstr "Cast" + +msgctxt "#32420" +msgid "Disc" +msgstr "Disc" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "Esci (Sign Out)" + +msgctxt "#32422" +msgid "Exit" +msgstr "Esci" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "Spegni" + +msgctxt "#32424" +msgid "Suspend" +msgstr "Sospenti" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "Iberna" + +msgctxt "#32426" +msgid "Reboot" +msgstr "Riavvia" + +msgctxt "#32427" +msgid "Failed" +msgstr "Fallito" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "Login fallita!" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "Riprendi da {0}" + +msgctxt "#32430" +msgid "Discovery" +msgstr "Ricerca" + +msgctxt "#32431" +msgid "Search" +msgstr "Cerca" + +msgctxt "#32432" +msgid "Space" +msgstr "Spazio" + +msgctxt "#32433" +msgid "Clear" +msgstr "Pulisci" + +msgctxt "#32434" +msgid "Searching..." +msgstr "In ricerca..." + +msgctxt "#32435" +msgid "No Results" +msgstr "Nessun risultato" + +msgctxt "#32436" +msgid "Paused" +msgstr "In Pausa" + +msgctxt "#32437" +msgid "Welcome" +msgstr "Benvenuto" + +msgctxt "#32438" +msgid "Previous" +msgstr "Precedente" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "Titolo successivo" + +msgctxt "#32440" +msgid "On Deck" +msgstr "Scoprire" + +msgctxt "#32441" +msgid "Unknown" +msgstr "Sconosciuto" + +msgctxt "#32442" +msgid "Embedded" +msgstr "Integrato" + +msgctxt "#32443" +msgid "Forced" +msgstr "Forzato" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "Testi" + +msgctxt "#32445" +msgid "Mono" +msgstr "Mono" + +msgctxt "#32446" +msgid "Stereo" +msgstr "Stereo" + +msgctxt "#32447" +msgid "None" +msgstr "Nessuno" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "Riproduzione fallita!" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "Impossibile connettersi a plex.tv[CR]Controlla la tua connessione ad Internet e riprova." + +msgctxt "#32450" +msgid "Choose Version" +msgstr "Seleziona Versione" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "Versione in Play..." + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "Nessun contenuto disponibile in questa libreria" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "Per favore aggiungi contenuti e/o controlla che 'Includi nella dashboard' è abilitato." + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "Nessun contenuto disponibile per questo filtro" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "Per favore cambia o rimuovi il filtro corrente" + +msgctxt "#32456" +msgid "Show" +msgstr "Serie" + +msgctxt "#32457" +msgid "By Show" +msgstr "Per Serie" + +msgctxt "#32458" +msgid "Episodes" +msgstr "Episodi" + +msgctxt "#32459" +msgid "Offline Mode" +msgstr "Modo Offline" + +msgctxt "#32460" +msgid "Sign In" +msgstr "Accedi (Sign In)" + +msgctxt "#32461" +msgid "Albums" +msgstr "Albums" + +msgctxt "#32462" +msgid "Artist" +msgstr "Artista" + +msgctxt "#32463" +msgid "By Artist" +msgstr "Per Artista" diff --git a/script.plexmod/resources/language/resource.language.pl_pl/strings.po b/script.plexmod/resources/language/resource.language.pl_pl/strings.po new file mode 100644 index 0000000000..d8b263ae0c --- /dev/null +++ b/script.plexmod/resources/language/resource.language.pl_pl/strings.po @@ -0,0 +1,984 @@ +# XBMC Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2013-12-12 22:56+0000\n" +"PO-Revision-Date: 2020-06-25 12:04+0200\n" +"Last-Translator: Lukasz Zacharski \n" +"Language-Team: LANGUAGE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pl\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +msgctxt "#32000" +msgid "Main" +msgstr "Główne" + +msgctxt "#32001" +msgid "Original" +msgstr "Oryginalna" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "20 Mb/s 1080p" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "12 Mb/s 1080p" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "10 Mb/s 1080p" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "8 Mb/s 1080p" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "4 Mb/s 720p" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "3 Mb/s 720p" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "2 Mb/s 720p" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "1.5 Mb/s 480p" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "720 kb/s" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "320 kb/s" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "208 kb/s" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "96 kb/s" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "64 kb/s" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "Jakość lokalna" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "Jakość zdalna" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "Jakość online" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "Format transkodowania" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "Dziennik debugowania" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "Zezwól na bezpośrednie odtwarzanie" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "Zezwól na bezpośrednie strumieniowanie" + +msgctxt "#32027" +msgid "Force" +msgstr "Wymuszaj" + +msgctxt "#32028" +msgid "Always" +msgstr "Zawsze" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "Tylko formaty graficzne" + +msgctxt "#32030" +msgid "Auto" +msgstr "Automatyczne" + +msgctxt "#32031" +msgid "Burn Subtitles (Direct Play Only)" +msgstr "Wypalaj napisy (tylko bezpośrednie odtwarzanie)" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "Zezwól na niezabezpieczone połączenia" + +msgctxt "#32033" +msgid "Never" +msgstr "Nigdy" + +msgctxt "#32034" +msgid "On Same network" +msgstr "W tej samej sieci" + +msgctxt "#32035" +msgid "Always" +msgstr "Zawsze" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "Zezwól na 4K" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "Zezwól na HEVC (H.265)" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "Zaloguj się automatycznie" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "Odtwarzaj „Następne” automatycznie" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "Włącz pobieranie napisów" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "Włącz pobieranie napisów" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "Odnajdowanie serwera (GDM)" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "Uruchom Plex przy starcie Kodi" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "IP połączenia 1" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "Port połączenia 1" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "IP połączenia 2" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "Port połączenia 2" + +msgctxt "#32048" +msgid "Audio" +msgstr "Audio" + +msgctxt "#32049" +msgid "Advanced" +msgstr "Zaawansowane" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "Ręcznie dodane serwery" + +msgctxt "#32051" +msgid "Privacy" +msgstr "Prywatność" + +msgctxt "#32052" +msgid "About" +msgstr "O dodatku" + +msgctxt "#32053" +msgid "Video" +msgstr "Wideo" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "Wersja dodatku" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Wersja Kodi" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "Rozdzielczość ekranu" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "Obecna wersja serwera" + + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "Pomiń wybór użytkownika i kod PIN przy starcie." + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "Jeśli włączone, po zakończeniu odtwarzania i dostępnej pozycji w „Następne”, zostanie ona automatycznie odtworzona po 15 sekundach." + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "Włącz, jeśli Twój sprzęt obsługuje odtwarzanie 4K. Wyłącz, aby wymusić transkodowanie." + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "Włącz, jeśli Twój sprzęt obsługuje HEVC/H.265. Wyłącz, aby wymusić transkodowanie." + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "Kiedy łączyć z serwerami bez zabezpieczonych połączeń.[CR][CR]* [B]Nigdy[/B]: Nigdy nie łącz w sposób niezabezpieczony[CR]* [B]W tej samej sieci[/B]: Zezwól, jeśli w tej samej sieci[CR]* [B]Zawsze[/B]: Zezwól w tej samej sieci i zdalnie" + + +msgctxt "#32201" +msgid "Trailer" +msgstr "Zwiastun" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "Usunięta scena" + +msgctxt "#32203" +msgid "Interview" +msgstr "Wywiad" + +msgctxt "#32204" +msgid "Music Video" +msgstr "Teledysk" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "Za kulisami" + +msgctxt "#32206" +msgid "Scene" +msgstr "Scena" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "Teledysk na żywo" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "Teledysk z tekstem" + +msgctxt "#32209" +msgid "Concert" +msgstr "Koncert" + +msgctxt "#32210" +msgid "Featurette" +msgstr "Średniometrażowy" + +msgctxt "#32211" +msgid "Short" +msgstr "Krótkometrażowy" + +msgctxt "#32212" +msgid "Other" +msgstr "Inne" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "Przejdź do albumu" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "Przejdź do wykonawcy" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "Przejdź do {0}" + +msgctxt "#32303" +msgid "Season" +msgstr "Sezon" + +msgctxt "#32304" +msgid "Episode" +msgstr "Odcinek" + +msgctxt "#32305" +msgid "Extras" +msgstr "Dodatki" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "Powiązane seriale" + +msgctxt "#32307" +msgid "More" +msgstr "Więcej" + +msgctxt "#32308" +msgid "Available" +msgstr "Dostępne" + +msgctxt "#32309" +msgid "None" +msgstr "Brak" + +msgctxt "#32310" +msgid "S" +msgstr "S" + +msgctxt "#32311" +msgid "E" +msgstr "O" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "Niedostępne" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "Ten element jest obecnie niedostępny." + +msgctxt "#32314" +msgid "In Progress" +msgstr "W toku" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "Wznowić odtwarzanie" + +msgctxt "#32316" +msgid "Resume" +msgstr "Wznów" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "Odtwórz od początku" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "Oznacz jako nieodtworzone" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "Oznacz jako odtworzone" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "Oznacz sezon jako nieodtworzony" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "Oznacz sezon jako odtworzony" + +msgctxt "#32322" +msgid "Delete" +msgstr "Usuń" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "Przejdź do serialu" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "Przejdź do {0}" + +msgctxt "#32325" +msgid "Play Next" +msgstr "Odtwórz następne" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "Na pewno usunąć?" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "Czy na pewno chcesz usunąć te multimedia?" + +msgctxt "#32328" +msgid "Yes" +msgstr "Tak" + +msgctxt "#32329" +msgid "No" +msgstr "Nie" + +msgctxt "#32330" +msgid "Message" +msgstr "Wiadomość" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "Wystąpił problem z usunięciem multimediów." + +msgctxt "#32332" +msgid "Home" +msgstr "Strona główna" + +msgctxt "#32333" +msgid "Playlists" +msgstr "Playlisty" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "Potwierdź wyjście" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "Czy chcesz wyjść z Plex?" + +msgctxt "#32336" +msgid "Exit" +msgstr "Wyjdź" + +msgctxt "#32337" +msgid "Cancel" +msgstr "Anuluj" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "Nie znaleziono serwerów" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "Serwer jest niedostępny" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "Trwa testowanie połączeń. Proszę czekać." + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "Serwer jest niedostępny. Zaloguj się na swój serwer i sprawdź połączenie." + +msgctxt "#32342" +msgid "Switch User" +msgstr "Przełącz użytkownika" + +msgctxt "#32343" +msgid "Settings" +msgstr "Ustawienia" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "Wyloguj się" + +msgctxt "#32345" +msgid "All" +msgstr "Wszystkie" + +msgctxt "#32346" +msgid "By Name" +msgstr "Wg nazwy" + +msgctxt "#32347" +msgid "Artists" +msgstr "Wykonawcy" + +msgctxt "#32348" +msgid "movies" +msgstr "Filmy" + +msgctxt "#32349" +msgid "photos" +msgstr "Zdjęcia" + +msgctxt "#32350" +msgid "Shows" +msgstr "Seriale" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "Wg daty dodania" + +msgctxt "#32352" +msgid "Date Added" +msgstr "Data dodania" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "Wg daty wydania" + +msgctxt "#32354" +msgid "Release Date" +msgstr "Data wydania" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "Wg daty wyświetlenia" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "Data wyświetlenia" + +msgctxt "#32357" +msgid "By Name" +msgstr "Wg nazwy" + +msgctxt "#32358" +msgid "Name" +msgstr "Nazwa" + +msgctxt "#32359" +msgid "By Rating" +msgstr "Wg oceny" + +msgctxt "#32360" +msgid "Rating" +msgstr "Ocena" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "Wg rozdzielczości" + +msgctxt "#32362" +msgid "Resolution" +msgstr "Rozdzielczość" + +msgctxt "#32363" +msgid "By Duration" +msgstr "Wg czasu trwania" + +msgctxt "#32364" +msgid "Duration" +msgstr "Czas trwania" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "Wg pierwszej emisji" + +msgctxt "#32366" +msgid "First Aired" +msgstr "Pierwsza emisja" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "Wg nieodtworzonych" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "Nieodtworzone" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "Wg daty odtworzenia" + +msgctxt "#32370" +msgid "Date Played" +msgstr "Data odtworzenia" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "Wg ilości odtworzeń" + +msgctxt "#32372" +msgid "Play Count" +msgstr "Ilość odtworzeń" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "Wg daty wykonania" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "Data wykonania" + +msgctxt "#32375" +msgid "No filters available" +msgstr "Brak dostępnych filtrów" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "Wyczyść filtr" + +msgctxt "#32377" +msgid "Year" +msgstr "Rok" + +msgctxt "#32378" +msgid "Decade" +msgstr "Dekada" + +msgctxt "#32379" +msgid "Genre" +msgstr "Gatunek" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "Ocena treści" + +msgctxt "#32381" +msgid "Network" +msgstr "Stacja" + +msgctxt "#32382" +msgid "Collection" +msgstr "Kolekcja" + +msgctxt "#32383" +msgid "Director" +msgstr "Reżyser" + +msgctxt "#32384" +msgid "Actor" +msgstr "Aktor" + +msgctxt "#32385" +msgid "Country" +msgstr "Kraj" + +msgctxt "#32386" +msgid "Studio" +msgstr "Studio" + +msgctxt "#32387" +msgid "Labels" +msgstr "Etykiety" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "Producent aparatu" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "Model aparatu" + +msgctxt "#32390" +msgid "Aperture" +msgstr "Przysłona" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "Czas migawki" + +msgctxt "#32392" +msgid "Lens" +msgstr "Obiektyw" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "Seriale" + +msgctxt "#32394" +msgid "Music" +msgstr "Muzyka" + +msgctxt "#32395" +msgid "Audio" +msgstr "Audio" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "Napisy" + +msgctxt "#32397" +msgid "Quality" +msgstr "Jakość" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "Ustawienia wideo Kodi" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "Ustawienia audio Kodi" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "Przejdź do sezonu" + +msgctxt "#32401" +msgid "Directors" +msgstr "Reżyserzy" + +msgctxt "#32402" +msgid "Writer" +msgstr "Scenarzysta" + +msgctxt "#32403" +msgid "Writers" +msgstr "Scenarzyści" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "Powiązane filmy" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "Pobierz napisy" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "Opóźnienie napisów" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "Następne napisy" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "Wyłącz napisy" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "Włącz napisy" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "Wersja platformy" + +msgctxt "#32411" +msgid "Unknown" +msgstr "Nieznana" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "Edytuj lub wyczyść" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "Edytować adres IP lub wyczyścić obecne ustawienie?" + +msgctxt "#32414" +msgid "Clear" +msgstr "Wyczyść" + +msgctxt "#32415" +msgid "Edit" +msgstr "Edytuj" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "Wprowadź adres IP" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "Wprowadź numer portu" + +msgctxt "#32418" +msgid "Creator" +msgstr "Twórca" + +msgctxt "#32419" +msgid "Cast" +msgstr "Obsada" + +msgctxt "#32420" +msgid "Disc" +msgstr "Dysk" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "Wyloguj się" + +msgctxt "#32422" +msgid "Exit" +msgstr "Wyjdź" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "Zamknij" + +msgctxt "#32424" +msgid "Suspend" +msgstr "Uśpij" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "Hibernuj" + +msgctxt "#32426" +msgid "Reboot" +msgstr "Uruchom ponownie" + +msgctxt "#32427" +msgid "Failed" +msgstr "Nieudane" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "Logowanie nieudane!" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "Wznów od {0}" + +msgctxt "#32430" +msgid "Discovery" +msgstr "Odkrywanie" + +msgctxt "#32431" +msgid "Search" +msgstr "Wyszukiwanie" + +msgctxt "#32432" +msgid "Space" +msgstr "Spacja" + +msgctxt "#32433" +msgid "Clear" +msgstr "Wyczyść" + +msgctxt "#32434" +msgid "Searching..." +msgstr "Wyszukiwanie..." + +msgctxt "#32435" +msgid "No Results" +msgstr "Brak wyników" + +msgctxt "#32436" +msgid "Paused" +msgstr "Wstrzymano" + +msgctxt "#32437" +msgid "Welcome" +msgstr "Witaj" + +msgctxt "#32438" +msgid "Previous" +msgstr "Poprzednie" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "Odtwarzanie następnego" + +msgctxt "#32440" +msgid "On Deck" +msgstr "Na tapecie" + +msgctxt "#32441" +msgid "Unknown" +msgstr "Nieznany" + +msgctxt "#32442" +msgid "Embedded" +msgstr "Osadzone" + +msgctxt "#32443" +msgid "Forced" +msgstr "Wymuszone" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "Tekst" + +msgctxt "#32445" +msgid "Mono" +msgstr "Mono" + +msgctxt "#32446" +msgid "Stereo" +msgstr "Stereo" + +msgctxt "#32447" +msgid "None" +msgstr "Brak" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "Odtwarzanie nieudane!" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "Nie można połączyć z plex.tv[CR]Sprawdź połączenie internetowe i spróbuj ponownie." + +msgctxt "#32450" +msgid "Choose Version" +msgstr "Wybierz wersję" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "Odtwórz wersję..." + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "Brak zawartości w tej bibliotece" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "Dodaj zawartość i/lub sprawdź, czy opcja „Załącz na pulpicie” jest włączona." + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "Brak zawartości dla tego filtra" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "Zmień lub usuń bieżący filtr" + +msgctxt "#32456" +msgid "Show" +msgstr "Serial" + +msgctxt "#32457" +msgid "By Show" +msgstr "Wg serialu" + +msgctxt "#32458" +msgid "Episodes" +msgstr "Odcinki(ów)" + +msgctxt "#32459" +msgid "Offline Mode" +msgstr "Tryb offline" + +msgctxt "#32460" +msgid "Sign In" +msgstr "Zaloguj się" + +msgctxt "#32461" +msgid "Albums" +msgstr "Albumy" + +msgctxt "#32462" +msgid "Artist" +msgstr "Wykonawca" + +msgctxt "#32463" +msgid "By Artist" +msgstr "Wg wykonawcy" + +msgctxt "#32464" +msgid "Player" +msgstr "Odtwarzacz" + +msgctxt "#32465" +msgid "Use skip step settings from Kodi" +msgstr "Użyj ustawień kroków przeskoku z Kodi" + +msgctxt "#32466" +msgid "Automatically seek selected position after a delay" +msgstr "Automatycznie szukaj wybranej pozycji po opóźnieniu" + +msgctxt "#32467" +msgid "User Interface" +msgstr "Interfejs użytkownika" + +msgctxt "#32471" +msgid "Use Plex/Kodi steps for timeline" +msgstr "Użyj kroków Plex/Kodi dla osi czasu" + +msgctxt "#32485" +msgid "Go back instantly with the previous menu action in scrolled views" +msgstr "Wróć natychmiast akcją menu „poprzednie” w przewijanych widokach" + +msgctxt "#32492" +msgid "Kodi Subtitle Settings" +msgstr "Ustawienia napisów Kodi" + +msgctxt "#32495" +msgid "Skip intro" +msgstr "Pomiń wstęp" diff --git a/script.plexmod/resources/language/resource.language.pt_br/strings.po b/script.plexmod/resources/language/resource.language.pt_br/strings.po new file mode 100644 index 0000000000..98bd80061d --- /dev/null +++ b/script.plexmod/resources/language/resource.language.pt_br/strings.po @@ -0,0 +1,951 @@ +# XBMC Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2013-12-12 22:56+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pt-BR\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +msgctxt "#32000" +msgid "Main" +msgstr "Principal" + +msgctxt "#32001" +msgid "Original" +msgstr "Original" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "20 Mbps 1080p" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "12 Mbps 1080p" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "10 Mbps 1080p" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "8 Mbps 1080p" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "4 Mbps 720p" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "3 Mbps 720p" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "2 Mbps 720p" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "1.5 Mbps 480p" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "720 kbps" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "320 kbps" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "208 kbps" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "96 kbps" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "64 kbps" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "Qualidade Local" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "Qualidade Remota" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "Qualidade Online" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "Formato de Transcodificação" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "Registro de Depuração" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "Permitir Reprodução Direta" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "Permitir Transmissão Direta" + +msgctxt "#32027" +msgid "Force" +msgstr "Forçar" + +msgctxt "#32028" +msgid "Always" +msgstr "Sempre" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "Apenas Formatos de Imagem" + +msgctxt "#32030" +msgid "Auto" +msgstr "Auto" + +msgctxt "#32031" +msgid "Burn Subtitles (Direct Play Only)" +msgstr "Gravar Legendas (Somente Reprodução Direta)" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "Permitir Conexões Inseguras" + +msgctxt "#32033" +msgid "Never" +msgstr "Nunca" + +msgctxt "#32034" +msgid "On Same network" +msgstr "Na Mesma Rede" + +msgctxt "#32035" +msgid "Always" +msgstr "Sempre" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "Permitir 4K" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "Permitir HEVC (h265)" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "Conectar Automaticamente" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "Reprodução Automática Após Reprodução" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "Habilitar Download de Legendas" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "Habilitar Download de Legendas" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "Descoberta de Servidor (GDM)" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "Iniciar Plex quando Kodi Iniciar" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "Conexão de IP 1" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "Conexão de Porta 1" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "Conexão de IP 2" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "Conexão de Porta 2" + +msgctxt "#32048" +msgid "Audio" +msgstr "Áudio" + +msgctxt "#32049" +msgid "Advanced" +msgstr "Avançado" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "Servidores Manuais" + +msgctxt "#32051" +msgid "Privacy" +msgstr "Privacidade" + +msgctxt "#32052" +msgid "About" +msgstr "Sobre" + +msgctxt "#32053" +msgid "Video" +msgstr "Vídeo" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "Versão do Addon" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Versão do Kodi" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "Resolução da Tela" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "Versão Atual do Servidor" + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "Pular seleção de usuário e inserção do PIN ao iniciar." + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "Se habilitado, quando a reprodução acabar e existir algum item 'A Seguir', será automáticamente reproduzido depois de 15 segudos." + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "Habilite isto se seu equipamento suporta reprodução 4K. Desabilite para forçar transcodificação." + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "Habilite isto se seu equipamento suporta HEVC/h265. Desabilite para forçar transcodificação." + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "Quando conectar à servidores sem conexão segura.[CR][CR]* [B]Nunca[/B]: Nunca conectar à um servidor inseguramente[CR]* [B]Na Mesma Rede[/B]: Permitir se na mesma reder[CR]* [B]Sempre[/B]: Permitir conexão na mesma rede e remotamente" + +msgctxt "#32201" +msgid "Trailer" +msgstr "Trailer" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "Cena apagada" + +msgctxt "#32203" +msgid "Interview" +msgstr "Entrevista" + +msgctxt "#32204" +msgid "Music Video" +msgstr "Videoclipe" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "Por trás das cenas" + +msgctxt "#32206" +msgid "Scene" +msgstr "Cena" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "Videoclipe ao vivo" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "Videclipe com Letra" + +msgctxt "#32209" +msgid "Concert" +msgstr "Show" + +msgctxt "#32210" +msgid "Featurette" +msgstr "Featurette" + +msgctxt "#32211" +msgid "Short" +msgstr "Curta" + +msgctxt "#32212" +msgid "Other" +msgstr "Outro" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "Ir para Álbum" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "Ir para Artista" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "Ir para {0}" + +msgctxt "#32303" +msgid "Season" +msgstr "Temporada" + +msgctxt "#32304" +msgid "Episode" +msgstr "Episódio" + +msgctxt "#32305" +msgid "Extras" +msgstr "Extras" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "Séries relacionadas" + +msgctxt "#32307" +msgid "More" +msgstr "Mais" + +msgctxt "#32308" +msgid "Available" +msgstr "Disponível" + +msgctxt "#32309" +msgid "None" +msgstr "Nenhum" + +msgctxt "#32310" +msgid "S" +msgstr "S" + +msgctxt "#32311" +msgid "E" +msgstr "E" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "Indisponível" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "Este item está atualmente indisponível." + +msgctxt "#32314" +msgid "In Progress" +msgstr "Em Progresso" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "Resumir reprodução" + +msgctxt "#32316" +msgid "Resume" +msgstr "Resumir" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "Reproduzir do começo" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "Marcar como Não-Visto" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "Marcar como Visto" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "Marcar Temporada como Não-Vista" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "Marcar Temporada como Vista" + +msgctxt "#32322" +msgid "Delete" +msgstr "Apagar" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "Ir para Série" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "Ir para {0}" + +msgctxt "#32325" +msgid "Play Next" +msgstr "Reproduzir Próximo" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "Realmente apagar?" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "Tem certeza que quer apagar esta mídia?" + +msgctxt "#32328" +msgid "Yes" +msgstr "Sim" + +msgctxt "#32329" +msgid "No" +msgstr "Não" + +msgctxt "#32330" +msgid "Message" +msgstr "Mensagem" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "Ocorreu um problema ao apagar esta mídia." + +msgctxt "#32332" +msgid "Home" +msgstr "Início" + +msgctxt "#32333" +msgid "Playlists" +msgstr "Listas de Reprodução" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "Confirmar Saída" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "Está pronto para sair do Plex?" + +msgctxt "#32336" +msgid "Exit" +msgstr "Sair" + +msgctxt "#32337" +msgid "Cancel" +msgstr "Cancelar" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "Nenhum Servidor Encontrado" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "Servidor inacessível" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "Testes de conexão estão em progresso. Por favor, aguarde." + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "Servidor inacessível. Conecte em seu servidor e teste sua conexão." + +msgctxt "#32342" +msgid "Switch User" +msgstr "Trocar Usuário" + +msgctxt "#32343" +msgid "Settings" +msgstr "Configurações" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "Desconectar" + +msgctxt "#32345" +msgid "All" +msgstr "Tudo" + +msgctxt "#32346" +msgid "By Name" +msgstr "Por Nome" + +msgctxt "#32347" +msgid "Artists" +msgstr "Artistas" + +msgctxt "#32348" +msgid "movies" +msgstr "filmes" + +msgctxt "#32349" +msgid "photos" +msgstr "fotos" + +msgctxt "#32350" +msgid "Shows" +msgstr "Séries" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "Por Data Adicionado" + +msgctxt "#32352" +msgid "Date Added" +msgstr "Data Adicionado" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "Por Data de Lançamento" + +msgctxt "#32354" +msgid "Release Date" +msgstr "Data de Lançamento" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "Por Data de Visualização" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "Data de Visualização" + +msgctxt "#32357" +msgid "By Name" +msgstr "Por Nome" + +msgctxt "#32358" +msgid "Name" +msgstr "Nome" + +msgctxt "#32359" +msgid "By Rating" +msgstr "Por Avaliação" + +msgctxt "#32360" +msgid "Rating" +msgstr "Avaliação" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "Por Resolução" + +msgctxt "#32362" +msgid "Resolution" +msgstr "Resolução" + +msgctxt "#32363" +msgid "By Duration" +msgstr "Por Duração" + +msgctxt "#32364" +msgid "Duration" +msgstr "Duração" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "Por Data de Estreia" + +msgctxt "#32366" +msgid "First Aired" +msgstr "Data de Estreia" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "Por Não-Vistos" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "Não-Vistos" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "Por Data de Reprodução" + +msgctxt "#32370" +msgid "Date Played" +msgstr "Data de Reprodução" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "Por Número de Reproduções" + +msgctxt "#32372" +msgid "Play Count" +msgstr "Número de Reproduções" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "Por Data Tirada" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "Data Tirada" + +msgctxt "#32375" +msgid "No filters available" +msgstr "Nenhum filtro disponível" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "Limpar filtro" + +msgctxt "#32377" +msgid "Year" +msgstr "Ano" + +msgctxt "#32378" +msgid "Decade" +msgstr "Década" + +msgctxt "#32379" +msgid "Genre" +msgstr "Gênero" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "Classificação do Conteúdo" + +msgctxt "#32381" +msgid "Network" +msgstr "Rede" + +msgctxt "#32382" +msgid "Collection" +msgstr "Coleção" + +msgctxt "#32383" +msgid "Director" +msgstr "Diretor" + +msgctxt "#32384" +msgid "Actor" +msgstr "Ator" + +msgctxt "#32385" +msgid "Country" +msgstr "País" + +msgctxt "#32386" +msgid "Studio" +msgstr "Estúdio" + +msgctxt "#32387" +msgid "Labels" +msgstr "Rótulos" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "Fabricante da câmera" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "Modelo da câmera" + +msgctxt "#32390" +msgid "Aperture" +msgstr "Abertura" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "Velocidade do Obturador" + +msgctxt "#32392" +msgid "Lens" +msgstr "Lente" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "Séries" + +msgctxt "#32394" +msgid "Music" +msgstr "Música" + +msgctxt "#32395" +msgid "Audio" +msgstr "Áudio" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "Legendas" + +msgctxt "#32397" +msgid "Quality" +msgstr "Qualidade" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "Configurações de Vídeo do Kodi" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "Configurações de Áudio do Kodi" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "Ir para Temporada" + +msgctxt "#32401" +msgid "Directors" +msgstr "Diretores" + +msgctxt "#32402" +msgid "Writer" +msgstr "Escritor" + +msgctxt "#32403" +msgid "Writers" +msgstr "Escritores" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "Filmes relacionados" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "Baixar Legendas" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "Atraso da Legenda" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "Próxima Legenda" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "Desabilitar Legendas" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "Habilitar Legendas" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "Versão da Plataforma" + +msgctxt "#32411" +msgid "Unknown" +msgstr "Desconhecido" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "Editar ou Limpar" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "Editar endereço de IP ou limpar configurações atuais?" + +msgctxt "#32414" +msgid "Clear" +msgstr "Limpar" + +msgctxt "#32415" +msgid "Edit" +msgstr "Editar" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "Insira o endereço de IP" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "Insira o número da Porta" + +msgctxt "#32418" +msgid "Creator" +msgstr "Criador" + +msgctxt "#32419" +msgid "Cast" +msgstr "Elenco" + +msgctxt "#32420" +msgid "Disc" +msgstr "Disco" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "Desconectar" + +msgctxt "#32422" +msgid "Exit" +msgstr "Sair" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "Desligar" + +msgctxt "#32424" +msgid "Suspend" +msgstr "Suspender" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "Hibernar" + +msgctxt "#32426" +msgid "Reboot" +msgstr "Reiniciar" + +msgctxt "#32427" +msgid "Failed" +msgstr "Falhou" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "Login falhou!" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "Resumir de {0}" + +msgctxt "#32430" +msgid "Discovery" +msgstr "Descobrir" + +msgctxt "#32431" +msgid "Search" +msgstr "Procurar" + +msgctxt "#32432" +msgid "Space" +msgstr "Espaço" + +msgctxt "#32433" +msgid "Clear" +msgstr "Limpar" + +msgctxt "#32434" +msgid "Searching..." +msgstr "Procurando..." + +msgctxt "#32435" +msgid "No Results" +msgstr "Sem Resultados" + +msgctxt "#32436" +msgid "Paused" +msgstr "Pausado" + +msgctxt "#32437" +msgid "Welcome" +msgstr "Bem-Vindo" + +msgctxt "#32438" +msgid "Previous" +msgstr "Anterior" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "Reproduzindo a seguir" + +msgctxt "#32440" +msgid "On Deck" +msgstr "No Deck" + +msgctxt "#32441" +msgid "Unknown" +msgstr "Desconhecido" + +msgctxt "#32442" +msgid "Embedded" +msgstr "Embutido" + +msgctxt "#32443" +msgid "Forced" +msgstr "Forçado" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "Letra da música" + +msgctxt "#32445" +msgid "Mono" +msgstr "Mono" + +msgctxt "#32446" +msgid "Stereo" +msgstr "Estéreo" + +msgctxt "#32447" +msgid "None" +msgstr "Nenhum" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "Reprodução falhou!" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "Nao pôde conectar com o plex.tv[CR]Teste sua conexão com a internet e tente novamente." + +msgctxt "#32450" +msgid "Choose Version" +msgstr "Escolha a Versão" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "Reproduzir Versão..." + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "Nenhum conteúdo disponível nesta biblioteca" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "Por favor adicione e/ou confirme que 'Incluir no Painel' está habilitado." + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "Nenhum conteúdo disponível para este filtro" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "Por favor, troque ou remova o filtro atual" + +msgctxt "#32456" +msgid "Show" +msgstr "Série" + +msgctxt "#32457" +msgid "By Show" +msgstr "Por Série" + +msgctxt "#32458" +msgid "Episodes" +msgstr "Episódios" + +msgctxt "#32459" +msgid "Offline Mode" +msgstr "Modo Offline" + +msgctxt "#32460" +msgid "Sign In" +msgstr "Conectar" + +msgctxt "#32461" +msgid "Albums" +msgstr "Álbuns" + +msgctxt "#32462" +msgid "Artist" +msgstr "Artista" + +msgctxt "#32463" +msgid "By Artist" +msgstr "Por Artista" + diff --git a/script.plexmod/resources/language/resource.language.pt_pt/strings.po b/script.plexmod/resources/language/resource.language.pt_pt/strings.po new file mode 100644 index 0000000000..7c265ff3c6 --- /dev/null +++ b/script.plexmod/resources/language/resource.language.pt_pt/strings.po @@ -0,0 +1,980 @@ +# XBMC Media Center language file +# Guerreiro , 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2013-12-12 22:56+0000\n" +"PO-Revision-Date: 2019-09-10 18:44+0100\n" +"Last-Translator: Guerreiro \n" +"Language-Team: Português <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pt\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgctxt "#32000" +msgid "Main" +msgstr "Principal" + +msgctxt "#32001" +msgid "Original" +msgstr "Original" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "20 Mbps 1080p" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "12 Mbps 1080p" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "10 Mbps 1080p" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "8 Mbps 1080p" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "4 Mbps 720p" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "3 Mbps 720p" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "2 Mbps 720p" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "1.5 Mbps 480p" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "720 kbps" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "320 kbps" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "208 kbps" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "96 kbps" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "64 kbps" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "Qualidade Local" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "Qualidade Remota" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "Qualidade Online" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "Formato de Transcodificação" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "Registo de Depuração" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "Permitir Reprodução Direta" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "Permitir Transmissão Direta" + +msgctxt "#32027" +msgid "Force" +msgstr "Forçar" + +msgctxt "#32028" +msgid "Always" +msgstr "Sempre" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "Apenas Formatos de Imagem" + +msgctxt "#32030" +msgid "Auto" +msgstr "Auto" + +msgctxt "#32031" +msgid "Burn Subtitles (Direct Play Only)" +msgstr "Gravar Legendas (Somente Reprodução Direta)" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "Permitir Ligações Inseguras" + +msgctxt "#32033" +msgid "Never" +msgstr "Nunca" + +msgctxt "#32034" +msgid "On Same network" +msgstr "Na Mesma Rede" + +msgctxt "#32035" +msgid "Always" +msgstr "Sempre" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "Permitir 4K" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "Permitir HEVC (h265)" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "Entrar Automaticamente" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "Reprodução Automática" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "Ativar a Transferência de Legendas" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "Ativar a Transferência de Legendas" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "Descoberta de Servidor (GDM)" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "Iniciar Plex Automaticamente" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "IP de Ligação 1" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "Porta de Ligação 1" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "IP de Ligação 2" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "Porta de Ligação 2" + +msgctxt "#32048" +msgid "Audio" +msgstr "Áudio" + +msgctxt "#32049" +msgid "Advanced" +msgstr "Avançado" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "Servidores Manuais" + +msgctxt "#32051" +msgid "Privacy" +msgstr "Privacidade" + +msgctxt "#32052" +msgid "About" +msgstr "Sobre" + +msgctxt "#32053" +msgid "Video" +msgstr "Vídeo" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "Versão do Addon" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Versão do Kodi" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "Resolução de Ecrã" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "Versão Atual do Servidor" + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "Saltar seleção de utilizador e inserção do PIN ao iniciar." + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "Se ativado, quando a reprodução acabar e existir algum item 'A Seguir', será automáticamente reproduzido depois de 15 segundos." + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "Ative isto se seu equipamento suportar reprodução 4K. Desative para forçar conversão." + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "Ative isto se seu equipamento suportar HEVC/h265. Desative para forçar conversão." + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "Quando ligar à servidores sem ligação segura.[CR][CR]* [B]Nunca[/B]: Nunca ligar à um servidor de forma insegura[CR]* [B]Na Mesma Rede[/B]: Permitir se na mesma rede[CR]* [B]Sempre[/B]: Permitir ligação na mesma rede e remotamente" + +msgctxt "#32201" +msgid "Trailer" +msgstr "Trailer" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "Cena apagada" + +msgctxt "#32203" +msgid "Interview" +msgstr "Entrevista" + +msgctxt "#32204" +msgid "Music Video" +msgstr "Vídeo Clipe" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "Nos Bastidores" + +msgctxt "#32206" +msgid "Scene" +msgstr "Cena" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "Vídeo Clipe ao Vivo" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "Vide Clipe com Letra" + +msgctxt "#32209" +msgid "Concert" +msgstr "Concerto" + +msgctxt "#32210" +msgid "Featurette" +msgstr "Destaques" + +msgctxt "#32211" +msgid "Short" +msgstr "Curta" + +msgctxt "#32212" +msgid "Other" +msgstr "Outro" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "Ir para Álbum" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "Ir para Artista" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "Ir para {0}" + +msgctxt "#32303" +msgid "Season" +msgstr "Temporada" + +msgctxt "#32304" +msgid "Episode" +msgstr "Episódio" + +msgctxt "#32305" +msgid "Extras" +msgstr "Extras" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "Séries relacionadas" + +msgctxt "#32307" +msgid "More" +msgstr "Mais" + +msgctxt "#32308" +msgid "Available" +msgstr "Disponível" + +msgctxt "#32309" +msgid "None" +msgstr "Nenhum" + +msgctxt "#32310" +msgid "S" +msgstr "T" + +msgctxt "#32311" +msgid "E" +msgstr "E" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "Indisponível" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "Este item está atualmente indisponível." + +msgctxt "#32314" +msgid "In Progress" +msgstr "Em Progresso" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "Resumir reprodução" + +msgctxt "#32316" +msgid "Resume" +msgstr "Resumir" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "Reproduzir do inicio" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "Marcar como Não-Visto" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "Marcar como Visto" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "Marcar Temporada como Não-Vista" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "Marcar Temporada como Vista" + +msgctxt "#32322" +msgid "Delete" +msgstr "Apagar" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "Ir para Série" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "Ir para {0}" + +msgctxt "#32325" +msgid "Play Next" +msgstr "Reproduzir Próximo" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "Realmente Apagar?" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "Tem certeza que quer apagar este item?" + +msgctxt "#32328" +msgid "Yes" +msgstr "Sim" + +msgctxt "#32329" +msgid "No" +msgstr "Não" + +msgctxt "#32330" +msgid "Message" +msgstr "Mensagem" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "Ocorreu um problema ao apagar este item." + +msgctxt "#32332" +msgid "Home" +msgstr "Início" + +msgctxt "#32333" +msgid "Playlists" +msgstr "Listas de Reprodução" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "Confirmar Saída" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "Está pronto para sair do Plex?" + +msgctxt "#32336" +msgid "Exit" +msgstr "Sair" + +msgctxt "#32337" +msgid "Cancel" +msgstr "Cancelar" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "Nenhum Servidor Encontrado" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "Servidor inacessível" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "Testes de ligação estão em progresso. Por favor, aguarde." + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "Servidor inacessível. Ligue-se ao servidor e teste a ligação." + +msgctxt "#32342" +msgid "Switch User" +msgstr "Mudar de Utilizador" + +msgctxt "#32343" +msgid "Settings" +msgstr "Definições" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "Terminar Sessão" + +msgctxt "#32345" +msgid "All" +msgstr "Tudo" + +msgctxt "#32346" +msgid "By Name" +msgstr "Por Nome" + +msgctxt "#32347" +msgid "Artists" +msgstr "Artistas" + +msgctxt "#32348" +msgid "Movies" +msgstr "Filmes" + +msgctxt "#32349" +msgid "photos" +msgstr "fotos" + +msgctxt "#32350" +msgid "Shows" +msgstr "Séries" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "Por Data Adicionado" + +msgctxt "#32352" +msgid "Date Added" +msgstr "Data Adicionado" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "Por Data de Lançamento" + +msgctxt "#32354" +msgid "Release Date" +msgstr "Data de Lançamento" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "Por Data de Visualização" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "Data de Visualização" + +msgctxt "#32357" +msgid "By Name" +msgstr "Por Nome" + +msgctxt "#32358" +msgid "Name" +msgstr "Nome" + +msgctxt "#32359" +msgid "By Rating" +msgstr "Por Avaliação" + +msgctxt "#32360" +msgid "Rating" +msgstr "Avaliação" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "Por Resolução" + +msgctxt "#32362" +msgid "Resolution" +msgstr "Resolução" + +msgctxt "#32363" +msgid "By Duration" +msgstr "Por Duração" + +msgctxt "#32364" +msgid "Duration" +msgstr "Duração" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "Por Data de Estreia" + +msgctxt "#32366" +msgid "First Aired" +msgstr "Data de Estreia" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "Por Não-Vistos" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "Não-Vistos" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "Por Data de Reprodução" + +msgctxt "#32370" +msgid "Date Played" +msgstr "Data de Reprodução" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "Por Número de Reproduções" + +msgctxt "#32372" +msgid "Play Count" +msgstr "Número de Reproduções" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "Por Data Tirada" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "Data Tirada" + +msgctxt "#32375" +msgid "No filters available" +msgstr "Nenhum filtro disponível" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "Limpar filtro" + +msgctxt "#32377" +msgid "Year" +msgstr "Ano" + +msgctxt "#32378" +msgid "Decade" +msgstr "Década" + +msgctxt "#32379" +msgid "Genre" +msgstr "Género" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "Classificação do Conteúdo" + +msgctxt "#32381" +msgid "Network" +msgstr "Rede" + +msgctxt "#32382" +msgid "Collection" +msgstr "Coleção" + +msgctxt "#32383" +msgid "Director" +msgstr "Diretor" + +msgctxt "#32384" +msgid "Actor" +msgstr "Ator" + +msgctxt "#32385" +msgid "Country" +msgstr "País" + +msgctxt "#32386" +msgid "Studio" +msgstr "Estúdio" + +msgctxt "#32387" +msgid "Labels" +msgstr "Rótulos" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "Fabricante da câmara" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "Modelo da câmara" + +msgctxt "#32390" +msgid "Aperture" +msgstr "Abertura" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "Velocidade do Obturador" + +msgctxt "#32392" +msgid "Lens" +msgstr "Lente" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "Séries TV" + +msgctxt "#32394" +msgid "Music" +msgstr "Música" + +msgctxt "#32395" +msgid "Audio" +msgstr "Áudio" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "Legendas" + +msgctxt "#32397" +msgid "Quality" +msgstr "Qualidade" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "Configurações de Vídeo do Kodi" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "Configurações de Áudio do Kodi" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "Ir para Temporada" + +msgctxt "#32401" +msgid "Directors" +msgstr "Diretores" + +msgctxt "#32402" +msgid "Writer" +msgstr "Escritor" + +msgctxt "#32403" +msgid "Writers" +msgstr "Escritores" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "Filmes relacionados" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "Transferir Legendas" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "Atraso da Legenda" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "Próxima Legenda" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "Desativar Legendas" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "Ativar Legendas" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "Versão da Plataforma" + +msgctxt "#32411" +msgid "Unknown" +msgstr "Desconhecido" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "Editar ou Limpar" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "Editar endereço de IP ou limpar configurações atuais?" + +msgctxt "#32414" +msgid "Clear" +msgstr "Limpar" + +msgctxt "#32415" +msgid "Edit" +msgstr "Editar" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "Insira o endereço de IP" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "Insira o número da Porta" + +msgctxt "#32418" +msgid "Creator" +msgstr "Criador" + +msgctxt "#32419" +msgid "Cast" +msgstr "Elenco" + +msgctxt "#32420" +msgid "Disc" +msgstr "Disco" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "Terminar Sessão" + +msgctxt "#32422" +msgid "Exit" +msgstr "Sair" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "Desligar" + +msgctxt "#32424" +msgid "Suspend" +msgstr "Suspender" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "Hibernar" + +msgctxt "#32426" +msgid "Reboot" +msgstr "Reiniciar" + +msgctxt "#32427" +msgid "Failed" +msgstr "Falhou" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "Falha ao iniciar sessão!" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "Resumir de {0}" + +msgctxt "#32430" +msgid "Discovery" +msgstr "Descobrir" + +msgctxt "#32431" +msgid "Search" +msgstr "Procurar" + +msgctxt "#32432" +msgid "Space" +msgstr "Espaço" + +msgctxt "#32433" +msgid "Clear" +msgstr "Limpar" + +msgctxt "#32434" +msgid "Searching..." +msgstr "A Procurar..." + +msgctxt "#32435" +msgid "No Results" +msgstr "Sem Resultados" + +msgctxt "#32436" +msgid "Paused" +msgstr "Em Pausa" + +msgctxt "#32437" +msgid "Welcome" +msgstr "Bem-Vindo" + +msgctxt "#32438" +msgid "Previous" +msgstr "Anterior" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "Reproduzindo a seguir" + +msgctxt "#32440" +msgid "On Deck" +msgstr "Próximos a Ver" + +msgctxt "#32441" +msgid "Unknown" +msgstr "Desconhecido" + +msgctxt "#32442" +msgid "Embedded" +msgstr "Embutido" + +msgctxt "#32443" +msgid "Forced" +msgstr "Forçado" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "Letra da música" + +msgctxt "#32445" +msgid "Mono" +msgstr "Mono" + +msgctxt "#32446" +msgid "Stereo" +msgstr "Estéreo" + +msgctxt "#32447" +msgid "None" +msgstr "Nenhum" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "Falha ao Reproduzir!" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "Não foi possivel ligar ao plex.tv[CR]Teste a ligação de internet e tente novamente." + +msgctxt "#32450" +msgid "Choose Version" +msgstr "Escolher Versão" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "Reproduzir Versão..." + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "Nenhum conteúdo disponível nesta biblioteca" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "Por favor adicione e/ou confirme que 'Incluir no Painel' está desativado." + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "Nenhum conteúdo disponível para este filtro" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "Por favor, troque ou remova o filtro atual" + +msgctxt "#32456" +msgid "Show" +msgstr "Série" + +msgctxt "#32457" +msgid "By Show" +msgstr "Por Série" + +msgctxt "#32458" +msgid "Episodes" +msgstr "Episódios" + +msgctxt "#32459" +msgid "Offline Mode" +msgstr "Modo Offline" + +msgctxt "#32460" +msgid "Sign In" +msgstr "Iniciar Sessão" + +msgctxt "#32461" +msgid "Albums" +msgstr "Álbuns" + +msgctxt "#32462" +msgid "Artist" +msgstr "Artista" + +msgctxt "#32463" +msgid "By Artist" +msgstr "Por Artista" + +msgctxt "#32464" +msgid "Player" +msgstr "Reprodutor" + +msgctxt "#32465" +msgid "Use skip step settings from Kodi" +msgstr "Use as definições de saltar etapas do Kodi" + +msgctxt "#32466" +msgid "Automatically seek selected position after a delay" +msgstr "Procurar automaticamente a posição selecionada após atrasar" + +msgctxt "#32467" +msgid "User Interface" +msgstr "Interface de Utilizador" + +msgctxt "#32471" +msgid "Use Plex/Kodi steps for timeline" +msgstr "Use as etapas do Plex/Kodi para a linha de tempo" + +msgctxt "#32485" +msgid "Go back instantly with the previous menu action in scrolled views" +msgstr "Recuar instantaneamente com a ação recuar do menu em visualizações deslocáveis" + +msgctxt "#32492" +msgid "Kodi Subtitle Settings" +msgstr "Definições de Legendas do Kodi" diff --git a/script.plexmod/resources/language/resource.language.ru_ru/strings.po b/script.plexmod/resources/language/resource.language.ru_ru/strings.po new file mode 100644 index 0000000000..50b5ba08d2 --- /dev/null +++ b/script.plexmod/resources/language/resource.language.ru_ru/strings.po @@ -0,0 +1,951 @@ +# XBMC Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2013-12-12 22:56+0000\n" +"PO-Revision-Date: 2018-01-15 11:26+0300\n" +"Language-Team: LANGUAGE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ru\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Last-Translator: \n" +"X-Generator: Poedit 2.0.5\n" + +msgctxt "#32000" +msgid "Main" +msgstr "Главный" + +msgctxt "#32001" +msgid "Original" +msgstr "Оригинал" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "20 Мбит/с 1080p" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "12 Мбит/с 1080p" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "10 Мбит/с 1080p" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "8 Мбит/с 1080p" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "4 Мбит/с 720p" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "3 Мбит/с 720p" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "2 Мбит/с 720p" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "1.5 Мбит/с 480p" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "720 кбит/с" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "320 кбит/с" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "208 кбит/с" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "96 кбит/с" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "64 кбит/с" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "Локальное качество" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "Удаленное качество" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "Онлайн качество" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "Формат перекодирования" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "Отладка" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "Разрешить прямое воспроизведение" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "Разрешить прямую трансляцию" + +msgctxt "#32027" +msgid "Force" +msgstr "Принудительно" + +msgctxt "#32028" +msgid "Always" +msgstr "Всегда" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "Только изображения" + +msgctxt "#32030" +msgid "Auto" +msgstr "Авто" + +msgctxt "#32031" +msgid "Burn Subtitles (Direct Play Only)" +msgstr "Наложение субтитров (только прямое воспроизведение)" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "Разрешить небезопасные соединения" + +msgctxt "#32033" +msgid "Never" +msgstr "Никогда" + +msgctxt "#32034" +msgid "On Same network" +msgstr "В той же сети" + +msgctxt "#32035" +msgid "Always" +msgstr "Всегда" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "Разрешить 4K" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "Разрешить HEVC (h265)" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "Автоматический вход" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "Автоматическое воспроизведение" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "Включить скачивание субтитров" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "Включить скачивание субтитров" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "Обнаружение сервера (GDM)" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "Запускать Plex при старте Kodi" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "Соединение 1 IP" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "Соединение 1 порт" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "Соединение 2 IP" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "Соединение 2 порт" + +msgctxt "#32048" +msgid "Audio" +msgstr "Аудио" + +msgctxt "#32049" +msgid "Advanced" +msgstr "Продвинутый" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "Задать сервер вручную" + +msgctxt "#32051" +msgid "Privacy" +msgstr "Приватность" + +msgctxt "#32052" +msgid "About" +msgstr "Сведения" + +msgctxt "#32053" +msgid "Video" +msgstr "Видео" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "Версия аддона" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Версия Kodi" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "Разрешение экрана" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "Версия сервера" + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "Пропустить выбор пользователя и ввод пин-кода при старте." + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "Если включено, после окончании воспроизведения, если есть следующая запись, она будет автоматически запущена после 15 секундной задержки." + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "Включите, если ваше оборудование поддерживает воспроизведение 4K. Отключите, чтобы использовать преобразование." + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "Включите, если ваше оборудование поддерживает HEVC/h265. Отключите, чтобы использовать преобразование." + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "Когда подключаться к серверам, не поддерживающим безопасные соединения.[CR][CR]* [B]Никогда[/B]: Никогда не подключаться к серверам с небезопасным соединением[CR]* [B]В той же сети[/B]: Разрешить, если сервер находится в той же сети[CR]* [B]Всегда[/B]: Разрешить в той же сети и удаленные соединения" + +msgctxt "#32201" +msgid "Trailer" +msgstr "Трейлер" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "Удаленные эпизоды" + +msgctxt "#32203" +msgid "Interview" +msgstr "Интервью" + +msgctxt "#32204" +msgid "Music Video" +msgstr "Клип" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "За кулисами" + +msgctxt "#32206" +msgid "Scene" +msgstr "Эпизод" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "Живая музыка" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "Лирический клип" + +msgctxt "#32209" +msgid "Concert" +msgstr "Концерт" + +msgctxt "#32210" +msgid "Featurette" +msgstr "Короткометражный фильм" + +msgctxt "#32211" +msgid "Short" +msgstr "Короткий" + +msgctxt "#32212" +msgid "Other" +msgstr "Прочее" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "Перейти к альбому" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "Перейти к артисту" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "Перейти к {0}" + +msgctxt "#32303" +msgid "Season" +msgstr "Сезон" + +msgctxt "#32304" +msgid "Episode" +msgstr "Эпизод" + +msgctxt "#32305" +msgid "Extras" +msgstr "Дополнения" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "Связанные вупыски" + +msgctxt "#32307" +msgid "More" +msgstr "Еще" + +msgctxt "#32308" +msgid "Available" +msgstr "Доступно" + +msgctxt "#32309" +msgid "None" +msgstr "Нет" + +msgctxt "#32310" +msgid "S" +msgstr "S" + +msgctxt "#32311" +msgid "E" +msgstr "E" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "Недосутпно" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "Эта запись сейчас недоступна." + +msgctxt "#32314" +msgid "In Progress" +msgstr "В работе" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "Возобновить воспроизведение?" + +msgctxt "#32316" +msgid "Resume" +msgstr "Возобновить" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "Начать сначала" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "Пометить как не просмотренное" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "Пометить как просмотренное" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "Пометить сезон как не просмотренный" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "Пометить сезон как просмотренный" + +msgctxt "#32322" +msgid "Delete" +msgstr "Удалить" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "Перейти к просмотру" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "Перейти к {0}" + +msgctxt "#32325" +msgid "Play Next" +msgstr "Воспроизвести следующий" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "Действительно удалить?" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "Вы действительно хотите удалить?" + +msgctxt "#32328" +msgid "Yes" +msgstr "Да" + +msgctxt "#32329" +msgid "No" +msgstr "Нет" + +msgctxt "#32330" +msgid "Message" +msgstr "Сообщение" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "Возникла проблема при удалении." + +msgctxt "#32332" +msgid "Home" +msgstr "Домой" + +msgctxt "#32333" +msgid "Playlists" +msgstr "Плейлисты" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "Подтверждение выхода" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "Вы действительно хотите выйти из Plex?" + +msgctxt "#32336" +msgid "Exit" +msgstr "Выход" + +msgctxt "#32337" +msgid "Cancel" +msgstr "Отмена" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "Сервера не найдены" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "Сервер недоступен" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "Пожалуйста, подождите, идет проверка соединения." + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "Сервер недоступен. Пожалуйста, войдите на ваш сервер и проверьте соединение." + +msgctxt "#32342" +msgid "Switch User" +msgstr "Сменить пользователя" + +msgctxt "#32343" +msgid "Settings" +msgstr "Настройки" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "Выйти" + +msgctxt "#32345" +msgid "All" +msgstr "Все" + +msgctxt "#32346" +msgid "By Name" +msgstr "По имени" + +msgctxt "#32347" +msgid "Artists" +msgstr "Артисты" + +msgctxt "#32348" +msgid "movies" +msgstr "фильмы" + +msgctxt "#32349" +msgid "photos" +msgstr "фото" + +msgctxt "#32350" +msgid "Shows" +msgstr "Сериалы" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "По дате добавления" + +msgctxt "#32352" +msgid "Date Added" +msgstr "Дата добавления" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "По дате выхода" + +msgctxt "#32354" +msgid "Release Date" +msgstr "Дата выхода" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "По дате просмотра" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "Дата просмотра" + +msgctxt "#32357" +msgid "By Name" +msgstr "По имени" + +msgctxt "#32358" +msgid "Name" +msgstr "Имя" + +msgctxt "#32359" +msgid "By Rating" +msgstr "По рейтингу" + +msgctxt "#32360" +msgid "Rating" +msgstr "Рейтинг" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "По разрешению" + +msgctxt "#32362" +msgid "Resolution" +msgstr "Разрешение" + +msgctxt "#32363" +msgid "By Duration" +msgstr "По длительности" + +msgctxt "#32364" +msgid "Duration" +msgstr "Длительность" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "По дате показа" + +msgctxt "#32366" +msgid "First Aired" +msgstr "Дата показа" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "По не просмотренным" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "Не просмотренные" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "По дате воспроизведения" + +msgctxt "#32370" +msgid "Date Played" +msgstr "Дата воспроизведения" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "По количеству просмотров" + +msgctxt "#32372" +msgid "Play Count" +msgstr "Количество просмотров" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "По выбранной дате" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "Выбранная дата" + +msgctxt "#32375" +msgid "No filters available" +msgstr "Нет фильтров" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "Очистить фильтр" + +msgctxt "#32377" +msgid "Year" +msgstr "Год" + +msgctxt "#32378" +msgid "Decade" +msgstr "Десятилетие" + +msgctxt "#32379" +msgid "Genre" +msgstr "Жанр" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "Рейтинг контента" + +msgctxt "#32381" +msgid "Network" +msgstr "Сеть" + +msgctxt "#32382" +msgid "Collection" +msgstr "Коллекция" + +msgctxt "#32383" +msgid "Director" +msgstr "Режиссер" + +msgctxt "#32384" +msgid "Actor" +msgstr "Актер" + +msgctxt "#32385" +msgid "Country" +msgstr "Страна" + +msgctxt "#32386" +msgid "Studio" +msgstr "Студия" + +msgctxt "#32387" +msgid "Labels" +msgstr "Лейбл" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "Камера" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "Модель камеры" + +msgctxt "#32390" +msgid "Aperture" +msgstr "Диафрагма" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "Скорость затвора" + +msgctxt "#32392" +msgid "Lens" +msgstr "Объектив" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "Сериалы" + +msgctxt "#32394" +msgid "Music" +msgstr "Музыка" + +msgctxt "#32395" +msgid "Audio" +msgstr "Аудио" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "Субтитры" + +msgctxt "#32397" +msgid "Quality" +msgstr "Качетсво" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "Настройки видео Kodi" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "Настройки аудио Kodi" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "Перейти к сезону" + +msgctxt "#32401" +msgid "Directors" +msgstr "Режиссеры" + +msgctxt "#32402" +msgid "Writer" +msgstr "Сценарист" + +msgctxt "#32403" +msgid "Writers" +msgstr "Сценаристы" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "Похожие фильмы" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "Скачать субтитры" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "Задержка субтитров" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "Следующие субтитры" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "Отключить субтитры" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "Включить субтитры" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "Версия платформы" + +msgctxt "#32411" +msgid "Unknown" +msgstr "Неизсвестно" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "Изменить или удалить" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "Изменить IP адрес или удалить настройки?" + +msgctxt "#32414" +msgid "Clear" +msgstr "Удалить" + +msgctxt "#32415" +msgid "Edit" +msgstr "Изменить" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "Введите IP адрес" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "Введите номер порта" + +msgctxt "#32418" +msgid "Creator" +msgstr "Автор" + +msgctxt "#32419" +msgid "Cast" +msgstr "В ролях" + +msgctxt "#32420" +msgid "Disc" +msgstr "Диск" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "Выйти из учетной записи" + +msgctxt "#32422" +msgid "Exit" +msgstr "Выход" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "Завершить работу" + +msgctxt "#32424" +msgid "Suspend" +msgstr "Перейти в режим сна" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "Гибернация" + +msgctxt "#32426" +msgid "Reboot" +msgstr "Перезагрузка" + +msgctxt "#32427" +msgid "Failed" +msgstr "Ошибка" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "Ошибка входа!" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "Начать с {0}" + +msgctxt "#32430" +msgid "Discovery" +msgstr "Обнаружение" + +msgctxt "#32431" +msgid "Search" +msgstr "Поиск" + +msgctxt "#32432" +msgid "Space" +msgstr "Пробел" + +msgctxt "#32433" +msgid "Clear" +msgstr "Удалить" + +msgctxt "#32434" +msgid "Searching..." +msgstr "Поиск..." + +msgctxt "#32435" +msgid "No Results" +msgstr "Нет результатов" + +msgctxt "#32436" +msgid "Paused" +msgstr "Пауза" + +msgctxt "#32437" +msgid "Welcome" +msgstr "Добро пожаловать" + +msgctxt "#32438" +msgid "Previous" +msgstr "Предыдущий" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "Следующий" + +msgctxt "#32440" +msgid "On Deck" +msgstr "Сейчас просматривается" + +msgctxt "#32441" +msgid "Unknown" +msgstr "Неизвестно" + +msgctxt "#32442" +msgid "Embedded" +msgstr "Встроенный" + +msgctxt "#32443" +msgid "Forced" +msgstr "Принудительно" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "Текст песни" + +msgctxt "#32445" +msgid "Mono" +msgstr "Моно" + +msgctxt "#32446" +msgid "Stereo" +msgstr "Стерео" + +msgctxt "#32447" +msgid "None" +msgstr "Нет" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "Ошибка воспроизведения!" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "Нет соединения с plex.tv[CR]Проверьте ваше интернет-соединение и попробуйте еще раз." + +msgctxt "#32450" +msgid "Choose Version" +msgstr "Выберите версию" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "Версия воспроизведения..." + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "В этой библиотеке ничего нет" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "Пожалуйста, добавьте контент и/или проверьте включено ли \"Добавить на панель\"." + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "Нет результатов с выбранными условиями" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "Пожалуйста, измените или удалите текущий фильтр" + +msgctxt "#32456" +msgid "Show" +msgstr "Показ" + +msgctxt "#32457" +msgid "By Show" +msgstr "По показу" + +msgctxt "#32458" +msgid "Episodes" +msgstr "Эпизоды" + +msgctxt "#32459" +msgid "Offline Mode" +msgstr "Автономный режим" + +msgctxt "#32460" +msgid "Sign In" +msgstr "Войти" + +msgctxt "#32461" +msgid "Albums" +msgstr "Альбомы" + +msgctxt "#32462" +msgid "Artist" +msgstr "Артист" + +msgctxt "#32463" +msgid "By Artist" +msgstr "По артисту" diff --git a/script.plexmod/resources/language/resource.language.zh_cn/strings.po b/script.plexmod/resources/language/resource.language.zh_cn/strings.po new file mode 100644 index 0000000000..46b8c93dac --- /dev/null +++ b/script.plexmod/resources/language/resource.language.zh_cn/strings.po @@ -0,0 +1,1075 @@ +# XBMC Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC-Addons\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"POT-Creation-Date: 2020-3-4 22:56+0000\n" +"PO-Revision-Date: 2022-02-08 19:00+0800\n" +"Last-Translator: Qianyu Li \n" +"Language-Team: LANGUAGE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: zh_CN\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgctxt "#32000" +msgid "Main" +msgstr "一般" + +msgctxt "#32001" +msgid "Original" +msgstr "原始" + +msgctxt "#32002" +msgid "20 Mbps 1080p" +msgstr "" + +msgctxt "#32003" +msgid "12 Mbps 1080p" +msgstr "" + +msgctxt "#32004" +msgid "10 Mbps 1080p" +msgstr "" + +msgctxt "#32005" +msgid "8 Mbps 1080p" +msgstr "" + +msgctxt "#32006" +msgid "4 Mbps 720p" +msgstr "" + +msgctxt "#32007" +msgid "3 Mbps 720p" +msgstr "" + +msgctxt "#32008" +msgid "2 Mbps 720p" +msgstr "" + +msgctxt "#32009" +msgid "1.5 Mbps 480p" +msgstr "" + +msgctxt "#32010" +msgid "720 kbps" +msgstr "" + +msgctxt "#32011" +msgid "320 kbps" +msgstr "" + +msgctxt "#32012" +msgid "208 kbps" +msgstr "" + +msgctxt "#32013" +msgid "96 kbps" +msgstr "" + +msgctxt "#32014" +msgid "64 kbps" +msgstr "" + +msgctxt "#32020" +msgid "Local Quality" +msgstr "本地播放质量" + +msgctxt "#32021" +msgid "Remote Quality" +msgstr "远程播放质量" + +msgctxt "#32022" +msgid "Online Quality" +msgstr "在线播放质量" + +msgctxt "#32023" +msgid "Transcode Format" +msgstr "转码格式" + +msgctxt "#32024" +msgid "Debug Logging" +msgstr "调试日志" + +msgctxt "#32025" +msgid "Allow Direct Play" +msgstr "允许直接播放" + +msgctxt "#32026" +msgid "Allow Direct Stream" +msgstr "允许直连串流" + +msgctxt "#32027" +msgid "Force" +msgstr "强制直接播放" + +msgctxt "#32028" +msgid "Always" +msgstr "总是" + +msgctxt "#32029" +msgid "Only Image Formats" +msgstr "仅图像格式" + +msgctxt "#32030" +msgid "Auto" +msgstr "自动" + +msgctxt "#32031" +msgid "Burn Subtitles (Direct Play Only)" +msgstr "固化字幕(仅直接播放)" + +msgctxt "#32032" +msgid "Allow Insecure Connections" +msgstr "允许非加密连接" + +msgctxt "#32033" +msgid "Never" +msgstr "从不" + +msgctxt "#32034" +msgid "On Same network" +msgstr "在同一网络" + +msgctxt "#32035" +msgid "Always" +msgstr "总是" + +msgctxt "#32036" +msgid "Allow 4K" +msgstr "允许4K" + +msgctxt "#32037" +msgid "Allow HEVC (h265)" +msgstr "允许HEVC (h265)" + +msgctxt "#32038" +msgid "Automatically Sign In" +msgstr "自动登录" + +msgctxt "#32039" +msgid "Post Play Auto Play" +msgstr "点击海报自动播放" + +msgctxt "#32040" +msgid "Enable Subtitle Downloading" +msgstr "允许下载字幕" + +msgctxt "#32041" +msgid "Enable Subtitle Downloading" +msgstr "允许下载字幕" + +msgctxt "#32042" +msgid "Server Discovery (GDM)" +msgstr "发现服务器(GDM)" + +msgctxt "#32043" +msgid "Start Plex On Kodi Startup" +msgstr "打开Kodi时自动启动PLEX" + +msgctxt "#32044" +msgid "Connection 1 IP" +msgstr "服务器1的IP" + +msgctxt "#32045" +msgid "Connection 1 Port" +msgstr "服务器1的端口" + +msgctxt "#32046" +msgid "Connection 2 IP" +msgstr "服务器2的IP" + +msgctxt "#32047" +msgid "Connection 2 Port" +msgstr "服务器2的端口" + +msgctxt "#32048" +msgid "Audio" +msgstr "音频" + +msgctxt "#32049" +msgid "Advanced" +msgstr "高级" + +msgctxt "#32050" +msgid "Manual Servers" +msgstr "手动输入服务器地址" + +msgctxt "#32051" +msgid "Privacy" +msgstr "隐私" + +msgctxt "#32052" +msgid "About" +msgstr "关于" + +msgctxt "#32053" +msgid "Video" +msgstr "视频" + +msgctxt "#32054" +msgid "Addon Version" +msgstr "插件版本" + +msgctxt "#32055" +msgid "Kodi Version" +msgstr "Kodi版本" + +msgctxt "#32056" +msgid "Screen Resolution" +msgstr "屏幕分辨率" + +msgctxt "#32057" +msgid "Current Server Version" +msgstr "PLEX服务器版本" + +msgctxt "#32100" +msgid "Skip user selection and pin entry on startup." +msgstr "启动时跳过选择用户和图钉." + +msgctxt "#32101" +msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." +msgstr "如果启用,当播放结束并且有一个“Next Up”项目可用时,它将在15秒的延迟后自动播放." + +msgctxt "#32102" +msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." +msgstr "如果您的硬件可以处理4K播放,请启用此选项.禁用它以强制转码." + +msgctxt "#32103" +msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." +msgstr "如果您的硬件可以处理HEVC/h265,请启用此选项.禁用它以强制转码." + +msgctxt "#32104" +msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" +msgstr "何时连接到没有安全连接的服务器。[CR][CR]* [B]从不[/B]: 从不以不安全方式连接服务器[CR]* [B]在同一网络[/B]: 允许同一网络时[CR]* [B]总是[/B]: 允许同一网络和远程连接时" + +msgctxt "#32201" +msgid "Trailer" +msgstr "预告片" + +msgctxt "#32202" +msgid "Deleted Scene" +msgstr "删除的场景" + +msgctxt "#32203" +msgid "Interview" +msgstr "访问" + +msgctxt "#32204" +msgid "Music Video" +msgstr "音乐视频" + +msgctxt "#32205" +msgid "Behind the Scenes" +msgstr "幕后花絮" + +msgctxt "#32206" +msgid "Scene" +msgstr "现场" + +msgctxt "#32207" +msgid "Live Music Video" +msgstr "现场音乐视频" + +msgctxt "#32208" +msgid "Lyric Music Video" +msgstr "歌词音乐视频" + +msgctxt "#32209" +msgid "Concert" +msgstr "演奏会" + +msgctxt "#32210" +msgid "Featurette" +msgstr "电影短片" + +msgctxt "#32211" +msgid "Short" +msgstr "短篇" + +msgctxt "#32212" +msgid "Other" +msgstr "其他" + +msgctxt "#32300" +msgid "Go to Album" +msgstr "跳转到相册" + +msgctxt "#32301" +msgid "Go to Artist" +msgstr "跳转到演员" + +msgctxt "#32302" +msgid "Go to {0}" +msgstr "跳转到 {0}" + +msgctxt "#32303" +msgid "Season" +msgstr "季数" + +msgctxt "#32304" +msgid "Episode" +msgstr "集数" + +msgctxt "#32305" +msgid "Extras" +msgstr "其他" + +msgctxt "#32306" +msgid "Related Shows" +msgstr "相关节目" + +msgctxt "#32307" +msgid "More" +msgstr "更多" + +msgctxt "#32308" +msgid "Available" +msgstr "可用的" + +msgctxt "#32309" +msgid "None" +msgstr "无" + +msgctxt "#32310" +msgid "S" +msgstr "" + +msgctxt "#32311" +msgid "E" +msgstr "" + +msgctxt "#32312" +msgid "Unavailable" +msgstr "不可用" + +msgctxt "#32313" +msgid "This item is currently unavailable." +msgstr "这个项目现在不可用." + +msgctxt "#32314" +msgid "In Progress" +msgstr "进行中" + +msgctxt "#32315" +msgid "Resume playback?" +msgstr "恢复播放?" + +msgctxt "#32316" +msgid "Resume" +msgstr "恢复" + +msgctxt "#32317" +msgid "Play from beginning" +msgstr "从头播放" + +msgctxt "#32318" +msgid "Mark Unplayed" +msgstr "标记为未播放" + +msgctxt "#32319" +msgid "Mark Played" +msgstr "标记为已播放" + +msgctxt "#32320" +msgid "Mark Season Unplayed" +msgstr "标记整季未播放" + +msgctxt "#32321" +msgid "Mark Season Played" +msgstr "标记整季已播放" + +msgctxt "#32322" +msgid "Delete" +msgstr "删除" + +msgctxt "#32323" +msgid "Go To Show" +msgstr "转到剧集" + +msgctxt "#32324" +msgid "Go To {0}" +msgstr "跳转到 {0}" + +msgctxt "#32325" +msgid "Play Next" +msgstr "播放下一个" + +msgctxt "#32326" +msgid "Really Delete?" +msgstr "确定删除?" + +msgctxt "#32327" +msgid "Are you sure you really want to delete this media?" +msgstr "你确定你要删除这个媒体么?" + +msgctxt "#32328" +msgid "Yes" +msgstr "是" + +msgctxt "#32329" +msgid "No" +msgstr "否" + +msgctxt "#32330" +msgid "Message" +msgstr "消息" + +msgctxt "#32331" +msgid "There was a problem while attempting to delete the media." +msgstr "尝试删除媒体时出现问题." + +msgctxt "#32332" +msgid "Home" +msgstr "主页" + +msgctxt "#32333" +msgid "Playlists" +msgstr "播放列表" + +msgctxt "#32334" +msgid "Confirm Exit" +msgstr "确定退出" + +msgctxt "#32335" +msgid "Are you ready to exit Plex?" +msgstr "你确定要退出PLEX么?" + +msgctxt "#32336" +msgid "Exit" +msgstr "退出" + +msgctxt "#32337" +msgid "Cancel" +msgstr "返回" + +msgctxt "#32338" +msgid "No Servers Found" +msgstr "没有找到服务器" + +msgctxt "#32339" +msgid "Server is not accessible" +msgstr "服务器不能访问" + +msgctxt "#32340" +msgid "Connection tests are in progress. Please wait." +msgstr "连接测试正在进行中.请耐心等待." + +msgctxt "#32341" +msgid "Server is not accessible. Please sign into your server and check your connection." +msgstr "服务器不可访问.请登录您的服务器并检查您的连接." + +msgctxt "#32342" +msgid "Switch User" +msgstr "切换用户" + +msgctxt "#32343" +msgid "Settings" +msgstr "设置" + +msgctxt "#32344" +msgid "Sign Out" +msgstr "登出" + +msgctxt "#32345" +msgid "All" +msgstr "所有" + +msgctxt "#32346" +msgid "By Name" +msgstr "按名称排序" + +msgctxt "#32347" +msgid "Artists" +msgstr "艺人" + +msgctxt "#32348" +msgid "Movies" +msgstr "电影" + +msgctxt "#32349" +msgid "photos" +msgstr "相片" + +msgctxt "#32350" +msgid "Shows" +msgstr "演出" + +msgctxt "#32351" +msgid "By Date Added" +msgstr "按添加日期排序" + +msgctxt "#32352" +msgid "Date Added" +msgstr "添加日期" + +msgctxt "#32353" +msgid "By Release Date" +msgstr "按发布日期排序" + +msgctxt "#32354" +msgid "Release Date" +msgstr "发布日期" + +msgctxt "#32355" +msgid "By Date Viewed" +msgstr "按观看日期排序" + +msgctxt "#32356" +msgid "Date Viewed" +msgstr "观看日期" + +msgctxt "#32357" +msgid "By Name" +msgstr "按名称排序" + +msgctxt "#32358" +msgid "Name" +msgstr "名称" + +msgctxt "#32359" +msgid "By Rating" +msgstr "按热度排序" + +msgctxt "#32360" +msgid "Rating" +msgstr "热度" + +msgctxt "#32361" +msgid "By Resolution" +msgstr "按分辨率排序" + +msgctxt "#32362" +msgid "Resolution" +msgstr "分辨率" + +msgctxt "#32363" +msgid "By Duration" +msgstr "按时长排序" + +msgctxt "#32364" +msgid "Duration" +msgstr "时长" + +msgctxt "#32365" +msgid "By First Aired" +msgstr "按首次播出排序" + +msgctxt "#32366" +msgid "First Aired" +msgstr "首次播出" + +msgctxt "#32367" +msgid "By Unplayed" +msgstr "按未播放排序" + +msgctxt "#32368" +msgid "Unplayed" +msgstr "未播放" + +msgctxt "#32369" +msgid "By Date Played" +msgstr "按播放日期排序" + +msgctxt "#32370" +msgid "Date Played" +msgstr "播放日期" + +msgctxt "#32371" +msgid "By Play Count" +msgstr "按播放次数排序" + +msgctxt "#32372" +msgid "Play Count" +msgstr "播放次数" + +msgctxt "#32373" +msgid "By Date Taken" +msgstr "按拍摄日期排序" + +msgctxt "#32374" +msgid "Date Taken" +msgstr "拍摄日期" + +msgctxt "#32375" +msgid "No filters available" +msgstr "没找到相关内容" + +msgctxt "#32376" +msgid "Clear Filter" +msgstr "清空内容" + +msgctxt "#32377" +msgid "Year" +msgstr "年" + +msgctxt "#32378" +msgid "Decade" +msgstr "年代" + +msgctxt "#32379" +msgid "Genre" +msgstr "类型" + +msgctxt "#32380" +msgid "Content Rating" +msgstr "内容分级" + +msgctxt "#32381" +msgid "Network" +msgstr "网络" + +msgctxt "#32382" +msgid "Collection" +msgstr "合集" + +msgctxt "#32383" +msgid "Director" +msgstr "导演" + +msgctxt "#32384" +msgid "Actor" +msgstr "演员" + +msgctxt "#32385" +msgid "Country" +msgstr "国家" + +msgctxt "#32386" +msgid "Studio" +msgstr "工作室" + +msgctxt "#32387" +msgid "Labels" +msgstr "标签" + +msgctxt "#32388" +msgid "Camera Make" +msgstr "相机品牌" + +msgctxt "#32389" +msgid "Camera Model" +msgstr "相机型号" + +msgctxt "#32390" +msgid "Aperture" +msgstr "光圈" + +msgctxt "#32391" +msgid "Shutter Speed" +msgstr "快门速度" + +msgctxt "#32392" +msgid "Lens" +msgstr "镜头" + +msgctxt "#32393" +msgid "TV Shows" +msgstr "剧集" + +msgctxt "#32394" +msgid "Music" +msgstr "音乐" + +msgctxt "#32395" +msgid "Audio" +msgstr "音频" + +msgctxt "#32396" +msgid "Subtitles" +msgstr "字幕" + +msgctxt "#32397" +msgid "Quality" +msgstr "质量" + +msgctxt "#32398" +msgid "Kodi Video Settings" +msgstr "KODI视频设置" + +msgctxt "#32399" +msgid "Kodi Audio Settings" +msgstr "KODI音频设置" + +msgctxt "#32400" +msgid "Go To Season" +msgstr "跳转到季" + +msgctxt "#32401" +msgid "Directors" +msgstr "导演" + +msgctxt "#32402" +msgid "Writer" +msgstr "编剧" + +msgctxt "#32403" +msgid "Writers" +msgstr "编剧" + +msgctxt "#32404" +msgid "Related Movies" +msgstr "相关电影" + +msgctxt "#32405" +msgid "Download Subtitles" +msgstr "下载字幕" + +msgctxt "#32406" +msgid "Subtitle Delay" +msgstr "字幕延迟" + +msgctxt "#32407" +msgid "Next Subtitle" +msgstr "下一个字幕" + +msgctxt "#32408" +msgid "Disable Subtitles" +msgstr "禁用字幕" + +msgctxt "#32409" +msgid "Enable Subtitles" +msgstr "允许字幕" + +msgctxt "#32410" +msgid "Platform Version" +msgstr "平台版本" + +msgctxt "#32411" +msgid "Unknown" +msgstr "未知" + +msgctxt "#32412" +msgid "Edit Or Clear" +msgstr "编辑或清除" + +msgctxt "#32413" +msgid "Edit IP address or clear the current setting?" +msgstr "编辑IP地址或清除当前设置?" + +msgctxt "#32414" +msgid "Clear" +msgstr "清除" + +msgctxt "#32415" +msgid "Edit" +msgstr "编辑" + +msgctxt "#32416" +msgid "Enter IP Address" +msgstr "填写IP地址" + +msgctxt "#32417" +msgid "Enter Port Number" +msgstr "填写端口" + +msgctxt "#32418" +msgid "Creator" +msgstr "创作者" + +msgctxt "#32419" +msgid "Cast" +msgstr "阵容" + +msgctxt "#32420" +msgid "Disc" +msgstr "碟片" + +msgctxt "#32421" +msgid "Sign Out" +msgstr "登出" + +msgctxt "#32422" +msgid "Exit" +msgstr "离开" + +msgctxt "#32423" +msgid "Shutdown" +msgstr "关机" + +msgctxt "#32424" +msgid "Suspend" +msgstr "暂停" + +msgctxt "#32425" +msgid "Hibernate" +msgstr "休眠" + +msgctxt "#32426" +msgid "Reboot" +msgstr "重启" + +msgctxt "#32427" +msgid "Failed" +msgstr "失败" + +msgctxt "#32428" +msgid "Login failed!" +msgstr "登陆失败!" + +msgctxt "#32429" +msgid "Resume from {0}" +msgstr "从{0}恢复" + +msgctxt "#32430" +msgid "Discovery" +msgstr "发现" + +msgctxt "#32431" +msgid "Search" +msgstr "搜索" + +msgctxt "#32432" +msgid "Space" +msgstr "空格" + +msgctxt "#32433" +msgid "Clear" +msgstr "清除" + +msgctxt "#32434" +msgid "Searching..." +msgstr "搜索中..." + +msgctxt "#32435" +msgid "No Results" +msgstr "无结果" + +msgctxt "#32436" +msgid "Paused" +msgstr "暂停" + +msgctxt "#32437" +msgid "Welcome" +msgstr "欢迎" + +msgctxt "#32438" +msgid "Previous" +msgstr "重播" + +msgctxt "#32439" +msgid "Playing Next" +msgstr "播放下一集" + +msgctxt "#32440" +msgid "On Deck" +msgstr "已播项目" + +msgctxt "#32441" +msgid "Unknown" +msgstr "未知" + +msgctxt "#32442" +msgid "Embedded" +msgstr "内嵌" + +msgctxt "#32443" +msgid "Forced" +msgstr "强制" + +msgctxt "#32444" +msgid "Lyrics" +msgstr "歌词" + +msgctxt "#32445" +msgid "Mono" +msgstr "单声道" + +msgctxt "#32446" +msgid "Stereo" +msgstr "立体声" + +msgctxt "#32447" +msgid "None" +msgstr "无" + +msgctxt "#32448" +msgid "Playback Failed!" +msgstr "播放失败!" + +msgctxt "#32449" +msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." +msgstr "无法连接至plex.tv[CR]检查您的互联网连接,然后重试." + +msgctxt "#32450" +msgid "Choose Version" +msgstr "选择版本" + +msgctxt "#32451" +msgid "Play Version..." +msgstr "播放版本" + +msgctxt "#32452" +msgid "No Content available in this library" +msgstr "库里没有可播放的内容" + +msgctxt "#32453" +msgid "Please add content and/or check that 'Include in dashboard' is enabled." +msgstr "请添加内容和/或检查 '包括在仪表板' 是否已启用." + +msgctxt "#32454" +msgid "No Content available for this filter" +msgstr "没有可用于此过滤器的内容" + +msgctxt "#32455" +msgid "Please change change or remove the current filter" +msgstr "请更改或删除当前过滤器" + +msgctxt "#32456" +msgid "Show" +msgstr "节目" + +msgctxt "#32457" +msgid "By Show" +msgstr "按节目排序" + +msgctxt "#32458" +msgid "Episodes" +msgstr "集数" + +msgctxt "#32459" +msgid "Offline Mode" +msgstr "离线模式" + +msgctxt "#32460" +msgid "Sign In" +msgstr "登录" + +msgctxt "#32461" +msgid "Albums" +msgstr "专辑" + +msgctxt "#32462" +msgid "Artist" +msgstr "艺人" + +msgctxt "#32463" +msgid "By Artist" +msgstr "按艺人排序" + +msgctxt "#32464" +msgid "Player" +msgstr "播放" + +msgctxt "#32465" +msgid "Use skip step settings from Kodi" +msgstr "使用Kodi设置的跳过步骤" + +msgctxt "#32466" +msgid "Automatically seek selected position after a delay" +msgstr "延迟后自动跳到所选位置" + +msgctxt "#32467" +msgid "User Interface" +msgstr "用户界面" + +msgctxt "#32468" +msgid "Show dynamic background art" +msgstr "显示动态背景艺术" + +msgctxt "#32469" +msgid "Background art blur amount" +msgstr "背景艺术模糊量" + +msgctxt "#32470" +msgid "Background art opacity" +msgstr "背景艺术不透明度" + +msgctxt "#32471" +msgid "Use Plex/Kodi steps for timeline" +msgstr "使用Plex/Kodi的时间轴步骤" + +msgctxt "#32480" +msgid "Theme music" +msgstr "主题音乐" + +msgctxt "#32481" +msgid "Off" +msgstr "关闭" + +msgctxt "#32482" +msgid "%(percentage)s %%" +msgstr "" + +msgctxt "#32483" +msgid "Hide Stream Info" +msgstr "隐藏流信息" + +msgctxt "#32484" +msgid "Show Stream Info" +msgstr "显示流信息" + +msgctxt "#32485" +msgid "Go back instantly with the previous menu action in scrolled views" +msgstr "滚动视图中的上一个菜单操作后立即返回" + +msgctxt "#32487" +msgid "Seek Delay" +msgstr "跳过延迟" + +msgctxt "#32488" +msgid "Screensaver" +msgstr "屏幕保护" + +msgctxt "#32489" +msgid "Quiz Mode" +msgstr "测验模式" + +msgctxt "#32490" +msgid "Collections" +msgstr "合集" + +msgctxt "#32491" +msgid "Folders" +msgstr "文件夹" + +msgctxt "#32492" +msgid "Kodi Subtitle Settings" +msgstr "KODI字幕设置" + +msgctxt "#32493" +msgid "Prefer normal over forced subtitles if available (PMS selects forced by default)" +msgstr "如果有的话,优先选择正常字幕而不是强制字幕(PMS默认选择强制字幕)" + +msgctxt "#32495" +msgid "Skip intro" +msgstr "跳过片头" + +msgctxt "#32500" +msgid "Always show post-play screen (even for short videos)" +msgstr "始终显示播放后的画面(即使是短视频)" + +msgctxt "#32501" +msgid "Time-to-wait between videos on post-play" +msgstr "播放后的视频之间的等待时间" + +msgctxt "#32505" +msgid "Visit media in video playlist instead of playing it" +msgstr "访问视频播放列表中的媒体而不是播放它" + +msgctxt "#32601" +msgid "Allow AV1" +msgstr "允许AV1" + +msgctxt "#32602" +msgid "Enable this if your hardware can handle AV1. Disable it to force transcoding." +msgstr "如果你的硬件可以处理AV1,请启用此功能.禁用它可以强制进行转码." + +msgctxt "#32521" +msgid "Skip Intro Button Timeout" +msgstr "跳过片头按钮超时" + +msgctxt "#32522" +msgid "Automatically Skip Intro" +msgstr "自动跳过片头" + +msgctxt "#32523" +msgid "Automatically skip intros if available." +msgstr "如果可用既自动跳过片头." + +msgctxt "#32524" +msgid "Set how long the skip intro button shows for." +msgstr "设置跳过片头按钮的显示时间." + diff --git a/script.plexmod/resources/settings.xml b/script.plexmod/resources/settings.xml new file mode 100644 index 0000000000..973bb4a124 --- /dev/null +++ b/script.plexmod/resources/settings.xml @@ -0,0 +1,335 @@ + + +
+ + + + + + + + + 0 + false + + + + 0 + false + + + + 0 + true + + + + 0 + 100 + + 25 + 25 + 750 + + + false + + + + + + + + + 0 + true + + + + 0 + 1 + + 0 + 0.1 + 5 + + + false + + + true + + + + 0 + false + + + + 0 + false + + + + 0 + true + + + + 0 + true + + + true + + + + 0 + true + + + + 0 + 120 + + 0 + 1 + 600 + + + false + + + + 0 + 10 + + 0 + 1 + 600 + + + false + + + + + + + + + 0 + 2.5 + + -10 + 0.5 + 10 + + + 33630 + false + + + + 0 + 10 + + 1 + 1 + 40 + + + 32524 + false + + + + 0 + 10 + + 1 + 1 + 40 + + + 32528 + false + + + + 0 + 60 + + 10 + 10 + 1800 + + + 33510 + false + + + + 0 + true + + + + 0 + false + + + + + + + + + 0 + false + + + + 0 + false + + + + 0 + true + + + + 0 + true + + + true + + + + 0 + - + + + false + + + + 0 + 0 + + 0 + 1 + 256 + + + false + + + true + + + + 0 + 20 + + 0 + 1 + 100 + + + false + + + true + + + + 0 + false + + + true + + + + 0 + true + + + + 0 + true + + + + 0 + 16 + + 32501 + + + + 0 + true + + + + 0 + true + + + + + + + + 0 + false + + + + + + + + 0 + 5 + + 0.1 + 0.1 + 20 + + + false + + + + 0 + 2.5 + + 0.1 + 0.1 + 20 + + + false + + + + 0 + 10 + + 1 + 1 + 1000 + + + false + + + + +
+
diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-album.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-album.xml new file mode 100644 index 0000000000..e9c0d979a2 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-album.xml @@ -0,0 +1,628 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + 0 + 135 + 101 + + + 60 + 0 + + 0 + 5 + 420 + 40 + font13 + left + center + FFFFFFFF + + + + 0 + 60 + 420 + 40 + font13 + left + center + FFFFFFFF + + + + 0 + 142 + 630 + 630 + $INFO[Window.Property(album.thumb)] + scale + + + + + VisibleChange + 301 + 50 + 784 + 650 + 145 + 200 + 101 + -50 + horizontal + center + 200 + true + + Focus + UnFocus + + 0 + 0 + 174 + 139 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + Focus + UnFocus + + 0 + 0 + 174 + 139 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + Focus + UnFocus + + 0 + 0 + 174 + 139 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 750 + 0 + 1170 + 945 + + 0 + 0 + 1380 + 945 + script.plex/white-square.png + 20000000 + + + + 0 + 0 + 1170 + 945 + 200 + 152 + 300 + 200 + vertical + 4 + 152 + + + + String.IsEmpty(ListItem.Property(is.header)) + 120 + 24 + + !String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + -10 + 0 + 60 + 76 + font10 + center + center + D8FFFFFF + + + + String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 2 + 21 + 35 + 35 + script.plex/indicators/playing-circle.png + FFE5A00D + + + 90 + 0 + + 0 + 0 + 723 + 76 + font10 + left + center + FFFFFFFF + + + + + 730 + 0 + 200 + 76 + font10 + right + center + D8FFFFFF + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 73 + 930 + 2 + script.plex/white-square.png + 40000000 + + + + + !String.IsEmpty(ListItem.Property(is.header)) + 120 + 24 + 400 + 76 + font10 + left + center + FFFFFFFF + + + + + + + + + String.IsEmpty(ListItem.Property(is.header)) + + !Control.HasFocus(101) + 120 + 24 + + !String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + -10 + 0 + 60 + 76 + font10 + center + center + D8FFFFFF + + + + String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 2 + 21 + 35 + 35 + script.plex/indicators/playing-circle.png + FFE5A00D + + + 90 + 0 + + 0 + 0 + 723 + 76 + font10 + left + center + FFFFFFFF + + + + + 730 + 0 + 200 + 76 + font10 + right + center + D8FFFFFF + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 73 + 930 + 2 + script.plex/white-square.png + 40000000 + + + + + Control.HasFocus(101) + 63 + 21 + + -40 + -40 + 1130 + 156 + script.plex/square-rounded-shadow.png + + + 0 + 0 + 1044 + 76 + script.plex/white-square-rounded.png + FFE5A00D + + + !String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 48 + 0 + 50 + 76 + font12 + left + center + B8000000 + + + + String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 36 + 21 + 35 + 35 + script.plex/indicators/playing-circle.png + FF000000 + + + 140 + 0 + + 0 + 0 + 738 + 76 + font12 + left + center + DF000000 + + + + + 796 + 0 + 200 + 76 + font12 + right + center + B8000000 + + + + + + + !String.IsEmpty(ListItem.Property(is.header)) + 120 + 24 + 400 + 76 + font10 + left + center + FFFFFFFF + + + + + + + + 1128 + 33 + 10 + 874 + 101 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + + + + + 201 + 0 + 0 + 1920 + 135 + + ControlGroup(200).HasFocus(0) + false + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-artist.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-artist.xml new file mode 100644 index 0000000000..797137b023 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-artist.xml @@ -0,0 +1,527 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + 0 + 135 + 101 + + + VisibleChange + 301 + 594 + 418 + 600 + 145 + 200 + 101 + -50 + horizontal + center + 200 + true + + Focus + UnFocus + + 0 + 0 + 174 + 139 + font12 + script.plex/buttons/info-focus.png + script.plex/buttons/info.png + + + + Focus + UnFocus + + 0 + 0 + 174 + 139 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + Focus + UnFocus + + 0 + 0 + 174 + 139 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + Focus + UnFocus + + 0 + 0 + 174 + 139 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + + 60 + 0 + 1920 + 200 + + 0 + 0 + 519 + 519 + $INFO[Window.Property(thumb)] + scale + + + 579 + 5 + 1190 + 40 + font13 + left + center + FFFFFFFF + + + + 579 + 55 + 1190 + 40 + font13 + left + center + FFDDDDDD + + + + 579 + 158 + 1221 + 250 + font13 + left + FFDDDDDD + + 152 + + + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 0 + 585 + 1920 + 360 + + 0 + 0 + 1920 + 360 + script.plex/white-square.png + 20000000 + + + 0 + -20 + 1920 + 700 + 300 + 200 + horizontal + 2 + + + + 60 + 60 + + 0 + 0 + + 0 + 0 + 215 + 215 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 215 + 215 + $INFO[ListItem.Thumb] + scale + + + 0 + 220 + + 0 + 0 + 215 + 30 + font10 + center + FFFFFFFF + + + + 0 + 30 + 215 + 30 + font10 + center + FFFFFFFF + + + + + + + + + + + 60 + 60 + + Focus + UnFocus + + 0 + 0 + + Control.HasFocus(101) + -40 + -40 + 295 + 295 + script.plex/square-rounded-shadow.png + + + 0 + 0 + 215 + 215 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 215 + 215 + $INFO[ListItem.Thumb] + scale + + + 0 + 220 + + false + 0 + 0 + 215 + 30 + font10 + center + FFFFFFFF + + + + 0 + 30 + 215 + 30 + font10 + center + FFFFFFFF + + + + + + Control.HasFocus(101) + -5 + -5 + 225 + 225 + script.plex/home/selected.png + + + + + + + + + + + 201 + 0 + 0 + 1920 + 135 + + VisibleChange + ControlGroup(200).HasFocus(0) + false + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-background.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-background.xml new file mode 100644 index 0000000000..7d28bf2fbc --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-background.xml @@ -0,0 +1,65 @@ + + + 100 + + 1 + 0 + 0 + + 0xff111111 + + + !String.IsEmpty(Window(10000).Property(script.plex.background.splash)) + 710 + 459 + 500 + 162 + script.plex/splash.png + + + + !String.IsEmpty(Window(10000).Property(script.plex.background.busy)) + + 812 + 135 + 300 + 97 + script.plex/user_select/plex.png + + + 840 + 465 + 240 + 150 + script.plex/busy-back.png + A0FFFFFF + + + 915 + 521 + 90 + 38 + script.plex/busy.gif + + + + + !String.IsEmpty(Window(10000).Property(script.plex.background.shutdown)) + + 840 + 465 + 240 + 150 + script.plex/busy-back.png + A0FFFFFF + + + 915 + 521 + 90 + 38 + script.plex/busy.gif + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-blank.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-blank.xml new file mode 100644 index 0000000000..2f887866c6 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-blank.xml @@ -0,0 +1,12 @@ + + + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-busy.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-busy.xml new file mode 100644 index 0000000000..31b167f2b7 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-busy.xml @@ -0,0 +1,28 @@ + + + + 1 + 0 + 0 + + + + WindowOpen + + 840 + 465 + 240 + 150 + script.plex/busy-back.png + A0FFFFFF + + + 915 + 521 + 90 + 38 + script.plex/busy.gif + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-busy_msg.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-busy_msg.xml new file mode 100644 index 0000000000..5fc2a6bb5b --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-busy_msg.xml @@ -0,0 +1,35 @@ + + + + 1 + 0 + 0 + + + + 0 + 0 + WindowOpen + + 840 + 465 + 240 + 150 + script.plex/busy-back.png + A0FFFFFF + + + 840 + 465 + 240 + 150 + center + center + FFFFFFFF + + font14 + black + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown.xml new file mode 100644 index 0000000000..8ace797b8b --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown.xml @@ -0,0 +1,201 @@ + + SetProperty(dropdown,1) + 100 + + 1 + 0 + 0 + + 100 + + + + 0 + 0 + 1920 + 1080 + - + - + + + 250 + !String.IsEmpty(Window.Property(show)) + 0 + 0 + + -40 + -40 + 380 + 146 + script.plex/drop-shadow.png + + + 0 + 0 + 300 + 924 + Close + noop + Close + Close + Close + noop + 200 + vertical + + + + !String.IsEmpty(ListItem.Property(first)) + 0 + 0 + 300 + 66 + script.plex/white-square-top-rounded.png + + + String.IsEmpty(ListItem.Property(first)) + String.IsEmpty(ListItem.Property(last)) + String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 300 + 66 + script.plex/white-square.png + + + !String.IsEmpty(ListItem.Property(last)) + 0 + 0 + 300 + 66 + script.plex/white-square-top-rounded.png + + + !String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 300 + 66 + script.plex/white-square-rounded.png + + + String.IsEmpty(ListItem.Property(with.indicator)) + 0 + 0 + 300 + 66 + font12 + center + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(with.indicator)) + + 20 + 0 + 280 + 66 + font12 + left + center + FFFFFFFF + + + + 254 + 20 + 26 + 26 + $INFO[ListItem.Thumb] + keep + + + + !String.IsEmpty(ListItem.Property(separator)) + 0 + 64 + 300 + 2 + script.plex/white-square.png + + + + + !String.IsEmpty(ListItem.Property(first)) + 0 + 0 + 300 + 66 + script.plex/white-square-top-rounded.png + + + String.IsEmpty(ListItem.Property(first)) + String.IsEmpty(ListItem.Property(last)) + String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 300 + 66 + script.plex/white-square.png + + + !String.IsEmpty(ListItem.Property(last)) + 0 + 0 + 300 + 66 + script.plex/white-square-top-rounded.png + + + !String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 300 + 66 + script.plex/white-square-rounded.png + + + String.IsEmpty(ListItem.Property(with.indicator)) + 0 + 0 + 300 + 66 + font12 + center + center + FF000000 + + + + !String.IsEmpty(ListItem.Property(with.indicator)) + + 20 + 0 + 280 + 66 + font12 + left + center + FF000000 + + + + 254 + 20 + 26 + 26 + $INFO[ListItem.Thumb] + keep + + + + !String.IsEmpty(ListItem.Property(separator)) + 0 + 64 + 300 + 2 + script.plex/white-square.png + + + + + + \ No newline at end of file diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown_header.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown_header.xml new file mode 100644 index 0000000000..3c623d851a --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown_header.xml @@ -0,0 +1,247 @@ + + SetProperty(dropdown,1) + 100 + + 1 + 0 + 0 + + + + + 0 + 0 + 1920 + 1080 + - + - + + + 250 + !String.IsEmpty(Window.Property(show)) + 0 + 0 + + -60 + -106 + 720 + 146 + script.plex/drop-shadow.png + + + !String.IsEmpty(Window.Property(header)) + -20 + -66 + + 0 + 0 + 640 + 132 + script.plex/white-square-rounded.png + + + 20 + 0 + 600 + 66 + font12 + center + center + FFFFFFFF + + + + + 0 + 0 + 600 + 924 + Close + noop + Close + Close + Close + noop + 200 + vertical + + + + !String.IsEmpty(ListItem.Property(first)) + 0 + 0 + 600 + 66 + script.plex/white-square-top-rounded.png + + + String.IsEmpty(ListItem.Property(first)) + String.IsEmpty(ListItem.Property(last)) + String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 600 + 66 + script.plex/white-square.png + + + !String.IsEmpty(ListItem.Property(last)) + 0 + 0 + 600 + 66 + script.plex/white-square-top-rounded.png + + + !String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 600 + 66 + script.plex/white-square-rounded.png + + + String.IsEmpty(ListItem.Property(with.indicator)) + String.IsEqual(ListItem.Property(align),center) + 0 + 0 + 600 + 66 + font12 + center + center + FFFFFFFF + + + + String.IsEmpty(ListItem.Property(with.indicator)) + String.IsEqual(ListItem.Property(align),left) + 20 + 0 + 600 + 66 + font12 + left + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(with.indicator)) + + 60 + 0 + 520 + 66 + font12 + left + center + FFFFFFFF + + + + 20 + 20 + 26 + 26 + $INFO[ListItem.Thumb] + keep + + + + !String.IsEmpty(ListItem.Property(separator)) + 0 + 64 + 600 + 2 + script.plex/white-square.png + + + + + !String.IsEmpty(ListItem.Property(first)) + 0 + 0 + 600 + 66 + script.plex/white-square-top-rounded.png + + + String.IsEmpty(ListItem.Property(first)) + String.IsEmpty(ListItem.Property(last)) + String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 600 + 66 + script.plex/white-square.png + + + !String.IsEmpty(ListItem.Property(last)) + 0 + 0 + 600 + 66 + script.plex/white-square-top-rounded.png + + + !String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 600 + 66 + script.plex/white-square-rounded.png + + + String.IsEmpty(ListItem.Property(with.indicator)) + String.IsEqual(ListItem.Property(align),center) + 0 + 0 + 600 + 66 + font12 + center + center + FF000000 + + + + String.IsEmpty(ListItem.Property(with.indicator)) + String.IsEqual(ListItem.Property(align),left) + 20 + 0 + 600 + 66 + font12 + left + center + FF000000 + + + + !String.IsEmpty(ListItem.Property(with.indicator)) + + 60 + 0 + 520 + 66 + font12 + left + center + FF000000 + + + + 20 + 20 + 26 + 26 + $INFO[ListItem.Thumb] + keep + + + + !String.IsEmpty(ListItem.Property(separator)) + 0 + 64 + 600 + 2 + script.plex/white-square.png + + + + + + \ No newline at end of file diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-episodes.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-episodes.xml new file mode 100644 index 0000000000..47428c7014 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-episodes.xml @@ -0,0 +1,1820 @@ + + + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + Conditional + + + + + + + + + + + + + + + + + + 0 + 155 + 101 + + + VisibleChange + !String.IsEmpty(Window.Property(initialized)) + 301 + 30 + 405 + 717 + 200 + 200 + 400 + center + -50 + horizontal + 200 + true + + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/info-focus.png + script.plex/buttons/info.png + + + + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + !String.IsEmpty(Container(400).ListItem.Property(media.multiple)) + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/media-focus.png + script.plex/buttons/media.png + + + + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/settings-focus.png + script.plex/buttons/settings.png + + + + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + + 0 + 0 + 1920 + 600 + + + 60 + 0 + 657 + 393 + script.plex/thumb_fallbacks/show.png + WindowOpen + scale + + + 60 + 0 + 657 + 393 + $INFO[Container(400).ListItem.Thumb] + scale + + + !String.IsEmpty(Container(400).ListItem.Property(unwatched)) + 682 + 0 + 35 + 35 + script.plex/indicators/unwatched.png + + + + + 776 + 0 + 1360 + 60 + left + 0 + horizontal + true + + auto + 60 + font13 + left + top + FFFFFFFF + + + + !String.IsEmpty(Container(400).ListItem.Property(remainingTime)) + 10 + 6 + auto + 34 + font12 + center + center + FFE5A00D + FFE5A00D + 15 + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + + + + + 776 + 50 + 1360 + 60 + font13 + left + top + FFFFFFFF + + + + 776 + 140 + 1360 + 30 + left + 0 + horizontal + true + + auto + 30 + font12 + left + FFFFFFFF + + + + !String.IsEmpty(Container(400).ListItem.Property(unavailable)) + 10 + auto + 30 + font12 + center + center + FFFFFFFF + FFFFFFFF + 15 + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + + + + + + 776 + 188 + 1360 + 34 + left + 0 + horizontal + true + + auto + 34 + font12 + left + FFFFFFFF + + + + !String.IsEmpty(Container(400).ListItem.Property(rating.stars)) + auto + 34 + font12 + left + FFFFFFFF + + + + !String.IsEmpty(Container(400).ListItem.Property(rating.stars)) + 6 + 134 + 22 + script.plex/stars/$INFO[Container(400).ListItem.Property(rating.stars)].png + + + !String.IsEmpty(Container(400).ListItem.Property(video.res)) + 10 + auto + 34 + font12 + center + center + FFFFFFFF + FFFFFFFF + 15 + script.plex/white-square-rounded-top-padded.png + script.plex/white-square-rounded-top-padded.png + + + + + + !String.IsEmpty(Container(400).ListItem.Property(rating)) + 1560 + 140 + 300 + 32 + right + 15 + horizontal + true + + 2 + 63 + 30 + $INFO[Container(400).ListItem.Property(rating.image)] + keep + + + auto + 30 + font12 + left + FFFFFFFF + + + + !String.IsEmpty(Container(400).ListItem.Property(rating2)) + 2 + 40 + 30 + $INFO[Container(400).ListItem.Property(rating2.image)] + keep + + + !String.IsEmpty(Container(400).ListItem.Property(rating2)) + auto + 30 + font12 + left + FFFFFFFF + + + + + + 776 + 263 + 1360 + 34 + left + 15 + horizontal + true + + !String.IsEmpty(Container(400).ListItem.Property(audio)) + auto + 34 + font12 + center + center + FFFFFFFF + FFFFFFFF + 15 + script.plex/white-square-rounded-top-padded.png + script.plex/white-square-rounded-top-padded.png + + + + auto + 34 + font12 + left + center + FFFFFFFF + + + + !String.IsEmpty(Container(400).ListItem.Property(subtitles)) + 34 + auto + 34 + font12 + center + center + FFFFFFFF + FFFFFFFF + 15 + script.plex/white-square-rounded-top-padded.png + script.plex/white-square-rounded-top-padded.png + + + + !String.IsEmpty(Container(400).ListItem.Property(subtitles)) + auto + 34 + font12 + left + center + FFFFFFFF + + + + + 776 + 340 + 1084 + 172 + font12 + left + FFFFFFFF + + + + + WindowOpen + -1 + 557 + 1 + 8 + script.plex/white-square.png + FFCC7B19 + + + !Control.IsVisible(500) + 0 + 565 + 1920 + 2 + script.plex/white-square.png + A0000000 + + + + + !String.IsEmpty(Window.Property(initialized)) + 0 + 565 + 1920 + 1800 + + 300 + 0 + + + Integer.IsGreater(Container(400).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 360 + 1920 + + 0 + 0 + 1920 + 360 + script.plex/white-square.png + 40000000 + + + 60 + 0 + 800 + 80 + font12 + left + center + AAFFFFFF + + + + 0 + 18 + 1920 + 430 + 300 + 401 + false + false + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 299 + 168 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 299 + 168 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 158 + + 0 + 0 + 299 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 299 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 264 + 0 + 35 + 35 + script.plex/indicators/unwatched.png + + + false + 0 + 175 + 299 + 60 + font12 + center + AAFFFFFF + + + + false + 0 + 210 + 299 + 60 + font12 + center + AAFFFFFF + + + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 299 + 168 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 119 + 34 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 119 + 34 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 85.5 + 20 + 128 + 128 + script.plex/home/busy.gif + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(400) + -40 + -40 + 389 + 258 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 299 + 168 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 299 + 168 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 158 + + 0 + 0 + 299 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 299 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 264 + 0 + 35 + 35 + script.plex/indicators/unwatched.png + + + Control.HasFocus(400) + + true + 0 + 175 + 299 + 60 + font12 + center + AAFFFFFF + + + + true + 0 + 210 + 299 + 60 + font12 + center + AAFFFFFF + + + + + !Control.HasFocus(400) + + false + 0 + 175 + 299 + 60 + font12 + center + FFCC7B19 + + + + false + 0 + 210 + 299 + 60 + font12 + center + FFCC7B19 + + + + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 299 + 168 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 119 + 34 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 119 + 34 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 85.5 + 20 + 128 + 128 + script.plex/home/busy.gif + + + + + Control.HasFocus(400) + 0 + 0 + 309 + 178 + script.plex/home/selected.png + + + + + + + + + + Integer.IsGreater(Container(401).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 400 + 1920 + + 60 + 20 + 800 + 40 + font12 + left + center + FFFFFFFF + + + + 0 + 50 + 1920 + 360 + 400 + 402 + 200 + horizontal + 4 + + + + 55 + 29 + + 5 + 5 + + 0 + 0 + 158 + 236 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 158 + 236 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 113 + 0 + 45 + 40 + script.plex/white-square.png + FF000000 + + + 114 + 0 + 44 + 39 + script.plex/white-square.png + FFCC7B19 + + + 114 + 0 + 44 + 39 + font10 + center + center + FF000000 + + + + + false + 0 + 240 + 158 + 54 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 29 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(401) + -40 + -40 + 248 + 326 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 158 + 236 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 158 + 236 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 113 + 0 + 45 + 40 + script.plex/white-square.png + FF000000 + + + 114 + 0 + 44 + 39 + script.plex/white-square.png + FFCC7B19 + + + 114 + 0 + 44 + 39 + font10 + center + center + FF000000 + + + + + Control.HasFocus(401) + 0 + 240 + 158 + 54 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(401) + 0 + 0 + 168 + 246 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(402).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 360 + 1920 + + !String.IsEmpty(Window.Property(divider.402)) + 60 + 0 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 800 + 80 + font12 + left + center + AAFFFFFF + + + + 0 + 18 + 1920 + 430 + 401 + 403 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 299 + 168 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 299 + 168 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 175 + 299 + 60 + font10 + center + AAFFFFFF + + + + false + 0 + 205 + 299 + 60 + font10 + center + AAFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(402) + -40 + -40 + 389 + 258 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 299 + 168 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 299 + 168 + $INFO[ListItem.Thumb] + scale + + + + Control.HasFocus(402) + 0 + 175 + 299 + 60 + font10 + center + AAFFFFFF + + + + Control.HasFocus(402) + 0 + 205 + 299 + 60 + font10 + center + AAFFFFFF + + + + + + Control.HasFocus(402) + 0 + 0 + 309 + 178 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(403).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 402 + 1920 + 520 + + !String.IsEmpty(Window.Property(divider.403)) + 60 + 0 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 16 + 1920 + 520 + 402 + 404 + false + false + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 369 + 244 + 38 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + Control.HasFocus(403) + -40 + -40 + 324 + 441 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + Control.HasFocus(403) + 0 + 369 + 244 + 38 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(403) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(404).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 403 + 1920 + 410 + + !String.IsEmpty(Window.Property(divider.404)) + 60 + 20 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 20 + 1000 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 36 + 1920 + 410 + 403 + 404 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + script.plex/thumb_fallbacks/role.png + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + 0 + 253 + + false + 0 + 0 + 244 + 60 + font10 + center + AAFFFFFF + + + + false + 0 + 30 + 244 + 60 + font10 + center + AAFFFFFF + + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(404) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + script.plex/thumb_fallbacks/role.png + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + 0 + 253 + + Control.HasFocus(404) + 0 + 0 + 244 + 60 + font10 + center + AAFFFFFF + + + + Control.HasFocus(404) + 0 + 30 + 244 + 60 + font10 + center + AAFFFFFF + + + + + + Control.HasFocus(404) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + + + Conditional + 201 + 0 + 0 + 1920 + 135 + + VisibleChange + ControlGroup(200).HasFocus(0) + !String.IsEmpty(Window.Property(on.extras)) + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-home.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-home.xml new file mode 100644 index 0000000000..e5431162c0 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-home.xml @@ -0,0 +1,8622 @@ + + + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + Conditional + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 101 + 0 + 96 + 2130 + 5540 + 20 + vertical + true + 200 + + 2130 + 200 + + Conditional + Conditional + -300 + 0 + 2430 + 240 + 101 + 203 + 204 + 400 + 200 + horizontal + 4 + 3 + 102 + + + + !String.IsEmpty(ListItem.Property(item)) + 60 + 40 + 298 + 200 + + 0 + 0 + 238 + 117 + + String.IsEmpty(ListItem.Property(is.home)) + 0 + 0 + 238 + 117 + script.plex/white-square-rounded.png + FF1F1F1F + + + + String.IsEmpty(ListItem.Property(is.home)) + 84 + 23.5 + 70 + 70 + $INFO[ListItem.Thumb] + keep + + + !String.IsEmpty(ListItem.Property(is.home)) + 74 + 13.5 + 90 + 90 + script.plex/home/type/home.png + keep + + + + + false + 0 + 125 + 238 + 35 + font10 + center + FFFFFFFF + + + + + + + + + !String.IsEmpty(ListItem.Property(item)) + 60 + 40 + + Focus + UnFocus + 0 + 0 + + String.IsEmpty(ListItem.Property(is.home)) + + Control.HasFocus(101) + + -40 + -40 + 318 + 197 + script.plex/drop-shadow.png + + + UnFocus + 0 + 0 + 238 + 117 + script.plex/white-square-rounded.png + FF1F1F1F + + + UnFocus + 0 + 0 + 238 + 117 + script.plex/white-square-rounded.png + FFE5A00D + + + + !Control.HasFocus(101) + 0 + 0 + 238 + 117 + script.plex/white-square-rounded.png + FFCC7B19 + + + 84 + 23.5 + 70 + 70 + $INFO[ListItem.Thumb] + keep + + + + !String.IsEmpty(ListItem.Property(is.home)) + 74 + 13.5 + + 0 + 0 + 90 + 90 + script.plex/home/type/home.png + keep + + + Control.HasFocus(101) + UnFocus + -40 + -40 + 170 + 170 + script.plex/home/type/home-selected.png + keep + + + + Control.HasFocus(100) + 0 + 125 + 238 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + Integer.IsGreater(Container(400).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1920 + 440 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1920 + 440 + 101 + 401 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.400)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(400) + -40 + -40 + 622 + 389 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + Control.HasFocus(400) + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + Control.HasFocus(400) + !String.IsEmpty(Window.Property(hub.text2lines.400)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(400) + 0 + 0 + 542 + 309 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(400).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.400)) + 10 + 12 + + + + Integer.IsGreater(Container(401).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 401 + 1920 + 515 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 515 + 400 + 402 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.401)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(401) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(401) + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(401) + !String.IsEmpty(Window.Property(hub.text2lines.401)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + Control.HasFocus(401) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(401).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.401)) + 10 + 7 + + + + Integer.IsGreater(Container(402).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 402 + 1920 + 515 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 515 + 401 + 403 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.402)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(402) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(402) + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(402) + !String.IsEmpty(Window.Property(hub.text2lines.402)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + Control.HasFocus(402) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(402).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.402)) + 10 + 7 + + + + Integer.IsGreater(Container(403).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 403 + 1920 + 515 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 515 + 402 + 404 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.403)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(403) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(403) + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(403) + !String.IsEmpty(Window.Property(hub.text2lines.403)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + Control.HasFocus(403) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(403).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.403)) + 10 + 7 + + + + Integer.IsGreater(Container(404).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 404 + 1920 + 515 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 515 + 403 + 405 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.404)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(404) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(404) + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(404) + !String.IsEmpty(Window.Property(hub.text2lines.404)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + Control.HasFocus(404) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(404).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.404)) + 10 + 7 + + + + Integer.IsGreater(Container(405).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 405 + 1920 + 392 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 392 + 404 + 406 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.405)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(405) + -40 + -40 + 324 + 324 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(405) + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(405) + !String.IsEmpty(Window.Property(hub.text2lines.405)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(405) + 0 + 0 + 254 + 254 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(405).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.405)) + 10 + 7 + + + + Integer.IsGreater(Container(406).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1920 + 440 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1920 + 440 + 405 + 407 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.406)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(406) + -40 + -40 + 622 + 389 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + Control.HasFocus(406) + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + Control.HasFocus(406) + !String.IsEmpty(Window.Property(hub.text2lines.406)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(406) + 0 + 0 + 542 + 309 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(406).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.406)) + 10 + 12 + + + + Integer.IsGreater(Container(407).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 407 + 1920 + 515 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 515 + 406 + 408 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.407)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(407) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(407) + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(407) + !String.IsEmpty(Window.Property(hub.text2lines.407)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + Control.HasFocus(407) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(407).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.407)) + 10 + 7 + + + + Integer.IsGreater(Container(408).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 408 + 1920 + 515 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 515 + 407 + 409 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.408)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(408) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(408) + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(408) + !String.IsEmpty(Window.Property(hub.text2lines.408)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + Control.HasFocus(408) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(408).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.408)) + 10 + 7 + + + + Integer.IsGreater(Container(409).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 409 + 1920 + 392 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 392 + 408 + 410 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.409)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(409) + -40 + -40 + 324 + 324 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(409) + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(409) + !String.IsEmpty(Window.Property(hub.text2lines.409)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(409) + 0 + 0 + 254 + 254 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(409).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.409)) + 10 + 7 + + + + Integer.IsGreater(Container(410).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 410 + 1920 + 392 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 392 + 409 + 411 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.410)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(410) + -40 + -40 + 324 + 324 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(410) + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(410) + !String.IsEmpty(Window.Property(hub.text2lines.410)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(410) + 0 + 0 + 254 + 254 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(410).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.410)) + 10 + 7 + + + + Integer.IsGreater(Container(411).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 411 + 1920 + 392 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 392 + 410 + 412 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.411)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(411) + -40 + -40 + 324 + 324 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(411) + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(411) + !String.IsEmpty(Window.Property(hub.text2lines.411)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(411) + 0 + 0 + 254 + 254 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(411).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.411)) + 10 + 7 + + + + Integer.IsGreater(Container(412).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 412 + 1920 + 392 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 392 + 411 + 420 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.412)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(412) + -40 + -40 + 324 + 324 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(412) + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(412) + !String.IsEmpty(Window.Property(hub.text2lines.412)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(412) + 0 + 0 + 254 + 254 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(412).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.412)) + 10 + 7 + + + + Integer.IsGreater(Container(420).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 420 + 1920 + 392 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 392 + 412 + 421 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.420)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(420) + -40 + -40 + 324 + 324 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(420) + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(420) + !String.IsEmpty(Window.Property(hub.text2lines.420)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(420) + 0 + 0 + 254 + 254 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(420).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.420)) + 10 + 7 + + + + Integer.IsGreater(Container(421).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 421 + 1920 + 392 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 392 + 420 + 422 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.421)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(421) + -40 + -40 + 324 + 324 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(421) + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(421) + !String.IsEmpty(Window.Property(hub.text2lines.421)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(421) + 0 + 0 + 254 + 254 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(421).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.421)) + 10 + 7 + + + + Integer.IsGreater(Container(422).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 422 + 1920 + 392 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 392 + 421 + 413 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.422)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(422) + -40 + -40 + 324 + 324 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 244 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 72 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 58 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 234 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(422) + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(422) + !String.IsEmpty(Window.Property(hub.text2lines.422)) + 0 + 281 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(422) + 0 + 0 + 254 + 254 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(422).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.422)) + 10 + 7 + + + + Integer.IsGreater(Container(413).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 413 + 1920 + 515 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 515 + 422 + 414 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.413)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(413) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(413) + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(413) + !String.IsEmpty(Window.Property(hub.text2lines.413)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + Control.HasFocus(413) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(413).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.413)) + 10 + 7 + + + + Integer.IsGreater(Container(414).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 414 + 1920 + 515 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 515 + 413 + 415 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.414)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(414) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(414) + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(414) + !String.IsEmpty(Window.Property(hub.text2lines.414)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + Control.HasFocus(414) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(414).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.414)) + 10 + 7 + + + + Integer.IsGreater(Container(415).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 415 + 1920 + 515 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 515 + 414 + 416 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.415)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(415) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(415) + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(415) + !String.IsEmpty(Window.Property(hub.text2lines.415)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + Control.HasFocus(415) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(415).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.415)) + 10 + 7 + + + + Integer.IsGreater(Container(416).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 416 + 1920 + 515 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 29 + 1920 + 515 + 415 + 417 + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + false + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.416)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(416) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + Control.HasFocus(416) + 0 + 371 + 244 + 35 + font10 + center + FFFFFFFF + + + + Control.HasFocus(416) + !String.IsEmpty(Window.Property(hub.text2lines.416)) + 0 + 398 + 244 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + Control.HasFocus(416) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(416).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.416)) + 10 + 7 + + + + Integer.IsGreater(Container(417).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1920 + 440 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1920 + 440 + 416 + 418 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.417)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(417) + -40 + -40 + 622 + 389 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + Control.HasFocus(417) + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + Control.HasFocus(417) + !String.IsEmpty(Window.Property(hub.text2lines.417)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(417) + 0 + 0 + 542 + 309 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(417).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.417)) + 10 + 12 + + + + Integer.IsGreater(Container(418).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1920 + 440 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1920 + 440 + 417 + 419 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.418)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(418) + -40 + -40 + 622 + 389 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + Control.HasFocus(418) + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + Control.HasFocus(418) + !String.IsEmpty(Window.Property(hub.text2lines.418)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(418) + 0 + 0 + 542 + 309 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(418).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.418)) + 10 + 12 + + + + Integer.IsGreater(Container(419).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1920 + 440 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1920 + 440 + 418 + 423 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.419)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(419) + -40 + -40 + 622 + 389 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + Control.HasFocus(419) + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + Control.HasFocus(419) + !String.IsEmpty(Window.Property(hub.text2lines.419)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(419) + 0 + 0 + 542 + 309 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(419).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.419)) + 10 + 12 + + + + Integer.IsGreater(Container(423).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1920 + 440 + + 60 + 12 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1920 + 440 + 419 + 423 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + false + !String.IsEmpty(Window.Property(hub.text2lines.423)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(423) + -40 + -40 + 622 + 389 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.end)) + + 0 + 0 + 532 + 299 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + 235.5 + 99.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 202 + 85.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 532 + 299 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 289 + + 0 + 0 + 532 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 532 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 484 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 481 + 0 + + 0 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 1 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 1 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + Control.HasFocus(423) + 0 + 309 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + Control.HasFocus(423) + !String.IsEmpty(Window.Property(hub.text2lines.423)) + 0 + 337 + 532 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(423) + 0 + 0 + 542 + 309 + script.plex/home/selected.png + + + + + + + + Integer.IsGreater(Container(423).NumItems,0) + !String.IsEmpty(Window.Property(hub.text2lines.423)) + 10 + 12 + + + + + 1920 + 100 + font12 + left + center + 00FFFFFF + + + + + + + + Conditional + 201 + 0 + 0 + 1920 + 135 + + VisibleChange + ControlGroup(200).HasFocus(0) + !String.IsEmpty(Window(10000).Property(script.plex.off.sections)) + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + String.IsEmpty(Window.Property(search.dialog)) + + Focus + UnFocus + 60 + 47.5 + 40 + 40 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + 160 + 35 + 500 + 65 + font12 + left + center + FFFFFFFF + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 203 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + 576 + 34 + 1000 + 1046 + + 0 + 0 + 1000 + 1046 + 50 + 204 + right + 0 + horizontal + 200 + true + + auto + 66 + font12 + FFFFFFFF + FF000000 + FFFFFFFF + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + SetFocus(260) + + + + -93 + 93 + 66 + + 6 + 14 + 40 + 39 + $INFO[Window.Property(server.icon)] + + + 0 + 38 + 16 + 15 + $INFO[Window.Property(server.iconmod)] + + + + !String.IsEmpty(Window.Property(server.iconmod)) + 0 + 20 + 16 + 14 + $INFO[Window.Property(server.iconmod2)] + FFEEEEEE + + + + String.IsEmpty(Window.Property(server.iconmod)) + 0 + 38 + 16 + 14 + $INFO[Window.Property(server.iconmod2)] + FFEEEEEE + + + !Control.HasFocus(201) + 59 + 27 + 15 + 13 + script.plex/indicators/dropdown-triangle.png + 99FFFFFF + + + Control.HasFocus(201) + 59 + 27 + 15 + 13 + script.plex/indicators/dropdown-triangle.png + FF222222 + + + Control.HasFocus(260) | !String.IsEmpty(Window.Property(show.servers)) + -413 + 70 + + -40 + -40 + 580 + 146 + script.plex/drop-shadow.png + + + 432 + -13 + 15 + 13 + script.plex/indicators/dropdown-triangle.png + FF1F1F1F + + + + 0 + 0 + 500 + 900 + 201 + 203 + 202 + SetProperty(show.servers,) + 200 + vertical + 261 + + + + !String.IsEmpty(ListItem.Property(first)) + 0 + 0 + 500 + 100 + script.plex/white-square-top-rounded.png + + + String.IsEmpty(ListItem.Property(first)) + String.IsEmpty(ListItem.Property(last)) + String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 500 + 100 + script.plex/white-square.png + + + !String.IsEmpty(ListItem.Property(last)) + 0 + 0 + 500 + 100 + script.plex/white-square-top-rounded.png + + + !String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 500 + 100 + script.plex/white-square-top-rounded.png + + + !String.IsEmpty(ListItem.Label2) + + 20 + 20 + 400 + 35 + font12 + left + center + FFFFFFFF + + + + 20 + 50 + 400 + 35 + font12 + left + center + FFA0A0A0 + + + + + String.IsEmpty(ListItem.Label2) + 20 + 0 + 400 + 100 + font12 + left + center + FFFFFFFF + + + + + + String.IsEmpty(ListItem.Property(status)) + String.IsEmpty(ListItem.Property(current)) + !String.IsEmpty(ListItem.Property(local)) + 456 + 38 + 24 + 21 + script.plex/home/device/home.png + + + + String.IsEmpty(ListItem.Property(status)) + !String.IsEmpty(ListItem.Property(current)) + !String.IsEmpty(ListItem.Property(local)) + 415 + 38 + 24 + 21 + script.plex/home/device/home.png + + + + !String.IsEmpty(ListItem.Property(status)) + String.IsEmpty(ListItem.Property(current)) + !String.IsEmpty(ListItem.Property(local)) + 415 + 38 + 24 + 21 + script.plex/home/device/home.png + + + + !String.IsEmpty(ListItem.Property(status)) + !String.IsEmpty(ListItem.Property(current)) + !String.IsEmpty(ListItem.Property(local)) + 374 + 38 + 24 + 21 + script.plex/home/device/home.png + + + + !String.IsEmpty(ListItem.Property(status)) + String.IsEmpty(ListItem.Property(current)) + 456 + 38 + 24 + 24 + script.plex/home/device/$INFO[ListItem.Property(status)] + + + + !String.IsEmpty(ListItem.Property(status)) + !String.IsEmpty(ListItem.Property(current)) + 415 + 38 + 24 + 24 + script.plex/home/device/$INFO[ListItem.Property(status)] + + + !String.IsEmpty(ListItem.Property(current)) + 449 + 38 + 31 + 24 + script.plex/home/device/check.png + + + + + + !String.IsEmpty(ListItem.Property(first)) + 0 + 0 + 500 + 100 + script.plex/white-square-top-rounded.png + + + String.IsEmpty(ListItem.Property(first)) + String.IsEmpty(ListItem.Property(last)) + String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 500 + 100 + script.plex/white-square.png + + + !String.IsEmpty(ListItem.Property(last)) + 0 + 0 + 500 + 100 + script.plex/white-square-top-rounded.png + + + !String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 500 + 100 + script.plex/white-square-top-rounded.png + + + !String.IsEmpty(ListItem.Label2) + + 20 + 20 + 400 + 35 + font12 + left + center + FF000000 + + + + 20 + 50 + 400 + 35 + font12 + left + center + FFFFFFFF + + + + + String.IsEmpty(ListItem.Label2) + 20 + 0 + 400 + 100 + font12 + left + center + FF000000 + + + + + + String.IsEmpty(ListItem.Property(status)) + String.IsEmpty(ListItem.Property(current)) + !String.IsEmpty(ListItem.Property(local)) + 456 + 38 + 24 + 21 + script.plex/home/device/home.png + + + + String.IsEmpty(ListItem.Property(status)) + !String.IsEmpty(ListItem.Property(current)) + !String.IsEmpty(ListItem.Property(local)) + 415 + 38 + 24 + 21 + script.plex/home/device/home.png + + + + !String.IsEmpty(ListItem.Property(status)) + String.IsEmpty(ListItem.Property(current)) + !String.IsEmpty(ListItem.Property(local)) + 415 + 38 + 24 + 21 + script.plex/home/device/home.png + + + + !String.IsEmpty(ListItem.Property(status)) + !String.IsEmpty(ListItem.Property(current)) + !String.IsEmpty(ListItem.Property(local)) + 374 + 38 + 24 + 21 + script.plex/home/device/home.png + + + !String.IsEmpty(ListItem.Property(status)) + String.IsEmpty(ListItem.Property(current)) + 456 + 38 + 24 + 24 + script.plex/home/device/focus-$INFO[ListItem.Property(status)] + + + !String.IsEmpty(ListItem.Property(status)) + !String.IsEmpty(ListItem.Property(current)) + 415 + 38 + 24 + 24 + script.plex/home/device/focus-$INFO[ListItem.Property(status)] + + + !String.IsEmpty(ListItem.Property(current)) + 449 + 38 + 31 + 24 + script.plex/home/device/check.png + + + + + + + 492 + 20 + 8 + 860 + - + script.plex/white-square.png + script.plex/white-square.png + - + - + false + vertical + false + 250 + + + + + + auto + 66 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + SetFocus(250) + + + -87 + 87 + 66 + + 0 + 14 + 40 + 39 + $INFO[Window.Property(user.avatar)] + + + String.IsEmpty(Window.Property(user.avatar)) + 0 + 14 + 40 + 39 + font10 + center + center + FFFFFFFF + + + + !Control.HasFocus(202) + 53 + 27 + 15 + 13 + script.plex/indicators/dropdown-triangle.png + 99FFFFFF + + + Control.HasFocus(202) + 53 + 27 + 15 + 13 + script.plex/indicators/dropdown-triangle.png + FF222222 + + + Control.HasFocus(250) | !String.IsEmpty(Window.Property(show.options)) + -213 + 70 + + -40 + -40 + 380 + 146 + script.plex/drop-shadow.png + + + 226 + -13 + 15 + 13 + script.plex/indicators/dropdown-triangle.png + FF1F1F1F + + + + 0 + 0 + 300 + 198 + 202 + noop + 201 + SetProperty(show.options,) + 200 + vertical + + + + !String.IsEmpty(ListItem.Property(first)) + 0 + 0 + 300 + 66 + script.plex/white-square-top-rounded.png + + + String.IsEmpty(ListItem.Property(first)) + String.IsEmpty(ListItem.Property(last)) + String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 300 + 66 + script.plex/white-square.png + + + !String.IsEmpty(ListItem.Property(last)) + 0 + 0 + 300 + 66 + script.plex/white-square-top-rounded.png + + + !String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 300 + 66 + script.plex/white-square-rounded.png + + + 0 + 0 + 300 + 66 + font12 + center + center + FFFFFFFF + + + + + + !String.IsEmpty(ListItem.Property(first)) + 0 + 0 + 300 + 66 + script.plex/white-square-top-rounded.png + + + String.IsEmpty(ListItem.Property(first)) + String.IsEmpty(ListItem.Property(last)) + String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 300 + 66 + script.plex/white-square.png + + + !String.IsEmpty(ListItem.Property(last)) + 0 + 0 + 300 + 66 + script.plex/white-square-top-rounded.png + + + !String.IsEmpty(ListItem.Property(only)) + 0 + 0 + 300 + 66 + script.plex/white-square-rounded.png + + + 0 + 0 + 300 + 66 + font12 + center + center + FF000000 + + + + + + + + + 40 + 10 + - + + + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + String.IsEmpty(Window.Property(busy)) + !String.IsEmpty(Window.Property(no.content)) + 0 + 465 + + false + 60 + 0 + 1800 + 35 + font13 + center + FFFFFFFF + + + + false + 60 + 60 + 1800 + 35 + font13 + center + FFCCCCCC + + + + + + !String.IsEmpty(Window.Property(busy)) + Visible + 840 + 465 + + 0 + 0 + 240 + 150 + script.plex/busy-back.png + A0FFFFFF + + + 75 + 56 + 90 + 38 + script.plex/busy.gif + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-info.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-info.xml new file mode 100644 index 0000000000..9c07ff9b22 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-info.xml @@ -0,0 +1,281 @@ + + + 152 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + 0 + 135 + + + 60 + 0 + + !String.IsEmpty(Window.Property(is.poster)) + + 0 + 0 + 519 + 769 + $INFO[Window.Property(thumb.fallback)] + scale + + + 0 + 0 + 519 + 769 + $INFO[Window.Property(thumb)] + scale + + + + !String.IsEmpty(Window.Property(is.square)) + + 0 + 0 + 519 + 519 + $INFO[Window.Property(thumb.fallback)] + keep + + + 0 + 0 + 519 + 519 + $INFO[Window.Property(thumb)] + scale + + + + !String.IsEmpty(Window.Property(is.16x9)) + + 0 + 0 + 519 + 292 + $INFO[Window.Property(thumb.fallback)] + scale + + + 0 + 0 + 519 + 292 + $INFO[Window.Property(thumb)] + scale + + + + 579 + 5 + 1190 + 40 + font13 + left + center + FFFFFFFF + + + + 579 + 55 + 1190 + 40 + font13 + left + center + FFDDDDDD + + + + 579 + 157 + 152 + 1190 + 718 + font13 + left + FFDDDDDD + + + + + 1794 + 157 + 6 + 718 + true + script.plex/white-square.png + script.plex/white-square.png + script.plex/white-square.png + - + - + false + vertical + false + 204 + + + + + + 201 + 0 + 0 + 1920 + 135 + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 152 + 152 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9-chunked.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9-chunked.xml new file mode 100644 index 0000000000..b209ee4612 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9-chunked.xml @@ -0,0 +1,879 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + 0 + 135 + 101 + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 750 + 0 + 1170 + 1080 + + 0 + 0 + 1170 + 1080 + script.plex/white-square.png + 20000000 + + + + 0 + 0 + 1170 + 945 + 600 + 151 + 304 + 0 + vertical + 4 + 152 + 5 + + + + 120 + 24 + + + !String.IsEmpty(ListItem.Property(unwatched)) + 880 + -3 + 35 + 35 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 861 + 14 + + 0 + 0 + 54 + 42 + script.plex/white-square-rounded.png + + + 0 + 0 + 54 + 42 + font10 + center + center + FF000000 + + + + + 0 + 0 + + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + + + String.IsEmpty(ListItem.Property(is.footer)) + !String.IsEmpty(ListItem.Label) + 0 + 72 + 915 + 2 + script.plex/white-square.png + 40000000 + + + + + + + + + !Control.HasFocus(101) + 120 + 24 + + + !String.IsEmpty(ListItem.Property(unwatched)) + 880 + -2 + 35 + 35 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 861 + 14 + + 0 + 0 + 54 + 42 + script.plex/white-square-rounded.png + + + 0 + 0 + 54 + 42 + font10 + center + center + FF000000 + + + + + 0 + 0 + + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + + + String.IsEmpty(ListItem.Property(is.footer)) + !String.IsEmpty(ListItem.Label) + 0 + 72 + 915 + 2 + script.plex/white-square.png + 40000000 + + + + + Control.HasFocus(101) + 63 + 21 + + -40 + -40 + 1085 + 156 + script.plex/square-rounded-shadow.png + + + 0 + 0 + 1005 + 76 + script.plex/white-square-rounded.png + FFE5A00D + + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 957 + 0 + 48 + 48 + script.plex/indicators/unwatched-rounded.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 933 + 15 + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 0 + 0 + 57 + 46 + script.plex/white-square-rounded.png + + + 0 + 0 + 57 + 46 + font10 + center + center + FF000000 + + + + + 60 + 0 + + 0 + 23 + 915 + 30 + font12 + left + center + DF000000 + + + + + + + + + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),episode) + + 1128 + 33 + 10 + 879 + 101 + 951 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + String.IsEqual(Window(10000).Property(script.plex.item.type),episode) + 1128 + 33 + 10 + 879 + + 0 + 0 + 10 + 879 + script.plex/white-square-rounded.png + + + 0 + 0 + + !Control.HasFocus(951) + String.IsEmpty(Window.Property(dragging)) + 0 + 0 + 10 + 10 + script.plex/white-square-rounded.png + + + Control.HasFocus(951) | !String.IsEmpty(Window.Property(dragging)) + 0 + 0 + 10 + 10 + script.plex/white-square-rounded.png + + + + + 0 + 0 + 10 + 879 + 152 + - + - + + + + + + + 0 + -135 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + VisibleChange + 301 + 30 + -25 + 1000 + 145 + 200 + 101 + 101 + -20 + horizontal + 200 + true + !String.IsEmpty(Window.Property(initialized)) + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + String.IsEmpty(Window.Property(no.options)) | Player.HasAudio + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/chapters-focus.png + script.plex/buttons/chapters.png + + + + + + + 60 + 248 + + !String.IsEqual(Window.Property(media),show) + !String.IsEqual(Window.Property(media),movie) + 0 + 0 + 630 + 355 + 500 + $INFO[Container(101).ListItem.Property(art)] + scale + + + String.IsEqual(Window.Property(media),show) | String.IsEqual(Window.Property(media),movie) + 0 + 0 + 630 + 355 + 500 + $INFO[Container(101).ListItem.Property(art)] + scale + + + 0 + 355 + 440 + 80 + font12 + left + center + FFFFFFFF + + + + 630 + 355 + 180 + 80 + font12 + right + center + FFFFFFFF + + + + 0 + 435 + 630 + 2 + script.plex/white-square.png + 40000000 + + + 0 + 463 + 630 + 307 + font12 + left + FFDDDDDD + + + + + + String.IsEqual(Window(10000).Property(script.plex.sort),titleSort) + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 151 + 1830 + 150 + 20 + 920 + + 0 + 0 + 34 + 1050 + 100 + 152 + 200 + vertical + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + Control.HasFocus(151) + 0 + 0 + + Control.HasFocus(151) + 0 + 0 + 34 + 34 + FFE5A00D + script.plex/white-outline-rounded.png + + + + + + + + + 201 + 0 + 0 + 1920 + 135 + !String.IsEmpty(Window.Property(initialized)) + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font12 + left + center + FFFFFFFF + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 211 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 311 + String.IsEmpty(Window.Property(hide.filteroptions)) + 340 + 35 + 1000 + 65 + right + 30 + horizontal + 204 + 210 + 50 + + !String.IsEqual(Window.Property(media.itemType),folder) + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 0 + 0 + + + + !String.IsEqual(Window.Property(media.itemType),folder) + auto + 65 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + !String.IsEqual(Window.Property(media),show) + !String.IsEqual(Window.Property(media),movie) + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 20 + 0 + + + + String.IsEqual(Window.Property(media),show) | String.IsEqual(Window.Property(media),movie) + auto + 65 + font12 + FFFFFFFF + FF000000 + FFFFFFFF + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + !String.IsEqual(Window.Property(media.itemType),folder) + auto + 65 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9.xml new file mode 100644 index 0000000000..efd185bf17 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9.xml @@ -0,0 +1,842 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + 60 + 248 + + !String.IsEqual(Window.Property(media),show) + !String.IsEqual(Window.Property(media),movie) + 0 + 0 + 630 + 355 + 500 + $INFO[Container(101).ListItem.Property(art)] + scale + + + String.IsEqual(Window.Property(media),show) | String.IsEqual(Window.Property(media),movie) + 0 + 0 + 630 + 355 + 500 + $INFO[Container(101).ListItem.Property(art)] + scale + + + 0 + 355 + 440 + 80 + font12 + left + center + FFFFFFFF + + + + 630 + 355 + 180 + 80 + font12 + right + center + FFFFFFFF + + + + 0 + 435 + 630 + 2 + script.plex/white-square.png + 40000000 + + + 0 + 463 + 630 + 307 + font12 + left + FFDDDDDD + + + + + + 0 + 135 + 101 + + + VisibleChange + 301 + 30 + -25 + 1000 + 145 + 200 + 101 + 101 + -20 + horizontal + 200 + true + !String.IsEmpty(Window.Property(initialized)) + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + String.IsEmpty(Window.Property(no.options)) | Player.HasAudio + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/chapters-focus.png + script.plex/buttons/chapters.png + + + + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 750 + 0 + 1170 + 1080 + + 0 + 0 + 1170 + 1080 + script.plex/white-square.png + 20000000 + + + + 0 + 0 + 1170 + 945 + 600 + 151 + 304 + 200 + vertical + 4 + 152 + + + + 120 + 24 + + + !String.IsEmpty(ListItem.Property(unwatched)) + 880 + -3 + 35 + 35 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 861 + 14 + + 0 + 0 + 54 + 42 + script.plex/white-square-rounded.png + + + 0 + 0 + 54 + 42 + font10 + center + center + FF000000 + + + + + 0 + 0 + + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 72 + 915 + 2 + script.plex/white-square.png + 40000000 + + + + + + + + + !Control.HasFocus(101) + 120 + 24 + + + !String.IsEmpty(ListItem.Property(unwatched)) + 880 + -2 + 35 + 35 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 861 + 14 + + 0 + 0 + 54 + 42 + script.plex/white-square-rounded.png + + + 0 + 0 + 54 + 42 + font10 + center + center + FF000000 + + + + + 0 + 0 + + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 72 + 915 + 2 + script.plex/white-square.png + 40000000 + + + + + Control.HasFocus(101) + 63 + 21 + + -40 + -40 + 1085 + 156 + script.plex/square-rounded-shadow.png + + + 0 + 0 + 1005 + 76 + script.plex/white-square-rounded.png + FFE5A00D + + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 957 + 0 + 48 + 48 + script.plex/indicators/unwatched-rounded.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 933 + 15 + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 0 + 0 + 57 + 46 + script.plex/white-square-rounded.png + + + 0 + 0 + 57 + 46 + font10 + center + center + FF000000 + + + + + 60 + 0 + + 0 + 0 + 510 + 72 + font12 + left + center + DF000000 + + + + + + + + + + + + 1128 + 33 + 10 + 879 + 101 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + + + + String.IsEqual(Window(10000).Property(script.plex.sort),titleSort) + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 151 + 1830 + 150 + 20 + 920 + + 0 + 0 + 34 + 1050 + 100 + 152 + 200 + vertical + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + Control.HasFocus(151) + 0 + 0 + + Control.HasFocus(151) + 0 + 0 + 34 + 34 + FFE5A00D + script.plex/white-outline-rounded.png + + + + + + + + + 201 + 0 + 0 + 1920 + 135 + !String.IsEmpty(Window.Property(initialized)) + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font12 + left + center + FFFFFFFF + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 211 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 311 + String.IsEmpty(Window.Property(hide.filteroptions)) + 340 + 35 + 1000 + 65 + right + 30 + horizontal + 204 + 210 + 50 + + !String.IsEqual(Window.Property(media.itemType),folder) + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 0 + 0 + + + + !String.IsEqual(Window.Property(media.itemType),folder) + auto + 65 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + !String.IsEqual(Window.Property(media),show) + !String.IsEqual(Window.Property(media),movie) + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 20 + 0 + + + + String.IsEqual(Window.Property(media),show) | String.IsEqual(Window.Property(media),movie) + auto + 65 + font12 + FFFFFFFF + FF000000 + FFFFFFFF + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + !String.IsEqual(Window.Property(media.itemType),folder) + auto + 65 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-listview-square-chunked.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-square-chunked.xml new file mode 100644 index 0000000000..b3aab30787 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-square-chunked.xml @@ -0,0 +1,943 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + 0 + 135 + 101 + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 750 + 0 + 1170 + 1080 + + 0 + 0 + 1170 + 1080 + script.plex/white-square.png + 20000000 + + + + 0 + 0 + 1170 + 945 + 600 + 151 + 304 + 0 + vertical + 4 + 152 + 5 + + + + 120 + 24 + + + !String.IsEmpty(ListItem.Property(unwatched)) + 880 + -3 + 35 + 35 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 861 + 14 + + 0 + 0 + 54 + 42 + script.plex/white-square-rounded.png + + + 0 + 0 + 54 + 42 + font10 + center + center + FF000000 + + + + + 0 + 0 + + String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + + + String.IsEmpty(ListItem.Property(is.footer)) + !String.IsEmpty(ListItem.Label) + 0 + 72 + 915 + 2 + script.plex/white-square.png + 40000000 + + + + + + + + + !Control.HasFocus(101) + 120 + 24 + + + !String.IsEmpty(ListItem.Property(unwatched)) + 880 + -2 + 35 + 35 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 861 + 14 + + 0 + 0 + 54 + 42 + script.plex/white-square-rounded.png + + + 0 + 0 + 54 + 42 + font10 + center + center + FF000000 + + + + + 0 + 0 + + 0 + 0 + + String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + + + + String.IsEmpty(ListItem.Property(is.footer)) + !String.IsEmpty(ListItem.Label) + 0 + 72 + 915 + 2 + script.plex/white-square.png + 40000000 + + + + + Control.HasFocus(101) + 63 + 21 + + -40 + -40 + 1085 + 156 + script.plex/square-rounded-shadow.png + + + 0 + 0 + 1005 + 76 + script.plex/white-square-rounded.png + FFE5A00D + + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 957 + 0 + 48 + 48 + script.plex/indicators/unwatched-rounded.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 933 + 15 + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 0 + 0 + 57 + 46 + script.plex/white-square-rounded.png + + + 0 + 0 + 57 + 46 + font10 + center + center + FF000000 + + + + + 60 + 0 + + String.IsEmpty(ListItem.Property(is.folder)) + 0 + 23 + 885 + 30 + font12 + left + center + DF000000 + + + + !String.IsEmpty(ListItem.Property(is.folder)) + 0 + 23 + 885 + 30 + font10 + left + center + FF000000 + + + + + + + + + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),album) + + 1128 + 33 + 10 + 879 + 101 + 951 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + String.IsEqual(Window(10000).Property(script.plex.item.type),album) + 1128 + 33 + 10 + 879 + + 0 + 0 + 10 + 879 + script.plex/white-square-rounded.png + + + 0 + 0 + + !Control.HasFocus(951) + String.IsEmpty(Window.Property(dragging)) + 0 + 0 + 10 + 10 + script.plex/white-square-rounded.png + + + Control.HasFocus(951) | !String.IsEmpty(Window.Property(dragging)) + 0 + 0 + 10 + 10 + script.plex/white-square-rounded.png + + + + + 0 + 0 + 10 + 879 + 152 + - + - + + + + + + + 0 + -135 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + 301 + 30 + -25 + 1000 + 145 + 200 + 101 + 101 + -20 + horizontal + 200 + true + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + String.IsEmpty(Window.Property(no.options)) | Player.HasAudio + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + String.IsEmpty(Window.Property(hide.filteroptions)) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/chapters-focus.png + script.plex/buttons/chapters.png + + + + + + + 60 + 248 + + String.IsEqual(Window.Property(media),photo) | String.IsEqual(Window.Property(media),photodirectory) + + 0 + 0 + 630 + 355 + script.plex/white-square.png + + + 0 + 0 + 630 + 355 + 500 + $INFO[Container(101).ListItem.Thumb] + keep + + + + String.IsEqual(Window.Property(media),artist) + 0 + 0 + 355 + 355 + 500 + $INFO[Container(101).ListItem.Thumb] + scale + + + !String.IsEmpty(Container(101).ListItem.Label2) + + 0 + 355 + 510 + 80 + font12 + left + center + FFFFFFFF + + + + 630 + 355 + 110 + 80 + font12 + right + center + FFFFFFFF + + + + + String.IsEmpty(Container(101).ListItem.Label2) + + 0 + 355 + 630 + 80 + font12 + left + center + FFFFFFFF + + + + + 0 + 435 + 630 + 2 + script.plex/white-square.png + 40000000 + + + 0 + 463 + 630 + 307 + font12 + left + FFDDDDDD + + + + + + String.IsEqual(Window(10000).Property(script.plex.sort),titleSort) + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 151 + 1830 + 150 + 20 + 920 + + 0 + 0 + 34 + 1050 + 100 + 152 + 200 + vertical + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + Control.HasFocus(151) + 0 + 0 + + Control.HasFocus(151) + 0 + 0 + 34 + 34 + FFE5A00D + script.plex/white-outline-rounded.png + + + + + + + + + 201 + 0 + 0 + 1920 + 135 + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font12 + left + center + FFFFFFFF + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 211 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 311 + String.IsEmpty(Window.Property(hide.filteroptions)) + 340 + 35 + 1000 + 65 + right + 30 + horizontal + 204 + 210 + 50 + + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 0 + 0 + + + + auto + 65 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + !String.IsEqual(Window.Property(media),artist) + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 20 + 0 + + + + String.IsEqual(Window.Property(media),artist) + auto + 65 + font12 + FFFFFFFF + FF000000 + FFFFFFFF + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + auto + 65 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-listview-square.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-square.xml new file mode 100644 index 0000000000..0b80694eef --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-square.xml @@ -0,0 +1,908 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + 60 + 248 + + String.IsEqual(Window.Property(media),photo) | String.IsEqual(Window.Property(media),photodirectory) + + 0 + 0 + 630 + 355 + script.plex/white-square.png + + + 0 + 0 + 630 + 355 + 500 + $INFO[Container(101).ListItem.Thumb] + keep + + + + String.IsEqual(Window.Property(media),artist) + 0 + 0 + 355 + 355 + 500 + $INFO[Container(101).ListItem.Thumb] + scale + + + !String.IsEmpty(Container(101).ListItem.Label2) + + 0 + 355 + 310 + 80 + font12 + left + center + FFFFFFFF + + + + 630 + 355 + 310 + 80 + font12 + right + center + FFFFFFFF + + + + + String.IsEmpty(Container(101).ListItem.Label2) + + 0 + 355 + 630 + 80 + font12 + left + center + FFFFFFFF + + + + + 0 + 435 + 630 + 2 + script.plex/white-square.png + 40000000 + + + 0 + 463 + 630 + 307 + font12 + left + FFDDDDDD + + + + + + 0 + 135 + 101 + + + 301 + 30 + -25 + 1000 + 145 + 200 + 101 + 101 + -20 + horizontal + 200 + true + !String.IsEmpty(Window.Property(initialized)) + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + String.IsEmpty(Window.Property(no.options)) | Player.HasAudio + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + String.IsEmpty(Window.Property(hide.filteroptions)) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/chapters-focus.png + script.plex/buttons/chapters.png + + + + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 750 + 0 + 1170 + 1080 + + 0 + 0 + 1170 + 1080 + script.plex/white-square.png + 20000000 + + + + 0 + 0 + 1170 + 945 + 600 + 151 + 304 + 200 + vertical + 4 + 152 + + + + 120 + 24 + + + !String.IsEmpty(ListItem.Property(unwatched)) + 880 + -3 + 35 + 35 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 861 + 14 + + 0 + 0 + 54 + 42 + script.plex/white-square-rounded.png + + + 0 + 0 + 54 + 42 + font10 + center + center + FF000000 + + + + + 0 + 0 + + String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 72 + 915 + 2 + script.plex/white-square.png + 40000000 + + + + + + + + + !Control.HasFocus(101) + 120 + 24 + + + !String.IsEmpty(ListItem.Property(unwatched)) + 880 + -2 + 35 + 35 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 861 + 14 + + 0 + 0 + 54 + 42 + script.plex/white-square-rounded.png + + + 0 + 0 + 54 + 42 + font10 + center + center + FF000000 + + + + + 0 + 0 + + 0 + 0 + + String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 915 + 72 + font10 + left + center + FFFFFFFF + + + + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 72 + 915 + 2 + script.plex/white-square.png + 40000000 + + + + + Control.HasFocus(101) + 63 + 21 + + -40 + -40 + 1085 + 156 + script.plex/square-rounded-shadow.png + + + 0 + 0 + 1005 + 76 + script.plex/white-square-rounded.png + FFE5A00D + + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 957 + 0 + 48 + 48 + script.plex/indicators/unwatched-rounded.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 933 + 15 + + !String.IsEmpty(ListItem.Property(unwatched.count)) + 0 + 0 + 57 + 46 + script.plex/white-square-rounded.png + + + 0 + 0 + 57 + 46 + font10 + center + center + FF000000 + + + + + 60 + 0 + + String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 885 + 72 + font12 + left + center + DF000000 + + + + !String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 885 + 72 + font10 + left + center + FF000000 + + + + + + + + + + + + 1128 + 33 + 10 + 879 + 101 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + + + + String.IsEqual(Window(10000).Property(script.plex.sort),titleSort) + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 151 + 1830 + 150 + 20 + 920 + + 0 + 0 + 34 + 1050 + 100 + 152 + 200 + vertical + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + Control.HasFocus(151) + 0 + 0 + + Control.HasFocus(151) + 0 + 0 + 34 + 34 + FFE5A00D + script.plex/white-outline-rounded.png + + + + + + + + + 201 + 0 + 0 + 1920 + 135 + !String.IsEmpty(Window.Property(initialized)) + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font12 + left + center + FFFFFFFF + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 211 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 311 + String.IsEmpty(Window.Property(hide.filteroptions)) + 340 + 35 + 1000 + 65 + right + 30 + horizontal + 204 + 210 + 50 + + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 0 + 0 + + + + auto + 65 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + !String.IsEqual(Window.Property(media),artist) + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 20 + 0 + + + + String.IsEqual(Window.Property(media),artist) + auto + 65 + font12 + FFFFFFFF + FF000000 + FFFFFFFF + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + auto + 65 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-music_current_playlist.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-music_current_playlist.xml new file mode 100644 index 0000000000..28881da16a --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-music_current_playlist.xml @@ -0,0 +1,790 @@ + + + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + + String.IsEmpty(Window.Property(use_solid_background)) + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + false + + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Player.Art(fanart)] + + + !String.IsEmpty(Player.Art(fanart)) + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + D0404040 + + + + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Player.Art(landscape)] + + + + + 0 + 0 + 101 + + + 90 + 0 + + -15 + 75 + 669 + 669 + script.plex/white-square.png + 20FFFFFF + + + 0 + 90 + 639 + 639 + $INFO[Player.Art(thumb)] + scale + + + 0 + 764 + 639 + 35 + font12 + left + center + FFFFFFFF + + + + 0 + 799 + 639 + 35 + font12 + left + center + FFFFFFFF + + + + 0 + 834 + 639 + 35 + font12 + left + center + FFFFFFFF + + + + 0 + 869 + 639 + 35 + font12 + left + center + FFFFFFFF + + + + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 819 + 0 + 1101 + 1080 + + 0 + 0 + 1101 + 1080 + script.plex/white-square.png + 20000000 + + + 0 + 0 + 1101 + 1080 + 200 + 152 + 411 + 200 + vertical + 4 + 152 + + + + 120 + 24 + + !String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + -10 + 0 + 60 + 100 + font10 + center + center + D8FFFFFF + + + + String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 2 + 32.5 + 35 + 35 + script.plex/indicators/playing-circle.png + FFE5A00D + + + 63 + 11 + 74 + 74 + $INFO[ListItem.Thumb] + scale + + + 168 + 0 + + 0 + 15 + 723 + 30 + font10 + left + center + FFFFFFFF + + + + 0 + 50 + 723 + 30 + font10 + left + center + B8FFFFFF + + + + + 661 + 0 + 200 + 100 + font10 + right + center + D8FFFFFF + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 97 + 861 + 2 + script.plex/white-square.png + 40000000 + + + + + + + + + !Control.HasFocus(101) + 120 + 24 + + !String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + -10 + 0 + 60 + 100 + font10 + center + center + D8FFFFFF + + + + String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 0 + 32.5 + 35 + 35 + script.plex/indicators/playing-circle.png + FFE5A00D + + + 63 + 11 + 74 + 74 + $INFO[ListItem.Thumb] + scale + + + 168 + 0 + + 0 + 15 + 723 + 30 + font10 + left + center + FFFFFFFF + + + + 0 + 50 + 723 + 30 + font10 + left + center + B8FFFFFF + + + + + 669 + 0 + 200 + 100 + font10 + right + center + D8FFFFFF + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 97 + 861 + 2 + script.plex/white-square.png + 40000000 + + + + + Control.HasFocus(101) + 63 + 21 + + -40 + -40 + 1055 + 180 + script.plex/square-rounded-shadow.png + + + 0 + 0 + 975 + 100 + script.plex/white-square-rounded.png + FFE5A00D + + + !String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 24 + 0 + 60 + 100 + font12 + center + center + B8000000 + + + + String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 36 + 32.5 + 35 + 35 + script.plex/indicators/playing-circle.png + FF000000 + + + 103 + 0 + 100 + 100 + $INFO[ListItem.Thumb] + scale + + + 235 + 0 + + 0 + 16 + 669 + 30 + font12 + left + center + DF000000 + + + + 0 + 51 + 669 + 30 + font10 + left + center + 98000000 + + + + + 735 + 0 + 200 + 100 + font12 + right + center + B8000000 + + + + + + + + + + + 1059 + 33 + 10 + 1014 + 101 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + + + + 406 + + 0 + 964 + 819 + + 124 + center + 500 + 100 + -40 + horizontal + 200 + false + + Conditional + Conditional + 125 + 101 + + + 0 + 0 + 125 + 101 + 100 + 402 + 411 + font12 + - + - + + + + !Control.HasFocus(401) + + !Playlist.IsRepeatOne + !Playlist.IsRepeat + String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat.png + + + Playlist.IsRepeat | !String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat.png + + + Playlist.IsRepeatOne + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-one.png + + + + Control.HasFocus(401) + + !Playlist.IsRepeatOne + !Playlist.IsRepeat + String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-focus.png + + + Playlist.IsRepeat | !String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-focus.png + + + Playlist.IsRepeatOne + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-one-focus.png + + + + + + String.IsEmpty(Window.Property(pq.isremote)) + Focus + UnFocus + + 125 + 101 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + Playlist.IsRandom + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + PlayerControl(RandomOn) + PlayerControl(RandomOff) + + + + + !String.IsEmpty(Window.Property(pq.isremote)) + Conditional + Conditional + 125 + 101 + + + 0 + 0 + 125 + 101 + 100 + 404 + 401 + font12 + - + - + + + + String.IsEmpty(Window.Property(pq.shuffled)) + + !Control.HasFocus(422) + 0 + 0 + 125 + 101 + script.plex/buttons/shuffle.png + + + Control.HasFocus(422) + 0 + 0 + 125 + 101 + script.plex/buttons/shuffle-focus.png + + + + !String.IsEmpty(Window.Property(pq.shuffled)) + + !Control.HasFocus(422) + 0 + 0 + 125 + 101 + script.plex/buttons/shuffle.png + + + Control.HasFocus(422) + 0 + 0 + 125 + 101 + script.plex/buttons/shuffle-focus.png + + + + + + MusicPlayer.HasPrevious | !String.IsEmpty(Window.Property(pq.hasprevious)) + Focus + UnFocus + + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + Focus + UnFocus + + 125 + 101 + font12 + script.plex/buttons/pause-focus.png + script.plex/buttons/pause.png + Player.Paused | Player.Forwarding | Player.Rewinding + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + PlayerControl(Play) + + + + Focus + UnFocus + + 125 + 101 + font12 + script.plex/buttons/stop-focus.png + script.plex/buttons/stop.png + PlayerControl(Stop) + + + + MusicPlayer.HasNext | !String.IsEmpty(Window.Property(pq.hasnext)) + Focus + UnFocus + + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + + Focus + UnFocus + + 125 + 101 + font12 + script.plex/buttons/pqueue-focus.png + script.plex/buttons/pqueue.png + + Close + + + Focus + UnFocus + + 125 + 101 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + + 0 + 940 + + Player.HasAudio + + 0 + 0 + 819 + 10 + 100 + 400 + script.plex/white-square.png + script.plex/white-square.png + A0000000 + + + Control.HasFocus(500) + Visible + 0 + 1 + 1 + 8 + script.plex/white-square.png + FFE5A00D + + + !Control.HasFocus(500) + Progressbar + 0 + 2 + 819 + 6 + script.plex/transparent-6px.png + - + script.plex/white-square-6px.png + - + - + Player.Progress + + + Control.HasFocus(500) + Progressbar + 0 + 2 + 819 + 6 + script.plex/transparent-6px.png + - + script.plex/white-square-6px.png + - + - + Player.Progress + + + + + + + + + Control.HasFocus(500) + 0 + 896 + + -50 + 0 + + Visible + 0 + 0 + 101 + 39 + script.plex/indicators/player-selection-time_box.png + D0000000 + + + 0 + 0 + 101 + 40 + font10 + center + center + FFFFFFFF + + + + + Visible + -6 + 39 + 15 + 7 + script.plex/indicators/player-selection-time_arrow.png + D0000000 + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-music_player.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-music_player.xml new file mode 100644 index 0000000000..18926cfc26 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-music_player.xml @@ -0,0 +1,578 @@ + + + + 1 + 0 + 0 + + 406 + + + + String.IsEmpty(Window.Property(use_solid_background)) + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + false + + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Player.Art(fanart)] + + + !String.IsEmpty(Player.Art(fanart)) + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + D0404040 + + + + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Player.Art(landscape)] + + + + + 75 + 75 + 786 + 786 + script.plex/white-square.png + 20FFFFFF + + + 90 + 90 + 756 + 756 + $INFO[Player.Art(thumb)] + + + + 939 + 0 + + 0 + 305 + 1000 + 54 + font13 + left + center + FFFFFFFF + + + + 0 + 359 + 1000 + 54 + font13 + left + center + FFFFFFFF + + + + 0 + 470 + 1000 + 54 + font13 + left + center + FFFFFFFF + + + + 0 + 580 + 1000 + 54 + font13 + left + center + FFFFFFFF + + + + + + 1845 + 0 + + 0 + 738 + 1000 + 54 + font13 + right + center + 80FFFFFF + + + + 0 + 794 + 1000 + 54 + font13 + right + center + 80FFFFFF + + + + + + + + 406 + + 360 + 964 + 1200 + + 124 + center + 100 + -40 + horizontal + 200 + true + + Conditional + Conditional + 125 + 101 + + + 0 + 0 + 125 + 101 + 100 + 402 + 411 + font12 + - + - + + + + !Control.HasFocus(401) + + !Playlist.IsRepeatOne + !Playlist.IsRepeat + String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat.png + + + Playlist.IsRepeat | !String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat.png + + + Playlist.IsRepeatOne + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-one.png + + + + Control.HasFocus(401) + + !Playlist.IsRepeatOne + !Playlist.IsRepeat + String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-focus.png + + + Playlist.IsRepeat | !String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-focus.png + + + Playlist.IsRepeatOne + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-one-focus.png + + + + + + String.IsEmpty(Window.Property(pq.isremote)) + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + Playlist.IsRandom + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + PlayerControl(RandomOn) + PlayerControl(RandomOff) + + + + + !String.IsEmpty(Window.Property(pq.isremote)) + Conditional + Conditional + 125 + 101 + + + 0 + 0 + 125 + 101 + 100 + 404 + 401 + font12 + - + - + + + + String.IsEmpty(Window.Property(pq.shuffled)) + + !Control.HasFocus(422) + 0 + 0 + 125 + 101 + script.plex/buttons/shuffle.png + + + Control.HasFocus(422) + 0 + 0 + 125 + 101 + script.plex/buttons/shuffle-focus.png + + + + !String.IsEmpty(Window.Property(pq.shuffled)) + + !Control.HasFocus(422) + 0 + 0 + 125 + 101 + script.plex/buttons/shuffle.png + + + Control.HasFocus(422) + 0 + 0 + 125 + 101 + script.plex/buttons/shuffle-focus.png + + + + + + MusicPlayer.HasPrevious | !String.IsEmpty(Window.Property(pq.hasprevious)) + Focus + UnFocus + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/pause-focus.png + script.plex/buttons/pause.png + Player.Paused | Player.Forwarding | Player.Rewinding + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + PlayerControl(Play) + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/stop-focus.png + script.plex/buttons/stop.png + PlayerControl(Stop) + + + + MusicPlayer.HasNext | !String.IsEmpty(Window.Property(pq.hasnext)) + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + + + Focus + UnFocus + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/pqueue-focus.png + script.plex/buttons/pqueue.png + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + + 0 + 940 + + Player.HasAudio + + 0 + 0 + 1920 + 10 + 400 + script.plex/white-square.png + script.plex/white-square.png + A0000000 + + + Control.HasFocus(100) + Visible + 0 + 1 + 1 + 8 + script.plex/white-square.png + FFE5A00D + + + !Control.HasFocus(100) + Progressbar + 0 + 2 + 1920 + 6 + script.plex/transparent-6px.png + - + script.plex/white-square-6px.png + - + - + Player.Progress + + + Control.HasFocus(100) + Progressbar + 0 + 2 + 1920 + 6 + script.plex/transparent-6px.png + - + script.plex/white-square-6px.png + - + - + Player.Progress + + + + + + + + + Control.HasFocus(100) + 0 + 896 + + -50 + 0 + + Visible + 0 + 0 + 101 + 39 + script.plex/indicators/player-selection-time_box.png + D0000000 + + + 0 + 0 + 101 + 40 + font10 + center + center + FFFFFFFF + + + + + Visible + -6 + 39 + 15 + 7 + script.plex/indicators/player-selection-time_arrow.png + D0000000 + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-options_dialog.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-options_dialog.xml new file mode 100644 index 0000000000..fb660d70ef --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-options_dialog.xml @@ -0,0 +1,136 @@ + + 1001 + + 1 + 0 + 0 + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + !String.IsEmpty(Window.Property(initialized)) + 585 + 360 + + -40 + -40 + 830 + 440 + script.plex/drop-shadow.png + + + 0 + 0 + 750 + 360 + script.plex/white-square-rounded.png + + + 0 + 0 + 750 + 80 + script.plex/white-square-top-rounded.png + + + + 48 + 31 + 19 + 19 + script.plex/indicators/circle-19.png + + + + 115 + 0 + 575 + 80 + font12 + left + center + FFE5A00D + + + + + 115 + 105 + 575 + 125 + font10 + left + FFFFFFFF + + + + + 1001 + -10 + 220 + 770 + 155 + right + -50 + horizontal + 0 + true + + !String.IsEmpty(Window.Property(button.0)) + Focus + UnFocus + 0 + 0 + auto + 143 + font10 + script.plex/buttons/blank-focus.png + script.plex/buttons/blank.png + 70 + FF000000 + FF000000 + + + + !String.IsEmpty(Window.Property(button.1)) + Focus + UnFocus + 0 + 0 + auto + 143 + font10 + script.plex/buttons/blank-focus.png + script.plex/buttons/blank.png + 70 + FF000000 + FF000000 + + + + !String.IsEmpty(Window.Property(button.2)) + Focus + UnFocus + 0 + 0 + auto + 143 + font10 + script.plex/buttons/blank-focus.png + script.plex/buttons/blank.png + 70 + FF000000 + FF000000 + + + + + + + \ No newline at end of file diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-photo.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-photo.xml new file mode 100644 index 0000000000..071430b70f --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-photo.xml @@ -0,0 +1,717 @@ + + + + 1 + 0 + 0 + + 250 + 100 + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + Conditional + Conditional + Conditional + Conditional + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(photo)] + keep + + + !String.IsEmpty(Window.Property(is.updating)) + VisibleChange + + 840 + 465 + 240 + 150 + script.plex/busy-back.png + A0FFFFFF + + + 915 + 521 + 90 + 38 + script.plex/busy.gif + + + + + 0 + 0 + 1920 + 1080 + - + - + !String.IsEmpty(Window.Property(OSD)) + - + - + + SetProperty(OSD,1) + SetFocus(400) + SetProperty(OSD,) + SetProperty(OSD,1) + SetFocus(400) + SetFocus(501) + SetFocus(400) + + + Conditional + 0 + 0 + + !String.IsEmpty(Window.Property(OSD)) + + 0 + 940 + 1920 + 140 + script.plex/white-square.png + A0000000 + + + 406 + + 360 + 964 + 1200 + + 124 + center + 250 + SetProperty(OSD,) + 250 + SetProperty(OSD,) + -40 + horizontal + 200 + true + + + String.IsEmpty(Window.Property(no.playlist)) + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/repeat-focus.png + script.plex/buttons/repeat.png + !String.IsEmpty(Window.Property(pq.repeat)) + script.plex/buttons/repeat-focus.png + script.plex/buttons/repeat.png + + + + false + !String.IsEmpty(Window.Property(no.playlist)) + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + String.IsEmpty(Window.Property(no.playlist)) + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + !String.IsEmpty(Window.Property(pq.shuffled)) + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + false + !String.IsEmpty(Window.Property(no.playlist)) + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/rotate-focus.png + script.plex/buttons/rotate.png + + + + + + String.IsEmpty(Window.Property(hide.prev)) + Focus + UnFocus + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + false + !String.IsEmpty(Window.Property(hide.prev)) + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + !String.IsEmpty(Window.Property(playing)) + script.plex/buttons/pause-focus.png + script.plex/buttons/pause.png + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/stop-focus.png + script.plex/buttons/stop.png + + + + String.IsEmpty(Window.Property(hide.next)) + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + false + !String.IsEmpty(Window.Property(hide.next)) + 0 + 0 + 125 + 101 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + + + Focus + UnFocus + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/square2x2-focus.png + script.plex/buttons/square2x2.png + !String.IsEmpty(Window.Property(show.pqueue)) + script.plex/buttons/square2x2-focus.png + script.plex/buttons/square2x2-focus.png + SetProperty(show.pqueue,1) + SetProperty(show.pqueue,) + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/info-focus.png + script.plex/buttons/info.png + !String.IsEmpty(Window.Property(show.info)) + script.plex/buttons/info-focus.png + script.plex/buttons/info-focus.png + SetProperty(show.info,1) + SetProperty(show.info,) + + + + false + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/tags-focus.png + script.plex/buttons/tags.png + + + + false + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + + + 0 + 1080 + 1920 + 135 + SetProperty(OSD,1) + 400 + font12 + - + - + + SetProperty(OSD,1) + SetFocus(400) + + + + 0 + 1080 + 1920 + 135 + script.plex/white-square.png + FF000000 + + + 0 + 1080 + 1920 + 135 + + + 0 + horizontal + 4 + 7 + + + + 0 + 0 + + 2.5 + 6 + + 0 + 0 + 123 + 123 + script.plex/thumb_fallbacks/photo.png + + + 0 + 0 + 123 + 123 + $INFO[ListItem.Thumb] + scale + + + + + + + + + 0 + 0 + + 2.5 + 6 + + 0 + 0 + 123 + 123 + script.plex/thumb_fallbacks/photo.png + + + 0 + 0 + 123 + 123 + $INFO[ListItem.Thumb] + scale + + + + + + + 892.5 + 1080 + 135 + 135 + script.plex/home/selected.png + + + + + + !String.IsEmpty(Window.Property(show.info)) + 1470 + 0 + 450 + 1080 + + 0 + 0 + 450 + 1080 + script.plex/white-square.png + 4C000000 + + + 0 + 0 + 450 + 1080 + 0 + vertical + + + + 450 + 21 + - + - + 00000000 + + + + 450 + 37 + script.plex/white-square.png + script.plex/white-square.png + 00000000 + left + center + 28 + font12 + + + + 450 + 37 + script.plex/white-square.png + script.plex/white-square.png + 00000000 + left + center + 28 + font12 + + + + + 450 + 21 + - + - + 00000000 + + + + + + 450 + 21 + script.plex/white-square.png + script.plex/white-square.png + 99000000 + + + + !String.IsEmpty(Window.Property(camera.model)) + 450 + 37 + + 0 + 0 + 450 + 37 + script.plex/white-square.png + script.plex/white-square.png + 99000000 + left + center + 28 + font12 + + + + 393 + 6 + 29 + 24 + script.plex/indicators/camera.png + A0FFFFFF + + + + !String.IsEmpty(Window.Property(camera.lens)) + 450 + 37 + script.plex/white-square.png + script.plex/white-square.png + 99000000 + left + center + 28 + font12 + + + + !String.IsEmpty(Window.Property(photo.container)) + 0 + 0 + 450 + 37 + + 0 + 0 + 450 + 37 + script.plex/white-square.png + script.plex/white-square.png + 99000000 + left + center + 28 + font12 + + + + 28 + 5 + 200 + 26 + 0 + horizontal + right + + auto + 26 + font10 + center + top + FF000000 + FF000000 + 5 + -3 + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + + + + + + + 450 + 21 + script.plex/white-square.png + script.plex/white-square.png + 99000000 + + + + !String.IsEmpty(Window.Property(camera.settings)) + 450 + 80 + + + 0 + 0 + 450 + 1 + script.plex/indicators/info-sep.png + 99000000 + + + 28 + 0 + 394 + 1 + script.plex/white-square.png + 999B9B9B + + + + 0 + 1 + 450 + 21 + script.plex/white-square.png + script.plex/white-square.png + 99000000 + + + + 0 + 22 + 450 + 37 + script.plex/white-square.png + script.plex/white-square.png + 99000000 + left + center + 28 + font12 + + + + + 0 + 59 + 450 + 21 + script.plex/white-square.png + script.plex/white-square.png + 99000000 + + + + + + !String.IsEmpty(Window.Property(photo.summary)) + 450 + 152 + + 0 + 0 + 450 + 152 + script.plex/white-square.png + 661F1F1F + + + 28 + 24 + 394 + 100 + font12 + left + center + + + + + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-pin_login.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-pin_login.xml new file mode 100644 index 0000000000..6dcac7f4ab --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-pin_login.xml @@ -0,0 +1,82 @@ + + + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + + !String.IsEmpty(Window.Property(pin.image.0)) + 0 + 0 + 1920 + 1080 + script.plex/sign_in/pin-display.jpg + + + String.IsEmpty(Window.Property(pin.image.0)) + String.IsEmpty(Window.Property(linking)) + 0 + 0 + 1920 + 1080 + script.plex/sign_in/generating-code.jpg + + + !String.IsEmpty(Window.Property(linking)) + 0 + 0 + 1920 + 1080 + script.plex/sign_in/linking-account.jpg + + + + 270 + 738 + 800 + 153 + WeatherTemp + left + center + FFFFFFFF + + + + + 406 + 265 + 708 + 1000 + + 200 + left + 0 + horizontal + + 200 + 200 + $INFO[Window.Property(pin.image.0)] + + + 200 + 200 + $INFO[Window.Property(pin.image.1)] + + + 200 + 200 + $INFO[Window.Property(pin.image.2)] + + + 200 + 200 + $INFO[Window.Property(pin.image.3)] + + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-playlist.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-playlist.xml new file mode 100644 index 0000000000..3e00fca9cb --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-playlist.xml @@ -0,0 +1,883 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + 0 + 135 + 101 + + + 60 + 0 + + 0 + 5 + 420 + 40 + font13 + left + center + FFFFFFFF + + + + 0 + 60 + 420 + 40 + font13 + left + center + FFFFFFFF + + + + 0 + 142 + 630 + 630 + $INFO[Window.Property(playlist.thumb)] + scale + + + + + VisibleChange + 303 + 50 + 784 + 650 + 145 + 200 + 101 + -50 + horizontal + center + 200 + true + + Focus + UnFocus + + 0 + 0 + 174 + 139 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + Focus + UnFocus + + 0 + 0 + 174 + 139 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + !String.IsEmpty(Window.Property(show.options)) | Player.HasAudio + Focus + UnFocus + + 0 + 0 + 174 + 139 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 750 + 0 + 1170 + 1080 + + 0 + 0 + 1170 + 1080 + script.plex/white-square.png + 20000000 + + + 0 + 0 + 1170 + 945 + 200 + 152 + 300 + 200 + vertical + 4 + 152 + + + + 120 + 24 + + String.IsEmpty(ListItem.Property(track.ID)) | !String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + -10 + 0 + 60 + 100 + font10 + center + center + D8FFFFFF + + + + !String.IsEmpty(ListItem.Property(track.ID)) + String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 2 + 32.5 + 35 + 35 + script.plex/indicators/playing-circle.png + FFE5A00D + + + String.IsEmpty(ListItem.Property(video)) + + 63 + 11 + 74 + 74 + $INFO[ListItem.Thumb] + scale + + + 168 + 0 + + 0 + 15 + 692 + 30 + font10 + left + center + FFFFFFFF + + + + 0 + 50 + 692 + 30 + font10 + left + center + B8FFFFFF + + + + + + !String.IsEmpty(ListItem.Property(video)) + + 63 + 11 + 132 + 74 + $INFO[ListItem.Thumb] + scale + + + String.IsEmpty(ListItem.Property(watched)) + 895 + -1 + 35 + 35 + script.plex/indicators/unwatched.png + + + 226 + 0 + + 0 + 15 + 584 + 30 + font10 + left + center + FFFFFFFF + + + + 0 + 50 + 584 + 30 + font10 + left + center + B8FFFFFF + + + + + + 730 + 0 + 200 + 100 + font10 + right + center + D8FFFFFF + + + + + False + 63 + 85 + + 0 + 0 + 870 + 8 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 870 + 6 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 97 + 930 + 2 + script.plex/white-square.png + 40000000 + + + + + + + + + !Control.HasFocus(101) + 120 + 24 + + String.IsEmpty(ListItem.Property(track.ID)) | !String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + -10 + 0 + 60 + 100 + font10 + center + center + D8FFFFFF + + + + !String.IsEmpty(ListItem.Property(track.ID)) + String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 0 + 32.5 + 35 + 35 + script.plex/indicators/playing-circle.png + FFE5A00D + + + String.IsEmpty(ListItem.Property(video)) + + 63 + 11 + 74 + 74 + $INFO[ListItem.Thumb] + scale + + + 168 + 0 + + 0 + 15 + 692 + 30 + font10 + left + center + FFFFFFFF + + + + 0 + 50 + 692 + 30 + font10 + left + center + B8FFFFFF + + + + + + !String.IsEmpty(ListItem.Property(video)) + + 63 + 11 + 132 + 74 + $INFO[ListItem.Thumb] + scale + + + String.IsEmpty(ListItem.Property(watched)) + 895 + -1 + 35 + 35 + script.plex/indicators/unwatched.png + + + 226 + 0 + + 0 + 15 + 584 + 30 + font10 + left + center + FFFFFFFF + + + + 0 + 50 + 584 + 30 + font10 + left + center + B8FFFFFF + + + + + + 730 + 0 + 200 + 100 + font10 + right + center + D8FFFFFF + + + + !String.IsEmpty(ListItem.Property(progress)) + 63 + 88 + + 0 + 0 + 870 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 870 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 97 + 930 + 2 + script.plex/white-square.png + 40000000 + + + + + Control.HasFocus(101) + 63 + 21 + + -40 + -40 + 1124 + 180 + script.plex/square-rounded-shadow.png + + + 0 + 0 + 1044 + 100 + script.plex/white-square-rounded.png + FFE5A00D + + + + + String.IsEmpty(ListItem.Property(track.ID)) | !String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 24 + 0 + 60 + 100 + font12 + center + center + B8000000 + + + + !String.IsEmpty(ListItem.Property(track.ID)) + String.IsEqual(ListItem.Property(track.ID),Window(10000).Property(script.plex.track.ID)) + 36 + 32.5 + 35 + 35 + script.plex/indicators/playing-circle.png + FF000000 + + + String.IsEmpty(ListItem.Property(video)) + + String.IsEmpty(ListItem.Property(video)) + 103 + 0 + 100 + 100 + $INFO[ListItem.Thumb] + scale + + + 235 + 0 + + 0 + 16 + 638 + 30 + font12 + left + center + DF000000 + + + + 0 + 51 + 638 + 30 + font10 + left + center + 98000000 + + + + + + !String.IsEmpty(ListItem.Property(video)) + + 103 + 0 + 178 + 100 + $INFO[ListItem.Thumb] + scale + + + String.IsEmpty(ListItem.Property(watched)) + 951 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + 313 + 0 + + 0 + 16 + 510 + 30 + font12 + left + center + DF000000 + + + + 0 + 51 + 510 + 30 + font10 + left + center + 98000000 + + + + + + 802 + 0 + 200 + 100 + font12 + right + center + B8000000 + + + + !String.IsEmpty(ListItem.Property(progress)) + 103 + 91 + + 0 + 0 + 899 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 899 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + + + + + + + + 1128 + 33 + 10 + 879 + 101 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + + + + 201 + 0 + 0 + 1920 + 135 + + VisibleChange + ControlGroup(200).HasFocus(0) + false + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font12 + left + center + FFFFFFFF + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-playlists.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-playlists.xml new file mode 100644 index 0000000000..7e5e9621ef --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-playlists.xml @@ -0,0 +1,567 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + 0 + 115 + 101 + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 0 + 0 + 1920 + 360 + + 60 + 0 + 1800 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1920 + 390 + 200 + 301 + 200 + horizontal + 2 + + + + 40 + 40 + + 21 + 21 + + 0 + 0 + 238 + 238 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 238 + 238 + $INFO[ListItem.Thumb] + scale + + + -30 + 248 + 298 + 40 + font10 + center + FFFFFFFF + + + + -30 + 278 + 298 + 40 + font10 + center + FFFFFFFF + + + + + + + + + + 40 + 40 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(101) + -19 + -19 + 318 + 318 + script.plex/drop-shadow.png + + + 21 + 21 + + 0 + 0 + 238 + 238 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 238 + 238 + $INFO[ListItem.Thumb] + scale + + + -30 + 248 + 298 + 40 + font10 + center + FFFFFFFF + + + + -30 + 278 + 298 + 40 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(101) + 16 + 16 + 248 + 248 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(301).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + Conditional + 301 + 0 + 445 + 1920 + 360 + + Control.IsVisible(100) + 60 + 0 + 1800 + 2 + script.plex/white-square.png + 661F1F1F + + + 60 + 0 + 1800 + 80 + font12 + left + center + FFFFFFFF + + + + -21.5 + 30 + 1941.5 + 700 + 101 + 200 + horizontal + 2 + + + + 40 + 40 + + 41.5 + 25.5 + + 0 + 0 + 537 + 303 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 537 + 303 + $INFO[ListItem.Thumb] + scale + + + -30 + 313 + 597 + 40 + font10 + center + FFFFFFFF + + + + -30 + 343 + 597 + 40 + font10 + center + FFFFFFFF + + + + + + + + + + 40 + 40 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(301) + 1.5 + -15.5 + 617 + 383 + script.plex/drop-shadow.png + + + 41.5 + 25.5 + + 0 + 0 + 537 + 303 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 537 + 303 + $INFO[ListItem.Thumb] + scale + + + -30 + 313 + 597 + 40 + font10 + center + FFFFFFFF + + + + -30 + 343 + 597 + 40 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(301) + 36.5 + 20.5 + 547 + 313 + script.plex/home/selected.png + + + + + + + + + + + 201 + 0 + 0 + 1920 + 135 + + VisibleChange + ControlGroup(200).HasFocus(0) + false + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font12 + left + center + FFFFFFFF + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-plex_pass.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-plex_pass.xml new file mode 100644 index 0000000000..d4c0be6d5c --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-plex_pass.xml @@ -0,0 +1,39 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + + 0 + 0 + 1920 + 1080 + script.plex/sign_in/plexpass.jpg + + + + 1436 + 802 + 275 + 100 + 200 + font13 + FFFFFFFF + FFFFFFFF + center + center + - + - + 0 + 0 + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-posters-small.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-posters-small.xml new file mode 100644 index 0000000000..bfd43ed7d6 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-posters-small.xml @@ -0,0 +1,877 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + Conditional + 0 + 135 + 101 + + + VisibleChange + !Integer.IsGreater(Container(101).ListItem.Property(index),9) + String.IsEmpty(Window.Property(no.content)) + String.IsEmpty(Window.Property(no.content.filtered)) + !String.IsEmpty(Window.Property(initialized)) + 301 + 30 + -25 + 1000 + 145 + 200 + 101 + -20 + horizontal + 200 + true + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + String.IsEmpty(Window.Property(no.options)) | Player.HasAudio + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/chapters-focus.png + script.plex/buttons/chapters.png + + + + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 0 + -35 + 1920 + 1080 + + + 0 + 0 + 1800 + 1190 + 300 + 151 + 200 + vertical + 2 + 152 + + + + 55 + 137 + + 5 + 5 + + 0 + 0 + 144 + 213 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 144 + 213 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 203 + + 0 + 0 + 144 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 144 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 115 + 0 + 29 + 29 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 93 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 94 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 94 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + String.IsEmpty(ListItem.Property(subtitle)) + false + 0 + 218 + 144 + 72 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(subtitle)) + false + 0 + 218 + 144 + 72 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 137 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(101) + -40 + -40 + 234 + 316 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 144 + 213 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 144 + 213 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 203 + + 0 + 0 + 144 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 144 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 115 + 0 + 29 + 29 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 93 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 94 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 94 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + String.IsEmpty(ListItem.Property(subtitle)) + true + 0 + 218 + 144 + 72 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(subtitle)) + true + 0 + 218 + 144 + 30 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(101) + 0 + 0 + 154 + 225 + script.plex/home/selected.png + + + + + + + + + + + String.IsEqual(Window(10000).Property(script.plex.sort),titleSort) + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 151 + 1780 + 150 + 20 + 920 + + 0 + 0 + 34 + 1050 + 100 + 152 + 200 + vertical + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + Control.HasFocus(151) + 0 + 0 + + Control.HasFocus(151) + 0 + 0 + 34 + 34 + FFE5A00D + script.plex/white-outline-rounded.png + + + + + + + + + + 1860 + 150 + 12 + 910 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + + + Conditional + !String.IsEmpty(Window.Property(initialized)) + 201 + 0 + 0 + 1920 + 135 + + VisibleChange + ControlGroup(200).HasFocus(0) + Integer.IsGreater(Container(101).ListItem.Property(index),9) + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font10 + left + center + FFFFFFFF + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 211 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + String.IsEmpty(Window.Property(hide.filteroptions)) + 340 + 35 + 870 + 65 + right + 30 + horizontal + 204 + 210 + 50 + + !String.IsEqual(Window.Property(media.itemType),folder) + false + auto + 65 + font10 + A0FFFFFF + A0FFFFFF + A0FFFFFF + center + center + - + - + 0 + 0 + + + + !String.IsEqual(Window.Property(media.itemType),folder) + auto + 65 + font10 + A0FFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + String.IsEqual(Window.Property(subDir),1) | ![String.IsEqual(Window.Property(media),show) | String.IsEqual(Window.Property(media),movie)] + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 20 + 0 + + + + !String.IsEqual(Window.Property(subDir),1) + [String.IsEqual(Window.Property(media),show) | String.IsEqual(Window.Property(media),movie)] + auto + 65 + font12 + FFFFFFFF + FF000000 + FFFFFFFF + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + !String.IsEqual(Window.Property(media.itemType),folder) + auto + 65 + font10 + A0FFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + + 213 + 35 + 200 + 65 + font10 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(no.content)) + 0 + 465 + + false + 60 + 0 + 1800 + 35 + font13 + center + FFFFFFFF + + + + false + 60 + 60 + 1800 + 35 + font13 + center + FFCCCCCC + + + + + + !String.IsEmpty(Window.Property(no.content.filtered)) + 0 + 465 + + false + 60 + 0 + 1800 + 35 + font13 + center + FFFFFFFF + + + + false + 60 + 60 + 1800 + 35 + font13 + center + FFCCCCCC + + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-posters.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-posters.xml new file mode 100644 index 0000000000..3dd6748994 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-posters.xml @@ -0,0 +1,851 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + Conditional + 0 + 135 + 101 + + + VisibleChange + !Integer.IsGreater(Container(101).ListItem.Property(index),5) + String.IsEmpty(Window.Property(no.content)) + String.IsEmpty(Window.Property(no.content.filtered)) + !String.IsEmpty(Window.Property(initialized)) + 301 + 30 + -25 + 1000 + 145 + 200 + 101 + -20 + horizontal + 200 + true + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + String.IsEmpty(Window.Property(no.options)) | Player.HasAudio + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/chapters-focus.png + script.plex/buttons/chapters.png + + + + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 0 + -35 + 1920 + 1080 + + + 0 + 0 + 1800 + 1190 + 300 + 151 + 200 + vertical + 2 + 152 + + + + 55 + 137 + + 5 + 5 + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 199 + 0 + 45 + 45 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + false + 0 + 371 + 244 + 72 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 137 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(101) + -40 + -40 + 334 + 451 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 199 + 0 + 45 + 45 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + + true + 0 + 371 + 244 + 72 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(101) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + + + + String.IsEqual(Window(10000).Property(script.plex.sort),titleSort) + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 151 + 1780 + 150 + 20 + 920 + + 0 + 0 + 34 + 1050 + 100 + 152 + 200 + vertical + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + Control.HasFocus(151) + 0 + 0 + + Control.HasFocus(151) + 0 + 0 + 34 + 34 + FFE5A00D + script.plex/white-outline-rounded.png + + + + + + + + + + 1860 + 150 + 12 + 910 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + + + Conditional + 201 + 0 + 0 + 1920 + 135 + !String.IsEmpty(Window.Property(initialized)) + + VisibleChange + ControlGroup(200).HasFocus(0) + Integer.IsGreater(Container(101).ListItem.Property(index),5) + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font10 + left + center + FFFFFFFF + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 211 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + String.IsEmpty(Window.Property(hide.filteroptions)) + 340 + 35 + 870 + 65 + right + 30 + horizontal + 204 + 210 + 50 + + !String.IsEqual(Window.Property(media.itemType),folder) + false + auto + 65 + font10 + A0FFFFFF + A0FFFFFF + A0FFFFFF + center + center + - + - + 0 + 0 + + + + !String.IsEqual(Window.Property(media.itemType),folder) + auto + 65 + font10 + A0FFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + String.IsEqual(Window.Property(subDir),1) | ![String.IsEqual(Window.Property(media),show) | String.IsEqual(Window.Property(media),movie)] + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 20 + 0 + + + + !String.IsEqual(Window.Property(subDir),1) + [String.IsEqual(Window.Property(media),show) | String.IsEqual(Window.Property(media),movie)] + auto + 65 + font12 + FFFFFFFF + FF000000 + FFFFFFFF + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + !String.IsEqual(Window.Property(media.itemType),folder) + auto + 65 + font10 + A0FFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + + 213 + 35 + 200 + 65 + font10 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(no.content)) + 0 + 465 + + false + 60 + 0 + 1800 + 35 + font13 + center + FFFFFFFF + + + + false + 60 + 60 + 1800 + 35 + font13 + center + FFCCCCCC + + + + + + !String.IsEmpty(Window.Property(no.content.filtered)) + 0 + 465 + + false + 60 + 0 + 1800 + 35 + font13 + center + FFFFFFFF + + + + false + 60 + 60 + 1800 + 35 + font13 + center + FFCCCCCC + + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-pre_play.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-pre_play.xml new file mode 100644 index 0000000000..9b7c28131f --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-pre_play.xml @@ -0,0 +1,1494 @@ + + + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + Conditional + + + + + + + + + + + + + + 0 + 155 + 101 + + + VisibleChange + !String.IsEmpty(Window.Property(initialized)) + 302 + 428 + 410 + 1000 + 145 + 200 + 400 + -50 + horizontal + 200 + true + + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/info-focus.png + script.plex/buttons/info.png + + + + + String.IsEmpty(Window.Property(unavailable)) + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + !String.IsEmpty(Window.Property(trailer.button)) + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/trailer-focus.png + script.plex/buttons/trailer.png + + + + !String.IsEmpty(Window.Property(media.multiple)) + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/media-focus.png + script.plex/buttons/media.png + + + + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/settings-focus.png + script.plex/buttons/settings.png + + + + Focus + UnFocus + + 0 + 0 + 176 + 140 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + + 0 + 0 + 1920 + 600 + + !String.IsEmpty(Window.Property(preview.no)) + + 60 + 0 + 347 + 518 + script.plex/thumb_fallbacks/movie.png + WindowOpen + scale + + + 60 + 0 + 347 + 518 + $INFO[Window.Property(thumb)] + scale + + + !String.IsEmpty(Window.Property(unwatched)) + 359 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + + + !String.IsEmpty(Window.Property(preview.yes)) + 60 + 0 + + 0 + 0 + 347 + 315 + script.plex/thumb_fallbacks/show.png + WindowOpen + scale + + + 0 + 323 + 347 + 195 + script.plex/white-square.png + scale + + + + 0 + 0 + 347 + 315 + $INFO[Window.Property(thumb)] + scale + + + 0 + 323 + 347 + 195 + $INFO[Window.Property(preview)] + scale + + + + 466 + 0 + 1360 + 60 + left + 0 + horizontal + true + + auto + 60 + font13 + left + FFFFFFFF + + + + !String.IsEmpty(Window.Property(remainingTime)) + 10 + 6 + auto + 34 + font12 + center + center + FFE5A00D + FFE5A00D + 15 + script.plex/white-square-rounded-top-padded.png + script.plex/white-square-rounded-top-padded.png + + + + + 466 + 68 + 1360 + 34 + left + 0 + horizontal + true + + auto + 34 + font12 + left + FFFFFFFF + + + + !String.IsEmpty(Window.Property(rating.stars)) + auto + 34 + font12 + left + FFFFFFFF + + + + !String.IsEmpty(Window.Property(rating.stars)) + 6 + 134 + 22 + script.plex/stars/$INFO[Window.Property(rating.stars)].png + + + !String.IsEmpty(Window.Property(video.res)) + 10 + auto + 34 + font12 + center + center + FFFFFFFF + FFFFFFFF + 15 + script.plex/white-square-rounded-top-padded.png + script.plex/white-square-rounded-top-padded.png + + + + !String.IsEmpty(Window.Property(unavailable)) + 10 + auto + 34 + font12 + center + center + FFFFFFFF + FFFFFFFF + 15 + script.plex/white-square-rounded-top-padded.png + script.plex/white-square-rounded-top-padded.png + + + + + + !String.IsEmpty(Window.Property(rating)) + 1560 + 4 + 300 + 32 + right + 15 + horizontal + true + + 2 + 63 + 30 + $INFO[Window.Property(rating.image)] + keep + + + auto + 30 + font12 + left + FFFFFFFF + + + + !String.IsEmpty(Window.Property(rating2)) + 2 + 40 + 30 + $INFO[Window.Property(rating2.image)] + keep + + + !String.IsEmpty(Window.Property(rating2)) + auto + 30 + font12 + left + FFFFFFFF + + + + + + !String.IsEmpty(Window.Property(directors)) + 466 + 130 + 1360 + 30 + font12 + left + 99FFFFFF + + + + !String.IsEmpty(Window.Property(writers)) + 466 + 165 + 1360 + 30 + font12 + left + 99FFFFFF + + + + 466 + 223 + 1360 + 34 + left + 15 + horizontal + true + + !String.IsEmpty(Window.Property(audio)) + auto + 34 + font12 + center + center + FFFFFFFF + FFFFFFFF + 15 + script.plex/white-square-rounded-top-padded.png + script.plex/white-square-rounded-top-padded.png + + + + auto + 34 + font12 + left + center + FFFFFFFF + + + + !String.IsEmpty(Window.Property(subtitles)) + 30 + auto + 34 + font12 + center + center + FFFFFFFF + FFFFFFFF + 15 + script.plex/white-square-rounded-top-padded.png + script.plex/white-square-rounded-top-padded.png + + + + !String.IsEmpty(Window.Property(subtitles)) + auto + 34 + font12 + left + center + FFFFFFFF + + + + + 466 + 290 + 1360 + 102 + font12 + left + FFFFFFFF + + + + WindowOpen + -1 + 557 + 1 + 8 + script.plex/white-square.png + FFCC7B19 + + + !Control.IsVisible(500) + 0 + 565 + 1920 + 2 + script.plex/white-square.png + A0000000 + + + + + 0 + 565 + 1920 + 1800 + + 300 + 0 + + + + Integer.IsGreater(Container(400).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 400 + 1920 + 446 + + 60 + 20 + 1000 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 36 + 1920 + 410 + 300 + 401 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + script.plex/thumb_fallbacks/role.png + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + 0 + 253 + + false + 0 + 0 + 244 + 60 + font10 + center + AAFFFFFF + + + + false + 0 + 30 + 244 + 60 + font10 + center + AAFFFFFF + + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(403) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + script.plex/thumb_fallbacks/role.png + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + 0 + 253 + + Control.HasFocus(400) + 0 + 0 + 244 + 60 + font10 + center + AAFFFFFF + + + + Control.HasFocus(400) + 0 + 30 + 244 + 60 + font10 + center + AAFFFFFF + + + + + + Control.HasFocus(400) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + + + Integer.IsGreater(Container(401).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 401 + 1920 + 446 + + 60 + 20 + 1000 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 36 + 1920 + 410 + 400 + 402 + 200 + horizontal + 4 + + + + 55 + 61 + + 0 + 0 + 520 + 310 + script.plex/white-square.png + 60000000 + + + 20 + 20 + + 0 + 0 + + 10 + -5 + 70 + 70 + script.plex/reviews/$INFO[ListItem.Thumb].png + + + false + 100 + 0 + 400 + 30 + font10 + left + DDFFFFFF + + + + false + 100 + 30 + 400 + 30 + font10 + left + 66FFFFFF + + + + + 0 + 80 + 480 + 190 + font10 + left + AAFFFFFF + + + + + + + + + + 55 + 61 + + 0 + 0 + 520 + 310 + script.plex/white-square.png + 80000000 + + + 20 + 20 + + 0 + 0 + + 10 + -5 + 70 + 70 + script.plex/reviews/$INFO[ListItem.Thumb].png + + + false + 100 + 0 + 400 + 30 + font10 + left + DDFFFFFF + + + + false + 100 + 30 + 400 + 30 + font10 + left + 66FFFFFF + + + + + 0 + 80 + 480 + 190 + font10 + left + DDFFFFFF + + Control.HasFocus(401) + + + + Control.HasFocus(401) + -5 + -5 + 530 + 320 + script.plex/home/selected.png + + + + + + + + + + Integer.IsGreater(Container(402).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 360 + 1920 + + 0 + 0 + 1920 + 360 + script.plex/white-square.png + 40000000 + + + 60 + 0 + 800 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 18 + 1920 + 430 + 401 + 403 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 299 + 168 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 299 + 168 + $INFO[ListItem.Thumb] + scale + + + 0 + 180 + 299 + 60 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(402) + -40 + -40 + 389 + 258 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 299 + 168 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 299 + 168 + $INFO[ListItem.Thumb] + scale + + + 0 + 180 + 299 + 60 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(402) + 0 + 0 + 309 + 178 + script.plex/home/selected.png + + + + + + + + + + + Integer.IsGreater(Container(403).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 403 + 1920 + 520 + + !String.IsEmpty(Window.Property(divider.403)) + 60 + 0 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 16 + 1920 + 520 + 402 + false + false + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 369 + 244 + 38 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(403) + -40 + -40 + 324 + 441 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + Control.HasFocus(403) + 0 + 369 + 244 + 38 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(403) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + + + + + + + + + + Conditional + 201 + 0 + 0 + 1920 + 135 + + VisibleChange + ControlGroup(200).HasFocus(0) + !String.IsEmpty(Window.Property(on.extras)) + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-pre_signin.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-pre_signin.xml new file mode 100644 index 0000000000..9c8b5d3910 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-pre_signin.xml @@ -0,0 +1,39 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + + 0 + 0 + 1920 + 1080 + script.plex/sign_in/pre-signin.jpg + + + + 1437 + 801 + 275 + 104 + 200 + font13 + FFFFFFFF + FFFFFFFF + center + center + - + - + 0 + 0 + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-refresh_code.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-refresh_code.xml new file mode 100644 index 0000000000..4826223894 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-refresh_code.xml @@ -0,0 +1,39 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + + 0 + 0 + 1920 + 1080 + script.plex/sign_in/refresh-code.jpg + + + + 1383 + 802 + 335 + 102 + 200 + font13 + FFFFFFFF + FFFFFFFF + center + center + - + - + 0 + 0 + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-search.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-search.xml new file mode 100644 index 0000000000..95db79fb57 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-search.xml @@ -0,0 +1,8839 @@ + + SetProperty(dropdown,1) + + 1 + 0 + 0 + + + + + + 0 + 0 + 564 + 1080 + script.plex/white-square.png + + + 0 + 135 + 564 + 810 + String.IsEmpty(Window.Property(hide.kbd)) + script.plex/white-square.png + + + 0 + 135 + 564 + 248 + !String.IsEmpty(Window.Property(hide.kbd)) + script.plex/white-square.png + + + 0 + 945 + 564 + 135 + String.IsEmpty(Window.Property(hide.kbd)) + script.plex/white-square.png + + + 0 + 383 + 564 + 697 + !String.IsEmpty(Window.Property(hide.kbd)) + script.plex/white-square.png + + + + + Focus + UnFocus + 60 + 47.5 + 40 + 40 + 900 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + Close + + + + false + 160 + 35 + 500 + 65 + font12 + left + center + FFFFFFFF + + + + + + + 60 + 186 + 459 + 60 + + + 0 + 0 + + 0 + 0 + 151 + 60 + script.plex/white-square.png + + + String.IsEqual(Window.Property(search.section),all) + + 0 + 0 + 151 + 60 + script.plex/white-square.png + + + false + 0 + 0 + 151 + 60 + font12 + center + center + FF000000 + + + + + false + !String.IsEqual(Window.Property(search.section),all) + 0 + 0 + 151 + 60 + font12 + center + center + FFFFFFFF + + + + + 154 + 0 + + 0 + 0 + 74 + 60 + script.plex/white-square.png + + + String.IsEqual(Window.Property(search.section),movie) + 0 + 0 + 74 + 60 + script.plex/white-square.png + + + + 231 + 0 + + 0 + 0 + 74 + 60 + script.plex/white-square.png + + + String.IsEqual(Window.Property(search.section),show) + 0 + 0 + 74 + 60 + script.plex/white-square.png + + + + 308 + 0 + + 0 + 0 + 74 + 60 + script.plex/white-square.png + + + String.IsEqual(Window.Property(search.section),artist) + 0 + 0 + 74 + 60 + script.plex/white-square.png + + + + 384 + 0 + + 0 + 0 + 74 + 60 + script.plex/white-square.png + + + String.IsEqual(Window.Property(search.section),photo) + 0 + 0 + 74 + 60 + script.plex/white-square.png + + + + + 901 + + 0 + 0 + + Focus + UnFocus + + -40 + -40 + 231 + 140 + 902 + 999 + 650 + font12 + center + center + FF000000 + 00000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 154 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 140 + 901 + 903 + 999 + 650 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 231 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 140 + 902 + 904 + 999 + 650 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 308 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 140 + 903 + 905 + 999 + 650 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 385 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 140 + 904 + 3000 + 999 + 650 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + + + 154 + 0 + + Conditional + 0 + 0 + 74 + 60 + + 26 + 20 + 22 + 20 + script.plex/home/type/movie.png + + + + + 231 + 0 + + Conditional + 0 + 0 + 74 + 60 + + 26 + 20 + 24 + 20 + script.plex/home/type/show.png + + + + + 308 + 0 + + Conditional + 0 + 0 + 74 + 60 + + 26 + 20 + 18 + 20 + script.plex/home/type/artist.png + + + + + 385 + 0 + + Conditional + 0 + 0 + 74 + 60 + + 26 + 20 + 22 + 20 + script.plex/home/type/photo.png + + + + + + + + 60 + 276 + 459 + 60 + + 0 + 0 + 459 + 60 + script.plex/white-square.png + + + 0 + 0 + 459 + 60 + left + center + 900 + 1001 + 3000 + 00000000 + + + font13 + 30 + script.plex/home/selected.png + - + no + + + false + 30 + 0 + 399 + 60 + left + center + FFFFFFFF + font13 + + + + + + + 60 + 360 + 459 + 439 + String.IsEmpty(Window.Property(hide.kbd)) + + + + 0 + 0 + + 0 + 0 + 74 + 74 + script.plex/white-square.png + + + 77 + 0 + 74 + 74 + script.plex/white-square.png + + + 154 + 0 + 74 + 74 + script.plex/white-square.png + + + 231 + 0 + 74 + 74 + script.plex/white-square.png + + + 308 + 0 + 74 + 74 + script.plex/white-square.png + + + 385 + 0 + 74 + 74 + script.plex/white-square.png + + + + + 0 + 77 + + 0 + 0 + 74 + 74 + script.plex/white-square.png + + + 77 + 0 + 74 + 74 + script.plex/white-square.png + + + 154 + 0 + 74 + 74 + script.plex/white-square.png + + + 231 + 0 + 74 + 74 + script.plex/white-square.png + + + 308 + 0 + 74 + 74 + script.plex/white-square.png + + + 385 + 0 + 74 + 74 + script.plex/white-square.png + + + + + 0 + 154 + + 0 + 0 + 74 + 74 + script.plex/white-square.png + + + 77 + 0 + 74 + 74 + script.plex/white-square.png + + + 154 + 0 + 74 + 74 + script.plex/white-square.png + + + 231 + 0 + 74 + 74 + script.plex/white-square.png + + + 308 + 0 + 74 + 74 + script.plex/white-square.png + + + 385 + 0 + 74 + 74 + script.plex/white-square.png + + + + + 0 + 231 + + 0 + 0 + 74 + 74 + script.plex/white-square.png + + + 77 + 0 + 74 + 74 + script.plex/white-square.png + + + 154 + 0 + 74 + 74 + script.plex/white-square.png + + + 231 + 0 + 74 + 74 + script.plex/white-square.png + + + 308 + 0 + 74 + 74 + script.plex/white-square.png + + + 385 + 0 + 74 + 74 + script.plex/white-square.png + + + + + 0 + 308 + + 0 + 0 + 74 + 74 + script.plex/white-square.png + + + 77 + 0 + 74 + 74 + script.plex/white-square.png + + + 154 + 0 + 74 + 74 + script.plex/white-square.png + + + 231 + 0 + 74 + 74 + script.plex/white-square.png + + + 308 + 0 + 74 + 74 + script.plex/white-square.png + + + 385 + 0 + 74 + 74 + script.plex/white-square.png + + + + + 0 + 385 + + 0 + 0 + 74 + 74 + script.plex/white-square.png + + + 77 + 0 + 74 + 74 + script.plex/white-square.png + + + 154 + 0 + 74 + 74 + script.plex/white-square.png + + + 231 + 0 + 74 + 74 + script.plex/white-square.png + + + 308 + 0 + 74 + 74 + script.plex/white-square.png + + + 385 + 0 + 74 + 74 + script.plex/white-square.png + + + + + + 0 + 0 + + 0 + 0 + + true + Focus + UnFocus + + -40 + -40 + 154 + 154 + 650 + 1007 + 1002 + 1006 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 77 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 650 + 1008 + 1003 + 1001 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 154 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 650 + 1009 + 1004 + 1002 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 231 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 650 + 1010 + 1005 + 1003 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 308 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 650 + 1011 + 1006 + 1004 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 385 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 650 + 1012 + 3000 + 1005 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + + + 0 + 77 + + 0 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1001 + 1013 + 1008 + 1012 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 77 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1002 + 1014 + 1009 + 1007 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 154 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1003 + 1015 + 1010 + 1008 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 231 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1004 + 1016 + 1011 + 1009 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 308 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1005 + 1017 + 1012 + 1010 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 385 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1006 + 1018 + 3000 + 1011 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + + + 0 + 154 + + 0 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1007 + 1019 + 1014 + 1018 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 77 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1008 + 1020 + 1015 + 1013 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 154 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1009 + 1021 + 1016 + 1014 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 231 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1010 + 1022 + 1017 + 1015 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 308 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1011 + 1023 + 1018 + 1016 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 385 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1012 + 1024 + 3000 + 1017 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + + + 0 + 231 + + 0 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1013 + 1025 + 1020 + 1024 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 77 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1014 + 1026 + 1021 + 1019 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 154 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1015 + 1027 + 1022 + 1020 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 231 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1016 + 1028 + 1023 + 1021 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 308 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1017 + 1029 + 1024 + 1022 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 385 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1018 + 1030 + 3000 + 1023 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + + + 0 + 308 + + 0 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1019 + 1031 + 1026 + 1030 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 77 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1020 + 1032 + 1027 + 1025 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 154 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1021 + 1033 + 1028 + 1026 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 231 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1022 + 1034 + 1029 + 1027 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 308 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1023 + 1035 + 1030 + 1028 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 385 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1024 + 1036 + 3000 + 1029 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + + + 0 + 385 + + 0 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1025 + 951 + 1032 + 1036 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 77 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1026 + 951 + 1033 + 1031 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 154 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1027 + 952 + 1034 + 1032 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 231 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1028 + 952 + 1035 + 1033 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 308 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1029 + 953 + 1036 + 1034 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 385 + 0 + + Focus + UnFocus + + -40 + -40 + 154 + 154 + 1030 + 953 + 3000 + 1035 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + + + + + 60 + 840 + 459 + 60 + String.IsEmpty(Window.Property(hide.kbd)) + + 0 + 0 + 151 + 60 + script.plex/white-square.png + + + 154 + 0 + 151 + 60 + script.plex/white-square.png + + + 308 + 0 + 151 + 60 + script.plex/white-square.png + + + + 0 + 0 + + Focus + UnFocus + + -40 + -40 + 231 + 140 + 953 + 952 + 1031 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 154 + 0 + + Focus + UnFocus + + -40 + -40 + 231 + 140 + 951 + 953 + 1033 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + 308 + 0 + + Focus + UnFocus + + -40 + -40 + 231 + 140 + 952 + 3000 + 1036 + font12 + center + center + FF000000 + script.plex/white-square-rounded-with-shadow.png + - + + + + + + + Visible + !String.IsEmpty(Window.Property(searching)) + 0 + 993 + + false + 420 + 0 + 434 + 39 + font12 + right + center + FFFFFFFF + + + + 480 + 0 + + !String.IsEmpty(Window.Property(searching)) + Visible + 0 + 0 + 39 + 39 + script.plex/indicators/spinner.png + + + + + !String.IsEmpty(Window.Property(no.results)) + String.IsEmpty(Window.Property(searching)) + 0 + 993 + + false + 0 + 0 + 564 + 39 + font12 + center + center + FFFFFFFF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2000 + 564 + 20 + 2130 + 5540 + 20 + vertical + true + 200 + + + 2100 + Integer.IsGreater(Container(2100).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2101 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2100) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2100) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2100 + 2102 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2101) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2101) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2102).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2101 + 2103 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2102) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2102) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2103).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2102 + 2104 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2103) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2103) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2104).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2103 + 2105 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2104) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2104) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2105).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2104 + 2106 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2105) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2105) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2106).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2105 + 2107 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2106) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2106) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2107).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2106 + 2108 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2107) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2107) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2108).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2107 + 2109 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2108) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2108) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2109).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2108 + 2110 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2109) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2109) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2110).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2109 + 2111 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2110) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2110) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2111).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2110 + 2112 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2111) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2111) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2112).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2111 + 2113 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2112) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2112) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2113).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2112 + 2114 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2113) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2113) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2114).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2113 + 2115 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2114) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2114) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2115).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2114 + 2116 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2115) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2115) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2116).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2115 + 2117 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2116) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2116) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2117).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2116 + 2118 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2117) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2117) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2118).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2117 + 2119 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2118) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2118) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2119).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2118 + 2120 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2119) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2119) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2120).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2119 + 2121 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2120) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2120) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2121).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2120 + 2122 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2121) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2121) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2122).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2121 + 2123 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2122) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2122) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2123).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2122 + 2124 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2123) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2123) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2124).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2123 + 2125 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2124) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2124) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2125).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2124 + 2126 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2125) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2125) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2126).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2125 + 2127 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2126) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2126) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2127).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2126 + 2128 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2127) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2127) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2128).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2127 + 2129 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2128) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2128) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2129).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2128 + 2130 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2129) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2129) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2130).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2129 + 2131 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2130) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2130) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2131).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2130 + 2132 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2131) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2131) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2132).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2131 + 2133 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2132) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2132) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2133).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2132 + 2134 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2133) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2133) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2134).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2133 + 2135 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2134) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2134) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2135).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2134 + 2136 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2135) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2135) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2136).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2135 + 2137 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2136) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2136) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2137).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2136 + 2138 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2137) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2137) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2138).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2137 + 2139 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2138) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2138) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2139).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2138 + 2140 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2139) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2139) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2140).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2139 + 2141 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2140) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2140) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2141).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2140 + 2142 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2141) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2141) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2142).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2141 + 2143 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2142) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2142) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2143).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2142 + 2144 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2143) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2143) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + Integer.IsGreater(Container(2144).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2143 + 2145 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2144) + -40 + -40 + 270 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 180 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 180 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 180 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2144) + 0 + 0 + 190 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2145).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2144 + 2146 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2145) + -40 + -40 + 360 + 360 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 270 + 270 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 270 + 270 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 280 + 270 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2145) + 0 + 0 + 280 + 280 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2146).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 320 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2145 + 2147 + 200 + horizontal + 4 + + + + 55 + 64 + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 64 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2146) + -40 + -40 + 390 + 259 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 300 + 169 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 300 + 169 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 179 + 300 + 35 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(2146) + 0 + 0 + 310 + 179 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(2147).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 1356 + 420 + + 60 + 0 + 1236 + 2 + script.plex/white-square.png + FF282828 + + + false + 60 + 0 + 1000 + 87 + font12 + left + center + FFFFFFFF + + + + 0 + 30 + 1356 + 440 + 899 + 2146 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(2147) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 254 + 244 + 35 + font10 + center + FFFFFFFF + + + + 0 + 282 + 244 + 35 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(2147) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + + \ No newline at end of file diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-seasons.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-seasons.xml new file mode 100644 index 0000000000..c86327de09 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-seasons.xml @@ -0,0 +1,1361 @@ + + + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + Conditional + + + + + + + + + + + + + + 0 + 155 + 101 + + + VisibleChange + !String.IsEmpty(Window.Property(initialized)) + 302 + 440 + 445 + 1000 + 145 + 200 + 400 + -20 + horizontal + 200 + true + + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/info-focus.png + script.plex/buttons/info.png + + + + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + + 0 + 0 + 1920 + 600 + + 60 + 0 + 347 + 518 + script.plex/thumb_fallbacks/movie.png + WindowOpen + scale + + + 60 + 0 + 347 + 518 + $INFO[Window.Property(thumb)] + scale + + + + 466 + 0 + 1360 + 60 + font13 + left + FFFFFFFF + + + + 466 + 70 + 1360 + 30 + left + 0 + horizontal + true + + auto + 30 + font12 + left + FFFFFFFF + + + + !String.IsEmpty(Window.Property(rating.stars)) + auto + 30 + font12 + left + FFFFFFFF + + + + !String.IsEmpty(Window.Property(rating.stars)) + 4 + 134 + 22 + script.plex/stars/$INFO[Window.Property(rating.stars)].png + + + + + !String.IsEmpty(Window.Property(rating)) + 1660 + 70 + 200 + 32 + right + 15 + horizontal + true + + 2 + 63 + 30 + $INFO[Window.Property(rating.image)] + keep + + + auto + 30 + font12 + left + FFFFFFFF + + + + !String.IsEmpty(Window.Property(rating2)) + 2 + 63 + 30 + $INFO[Window.Property(rating2.image)] + keep + + + !String.IsEmpty(Window.Property(rating2)) + auto + 30 + font12 + left + FFFFFFFF + + + + + + + !String.IsEmpty(Window.Property(directors)) + 466 + 130 + 1360 + 30 + font12 + left + 99FFFFFF + + + + !String.IsEmpty(Window.Property(writers)) + 466 + 165 + 1360 + 30 + font12 + left + 99FFFFFF + + + + + 466 + 234 + 1360 + 179 + font12 + left + FFFFFFFF + + + + WindowOpen + -1 + 557 + 1 + 8 + script.plex/white-square.png + FFCC7B19 + + + !Control.IsVisible(500) + 0 + 565 + 1920 + 2 + script.plex/white-square.png + A0000000 + + + + + 0 + 565 + 1920 + 1600 + + 300 + 0 + + + Integer.IsGreater(Container(400).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 360 + 1920 + + 0 + 0 + 1920 + 360 + script.plex/white-square.png + 40000000 + + + 0 + 14 + 1920 + 430 + 300 + 401 + 200 + horizontal + 4 + + + + 55 + 29 + + 5 + 5 + + 0 + 0 + 158 + 236 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 158 + 236 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 113 + 0 + 45 + 40 + script.plex/white-square.png + FF000000 + + + 114 + 0 + 44 + 39 + script.plex/white-square.png + FFCC7B19 + + + 114 + 0 + 44 + 39 + font10 + center + center + FF000000 + + + + + false + 0 + 240 + 158 + 54 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 29 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(400) + -40 + -40 + 248 + 326 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 158 + 236 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 158 + 236 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 113 + 0 + 45 + 40 + script.plex/white-square.png + FF000000 + + + 114 + 0 + 44 + 39 + script.plex/white-square.png + FFCC7B19 + + + 114 + 0 + 44 + 39 + font10 + center + center + FF000000 + + + + + Control.HasFocus(400) + 0 + 240 + 158 + 54 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(400) + 0 + 0 + 168 + 246 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(401).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 360 + 1920 + + 60 + 0 + 800 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 18 + 1920 + 430 + 400 + 402 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 299 + 168 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 299 + 168 + $INFO[ListItem.Thumb] + scale + + + false + 0 + 175 + 299 + 60 + font12 + center + FFFFFFFF + + + + false + 0 + 210 + 299 + 60 + font12 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(401) + -40 + -40 + 389 + 258 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 299 + 168 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 299 + 168 + $INFO[ListItem.Thumb] + scale + + + + Control.HasFocus(401) + 0 + 175 + 299 + 60 + font12 + center + FFFFFFFF + + + + Control.HasFocus(401) + 0 + 210 + 299 + 60 + font12 + center + FFFFFFFF + + + + + + Control.HasFocus(401) + 0 + 0 + 309 + 178 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(402).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 402 + 1920 + 520 + + !String.IsEmpty(Window.Property(divider.402)) + 60 + 0 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 16 + 1920 + 520 + 401 + 403 + false + false + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 369 + 244 + 38 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(402) + -40 + -40 + 324 + 441 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + Control.HasFocus(402) + 0 + 369 + 244 + 38 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(402) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + + + + + + + Integer.IsGreater(Container(403).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 403 + 1920 + 410 + + !String.IsEmpty(Window.Property(divider.403)) + 60 + 20 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 20 + 1000 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 36 + 1920 + 410 + 402 + 403 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + script.plex/thumb_fallbacks/role.png + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + 0 + 253 + 244 + 90 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(403) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + script.plex/thumb_fallbacks/role.png + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + 0 + 253 + 244 + 90 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(403) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + + + Conditional + 201 + 0 + 0 + 1920 + 135 + + VisibleChange + ControlGroup(200).HasFocus(0) + !String.IsEmpty(Window.Property(on.extras)) + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog.xml new file mode 100644 index 0000000000..d85f26fc42 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog.xml @@ -0,0 +1,1106 @@ + + + + 1 + 0 + 0 + + 100 + 800 + + + [!String.IsEmpty(Window.Property(show.OSD)) | Window.IsVisible(seekbar) | !String.IsEmpty(Window.Property(button.seek))] + !Window.IsVisible(osdvideosettings) + !Window.IsVisible(osdaudiosettings) + !Window.IsVisible(osdsubtitlesettings) + !Window.IsVisible(subtitlesearch) + !Window.IsActive(playerprocessinfo) + !Window.IsActive(selectdialog) + Hidden + + String.IsEmpty(Window.Property(settings.visible)) + [Window.IsVisible(seekbar) | Window.IsVisible(videoosd) | Player.ShowInfo] + Hidden + 0 + 0 + + 0 + 0 + 1920 + 1080 + script.plex/player-fade.png + FF080808 + + + + + 0 + 0 + + 0 + 0 + 1920 + 140 + script.plex/white-square.png + A0000000 + + + 0 + 940 + 1920 + 140 + script.plex/white-square.png + A0000000 + + + + + 0 + 40 + + !String.IsEmpty(Window.Property(is.show)) + 60 + 0 + 1500 + 60 + font13 + left + center + FFFFFFFF + + + + String.IsEmpty(Window.Property(is.show)) + 60 + 0 + 1500 + 60 + font13 + left + center + FFFFFFFF + + + + 1860 + 0 + 300 + 60 + font12 + right + center + FFFFFFFF + + + + + + 0 + 965 + + !String.IsEmpty(Window.Property(direct.play)) + 60 + 0 + 1000 + 60 + font13 + left + center + FFFFFFFF + + + + String.IsEmpty(Window.Property(direct.play)) + 60 + 0 + 1000 + 60 + font13 + left + center + FFFFFFFF + + + + Player.IsTempo + 60 + 40 + 1000 + 60 + font13 + left + center + A0FFFFFF + + + + !String.IsEmpty(Window.Property(direct.play)) + 1860 + 0 + 800 + 60 + font13 + right + center + FFFFFFFF + + + + String.IsEmpty(Window.Property(direct.play)) + 1860 + 0 + 800 + 60 + font13 + right + center + FFFFFFFF + + + + !String.IsEmpty(Window.Property(media.show_ends)) + !String.IsEmpty(Window.Property(direct.play)) + 1860 + 40 + 800 + 60 + font13 + right + center + A0FFFFFF + + + + !String.IsEmpty(Window.Property(media.show_ends)) + String.IsEmpty(Window.Property(direct.play)) + 1860 + 40 + 800 + 60 + font13 + right + center + A0FFFFFF + + + + Player.Paused + String.IsEmpty(Window.Property(show.OSD)) + Visible + 0 + 20 + 1920 + 60 + font13 + center + center + FFCC7B19 + + + + + + 0 + 940 + + 0 + 0 + 1920 + 10 + script.plex/white-square.png + A0000000 + + + !String.IsEmpty(Window.Property(show.buffer)) + 0 + 2 + 1 + 6 + script.plex/white-square.png + EE4E4842 + + + 0 + 2 + 1 + 6 + script.plex/white-square.png + FFAC5B00 + + + Control.HasFocus(100) | !String.IsEmpty(Window.Property(button.seek)) + 0 + 2 + 1 + 6 + script.plex/white-square.png + FFE5A00D + + + + + String.IsEmpty(Window.Property(show.OSD)) + 0 + 0 + 1920 + 1080 + - + - + + SetProperty(show.OSD,1) + + + + + 0 + 350 + !String.IsEmpty(Window.Property(show.PPI)) + String.IsEmpty(Window.Property(settings.visible)) + String.IsEmpty(Window.Property(playlist.visible)) + Visible + Hidden + + 10 + -220 + 10 + 420 + buttons/dialogbutton-nofo.png + + + 52 + -184 + 1786 + 350 + horizontal + 10 + + 0 + 0 + 793 + + 793 + 50 + bottom + + font14 + black + Player.HasVideo + + + 793 + 50 + bottom + + font14 + black + Player.HasVideo + + + 793 + 50 + bottom + + font14 + black + Player.HasVideo + + + 793 + 50 + bottom + + font14 + black + Player.HasVideo + + + 793 + 50 + bottom + + + font14 + black + + + 793 + 50 + bottom + + font14 + black + + + + 0 + 0 + 993 + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Status)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Mode)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Container)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Video)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Audio)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Subtitles)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.User)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + String.IsEmpty(Window.Property(ppi.Buffered)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Buffered)) + + + + + 52 + 120 + 1786 + 50 + bottom + + font14 + black + + + + !String.IsEmpty(Window.Property(show.OSD)) + !Window.IsVisible(osdvideosettings) + !Window.IsVisible(osdaudiosettings) + !Window.IsVisible(osdsubtitlesettings) + !Window.IsVisible(subtitlesearch) + !Window.IsActive(playerprocessinfo) + !Window.IsActive(selectdialog) + Hidden + + !String.IsEmpty(Window.Property(has.bif)) + [Control.HasFocus(100) | Control.HasFocus(501) | !String.IsEmpty(Window.Property(button.seek))] + Visible + 0 + 752 + + 0 + 0 + 324 + 184 + script.plex/white-square.png + FF000000 + + + 2 + 2 + 320 + 180 + 10 + $INFO[Window.Property(bif.image)] + + + + + 406 + + 360 + 964 + 1200 + + 124 + center + 100 + -40 + horizontal + 200 + true + + !String.IsEmpty(Window.Property(nav.repeat)) + Conditional + Conditional + 125 + 101 + + + 0 + 0 + 125 + 101 + 100 + 402 + 412 + font12 + - + - + + + + !Control.HasFocus(401) + + !Playlist.IsRepeatOne + !Playlist.IsRepeat + String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat.png + + + Playlist.IsRepeat | !String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat.png + + + Playlist.IsRepeatOne | !String.IsEmpty(Window.Property(pq.repeat.one)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-one.png + + + + Control.HasFocus(401) + + !Playlist.IsRepeatOne + !Playlist.IsRepeat + String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-focus.png + + + Playlist.IsRepeat | !String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-focus.png + + + Playlist.IsRepeatOne | !String.IsEmpty(Window.Property(pq.repeat.one)) + 0 + 0 + 125 + 101 + script.plex/buttons/repeat-one-focus.png + + + + + + !String.IsEmpty(Window.Property(has.playlist)) + !String.IsEmpty(Window.Property(nav.shuffle)) + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + !String.IsEmpty(Window.Property(pq.shuffled)) + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + false + String.IsEmpty(Window.Property(has.playlist)) + !String.IsEmpty(Window.Property(nav.shuffle)) + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/settings-focus.png + script.plex/buttons/settings.png + + + + + + !String.IsEmpty(Window.Property(pq.hasprev)) + !String.IsEmpty(Window.Property(nav.prevnext)) + Focus + UnFocus + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + false + String.IsEmpty(Window.Property(pq.hasprev)) + !String.IsEmpty(Window.Property(nav.prevnext)) + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + !String.IsEmpty(Window.Property(nav.ffwdrwd)) + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/skip-forward-focus.png + script.plex/buttons/skip-forward.png + + + + + Conditional + Conditional + 125 + 101 + + + 0 + 0 + 125 + 101 + 100 + 407 + 405 + font12 + - + - + + PlayerControl(Play) + + + !Control.HasFocus(406) + + !Player.Paused + !Player.Forwarding + !Player.Rewinding + 0 + 0 + 125 + 101 + script.plex/buttons/pause.png + + + Player.Paused | Player.Forwarding | Player.Rewinding + 0 + 0 + 125 + 101 + script.plex/buttons/play.png + + + + Control.HasFocus(406) + + !Player.Paused + !Player.Forwarding + !Player.Rewinding + 0 + 0 + 125 + 101 + script.plex/buttons/pause-focus.png + + + Player.Paused | Player.Forwarding | Player.Rewinding + 0 + 0 + 125 + 101 + script.plex/buttons/play-focus.png + + + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/stop-focus.png + script.plex/buttons/stop.png + + + + !String.IsEmpty(Window.Property(nav.ffwdrwd)) + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/skip-forward-focus.png + script.plex/buttons/skip-forward.png + + + + !String.IsEmpty(Window.Property(pq.hasnext)) + !String.IsEmpty(Window.Property(nav.prevnext)) + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + false + String.IsEmpty(Window.Property(pq.hasnext)) + !String.IsEmpty(Window.Property(nav.prevnext)) + 0 + 0 + 125 + 101 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + + + + + + [!String.IsEmpty(Window.Property(pq.hasnext)) | !String.IsEmpty(Window.Property(pq.hasprev))] + !String.IsEmpty(Window.Property(nav.playlist)) + Focus + UnFocus + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/pqueue-focus.png + script.plex/buttons/pqueue.png + + + + false + String.IsEmpty(Window.Property(pq.hasnext)) + String.IsEmpty(Window.Property(pq.hasprev)) + !String.IsEmpty(Window.Property(nav.playlist)) + Focus + UnFocus + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/pqueue-focus.png + script.plex/buttons/pqueue.png + + + + !String.IsEmpty(Window.Property(nav.quick_subtitles)) + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/subtitle-focus.png + script.plex/buttons/subtitle.png + + + + + + 0 + 940 + + + 0 + 0 + 1920 + 10 + 501 + 400 + - + - + + + + + Conditional + + + Conditional + + + String.IsEmpty(Window.Property(mouse.mode)) + String.IsEmpty(Window.Property(hide.bigseek)) + [Control.HasFocus(501) | Control.HasFocus(100)] + [!String.IsEmpty(Window.Property(show.chapters)) | String.IsEmpty(Window.Property(has.chapters))] + -8 + 917 + + -200 + 5 + 2320 + 6 + script.plex/white-square.png + A0000000 + String.IsEmpty(Window.Property(has.chapters)) + + + + 0 + -175 + 1928 + 200 + script.plex/white-square.png + A0000000 + !String.IsEmpty(Window.Property(has.chapters)) + + + 40 + -162 + auto + 20 + font10 + left + center + CC606060 + + !String.IsEmpty(Window.Property(has.chapters)) + !Control.HasFocus(501) + + + 40 + -162 + auto + 20 + font10 + left + center + FFFFFFFF + + !String.IsEmpty(Window.Property(has.chapters)) + Control.HasFocus(501) + + + + + 0 + 0 + 1928 + 16 + 100 + SetProperty(hide.bigseek,) + 200 + horizontal + 4 + + + + 0 + 0 + 16 + 16 + script.plex/indicators/seek-selection-marker.png + FF606060 + + + + + + + !Control.HasFocus(501) + 0 + 0 + 16 + 16 + script.plex/indicators/seek-selection-marker.png + FF606060 + + + Control.HasFocus(501) + 0 + 0 + 16 + 16 + script.plex/indicators/seek-selection-marker.png + FFE5A00D + + + + + + + + 40 + 0 + 178 + 100 + script.plex/thumb_fallbacks/movie16x9.png + scale + CC606060 + !Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + $INFO[ListItem.Thumb] + scale + DDAAAAAA + !Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + script.plex/thumb_fallbacks/movie16x9.png + scale + FFAAAAAA + Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + $INFO[ListItem.Thumb] + scale + FFAAAAAA + Control.HasFocus(501) + + + 40 + 120 + auto + 10 + font10 + center + center + CC606060 + + !Control.HasFocus(501) + + + 40 + 120 + auto + 10 + font10 + center + center + FFAAAAAA + + Control.HasFocus(501) + + + + + + + + + 40 + 0 + 178 + 100 + script.plex/thumb_fallbacks/movie16x9.png + scale + CC909090 + !Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + $INFO[ListItem.Thumb] + scale + FFAAAAAA + !Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + script.plex/thumb_fallbacks/movie16x9.png + scale + + Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + $INFO[ListItem.Thumb] + scale + + Control.HasFocus(501) + + + 40 + 120 + auto + 10 + font10 + center + center + FFAAAAAA + + !Control.HasFocus(501) + + + 40 + 120 + auto + 10 + font10 + center + center + + + Control.HasFocus(501) + + + + + + + + Control.HasFocus(100) | Control.HasFocus(501) | !String.IsEmpty(Window.Property(button.seek)) + 0 + 896 + + -50 + 0 + + Visible + 0 + 0 + 101 + 39 + script.plex/indicators/player-selection-time_box.png + D0000000 + + + 0 + 0 + 101 + 40 + font10 + center + center + FFFFFFFF + + + + + Visible + -6 + 39 + 15 + 7 + script.plex/indicators/player-selection-time_arrow.png + D0000000 + + + + + + 30 + 797 + 1670 + 143 + right + horizontal + + [!String.IsEmpty(Window.Property(show.markerSkip)) + String.IsEmpty(Window.Property(show.markerSkip_OSDOnly))] | [!String.IsEmpty(Window.Property(show.markerSkip_OSDOnly)) + !String.IsEmpty(Window.Property(show.OSD))] + Focus + UnFocus + + + + auto + 143 + center + 0 + 0 + script.plex/buttons/blank-focus.png + script.plex/buttons/blank.png + 70 + FF000000 + FF000000 + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-settings.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-settings.xml new file mode 100644 index 0000000000..3e2cdece47 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-settings.xml @@ -0,0 +1,684 @@ + + + 300 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + + Conditional + 0 + 0 + + + Conditional + + 843 + 135 + 1077 + 945 + script.plex/white-square.png + 32111111 + + + 0 + 810 + 1920 + 270 + script.plex/white-square.png + 32000000 + + + + 843 + 810 + 1077 + 270 + script.plex/white-square.png + 32111111 + + + Conditional + 1920 + 135 + 879 + 945 + script.plex/white-square.png + 66111111 + + + + + Control.HasFocus(100) | Control.HasFocus(125) + 903 + 870 + 1017 + 170 + font10 + FFFFFFFF + left + 200 + + + + + + 248 + 168 + 75 + + 0 + 0 + 590 + 666 + 201 + 100 + 200 + vertical + + + + 88 + 40 + + 0 + 0 + 414 + 75 + font12 + left + center + FFFFFFFF + + + + 0 + 75 + 414 + 2 + script.plex/white-square.png + 661F1F1F + + + + + + ControlGroup(50).HasFocus(0) + + 0 + 0 + 590 + 155 + script.plex/drop-shadow.png + + + Control.HasFocus(75) + 40 + 40 + 510 + 75 + script.plex/white-square-rounded.png + + + !Control.HasFocus(75) + 40 + 40 + 510 + 75 + script.plex/white-square-rounded.png + + + !Control.HasFocus(75) + 512 + 66 + 16 + 23 + script.plex/settings/expanded.png + FF000000 + + + 88 + 40 + 414 + 75 + font12 + left + center + FF000000 + + + + + !ControlGroup(50).HasFocus(0) + 88 + 40 + 414 + 75 + font12 + left + center + FFFFFFFF + + + + + + + Integer.IsGreater(Container(100).NumItems,0) + String.IsEmpty(Window.Property(section.about)) + 604 + 0 + 776 + 666 + 75 + 150 + 200 + vertical + 101 + + + + 88 + 40 + + 0 + 0 + 500 + 75 + font12 + left + center + FFFFFFFF + + + + 200 + 0 + 400 + true + 25 + 75 + font12 + right + center + FFFFFFFF + + + + 0 + 75 + 600 + 2 + script.plex/white-square.png + 661F1F1F + + + + 643 + 55 + + !String.IsEmpty(ListItem.Property(checkbox)) + 0 + 0 + 45 + 45 + script.plex/settings/checkbox.png + + + !String.IsEmpty(ListItem.Property(checkbox.checked)) + 0 + 0 + 45 + 45 + script.plex/settings/checkmark.png + + + + + + Control.HasFocus(100) | Control.HasFocus(125) + + 0 + 0 + 776 + 155 + script.plex/drop-shadow.png + + + !Control.HasFocus(125) + 40 + 40 + 696 + 75 + script.plex/white-square-rounded.png + + + Control.HasFocus(125) + 40 + 40 + 696 + 75 + script.plex/white-square-rounded.png + + + Control.HasFocus(125) + 698 + 66 + 16 + 23 + script.plex/settings/expanded.png + FF000000 + + + 88 + 40 + + 0 + 0 + 500 + 75 + font12 + left + center + FF000000 + + + + 200 + 0 + 400 + 75 + font12 + right + center + FF000000 + + + + + + !Control.HasFocus(100) + !Control.HasFocus(125) + 88 + 40 + + 0 + 0 + 400 + 75 + font12 + left + center + FFFFFFFF + + + + 200 + 0 + 400 + 75 + font12 + right + center + FFFFFFFF + + + + 0 + 75 + 600 + 2 + script.plex/white-square.png + 661F1F1F + + + + 643 + 55 + + !String.IsEmpty(ListItem.Property(checkbox)) + 0 + 0 + 45 + 45 + script.plex/settings/checkbox.png + + + !String.IsEmpty(ListItem.Property(checkbox.checked)) + 0 + 0 + 45 + 45 + script.plex/settings/checkmark.png + + + + + + + Control.IsVisible(100) + !Control.IsVisible(125) + 1388 + 40 + 9 + 525 + true + script.plex/white-square-rounded-4r.png + script.plex/white-square-rounded-4r.png + script.plex/white-square-rounded-4r.png + - + - + false + vertical + false + 151 + + + + Integer.IsGreater(Container(100).NumItems,0) + String.IsEmpty(Window.Property(section.about)) + 10 + 10 + 125 + 100 + font12 + FF000000 + - + - + + SetFocus(100) + + + + Control.HasFocus(125) + Integer.IsGreater(Container(100).NumItems,0) + Integer.IsGreater(Container(100).NumItems,0) + String.IsEmpty(Window.Property(section.about)) + + 1383 + 0 + 845 + 566 + 100 + 200 + vertical + 126 + + + + 88 + 40 + + 0 + 0 + 594 + 75 + font12 + left + center + FFFFFFFF + + + + 0 + 75 + 594 + 2 + script.plex/white-square.png + 661F1F1F + + + + 637 + 55 + + !String.IsEmpty(ListItem.Property(checkbox.checked)) + 0 + 0 + 45 + 45 + script.plex/settings/checkmark.png + + + + + + 0 + 0 + 610 + 155 + script.plex/drop-shadow.png + + + 40 + 40 + 690 + 75 + script.plex/white-square-rounded.png + + + 88 + 40 + + 0 + 0 + 594 + 75 + font12 + left + center + FF000000 + + + + + 637 + 55 + + !String.IsEmpty(ListItem.Property(checkbox.checked)) + 0 + 0 + 45 + 45 + script.plex/settings/checkmark.png + + + + + + + Control.IsVisible(125) + 2161 + 40 + 9 + 525 + true + script.plex/white-square-rounded-4r.png + script.plex/white-square-rounded-4r.png + script.plex/white-square-rounded-4r.png + - + - + false + vertical + false + 151 + + + + + + + + 201 + 0 + 0 + 1920 + 135 + + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font12 + left + center + FFFFFFFF + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 201 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-settings_select_dialog.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-settings_select_dialog.xml new file mode 100644 index 0000000000..f619fa164c --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-settings_select_dialog.xml @@ -0,0 +1,94 @@ + + + + 1 + 0 + 0 + + + + + 660 + 145 + + -40 + -40 + 680 + 870 + script.plex/drop-shadow.png + + + 0 + 0 + 600 + 80 + script.plex/white-square-top-rounded.png + F21F1F1F + + + 0 + 80 + 600 + 710 + script.plex/white-square-top-rounded.png + F2606060 + + + 0 + 0 + 600 + 80 + font12 + center + center + FFFFFFFF + + + + 0 + 80 + 600 + 700 + noop + noop + 200 + vertical + + + + 20 + 0 + 560 + 100 + font12 + left + center + FFFFFFFF + + + + + + 0 + 0 + 600 + 100 + script.plex/white-square.png + + + 20 + 0 + 560 + 100 + font12 + left + center + FF000000 + + + + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-signin_background.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-signin_background.xml new file mode 100644 index 0000000000..4747d54736 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-signin_background.xml @@ -0,0 +1,21 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + + 0 + 0 + 1920 + 1080 + script.plex/sign_in/back.jpg + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-signin_blank.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-signin_blank.xml new file mode 100644 index 0000000000..91e3fae5ee --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-signin_blank.xml @@ -0,0 +1,49 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + + 0 + 0 + 1920 + 1080 + script.plex/sign_in/back.jpg + + + + 210 + 375 + 1502 + 530 + font13 + FFFFFFFF + left + + + + + 0 + 0 + 1920 + 1080 + font20 + FFFFFFFF + FFFFFFFF + center + center + - + - + 0 + 0 + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-slideshow.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-slideshow.xml new file mode 100644 index 0000000000..869b7255bc --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-slideshow.xml @@ -0,0 +1,63 @@ + + 6 + + + + 0 + 0 + 1920 + 1080 + + keep + 1000 + $INFO[Window.Property(thumb)] + + + 20 + 20 + 100 + 1880 + + String.IsEqual(Window.Property(align),0) + 0 + 50 + font45 + left + FFFFFFFF + FF000000 + + + + String.IsEqual(Window.Property(align),0) + 50 + 20 + font13 + left + FFFFFFFF + FF000000 + + + + String.IsEqual(Window.Property(align),1) + 0 + 50 + font45 + right + FFFFFFFF + FF000000 + + + + String.IsEqual(Window.Property(align),1) + 50 + 20 + font13 + right + FFFFFFFF + FF000000 + + + + + + \ No newline at end of file diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-squares.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-squares.xml new file mode 100644 index 0000000000..eac7b3e1d1 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-squares.xml @@ -0,0 +1,769 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + + Conditional + Conditional + 0 + 135 + 101 + + + VisibleChange + !Integer.IsGreater(Container(101).ListItem.Property(index),5) + String.IsEmpty(Window.Property(no.content)) + String.IsEmpty(Window.Property(no.content.filtered)) + !String.IsEmpty(Window.Property(initialized)) + 301 + 30 + -25 + 1000 + 145 + 200 + 101 + -20 + horizontal + 200 + true + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + + + + + !String.IsEqual(Window(10000).Property(script.plex.item.type),collection) | String.IsEqual(Window.Property(media),collection) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/shuffle-focus.png + script.plex/buttons/shuffle.png + + + + + String.IsEmpty(Window.Property(no.options)) | Player.HasAudio + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/more-focus.png + script.plex/buttons/more.png + + + + + String.IsEmpty(Window.Property(hide.filteroptions)) + Focus + UnFocus + 0 + 0 + 126 + 100 + font12 + script.plex/buttons/chapters-focus.png + script.plex/buttons/chapters.png + + + + + + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 101 + 0 + 0 + 1920 + 1080 + + + 0 + 0 + 1800 + 1280 + 300 + 151 + 200 + vertical + 2 + 152 + + + + 55 + 97 + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(is.folder)) + 0 + 244 + 244 + 40 + script.plex/white-square.png + 80000000 + + + false + 0 + 260 + 244 + 40 + font10 + center + center + FFFFFFFF + + + + + + + + + + 55 + 97 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(101) + + String.IsEmpty(ListItem.Property(is.folder)) + -40 + -40 + 334 + 334 + script.plex/drop-shadow.png + + + !String.IsEmpty(ListItem.Property(is.folder)) + -40 + -40 + 334 + 374 + script.plex/drop-shadow.png + + + + 5 + 5 + + 0 + 0 + 244 + 244 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(is.folder)) + 0 + 244 + 244 + 40 + script.plex/white-square.png + 80000000 + + + Control.HasFocus(101) + 0 + 260 + 244 + 40 + font10 + center + center + FFFFFFFF + + + + + Control.HasFocus(101) + + String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 254 + 254 + script.plex/home/selected.png + + + !String.IsEmpty(ListItem.Property(is.folder)) + 0 + 0 + 254 + 294 + script.plex/home/selected.png + + + + + + + + + + + String.IsEqual(Window(10000).Property(script.plex.sort),titleSort) + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 151 + 1780 + 150 + 20 + 920 + + 0 + 0 + 34 + 1050 + 100 + 152 + 200 + vertical + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + + + + + 0 + 0 + + 0 + 0 + + !String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(letter)) + 0 + 0 + 34 + 32 + font10 + center + center + 99FFFFFF + + + + String.IsEqual(Window(10000).Property(script.plex.key), ListItem.Property(key)) + 0 + 0 + 34 + 32 + font10 + center + center + FFE5A00D + + + + + + Control.HasFocus(151) + 0 + 0 + + Control.HasFocus(151) + 0 + 0 + 34 + 34 + FFE5A00D + script.plex/white-outline-rounded.png + + + + + + + + + + 1860 + 150 + 12 + 910 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + + + Conditional + 201 + 0 + 0 + 1920 + 135 + !String.IsEmpty(Window.Property(initialized)) + + VisibleChange + ControlGroup(200).HasFocus(0) + Integer.IsGreater(Container(101).ListItem.Property(index),5) + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font12 + left + center + FFFFFFFF + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 211 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + String.IsEmpty(Window.Property(hide.filteroptions)) + 340 + 35 + 1000 + 65 + right + 30 + horizontal + 204 + 210 + 50 + + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 0 + 0 + + + + auto + 65 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + !String.IsEqual(Window.Property(media),artist) + false + auto + 65 + font12 + FFFFFFFF + FFFFFFFF + FFFFFFFF + center + center + - + - + 20 + 0 + + + + String.IsEqual(Window.Property(media),artist) + auto + 65 + font12 + FFFFFFFF + FF000000 + FFFFFFFF + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + auto + 65 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square-rounded.png + - + 20 + 0 + + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(no.content)) + 0 + 465 + + false + 60 + 0 + 1800 + 35 + font13 + center + FFFFFFFF + + + + false + 60 + 60 + 1800 + 35 + font13 + center + FFCCCCCC + + + + + + !String.IsEmpty(Window.Property(no.content.filtered)) + 0 + 465 + + false + 60 + 0 + 1800 + 35 + font13 + center + FFFFFFFF + + + + false + 60 + 60 + 1800 + 35 + font13 + center + FFCCCCCC + + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-track_context.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-track_context.xml new file mode 100644 index 0000000000..1597a70534 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-track_context.xml @@ -0,0 +1,67 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 236 + 131 + 638 + 638 + $INFO[Window.Property(track.thumb)] + + + + 236 + 131 + 1502 + 530 + font13 + FFFFFFFF + left + + + + + VisibleChange + 301 + 965 + 131 + 750 + 638 + 30 + vertical + 200 + + 30 + 30 + 1920 + 1080 + font20 + FFFFFFFF + FFFFFFFF + center + center + - + - + 0 + 0 + + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-user_select.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-user_select.xml new file mode 100644 index 0000000000..143893c08b --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-user_select.xml @@ -0,0 +1,901 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour_opaque)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + + + Conditional + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 441 + 780 + + + 0 + 0 + 225 + 225 + $INFO[Player.Art(thumb)] + + + + 255 + 0 + + 0 + 0 + 783 + 40 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 0 + 40 + 783 + 40 + font10 + left + center + FFFFFFFF + MusicPlayer.Album + + + 0 + 80 + 783 + 40 + font10 + left + center + FFFFFFFF + + + + + + 406 + + 255 + 134 + 783 + 124 + center + 101 + -40 + horizontal + 200 + true + + + MusicPlayer.HasPrevious + Focus + UnFocus + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + PlayerControl(Previous) + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/pause-focus.png + script.plex/buttons/pause.png + Player.Paused | Player.Forwarding | Player.Rewinding + script.plex/buttons/play-focus.png + script.plex/buttons/play.png + PlayerControl(Play) + + + + MusicPlayer.HasNext + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/next-focus.png + script.plex/buttons/next.png + PlayerControl(Next) + + + + Focus + UnFocus + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/stop-focus.png + script.plex/buttons/stop.png + PlayerControl(Stop) + + + + + + 255 + 177 + 783 + 40 + font10 + left + center + FFFFFFFF + MusicPlayer.Time + + + 1038 + 177 + 783 + 40 + font10 + right + center + FFFFFFFF + MusicPlayer.TimeRemaining + + + + + Progressbar + 255 + 222 + 783 + 3 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + + ControlGroup(400).HasFocus(0) + 770 + 275 + 380 + 695 + script.plex/drop-shadow.png + + + + 0 + 315 + 101 + + + -180 + -40 + 2100 + 455 + 200 + 500 + 600 + 400 + horizontal + 3 + + + + + + 0 + 40 + 300 + 300 + + 0 + 0 + $INFO[ListItem.Property(back.image)] + FFA0A0A0 + + + + 45 + 45 + 210 + 210 + script.plex/user_select/avatar-background.png + E0C0C0C0 + + + 54 + 54 + 192 + 192 + $INFO[ListItem.Thumb] + + + String.IsEmpty(ListItem.Thumb) + 54 + 54 + 192 + 192 + WeatherTemp + center + center + FFFFFFFF + + + + + !String.IsEmpty(ListItem.Property(protected)) + 15 + 231 + + 0 + 0 + 54 + 54 + script.plex/user_select/protected-back.png + A0000000 + + + 0 + 0 + 54 + 54 + script.plex/user_select/protected-icon.png + + + + + !String.IsEmpty(ListItem.Property(admin)) + 231 + 231 + + 0 + 0 + 54 + 54 + script.plex/user_select/admin-back.png + A0000000 + + + 0 + 0 + 54 + 54 + script.plex/user_select/admin-icon.png + + + + + + + + + + + 0 + 40 + + Control.HasFocus(101) + -40 + -40 + 380 + 455 + script.plex/drop-shadow.png + + + Control.HasFocus(101) | ControlGroup(400).HasFocus(0) + 0 + 0 + 300 + 300 + $INFO[ListItem.Property(back.image)] + FFA0A0A0 + + + !Control.HasFocus(101) + !ControlGroup(400).HasFocus(0) + 0 + 0 + 300 + 300 + $INFO[ListItem.Property(back.image)] + FFA0A0A0 + + + Control.HasFocus(101) + + 0 + 300 + 300 + 75 + script.plex/user_select/item-background-bottom.png + FF000000 + + + 0 + 300 + 300 + 75 + $INFO[ListItem.Property(back.image)] + stretch + 40FFFFFF + + + + + !Control.HasFocus(101) + !ControlGroup(400).HasFocus(0) + 45 + 45 + 210 + 210 + script.plex/user_select/avatar-background.png + E0C0C0C0 + + + ControlGroup(400).HasFocus(0) + 45 + 45 + 210 + 210 + script.plex/user_select/avatar-background.png + FFCC7B19 + + + Control.HasFocus(101) + 45 + 45 + 210 + 210 + script.plex/user_select/avatar-background.png + FFE5A00D + + + + 54 + 54 + 192 + 192 + $INFO[ListItem.Thumb] + + + String.IsEmpty(ListItem.Thumb) + 54 + 54 + 192 + 192 + WeatherTemp + center + center + FFFFFFFF + + + + + !String.IsEmpty(ListItem.Property(protected)) + 15 + 231 + + 0 + 0 + 54 + 54 + script.plex/user_select/protected-back.png + A0000000 + + + 0 + 0 + 54 + 54 + script.plex/user_select/protected-icon.png + + + + + !String.IsEmpty(ListItem.Property(admin)) + 231 + 231 + + 0 + 0 + 54 + 54 + script.plex/user_select/admin-back.png + A0000000 + + + 0 + 0 + 54 + 54 + script.plex/user_select/admin-icon.png + + + + + Control.HasFocus(101) + 10 + 300 + 280 + 75 + font13 + center + center + FFCC7B19 + + + + + + + + + 205 + !String.IsEmpty(Container(101).ListItem.Property(protected)) + ControlGroup(400).HasFocus(0) + !String.IsEmpty(Window.Property(initialized)) + 810 + 375 + + 0 + 0 + 300 + 239 + 400 + 400 + 400 + 400 + - + - + + + + 0 + -75 + 300 + 75 + script.plex/white-square.png + FF000000 + + + 0 + -75 + 300 + 75 + $INFO[Container(101).ListItem.Property(back.image)] + 40FFFFFF + + + String.IsEmpty(Container(101).ListItem.Property(editing.pin)) + 0 + -75 + 300 + 75 + font13 + center + center + FFCC7B19 + + + + !String.IsEmpty(Container(101).ListItem.Property(editing.pin)) + 0 + -75 + 300 + 75 + font13 + center + center + FFCC7B19 + + + + 0 + 0 + 300 + 239 + script.plex/white-square.png + FF000000 + + + 205 + + 205 + + 0 + 0 + 73 + 58 + 202 + 101 + 204 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square.png + script.plex/white-square.png + 0 + 0 + + + + 75 + 0 + 73 + 58 + 203 + 201 + 101 + 205 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square.png + script.plex/white-square.png + 0 + 0 + + + + 150 + 0 + 73 + 58 + 211 + 202 + 101 + 206 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square.png + script.plex/white-square.png + 0 + 0 + + + + 0 + 60 + 73 + 58 + 205 + 207 + 201 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square.png + script.plex/white-square.png + 0 + 0 + + + + 75 + 60 + 73 + 58 + 206 + 204 + 208 + 202 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square.png + script.plex/white-square.png + 0 + 0 + + + + 150 + 60 + 73 + 58 + 211 + 205 + 209 + 203 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square.png + script.plex/white-square.png + 0 + 0 + + + + 0 + 120 + 73 + 58 + 208 + 210 + 204 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square.png + script.plex/white-square.png + 0 + 0 + + + + 75 + 120 + 73 + 58 + 209 + 207 + 210 + 205 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square.png + script.plex/white-square.png + 0 + 0 + + + + 150 + 120 + 73 + 58 + 211 + 208 + 210 + 206 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square.png + script.plex/white-square.png + 0 + 0 + + + + + 0 + 180 + 223 + 59 + 211 + 200 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/white-square.png + script.plex/white-square.png + 0 + 0 + + + + + 225 + 0 + 75 + 239 + 300 + 101 + font12 + FFFFFFFF + FF000000 + center + center + script.plex/user_select/backspace.png + script.plex/user_select/backspace_nf.png + 0 + 0 + + + + + + + + 201 + 0 + 0 + 1920 + 135 + + 0 + 0 + 1920 + 135 + script.plex/white-square.png + 19000000 + + + + 60 + 34.5 + 1000 + 66 + left + 60 + horizontal + 101 + true + + 0 + 0 + 124 + 66 + + 0 + 0 + 124 + 66 + 101 + 101 + right + center + script.plex/white-square-rounded.png + - + + + + !String.IsEmpty(Window.Property(dropdown)) + 0 + 0 + 124 + 66 + script.plex/white-square-rounded.png + + + 27 + 13 + + !Control.HasFocus(500) + String.IsEmpty(Window.Property(dropdown)) + 0 + 0 + + 0 + 0 + 40 + 40 + script.plex/buttons/power.png + + + 55 + 13.5 + 15 + 13 + script.plex/indicators/dropdown-triangle.png + + + + Control.HasFocus(500) | !String.IsEmpty(Window.Property(dropdown)) + 0 + 0 + + 0 + 0 + 40 + 40 + script.plex/buttons/power.png + + + 55 + 13.5 + 15 + 13 + script.plex/indicators/dropdown-triangle.png + + + + + + -27 + 0 + auto + 66 + font12 + left + center + FFFFFFFF + + + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(busy)) + Visible + + 840 + 465 + 240 + 150 + script.plex/busy-back.png + A0FFFFFF + + + 915 + 521 + 90 + 38 + script.plex/busy.gif + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-video_current_playlist.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-video_current_playlist.xml new file mode 100644 index 0000000000..796140288d --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-video_current_playlist.xml @@ -0,0 +1,480 @@ + + + 100 + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + + + 101 + 750 + 140 + 1170 + 800 + + 0 + 0 + 1170 + 800 + script.plex/white-square.png + B3111111 + + + 0 + 0 + 1170 + 800 + 200 + 152 + 300 + 200 + vertical + 4 + 152 + + + + 120 + 24 + + String.IsEmpty(ListItem.Property(playing)) + -10 + 0 + 60 + 100 + font10 + center + center + D8FFFFFF + + + + !String.IsEmpty(ListItem.Property(playing)) + 2 + 32.5 + 35 + 35 + script.plex/indicators/playing-circle.png + FFE5A00D + + + String.IsEmpty(ListItem.Property(video)) + + 63 + 11 + 74 + 74 + $INFO[ListItem.Thumb] + scale + + + 168 + 0 + + 0 + 15 + 692 + 30 + font10 + left + center + FFFFFFFF + + + + 0 + 50 + 692 + 30 + font10 + left + center + B8FFFFFF + + + + + + !String.IsEmpty(ListItem.Property(video)) + + 63 + 11 + 132 + 74 + $INFO[ListItem.Thumb] + scale + + + String.IsEmpty(ListItem.Property(watched)) + 895 + -1 + 35 + 35 + script.plex/indicators/unwatched.png + + + 226 + 0 + + 0 + 15 + 584 + 30 + font10 + left + center + FFFFFFFF + + + + 0 + 50 + 584 + 30 + font10 + left + center + B8FFFFFF + + + + + + 730 + 0 + 200 + 100 + font10 + right + center + D8FFFFFF + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 98 + 930 + 2 + script.plex/white-square.png + 40000000 + + + + + + + + + !Control.HasFocus(101) + 120 + 24 + + String.IsEmpty(ListItem.Property(playing)) + -10 + 0 + 60 + 100 + font10 + center + center + D8FFFFFF + + + + !String.IsEmpty(ListItem.Property(playing)) + 0 + 32.5 + 35 + 35 + script.plex/indicators/playing-circle.png + FFE5A00D + + + String.IsEmpty(ListItem.Property(video)) + + 63 + 11 + 74 + 74 + $INFO[ListItem.Thumb] + scale + + + 168 + 0 + + 0 + 15 + 692 + 30 + font10 + left + center + FFFFFFFF + + + + 0 + 50 + 692 + 30 + font10 + left + center + B8FFFFFF + + + + + + !String.IsEmpty(ListItem.Property(video)) + + 63 + 11 + 132 + 74 + $INFO[ListItem.Thumb] + scale + + + String.IsEmpty(ListItem.Property(watched)) + 895 + -1 + 35 + 35 + script.plex/indicators/unwatched.png + + + 226 + 0 + + 0 + 15 + 584 + 30 + font10 + left + center + FFFFFFFF + + + + 0 + 50 + 584 + 30 + font10 + left + center + B8FFFFFF + + + + + + 756 + 0 + 200 + 100 + font10 + right + center + D8FFFFFF + + + + String.IsEmpty(ListItem.Property(is.footer)) + 0 + 97 + 930 + 2 + script.plex/white-square.png + 40000000 + + + + + Control.HasFocus(101) + 63 + 21 + + -40 + -40 + 1124 + 180 + script.plex/square-rounded-shadow.png + + + 0 + 0 + 1044 + 100 + script.plex/white-square-rounded.png + FFE5A00D + + + + + String.IsEmpty(ListItem.Property(playing)) + 24 + 0 + 60 + 100 + font12 + center + center + B8000000 + + + + !String.IsEmpty(ListItem.Property(playing)) + 36 + 32.5 + 35 + 35 + script.plex/indicators/playing-circle.png + FF000000 + + + String.IsEmpty(ListItem.Property(video)) + + String.IsEmpty(ListItem.Property(video)) + 103 + 0 + 100 + 100 + $INFO[ListItem.Thumb] + scale + + + 235 + 0 + + 0 + 16 + 638 + 30 + font12 + left + center + DF000000 + + + + 0 + 51 + 638 + 30 + font10 + left + center + 98000000 + + + + + + !String.IsEmpty(ListItem.Property(video)) + + 103 + 0 + 178 + 100 + $INFO[ListItem.Thumb] + scale + + + String.IsEmpty(ListItem.Property(watched)) + 951 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + 313 + 0 + + 0 + 16 + 510 + 30 + font12 + left + center + DF000000 + + + + 0 + 51 + 510 + 30 + font10 + left + center + 98000000 + + + + + + 802 + 0 + 200 + 100 + font12 + right + center + B8000000 + + + + + + + + + + + 1128 + 33 + 10 + 734 + 101 + true + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + script.plex/white-square-rounded.png + - + - + false + vertical + false + 151 + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-video_player.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-video_player.xml new file mode 100644 index 0000000000..12d2f4f3b6 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-video_player.xml @@ -0,0 +1,1343 @@ + + + + 1 + 0 + 0 + + $INFO[Window.Property(background_colour)] + + + String.IsEmpty(Window.Property(use_solid_background)) + + !String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background_static)] + + + String.IsEmpty(Window.Property(use_bg_fallback)) + 0 + 0 + 1920 + 1080 + 1000 + $INFO[Window.Property(background)] + + + + !String.IsEmpty(Window.Property(post.play)) + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(post.play.background)] + + + + + Conditional + + + + + + + + + + 0 + 135 + 102 + + + 60 + 0 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + + false + 60 + 57 + 462 + 40 + font12 + left + center + A0FFFFFF + + + + + 102 + + 0 + 0 + 1920 + 580 + + 60 + 131 + + Conditional + 0 + 0 + + Control.HasFocus(101) + -45 + -45 + 552 + 349 + script.plex/drop-shadow.png + + + 0 + 0 + + 0 + 0 + 462 + 259 + $INFO[Window.Property(thumb.fallback)] + scale + + + 0 + 0 + 462 + 259 + $INFO[Window.Property(prev.thumb)] + scale + + + 193 + 91.5 + + 0 + 0 + 76 + 76 + script.plex/indicators/circle-152.png + + + 15 + 15 + 46 + 46 + script.plex/indicators/replay.png + + + + false + 0 + 269 + 462 + 35 + font10 + center + FFFFFFFF + + + + false + 0 + 301 + 462 + 35 + font10 + center + FFFFFFFF + + + + + -5 + -5 + 472 + 269 + 200 + 400 + 102 + script.plex/home/selected.png + - + + + + + + !String.IsEmpty(Window.Property(has.next)) + + false + 572 + 57 + 462 + 40 + font12 + left + center + FFFFFFFF + + + + 582 + 131 + + Conditional + 0 + 0 + + Control.HasFocus(102) + -45 + -45 + 627 + 393 + script.plex/drop-shadow.png + + + 0 + 0 + + 0 + 0 + 537 + 303 + $INFO[Window.Property(thumb.fallback)] + scale + + + 0 + 0 + 537 + 303 + $INFO[Window.Property(next.thumb)] + scale + + + !String.IsEmpty(Window.Property(countdown)) + Integer.IsGreaterOrEqual(Window.Property(countdown), 0) + 192.5 + 75.5 + + 0 + 0 + 152 + 152 + script.plex/indicators/circle-152.png + + + 8 + 8 + 136 + 136 + script.plex/circle-progress/$INFO[Window.Property(countdown)].png + + + 59.5 + 57 + 33 + 38 + script.plex/indicators/pause.png + + + + false + 0 + 313 + 537 + 30 + font10 + center + FFFFFFFF + + + + false + 0 + 345 + 537 + 30 + font10 + center + FFFFFFFF + + + + + -5 + -5 + 547 + 313 + 200 + 400 + 101 + script.plex/home/selected.png + - + + + + + + + + !String.IsEmpty(Window.Property(has.next)) + + false + 1177 + 131 + 683 + 43 + font13 + left + center + FFFFFFFF + + + + false + 1177 + 189 + 683 + 32 + font12 + left + center + A0FFFFFF + + + + false + 1177 + 300 + 683 + 215 + font12 + left + FFFFFFFF + + + + + + String.IsEmpty(Window.Property(has.next)) + + false + 580 + 131 + 1280 + 43 + font13 + left + center + FFFFFFFF + + + + false + 580 + 189 + 1280 + 32 + font12 + left + center + A0FFFFFF + + + + false + 580 + 300 + 1280 + 225 + font12 + left + FFFFFFFF + + + + + + + 0 + 585 + 1920 + 1610 + + 300 + 0 + + + Integer.IsGreater(Container(400).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 360 + 1920 + + 0 + 0 + 1920 + 360 + script.plex/white-square.png + 40000000 + + + 60 + 0 + 800 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 18 + 1920 + 430 + 100 + 401 + false + false + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 299 + 168 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 299 + 168 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 158 + + 0 + 0 + 299 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 299 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 264 + 0 + 35 + 35 + script.plex/indicators/unwatched.png + + + false + 0 + 180 + 299 + 35 + font10 + center + FFFFFFFF + + + + false + 0 + 212 + 299 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 299 + 168 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 119 + 34 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 119 + 34 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 85.5 + 20 + 128 + 128 + script.plex/home/busy.gif + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(400) + -40 + -40 + 389 + 258 + script.plex/drop-shadow.png + + + 5 + 5 + + 0 + 0 + 299 + 168 + $INFO[ListItem.Property(thumb.fallback)] + scale + + + 0 + 0 + 299 + 168 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 158 + + 0 + 0 + 299 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 299 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 264 + 0 + 35 + 35 + script.plex/indicators/unwatched.png + + + false + 0 + 180 + 299 + 35 + font10 + center + FFFFFFFF + + + + false + 0 + 212 + 299 + 35 + font10 + center + FFFFFFFF + + + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 299 + 168 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 119 + 34 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 119 + 34 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 85.5 + 20 + 128 + 128 + script.plex/home/busy.gif + + + + + Control.HasFocus(400) + 0 + 0 + 309 + 178 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(401).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 401 + 1920 + 520 + + !String.IsEmpty(Window.Property(divider.401)) + 60 + 0 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 0 + 1000 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 16 + 1920 + 520 + 400 + 403 + false + false + 200 + horizontal + 4 + + + + 55 + 72 + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 369 + 244 + 38 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 72 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(401) + -40 + -40 + 324 + 441 + script.plex/drop-shadow.png + + + 5 + 5 + + !String.IsEmpty(ListItem.Property(is.boundary)) + + 0 + 0 + 244 + 361 + script.plex/white-square.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(right.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white.png + + + String.IsEmpty(ListItem.Property(is.updating)) + !String.IsEmpty(ListItem.Property(left.boundary)) + 91.5 + 130.5 + 61 + 100 + script.plex/indicators/chevron-white-l.png + + + !String.IsEmpty(ListItem.Property(is.updating)) + 58 + 116.5 + 128 + 128 + script.plex/home/busy.gif + + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Property(thumb.fallback)] + + + 0 + 0 + 244 + 361 + $INFO[ListItem.Thumb] + scale + + + !String.IsEmpty(ListItem.Property(progress)) + 0 + 351 + + 0 + 0 + 244 + 10 + script.plex/white-square.png + C0000000 + + + 0 + 1 + 244 + 8 + $INFO[ListItem.Property(progress)] + FFCC7B19 + + + + !String.IsEmpty(ListItem.Property(unwatched)) + 196 + 0 + 48 + 48 + script.plex/indicators/unwatched.png + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 193 + 0 + 51 + 39 + script.plex/white-square.png + FF000000 + + + 194 + 0 + 50 + 38 + script.plex/white-square.png + FFCC7B19 + + + 194 + 0 + 50 + 38 + font12 + center + center + FF000000 + + + + + false + 0 + 369 + 244 + 38 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(401) + 0 + 0 + 254 + 371 + script.plex/home/selected.png + + + + + + + + + Integer.IsGreater(Container(403).NumItems,0) + String.IsEmpty(Window.Property(drawing)) + 403 + 1920 + 410 + + !String.IsEmpty(Window.Property(divider.403)) + 60 + 20 + 1800 + 2 + script.plex/white-square.png + A0000000 + + + 60 + 20 + 1000 + 80 + font12 + left + center + FFFFFFFF + + + + 0 + 36 + 1920 + 410 + 401 + 404 + 200 + horizontal + 4 + + + + 55 + 61 + + 5 + 5 + + 0 + 0 + 244 + 244 + script.plex/thumb_fallbacks/role.png + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + 0 + 253 + 244 + 90 + font10 + center + FFFFFFFF + + + + + + + + + + 55 + 61 + + Focus + UnFocus + 0 + 0 + + Control.HasFocus(403) + -40 + -40 + 334 + 334 + script.plex/buttons/role-shadow.png + + + 5 + 5 + + 0 + 0 + 244 + 244 + script.plex/thumb_fallbacks/role.png + + + 0 + 0 + 244 + 244 + $INFO[ListItem.Thumb] + scale + + + 0 + 253 + 244 + 90 + font10 + center + FFFFFFFF + + + + + Control.HasFocus(403) + 0 + 0 + 254 + 254 + script.plex/buttons/role-selected.png + + + + + + + + + + + Conditional + 201 + 0 + 0 + 1920 + 135 + + VisibleChange + ControlGroup(200).HasFocus(0) + !String.IsEmpty(Window.Property(on.extras)) + 0 + 0 + 1920 + 135 + script.plex/white-square.png + C0000000 + + + 60 + 47.5 + 1000 + 40 + left + 60 + horizontal + 50 + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 202 + 50 + font12 + FF000000 + script.plex/buttons/home-focus.png + script.plex/buttons/home.png + + + + + auto + 40 + font12 + left + center + FFFFFFFF + + + + 40 + 40 + + Focus + UnFocus + 40 + 40 + 204 + 201 + 50 + font12 + FF000000 + script.plex/buttons/search-focus.png + script.plex/buttons/search.png + + + + + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + 438 + 0 + + Player.HasAudio + String.IsEmpty(Window(10000).Property(script.plex.theme_playing)) + -10 + 38 + 260 + 75 + 202 + 50 + font12 + FFFFFFFF + FF000000 + right + center + script.plex/white-square-rounded.png + - + 100 + 0 + + + + 0 + 48 + 42 + 42 + $INFO[Player.Art(thumb)] + + + + !Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FFFFFFFF + MusicPlayer.Title + + + + Control.HasFocus(204) + + 53 + 48 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Artist + + + 53 + 72 + 187 + 20 + font10 + left + center + FF000000 + MusicPlayer.Title + + + + + Progressbar + 0 + 102 + 240 + 1 + script.plex/white-square-1px.png + - + script.plex/white-square-1px.png + - + - + Player.Progress + + + + 213 + 35 + 200 + 65 + font12 + right + center + FFFFFFFF + + + + 153r + 54 + 93 + 30 + script.plex/home/plex.png + + + + + !String.IsEmpty(Window.Property(search.dialog)) + + !String.IsEmpty(Window.Property(search.dialog.hasresults)) + + 0 + 0 + 1920 + 1080 + script.plex/home/background-fallback.png + + + 0 + 0 + 1920 + 1080 + $INFO[Window.Property(background)] + + + + 0 + 0 + 1920 + 1080 + script.plex/white-square.png + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-video_settings_dialog.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-video_settings_dialog.xml new file mode 100644 index 0000000000..4bf41907b1 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-video_settings_dialog.xml @@ -0,0 +1,159 @@ + + + + 1 + 0 + 0 + + + + + !String.IsEmpty(Window.Property(via.OSD)) + Hidden + 0 + 0 + + 0 + 0 + 1920 + 1080 + script.plex/player-fade.png + FF080808 + + + + !Window.IsVisible(sliderdialog) + !Window.IsVisible(osdvideosettings) + !Window.IsVisible(osdaudiosettings) + !Window.IsVisible(osdsubtitlesettings) + !Window.IsVisible(subtitlesearch) + 460 + 200 + + -40 + -40 + 1080 + 770 + script.plex/drop-shadow.png + + + 0 + 0 + 1000 + 80 + script.plex/white-square-top-rounded.png + F21F1F1F + + + 0 + 80 + 1000 + 610 + script.plex/white-square-top-rounded.png + F2606060 + + + 0 + 80 + 400 + 610 + script.plex/white-square-tl-rounded.png + 30000000 + + + 0 + 0 + 1000 + 80 + font12 + center + center + FFFFFFFF + + + + 0 + 80 + 990 + 600 + noop + noop + 200 + vertical + 101 + 101 + + + + 20 + 0 + 300 + 100 + font12 + left + center + FFFFFFFF + + + + 320 + 0 + 650 + 100 + font12 + right + center + FFFFFFFF + + + + + + 0 + 0 + 1000 + 100 + script.plex/white-square.png + + + 20 + 0 + 300 + 100 + font12 + left + center + FF000000 + + + + 320 + 0 + 650 + 100 + font12 + right + center + FF000000 + + + + + + + + 1450 + 280 + 10 + 600 + 101 + true + script.plex/white-square.png + script.plex/white-square.png + script.plex/white-square.png + - + - + false + vertical + false + 100 + + + + diff --git a/script.plexmod/resources/skins/Main/media/script.plex/busy-back.png b/script.plexmod/resources/skins/Main/media/script.plex/busy-back.png new file mode 100644 index 0000000000000000000000000000000000000000..f193fb26be5d63d86ae77942bb0ba6f50c43ceb9 GIT binary patch literal 1280 zcmeAS@N?(olHy`uVBq!ia0vp^AAooo2OE%l@PqX#kYY>nc6VX;4}uH!E}sk(;Vkfo zEM{QfI|9OtQ?>b|fr9KMp1!W^4_H{l44Ec$S-u1cNtU=qlsM<-=BDPAFgO>bCYGe8 zD3oWGWGJ|M`UZqI@`*Druw;0;IEGZ*dV6RlDKfa16-BPv7Dx|mh|Mah~@=BNQ3cb4~ zFXZ~FYX3*#eb4?>oW8mavJ$dae)9Acw|_(G+0-@K$*l*`|!27D` z$3y#EYtnY>e)PNF_A6-5hI~Ii={cFZ=SDnVZGKkZ+tuRS&B@te2lCBt-sX9;Uwn1^ zD*5uyauqv&t+dL?+hA~Q_4C`GY+tqSW&h`~XF~y>|Lr?v+oZ5L- ze_{ApX13JQ$Esg~zRs>Z@W942ujo~HLWN)N>^a*dCFTh~R#T57u)V&FjUl*2iS{557K9pZ&HEwDxNxYS@InL>NO8*!CtBIeR zS~teo-Yf2TuPP6~n{7c7r+XK(vORBPO#eC+fIK2I;{?*f09XGe_j9h;& z_t?E>m8>z7`)Am#pSLp3pu8eSeAV^U^51@muQ#z|c$9y7lU!x&T(d3j!&Y_A6F7bA z>Mo1*1@6Usl{>A%*FM|eawBK$$;^U%uN31uW2Q8iN3Ze=RbTb^>c&?YUrS0g!rh+y w->Lj6Z}RH7ce0AkeU-ktwd{w@_x-=v6Z)dI*_Q5<2Np~Wp00i_>zopr0E!?(d;kCd literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/busy-diffuse.png b/script.plexmod/resources/skins/Main/media/script.plex/busy-diffuse.png new file mode 100644 index 0000000000000000000000000000000000000000..205b216d198e33c53a94e8ebef2a7a3ba5636952 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^Q9!K5!3HE^8q%{+I4w~^CsQI$yL7S_B zkg!1PtSf?bF4LI*Uk`{Z-_)9Vn+K>52-4EjR!%nYn5DXQ{(FU$%CF5`r93_Ft9tTA z{yyb%EA3YBs}+&a+^SDKQ;vRH*YWO6KX>Y`)wBot+eD;-bHm=b^dEFeUTAnV?Wtdhyv`MIsn7h8a~7|* rbT2m6sW5)BcJYO1_Vwjp=PXFde;;}!a)ZXgr69hitDnm{r-UW|gxQ9f literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/busy.gif b/script.plexmod/resources/skins/Main/media/script.plex/busy.gif new file mode 100644 index 0000000000000000000000000000000000000000..d97a260add8d5d441424419a5008577332922d1f GIT binary patch literal 739 zcmZ?wbhEHbjABq@XyIZ20wHcDK|w(kF%~s(77raxUp-EL1Fl#L?i5>|G&|mj;ezwy zg?AN*?Jf{ISt)U*S`sKoJW~A6?dKX2?CcoeYNTht%m}nk@t>e`QEFmIYKlU6W=V#E zyQgmegW^vXP9p|+1|5)#KyG7Tbzh*=my$UzW7WEx*ZT@|&X?rguUPlK=KcQz3kp1R zr20=RDLR>BHUGkj60fyU>u;q5|AP$`K6XV_&WXVwrzInBN+Gf z?oGYDb2i($jk#B(<;>5nEdBj=rv1CAwaWE=jZMuStxD}3o!!ozzI~1pCQa_0YCUB} z==9mfv*x+XU1+;_iQaU~Z8Glv=Z9xkl?s}>b?+UU(coF?FP*R%2Jnm4m9SNX==Dc9k;e!xmgQCKbHfA#%O|2lz&fTotlx^|z=F4wkRm;MQMlP23too3cEGi>%8 zlNs|37cNp?vebSa(3PuKR;^pSc4O-1Ez39VShs8S9#^c6oCu4iNdcf}+MS(y|K*zZ z`tSa0&nsZlk#aqp^8UmT&G~0D-maVy6?o-I>FHBkI}_fE?-BicB6TxgZRq-&LFR&T zQ%}DrwdT2h<^50hI`0P8CX<%dHi3@LwjPJB?tZ(8lc#h|^P4f#Z0elg+4HsLEwWs= iRDH<`wNlzR_dzmbKfrZQQYY*Sd*{4Auamz&+Xk literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/blank-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/blank-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..4b9fe6b3f73e01e8e0546db371be85f787be4d3f GIT binary patch literal 2808 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/blank.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..11f18ffd590dd4cde507daf5a8ee55f13d993273 GIT binary patch literal 436 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 IIVCg!05oRfA^-pY literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/home-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/home-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..baa780c30894e8027120b16aae1387e2f02f9909 GIT binary patch literal 1303 zcmV+y1?c*TP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00e(YL_t(|+U=Z8Y*bYg$AAAv zHNh!HET$V;Sy*Y48i|&=a6=3mrVHbS;6i2RMxw&j6_uSaHW+tA&_#s>c0<`Tt~3#X z3j--NxKS5oVy76Tl4#(#co&^cU#D;0_q@J;GHKGebMBenymvp&JLifFWoFxemw;!0 zF<=yU0@wjO3OoX=0(ac20sH{m1a1HelI~F!nc03b`@qZ=Eg3DD*@tE}*{eVX%(Y5iQ;FSHW_GS5U;yf2uOKf3m}%g3%B7=W#vpA1rVd=9ysAsO+%+6CdmLy|ehqB2 z4(fDUeaqI+m9EAdxAY##*vV_a5%)LKg<|NfhTBADtz&II9LvFnS{OKAX6VqbW;VQm zAH(kb%y#peff>rsnc0w6@@$4a4RvxPt3cJ^F1Ia*vkI66PUSAtxSaCf_mc}DG$QQl z2Hni^WXeA7lGJRUt=>+#(=(FxL;(XJsUc|(a3*Cx-wFC<(hP=ACF#AHO{E#MZ|`g( zrH+2*RQ=EFc{Ow zKLv#o*RMej=#OdSenH{H^{YP#IAv9TACODBhM8>#UITUk4+k{)+eHaJmvlD=7i)d^ zIe0sA==^Koxe)E%1fI{qzf})EF)PvJl{&|wdCO^ zKv&uT&W(yg@b<$47Ag*bTJT&gK{f8I)lEtFAHV??31+jQJ3Lnd4?M;4%E1>5n6Pk6}r_1j2EE=75*C;8-&!>6O-h z1i`807{`xeEor%FP%Bt0GUMwP)HC4=34pk8t? zQ=Lj2J66rOqKWB}f_Yz3#|?L=Vl-EubhJcZK9lsuW{s*!y$%Xp0P75%?Qt;Y!h(q; zcSc1os_W`tMFez+-ijV}tjJ3gPRlyz3dKK>U@~gDuNSpfNh^{@3cS@gE@>pKJm_w& zqMAE>qzJlLm{U;N<3Tx}pR>F0qn|r@Y1*BPl%|&5>{CV_ns)%FJodLE# zZQqqKsBQQe^W*qQNqh0LS^M3q2KXfI~A=J!dl*DIjSAxC`6^ZjlaazzVQxW>wk&N#S`! z(wwAC<;SL^c}b(uF;WYQh?|!5P13R2hhyiQsUI(`$g)l!SILKUGP~z--K5 z1>l(%i4J4P&iN5{|3!oSw%>iS(BSP~HnWX(Cr#}_P0|#Eo41+m0*|}kzxT+s)CMR2 zOX41$7tcW4Qp+ekB5C6Spx+Nd=DnYwSz;lvD zk}PT3BKmlwh<-ce@2y0N=!ru-OFEM=pCK*)cf8s^0gOfRn?2wwPz62!uYrRspCSGL XzU$zZ1&Zp600000NkvXXu0mjf;m3kH literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/info-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/info-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..407b37b5893395d4f784bf3610a51bc80a02b476 GIT binary patch literal 4487 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/media-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/media-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..a89f1c340e50da762c4e9fbeafe27858164cad5f GIT binary patch literal 3780 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/more-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/more-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..c814cf744c55762032fbc747e9ab2f8063206240 GIT binary patch literal 3286 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 Uh(QGN{Qv*}07*qoM6N<$f+)rw=>Px# literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/more-vertical.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/more-vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..4faa5ce6be3f67da5f9bd01d0c50496e406644a8 GIT binary patch literal 433 zcmeAS@N?(olHy`uVBq!ia0vp^x{XE)7O>#0XvI`h~hjevqL~3$r9Iy66gHf+|;}h2Ir#G#FEq$ zh4Rdj3$B>F!Z|@w;JnSIQ`tW;COgn#=qNlLs62AB~a(5i0 z3M8-D>Z+vv5IOwWl`(me!v>$SL-x~K?>5`9Z8TooJVzzV-px~g+xJONlwO>_ar0h? zv-hQ9*Dn!*wQD-AIk7UEWL#L_*v!T&1!eq|ztFrS?ov@y`%Za-@5g7k-+ufxZ4$d@ zyO^y!4MS~2bA+_$yiEY`0ceb-MFVdQ&MBb@0J*!cLI3~& literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/more.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/more.png new file mode 100644 index 0000000000000000000000000000000000000000..cfd025d39f9268aab287ea046f9e93d194e21356 GIT binary patch literal 663 zcmeAS@N?(olHy`uVBq!ia0vp^TYz{X2OE&gS~F=okYY>nc6VX;4}uH!E}sk(;Vkfo zEC%Yh4#JF18nY{ag6t)pzOL*KSUH8b7`jZ~`7kgrsd&0LhE&{od)F{eI8dbR;{Tnz zqRSR0ae4@D=nWA$$Fzqrg6&>Iw9}mp9bY)59Rh+Cr7k(@x!!4Hk$8M&w&n7|MBCWY z?=PQ_i#Fy2+JFlfh^?J29u?ZHa$3cIvdqn0%{x6d<*m(S*}H#6ylUmbwbom+*6tPg zQrCCpd6iVl<%RMq(`EN`dduGIHk4hs|JNBCiR){(RyY0IzQEg^nQPfrM|0!Nu05R# z1Wh=kSa_SOGo)b`)$o5w@H);1Zl+;zN=Zhh{) zPl4NZNB@`J57%8!v7Y~cC*9JjVC&;u<-&6mU+~r3EWG=i^PE5l`!nlx)dmM8o8BGx z$at+cwQYg*h8u-Y|DQ@!UI^aX^xt=qx#vB#ojGf3 zSFLK_xi|IB=eN(#&XnBGk@g_`L%BDXo9Gt%ACI@l;`eOE3#%8|w^Q_wiF{ew_vYw~ zrnuK9;(F9xT)U-q(#yL%Z|mLe#P63*?~Vk;!<{&nrylX_#S>HRI-kK6Z9wq@JN_^{ WyvcT-{o>YDAZ4DeelF{r5}E*EzYH+| literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/next-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/next-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..b9d5e0aa3ed30c1915272f50900b48e3ca90cdb2 GIT binary patch literal 3894 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/next.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/next.png new file mode 100644 index 0000000000000000000000000000000000000000..6ec144c458cd0d223c43094ccdba8127b2e72eac GIT binary patch literal 923 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/pause.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9f0083e82a1ee3d70a4d67d8dd734d981a22293d GIT binary patch literal 493 zcmeAS@N?(olHy`uVBq!ia0vp^TYz{X2OE&gS~F=okYY>nc6VX;4}uH!E}sk(;Vkfo zEC%Yh4#JF18nY{ag6t)pzOL*K*hIv{ct2=Pdc?rMSmo*B7*cWT?cI&O%!U$e58wB{ zaAG{1GQ+?@tif;xs}Vz_vh869$E?c%K?16~ew_KdMSZT{zxYV?odrxl6LEo_Mbkbl zT)Q=QQtTw(Nn0H*c_EJ1WZbvpA-6Xb|*X6 z+O7R6{QGTwtyy*4`2N#^lYG4k94{yURd7f-Hba>}JrE{XJBSH2sd<4QP#sXz4XTCZ zZ2i+uRp+>mJ^hMe22jbo(=UnhnMuyk&G$?|N<3ZtT-G@yGywoCD6h`| literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/play-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/play-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..e39c5ce15e5266a5de651ccb04d1163d6637c512 GIT binary patch literal 3790 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/pqueue-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/pqueue-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..cd23065b8d62f66b09a5c39c0587c9ac74a7cce1 GIT binary patch literal 4124 zcmaKvbyyQ#_rS-1p(79d)k!zRI z#IIxpdiF^30pRLCC8x14iEO#W4{-Wztz!cnX z6(o)eajS)us`~suz-jX(ifQ<0jY9O}o}5OqMp8>u)CHE`DFTOj!5~M)AQN;S%Ww7w ztN8*fOLd~!x)=&aD&cj^p5H+Lxq;!+RCep$$P(bw`#{Um2RVH}+GW$p4GG%#7J0A} zi!ta?bnbGE8hy))YsB&wmK^W!PSV3f$q0dRdz`g17|KH-PS?r+bSa{65bKfaR$~Ni z0ljQ%-9s}1iv-{w^x~zAedkvMxIpqCBf4@mIO_JW#sUSib@@f+=UfOqo|Ce`t(n2b z7T|viN5oIF+9jbwCJrV4WlV>=`s&&v)jK88B${EkYyM2*y6P;*2S`y4N4T@NfhekJ zKll$n!w3EhDYZ-P68Xa5H62if?3Q&<(8W;;F3aH^zKHtXDB_=fIq(6uEWf|P=a)iR zGN||=hTnwurM_o6ovxt_=N*`+Nu)iNcEI}%{$rI-WK;`X^pX`-OgRGHB~smsL8|eH zjl*!nNONkaW|-!u;f0fWjHp6Tc&d5J?4_72fCSkvfOp5)cJa98byU7*@EFt8y0%*{ z=857jGPGywn5&Q&usWZt=mt)nR&dBiJo@X9czH)H-~A{*u2_p;WMPKLlf4j6^)_cNv=6^#%}L*P={{xUf1p!0{R6P5RQC9t^KqutC<)a(p4fg zZpu~-J?5wQ^%kRyW_XsdS5eFRBbBuN?po%|f7BV~#Kwbns{m+Yj`XgoDAG#=+KS%r zLrlwR6z7d>3fpP&5*jv)KbO*OjPmr5w(s5I(m+OZT(;EStP!b>RZItk@l?2jWqkoe zuj+YLD`9T}V#$NGSh}x{vlQU6g&JzmIX}wv@9r`1mByje%V_D`$G-=rQ0mCR==u|8 zqcSY2fJMOsDVyI~YNx|@%;Thc`(H*yoyFZ$30Z4A{&C(uQDQp(ufo&Lo^O_E1(Og6 zWUy(!S2RCfdB11+(R--4NDky95N#%vnWxz^rvZ|1_4}W3rcHC zjWJuSHmQ|Isw=306c*tNgWsqAX^7>}7yu~=Ckv7?8YyD`eVgXTRMfKi#zX}?@_O`BKmV9*8~q7Yy<2&--pXD^ z2?COUtlAB67Nz7;3Pi31Bt(`BYuHqYNOLveq2Vcap-lPXcD5q-9%ky974bR=UsnnM zL(GG~?glUIgNvqIPMi2f0aavG2lb zlk+==Nlf6W6#i$jsOjIbTDbz}QbqPRnX1^oE)hTkw{1iME`Y?rwWf4@e0QC z%Wp=>u^U#6ow7ua^aUxihF=BgFzotpu7v9GobOfQ$uJ_Y5jC%{sUAoah(rG!H++Io zK}JF?=aZ>C3p^+t;Ml)x6;HZUH8Z=|R)}bUj`=j;;pph-;@sTaIY~@YpTCHf;kJ2P z(DqCXx58SDycggEjCOm4Q9i0W&mujRIX5z_(Jiq5^&qzzkv_N~cO4MX=e0H8d{szG zOZ%uhp6^OOQSd7(#DV9So`E4OuIxEwM2OfK;l26KCXkSErof&{;p5DDzr~JM$22rF z*%@SdsBn!=NVP_JMd6O3fHH{2$f56amE#a!;P#CF?u6-6m60XnWQDT#E?m7`djDhf+-6O1r=0w=+ z-^=r>YUi z$QFK9Tr?h!kJhOT2J?P4aBT=KEGTG_m6F=)6V!far@GrlE1~@HRBuI=5B5ArY2wD+ z>Zh^`JP$QBe=B+|v;-y!a+=&dAfOtWB0{w%cTOOX|d1am`?{$17M@IHyxwPxmP8Mo|Lqktz z>isvRqOe=xBL_}D!p^tnVOJLi%{ht&+-0FZdsbIhVKxCQ;l}5L+0%nH$KrSCG}TTn zYDdS%Uj~aybus>4?1)AWQa!9b{fx$fF`Da5#20zeTy7W1Yc;O!kN3hRcSw#Z~~foVVqEl zdxc)F#IX#I!eF)u?V6$AJB2HSUx%pp8o6ff!)Xzv52j2xs{dh)#!!eWUx3tjn}9L! zsk_wG#!;N*%I+&2IN}8AcS^ZL)C6NH&qCQ++Uf#o;A2m)j62ot{<*EHW zt&5y|NMg%|ka|u|PKbMZd-5~e0msB%CegPLLSL(*Xu=)sQS9zQ>r0@a zV|sOF;QUN7qxiw6U_2jh#iE8|%IOFqx=IgUPx6ou7Z=B@zvB_$0PHq3HBI14VIe}J z*vB$q)&1DVvQ569O5#)WJ&d!l`sKsdV)BIJ@|?sir=!YBEao(KPTTw`ULZd{uNO}f z6YKjPBk9E^`pbMd1(&i{V{~3AX((YkC6Xz!!FbE8pC)u}q|^3q#ZHPKccccGw*b+% zp(FpGR!sE=9&$U!l%CtIl#!&q;r9Rk)4V2+Fca#T7O-+*Y1nuP&IEh(N!quiT0fA8rF!Sk^q&&gIS@cGfnAM7af< zI@#X1_yzxKg#YAxCLqNceGhBJUfi|aGF}6hX8qXL%EbO2^6|xJU0ofPNypZ#5Nd~- zs{Bptol8ya8qzr!v<|DrF}P9PZh6T6uF3^u1410C|>mKQXbkkqP`bk(p&k` zh^t8J#)5{VI$pYDe43S&o$aM3e2)|hYweJ}i>Q+#Xnab_K{N8B0j2}i+A<>PtK)KvHDJ5`O5(yo znmV<`*Y#W|MuZ8AzObWf8EgS{&zn+wM18Vmx$i)_PB>v0I~iEW;raaM1_~%nhf2tM z%wqUn-JfA_j-C&y`4$|pa(&I%bos)CcN{7ZaJ@mI*8RN>6X>-&xN>m9%fh-s9jAwJ zwcX{-5)I-`s33suQyB+=rsNu8zJI`9CW~cm z)%&2}vHI3x9mDOCXcR+|ZuCx-h3%1XD>OI2TQ_;~2bDij-+2}-5?QB{BL%CWuZCIC z@6s7);m{!mx|GUeosbBc8IX&m4a!lfh2=ik$?1yZRIoMBLd)CZ#O}lTbX(e3$vL9R zU}*a>s`ZYFPeH4dF!Uh{g`BrqFX%(^kIv6Ux|T(Hm8|w-zDP=>o|kHQIf%kHdBaXI z04TN~B;WoeJSH(VFR{zo-@XAb>!6y-y9_PJG7g#iObM868CbDWBIk?labM|o9%y+@ zTsC9u#6$EtF?6A2?#yoM$+WV(nyX!37@(32)Ho4oX83T(RhAR8R&Ew!vCj!qX9&1` z_U&3gGvIYHm?2Y0mI@e2h`{-~XKWtUmvfu?lY3}c!0LX;|BzUP5A!- D{GZVH literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/pqueue.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/pqueue.png new file mode 100644 index 0000000000000000000000000000000000000000..231e9350d6095e947ab7e026dfe678f7880f4b66 GIT binary patch literal 1052 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 P00000NkvXXu0mjfZ;05x literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/repeat-one.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/repeat-one.png new file mode 100644 index 0000000000000000000000000000000000000000..485ad9c3664ec3ee7cddb82c2c04596f480299f4 GIT binary patch literal 873 zcmeAS@N?(olHy`uVBq!ia0vp^TYz{X2OE&gS~F=okYY>nc6VX;4}uH!E}sk(;Vkfo zEC%Yh4#JF18nY{ag6t)pzOL*KIGBYbt_4KxB9Q9nndOTo`$if{gj)g0u7jEfR$n8o#nKIq#mHdJkCyzRcv;Jic z(Rj2Vu;jzb2ZBv&%T822{=M({u4NM@Jel+R=aZAgb*h{|n{fdHG1DpBx1y|Pr6`{K zr!rgj?yg9`O(CJvS#0;tsQ3QVyv=Ua(N$L3FJ8VmQ~z?Mc;DCB<@2Nu2#A-Y=pNhR zY+s!Au6OFHTS_msvfeGZvN&N?)!j35RFiyIdKWleP{S9C1C%^Ig8Sl&Klg|0r0VQH|N2+Ix*d6Mq4~KV{9op2&R=O??SEqTq(8G#{xQ%0ojGZ5 zt+ny)>CIOa>n}#_HrRR4JYT8o#lp5fo|A$->%2bg?BuB0u-!8%`}5?-NA(^He7W#< zV#;zujw+pd;-B}bTvyMZZ=&YNfAguz{qU=oPyUR$AX}vGULL3Z)9~cP?S{%P7G`-q zTm33#lJDBB%x+3A6j!UXM`v44it+xmbs|UA3qSRpv!6Ijntn|2h2f1|uWUfU%pt|X z+tj94`J%e^P3Brzv$l6du8f( z+dY2d-`G2&+VX&;)SQLxU$Z5wfzt431FCEW8g1b0xIRKH+i=-}{8uNUdNg0C%0_ly zWQh%({^{9$&d-Iqe%BV=-^-IaYwgy>o??^U_-~4gf1PG|@{&LjD0AQf$DYdf)@(Z0 SaMOtiq{P$J&t;ucLK6VInTd1& literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/repeat.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/repeat.png new file mode 100644 index 0000000000000000000000000000000000000000..850245867f57b0b433bca3febed3a1c3ea6259a6 GIT binary patch literal 752 zcmeAS@N?(olHy`uVBq!ia0vp^TYz{X2OE&gS~F=okYY>nc6VX;4}uH!E}sk(;Vkfo zEC%Yh4#JF18nY{ag6t)pzOL*K*hIvnIHNyGerI4{s`Yen45_&F_U?NBsfiNDAHMIE zl99TSWSqEh#pE|L%F>QRYKWM1r!BvzdG3Wr#FAg^5*}jBV$J^;&z-gGev$UUu!8Ax z`U9DY``=^2TNvN(oPWNuf=`Bz6KESQU?6gJI(P0`UDZfWqxmVYRTn(GV?Ky4o z9%DgAe#KYsL$^+RQZmWfbKi`v1?>Xg%0lnTwf?o}jDPB1bT4-Q0ZyCgkDsvUe-93= z{eAwe<@_g(le+isd0jfmJ9*!{@4`Epr!BA+DG3)_vb9Y2q}wFs#pZigttyti&tqfR zd0%OE=2~6#ox7FO-dxyyKQSu%{G>S&kC(@!0<)G$%=lPPKXa0H-?=;W5NdM#`d%JH1lQzd%8~@g1w|2I>7gcRhbzpmjQrU}r zZ8aJvvnEA*_RZ{AQ2l$xlC9e;tm4i{wlDboE^t!tu?IZ1B1vMvpkV1;;0OzqW+=0X z%@M>jcw67}_264cF@09Egg7pqISUU;Rt4N|+vp6E1#0C5D-;Bo!W%5|Wm_sR__=-8?mAFTWu( eu0#M7Km3WA&P|& zje*`DJ9ruqL$(EIi~u@A?FUR5={0H#GzNeaYqT-fA!f(`;L4@}?Gt35?u-nxHK<90 zjfujHo*&mHxP4_}Spx3LpvJ^uMu+=tKU>pW+D9isT7aDt)K~$`E+C@^z}s9f+QbAM zz|tewvQ9wT!0ZAta0iDG3d;?Xps+F(H_XZmX82=cbgWv1TwA z-BvA4&y5asNT4Y&>tJEmPY9L;==ioh{T!0gV=bQ(^AE?h3dq+)XVCB>`yD zI%&Ai2I?R#jTOO61(>pq0(4zrMh_Eila);%Q`XtU5ARTSB1{4mX5BhhxOI-*WVfca zJUOOFAPgWE!A{B6)I42hz-`-edEoLu7C|feZf~v2 z6gjylH+zp6p^HLF)BuAE+g`VgA1Of{(xoX5Eein53S2x>fGzqU2gPfG1L)C!c7?;H zxXVK;h(HU6BC$yht&1J1sF7*hSrtpNK6p`67}~}MFCCChgvmieXTcON@=Kw)-?X8G zEDU8yKx4SH3RKj%vkHFEx5NU6mYUBP%$-94O@Y_s$~z$L^?K9YZg*yIaBy4*F$AnA zT3cINTwY$Do0yomrGOhO+**dr&Sji|(yG(tSe+9qudl4Ed^tQkJj-}hr`6TfZ$?H& zzRJatOmn@cGoou5dTHVLKAbMaovE1`0YLP6y=jKIdJPW`&-Qw~X`r=GDRUnrZdG-B zXkF|O`AfIkonf5P(B@o-zKdzEZB&Usu$o$R6n91dz`?=6aYiW(ZO(;{9bCb>O~Mnr zRKQK{yd!dO0ho?9=R!dF@74tC_y~^xQ;uk4+PR|Ybg;?>sJ_J$vIE9%YhC9VaizyblMr(rap=SxQILmHZg_Uc4@mafWMt5 zP$!@n=4Qu@q@Wg&2ZEBHlZ_mR_;W=37!iNAdHDzte|q7dC6-MMq;k6D&w4Rhi$ncJ4D=njn@;jI(crpHJCfD-h2GpS*ne@=-%0hwn4~*2$~oX0=ou9)dLU<>=_>(7k*2K09#Wz>j#?*r8*9xxG_C zN{PhBk~BR%y>D@G@iz=J10CC8T@Ie2{i^K6ixkrKzc@Jr5r~{B4b3PJX^c zVjsRPu8fony}4c)HO`(r`@_3;@BU%$-o0ZD$jiyhStq~;M8bWtrV&GR=2e^S1^@tD zxpL*hGiT0xzH8U6CY(QpGMCYc|4yQVl5#ZJ0X5N~0RZs!?b{z6J9g}h5JJ=(Vi^+5 zlz^r>myEsj28tb|_c$~(G_bh1_=_V)j(pruM|O!I-se|%_)yYgK_F`aGU@knTMj)o zHa7I+$&+6<0A?RhN)Ium@}f`@0G66{wI~i%I(hQs_ZJrzf4_hK{tp}0xsZnWtK`3J zr^3N#jQVzv1%(BYFk~sH4Bq{>AXh2*J55TH6 zL)+9mvI#&l)XjC|q+s?9v@Ef8bL6NO&|t{Ewx%Rg1lsjY77a$mK-VUAl$rC&9JEH4yC3>AG`f5iO#+wuk_+P0o_+(6!3Y zq(huJ6!@|VpnVRAYH--0(|2e{&5%SOSalU~(Fc_U|IS$H7KFOFqRzcc8E7CBc9cRQ zKVYo1i$Y2<2%6%sQim?{-DR7ON5+vO`N)wubT&e8<<+5Wn&vje#5UMjmaQ{GiCFXh z=fdRBV1PSlw?hQlf&u7#NbTj#n>YMzyF|1(7ZU6uha_;3e1^6uETAB6WB`yYFE7tA zN@-|wE;88p)li)~M-_T_j_w?Ts_O!Zzb~!4zOu6NYD#g1y1BCreVgA?^MU$9+!&xrV%iQh!Qni7|KFEOpbV?^A!hkS?p(x7~ zOC6w;SV1`oK(Kt>DG6)QZI_k|Dn4)?W{TrW!{aC*g?8x}8vB6K_fr9r34m*xp8-7V6VSkJ+HfGyn0g;%B;KaP1;~M$Un22hiWyh| zTva-=DSng%Tb03WcCL7j8zF%90X14)Y>Pmw&^=?x)C$vmH{Awo(~p~7U@ir8$HTy( z<6x_DG!op#)tNDZQ>F;C52uEbF#Gy%Q%O-+)B#Z)9~u<{j0TAN*HJPv)&yV-FzID7 zHGsPtOT)$#q%g#QuS1C*rYHgy1)psZ*hFWxjUJRvgy~z7rf3l*YJ`|nw1AunwF|)L zkd?8a5WBYXsDQh|9L%jl0!@XwDECsJcj;zeMdK3_U>m?CpP`j-25iRN#K|(`ac3l*hV**V9-34OK%x<7l+j=e_+k%@s z(7vFib}Z2HZ?svq#hJ8(zEYS&Pc)WT@9M%>@n>#A;ppPtF3`%D(8YLt7qD#rZfaik zk*7_MvvFKm^7U&4v=69#Jg!Y(``X=HrgvP~xhG>yVi_mJl8nc6R~NK=9LfcRi5eEbxdd z2I{yD!i-KDvnzmt>?NMQuIvxkcm?Gc^5nCQGcYhUdb&7B;idnpWNnGUX!mnT%hbQbzdIxSIHBj`mIeQ#FLd{r zY0NM*+ch(}uVW^MlwEWAx@U?#_`dQ-UtRUaAUe=gaTYUz0X(eqbNUzrDU zR83p{Oa5y1RsL%NUvvWhN6uYux4msadgrfq5|5i-?R~Y*mBrTkMtn$q_;0X^cick25hOgoVy6#qT z-L_xLs;){k#Z{kKzWV*DV32(Enfws*BRVf6llDc_#?Rf-rhR;tbKRm{A$#+|)}-(H zFZEj&=$N;L_VquG&o{4scVYE&({F;Gy*Js!7}R-+fkRO_L%@VXilrAEt^y`LB3~Ml zi^Pms|E}(vbJWN2{i_p^KEhullGoq5cqw^%afR6IyQibB#Y{_GeQVvh5cMymDeJ;_ iXLm^ANDCn08K-S~D{A-eI#Op1;(EIJxvXKRp)xY?|4IfO-eF0G7tzvsja1E3<81S_z#pA=y_gP zR116&JL+hvftEnIAj-D35lWzk)KAOm5eP(1kN$#PzokNiWh9H z*MKh8$Lf}kRec{kaPfHzQuTLnc8iWvmr0BNf!n+8p7We10u znB7=yZ`5uA1OVp6{zBuW>aNM5ig9pM`MDsge)&yQeOmJx}R z0-Hvdm_SXV81zNgJ!g6a4wqX(6Od2QK9h5>6GGp#S_b#g!i#XloP$%p0lksmGofwg z+l_9wIibWh`qp$qR9%E(QI9z&wTSM4g`ya+#1cfQ(Kk83RUp?d-%mjzhTwE?5tax` z$pBV_xJ9evf}|;b69i+mo4?%WbyI^nrV6;Ht9XK)!Sc~QN*1}~L$vPfs&+>VeiYIa z*C77U1lWk?FBb(_+9}APs;@uDyNJ(FKiJ*pK@n4=_99i*Mc1Fih2~^EOhMAX91$eX zA*xZ)SWs>-H!8-FgJgo(oA}P;_3crAmlv4Wvo|KZqI4`^3JarAGg>HNmn=KSl}*&> z$~glAiL}YJh0RmY$^Z$U0O^7-sb3p~a5@PeI?CSwl*}xruuH;014<*6pttO|uT#p$ zsTo5g^dyD_Nxk)S3ngw3*Sw84@7JyM@!=|Oj6cj^V-?bK{v_rghU-~sWS#(FNXCG5 z$Tj+_nX5b|lw|tDDoVT>$&>T*fJ8cTWyP>9=S#`OHTkU-OXa9Vq6ix|$Y*E~R62Q% zH3H0MRHj?xfB5QAB|-rS;T(Ts#gl*_RpJUM38NcQD=J>iKJFiq-F-i8{eJaz@$l__ zwUWn4!fR~z#U+~DJTvRyZI1&X=;*7d>)U4j>hYM^sWcNdKXyO3sJ`Snn~CM7+n|wR zX!75Qz>dMov*z#O%@^P(c&J;QEtsu@I z(AlD@*QrngG{ee}A3KZ9#!kFz6S+11z4*fR4s5r2DJpq{OdtF`I!$1SUz25s>TY)JS`#%L8^ znDvPiD`D@cHxRdxm=h4%f|=h~+-S9ZiRdDE1=1Y;ely#!yGRX}`QdpH++lJ!&aGAx zCObyDnl%!e$R1+NGCbYarNFdV?)7+@1;j+K1Lz6T|JzFp+xy%muz0jxX{V`BbMo1r z9eokI?fsgK7wv@Me$K*YO5NNDJsAS76U>2`faA9*vrREm&G@0Vpm5k$>N)vv;(LjVZQGx*FL@@>Du*f4^8_Tw zQY!Rgea}ywwQ8`kd392>>=41~WL-J`(Xv;0BFw(b!*1MvL8$pls|w1@8D~g{B$NZ4 zr|Kj=?dd4TaYdC<% zLE{wtV$(h_$Dgkp%v0%64}`yA(b)D)suR*O{S-4fEfn*v7o(n;wthwOiByo~eo~y+ z;5QkcP>TG!H|wl?A4@{f)I(C;h#mfM>&DQAI$i@tI}+Q}#+O`ZOQfmYLjCIX6|jrj1C$*(?zKbyc}oC7G&Zti+>genC-+VJ4U=(c_iDLWA%Tn0{U z)))y45?>fWB8>{sQ%=c=tURi6FOP%0gpfpSA&g~_r4g^+B?eFNIUHGxG*#%mEL%x5 zGT&x(;SnmDa-h*)*rD@?$E@oZZ$&FYKB7bVKg+>n1l(a~i9A}be z&)RCf<-V1&Y79(7ZsP*G21!1oDF~&Q)!sxBo|6Va!Vy|5fXY}_p<;O0TZ^zvJg5f< zQ_Vsqc8Y9d6*1&#)Mu0DR;g}DdZj)y8L%LxKkwz_8LV(cr8gkUxr6HDPUEz&%1GPK z`$D!-Rixp1MfPeu8v>FxBTs3W&h9y?-lF_8af9WJQu}}z0uIac3T&`LuG3rLiVHg- z259ozi5IuR`>ty7v#&(^MkNX4PsJ$6Sh`=U1rehqC>kPqM0Gw+F4A{-S`^jZAu#Cn zm*hgDk?Gfio(tR^JQzF;4t60T9}nt@t{i3#Cf6|iX8bfMWBD_bJlyCjyX%~@UYN5A zgjEQ=`63Wv(BnzXg@)7OD$V9qCeDl^BBPisOm_zv8ULI!TjWt_n9^yJc4~RC_{ocQ zU~Zoe$CJw4xeXTD{}s&~bqi1(9peBl^gAt2j$JuXfsws$cA=T|m}}#2vHJGeFH75$ z&kAEv+7=y6U=|PG2kTeU-SN1j(R<|QpSS&d(@^wQW<02Nkb(N$jI@o#9T@VXL(WcV zQ)ZhnEmCfl-V@<=c(m_Js6n~ovVGVrONVBsy{eu4d6{7PzN?3?EDxKodc6S2R}S5s ziCYr1T;d0}5svX0bxZUAM0A^XG?B8%dtvIjVLQ4Q&+VT~3%3E&({|>`524FsUz-@w zyYb;7H>>4ibUCq6Id_}IB!eRX`PqP)6u3a#`Yo~iLkq5Y>hk?DzgM$ABQ%_G(mXi& zpl498td*Pt@xX^Nz4bu{!*A;Em#gtiOOw{=71NEe*l!ko&PbFop+|>!Hn0UvZ2Q4z ztR!z3%_b-uaq=HdgxZw;yI-pCZl*pYxzDaQ+YRvld77IDl??=crmL}F)gpv(QHJwxZQOW1$)X2xYkG77o-ns6i z7w)QITsR&aZ3W~Hd0hgR>PK?Be~0$vHN(#x99WxQ{RsrY2y*fb(r9BX9igH(8p`e5 zg#Mns)jo`G$^SzBB~p!el47yzIf`MRjATuoHYxV6Ou;3T#l7|nf1a1dDWEBZB zeMn|W*izzi;f#joaW1IN+ton%tUgYU=M@SLZFYKfaA9bZ4fOi}qx}-rZOCV+W@J37c)TuEyHjir+5j_Z>_SD{L>AtZ7_hXp z++6v5>f$}MGffY+#)5AhM*m#|u;o6*t~al}g>ve_5OSGsHf1_UEf+E4GKX z;BQ7Vo?l8-j;I97G%7@#`tvI?5GfetpV5Ttc`3W=N)T-mZhNLVHXZeArgE37H4$an z2R4wanFriLJwDXmN2H~UN3JZjy+QDo+mr6Lr6MT~8Q9>w3&IQAzX^+5jy9Y%Vgp-N zK=t_Sb?>m?7k~blgsG|B=C1#|qKE%>T;`8dLBsN33bhRii|IB$> z-AG6UhHSf6p{ZP&Y8C~9%1O6-KX>h5qjN|y+}g~ryrjLCsA+b^>3j{xEZfp)tw@XH z_>qW1wYG%f*JZZ}ozC^h^7I9qHx14!Hc{8^YWCZ};X--N3j~d@f#nW(XYORscr22c z7t?IkoS^OK@00s3-NvKB4hZjdeeiD^i}Geab9(D;LErRq=0b)P`uC1mj}---KcN^t zQoO)*58l27uj|t(!qHPLpEkJJ@~iU*8s%+%_wOg|V0=Wg8xn3gzPW$QHan>6WzFM| z6cpzF>uqqaz^9%E_PG3ax?Lfr&%Q-$M-~Z6i(P~}UjsHk+#7uo$wwCEe+748VEU_? z+>V(l=n{x2tx(@dKz)6B0PjEgt5k7Yxl~dCr0_>!u>JV+DXpeZ3wo-ktA_)%uuO%_ z;QDakS@!TKmO6!BBF6ANp=tA({b30G zwYy^s|JoRCZ9HAFZuz?+OqEa-f;>|`c8g+?yAg+r8~Uu?#%C~{Nlzu>Ph`? zDe@j^Tbkoozi7|;B;lHnr>`61lg;LYH*^}G5OS`EkqW{EsW2hl%9dA1^}6X!Zn$J& z`$&^%WJt*faUuNoJKER~C!#9v1MvKSVk%!qsg z*rU-#B*xG;9sQ)C@3iRF)ocJ`-glVcR>RMpo~7C&!e#c}<7-EIp>DxL%P?+P9&!~y zKjXUZjO~FLA6MKbp1eOW3-zf=!NHYMs~4!rdkvZFNWI^9snIw--}?NiY^p5fChi0K z2fUL`!?HL{0-~7+_}Z>&_Ciow5L*4c1lx08^IZ0W4FfOcHtN3AHGIIy!`e7azAV2n zXS>C3nz!uMWy+@fLLGt%k2pW}H2C?l{KL@VBeTCgqA9q9PF)}|lu76TD;O|_aKN`5Gpjr)!pBPnCXzPe&N;#H7>=)U@1qCF5(w-rPG_s) zj-HyyCfngBkH(sG)||AV?7x}skn*5JezVcUHvA-C_{eD8dTZ{lfVcD)6IAQ>2hK+= zx6>jA21gTmmF-f47B5zFyu{&E|x;bIc@l$__{M2bhZXo<>ZXUz|z z3B@ayHujp+Py#IDGeX5)?*xE#-g@O8J2sJFcL}ZfncRbid#HL+MG^dSGYYWtsw0 z#a=pmG=h7@kcN$N9<;#>w09KO&|~yQZvYG4(CGpVo#vS5a-n>qM*S}d^M?KI)%~qR zk|au}i>wRPoR#1HxbY(SU(!yA)sP8{8CsoydRx{EhenLk+SRqac!&8R?_RW3Xm{1Z z#X{zzvV29V;`Cb+ciC>FAS!m?c~()uTZ5`)__|%70BAuI(#qw?K-s+oD8mTP{|eZl zn(x?n`Q~*amsQzAdgL8}`&B52%MT%?>MRju_gV%xwYRaY=sp(ts<~;TYu%!=4~WY; zcS3ZKM)h5dbg>$PO!fzhg=_x*-W`lfJ;M=DJz>j?993D?Wk z=HNTc|^=@?OBJ=n;mn_cE>7agj_2uV~Q3(tIM2N$7CFS)UdT zaH0Puz6CA}fAaYJl)^dR67WG)_%x%ofOLRL&2neG?QRNQ^2EAg8Ljnm^b#e4U~Z_2 z*(T@{+>YgKVT&8Q=JWzig4A?5$4^s+Uk;7m8EwmKYkm)iMC@A-|^ig zZ2zh+!yLn56O)alT1paV^~d2gm_F*&=P(cTD4uznbexY2HU5EF>?@x6Ae9r=&C+vY zuN0hw(=u?Q?vdLxvs)nf&m*v?S(h8f5w*i6<#rX8=E5aHM46s~)=iV_5=(*pRD{Z< zob%vjq++73*@wpUu5}+QL*MV^(}~*o72@O4o6s0T`eRV&ovo9`NAN*r3I0KwI?T3& zYliO;G3Dv?g|stf!o25yVzv!$l#PhL5dwUgD~Z6C)zzLs&D5;`5om`?4fUVxML(+~ zv$n=xUF%PrT)#WO=2uS1f57B!9ti^v_(La7!auaze|G>huhGWJjIH|8N zXR4Y-ZA8iqDz6}ask6x#G%O1)KEYFP<(++zfgxZj(7eul@)$p481*$n+p-Z^NhD6% zX}S0Q+yYFR??@2ZVdhWs$2PbKv14Nl2enZ*5K@vAQhgE#zIOr+t136*g2Vi;xM7e~o-E=KSryDh5f;|ciSGKyIahHiO zFGHH*w*dYZ0ep5U7Jb=SQ+X1i4C~{;E5;p{0Ikz+T9He6IvVEONpG`kVCp=-3o47k z^w%wDV(YaZzK07F8Gcqr<_ajW8aB_q zP3g^o+87foDOTu602p>sBbd zYegyH3RL$9q)8hJ6^N8exoxo8OYa5383fSa&c1;!%r3}VNBmHg>nS8zGprHp(j57C zS1JP7t{srnTPo+8h7Wm^87R}NzZg}TtBz6faClf09Mg|{)4_%IUPJ>ypWrt^Nue+> zxRXBkv`1ELKh?-QJgIUbbmkTyJ5E%M@f>IB8&o>3js9|hq)RB513KKmC|A_-NE^^C zil(bV#Xn#!xH3&XCwlbX|A`my7lf^+&lDn~2!s_^|BfURmXr<(SN#oa)E&o9${scVBGf;Yu4T6{9CZFu*GEKNc;@2=tn(@8h0V?fK`*a zvkOuZLK+4LV|)cu&*%v`5kM)vX@C$)D4=ff;J&_fDsioN#&R|#hynfk&A$i!Jl!_B zAvU5 zIOZ4jo0L{7aCLAQAn*aY*VtaW3d$6;uf`x^0CE3@`2Eyvz>G+6;4J-*!$7%eJjyh& z?#7UGK5ABNT$Fid>LbN&l$Mp)R6L@!~9yI0mM3a?C0fN&dGK^4=Gp+GZGI8pDwy(5Hi9gzP zRdYsQ5AQsc{EJw0Ez+5H|Fc@TsCq#;Q^Z)*O(*TfTQuoNK{r8Q$9oW4U@mR8*M{0& zP5EI0q=0zoVG9SbaR^d2`?8zx`EOEPFUf&kcEx|aOq8M)Aw@UBiA;eo^MV)5u|Qp) zY(*aGk~{LA5LlHE974NE&kIjmD~Uw>lansz4b)9EA~5dV+AsEh<`{?3z1I*P#>T12 zfC-__kTL$j1GwAo?opGTRPYne*hJI%d%`_Ef=9eimGs*Lu4o=iiwd`Mhkrhf@XU`m z;m3Ops8J`xGCeLa-6IxbjZF93qcr~~ltjj=n>?||H=ePAb~6&gglDD4g#VEifbL*6zY)vS$sWQX8y>4*yrSh1%@zRL zEOZTQ=#4V@OqbRj+ge9@_+ZJT@DeyLI({YcP%rx89`sIjjqHre=dQKPJ*_wi%G@Hl z47`!LgKJGMZ~Iexc`)a&nDWY_I2UsdaRI11&pn6`GBWYnou2jAds-!rDRU)<5bFkj z77vrTm!CWRer;sl*vWlABGt_6pIxhY#2`9?gz(d*^1qmd=REydCaC{jTeOvh0z!U6mSua;_N=6Iht@{Jp)EWr$~^_AQiU(Iwy z5Q{CD8`8wyZ6oU21e*E}Y_-k5_2@XHFe<&eJ=&hYnw$MkcK2VC)|#}HjcDf8Ou6>i zOdsWAHjQ(D=tKJ?H+x?XsX&IrxjNwyoG2=#(EoV)V&XoeyVoL8Pg&RP{j36A&vup8sgPbEmeKql)@zb=AaEWOHk z$xxZbGa*B1C7suq0=i>k7pQH8hx6=9syCm{F-27iUYpJn|kz$yXSVf|RSq$w$!PzXNMvYa)$x1o-#++w$rSYgVF|cg3svgel6?enuB;5BaL4uRiP$Ir^@ zT1j+NXtZxg@FV5wzlf=~N^r>f&gD};FNR@-Fx{;}AFzvNsHL}HbNCCQ+{&6lz+&|p zh*#0)4$js4eP+NEJFMb?6dzNai|Xmj*=0!Zx$+&Q`J3?89TwN}F%b(MI8a-slV<9> zbt^N|zm<{08o$uIyJwI|lZyJ(EJF{WSf?J5I&Szk+0MS%FCsmt_AC-*8e!!~4(s3o zMCFeR3=^9;LDO5-q1l;xq;TtjXB<$o*OboGt3E#09n^=O)d>T0Wb1T6M*;K*G#-y3 zRBnjHRG74h*4P9WjRC4!pZK;+%F-jvalI@SXEhMd0p)y5T;T<@WsZow>J-Y%@Vdts zy9t+eN@ui>qRWsBjaLSN=uPol06+GZys?& zW4P`II}FMHtO+^rSKLH6AKe9Pxvn!ia58e7pVDwV2}LO#;>QT0&*_ z84BX(x~#6++aEkC#$W*gz`nz|Bog0C-T~W}o~8CL*^sIf6gBQ+4VQ?xE8&r9n&vOx zB))CS?$c%St_FWGjRoS$qBB&~d&E9LsDo`o`0z)+O;0m|K4-;VcFDYo}A!TvlA%w}uzO{eu~}(L4kY zB*$gFv9FjX%bxN^A~nV*xd%xu$+}ut%xxQWOEEX#=B3z_cl!PH6T)WM2f+o71d}V zMk30V!U)6_Gy9L#n}LBhA&KT4J?W3&Kv_i>SD}f1;^X{rU%5OF_nA7V2k#mCFx6wc z#DF^;5^eYoLZuyBhs!~2DVlHK6$TAuOW*D7!bX^=Y?r7*6Z^-NLzMR;(qjm= zLy>^W>LI8Wf`3cHKC|bQ`TUhWkOz`z){z?gG=`?V)^ICm6Xqc=Zz?jZ3qiWUV_#nFJ@7-#yF1aeBemKh zh9=UP!0ADEVwSk%=CNQ4NTlpMmO^+|PnNQgMwe6Bhniyz*-W4UWA zk7@mm#4FpK1rMjmT6X$O>8_C*4MYuA1MM7NDWwSNbphZ?ajUZ`W!(UMd?TmExZ{kx z>YL>;fMpflk(w=yF6PyeY)ovx~9dj@v)RzN_81XaqfbPR?6GQRSkI-%~WPnLnHCr%kthXub6uG~!0#&ypl+ zva?1ZyRT(Ii!ig)hqUMlL9?Fo1SPK@_Bll>XIH4s6@5G->QWSYbcd6@P#^X-3V^T( zGBLUz_{Lvy{9unqUDtn-_{mil#`>^eq`u&yXuaHIda3pS0WnK&@p%p%z{ee9Q6wMz^&WGI1jVsH?^;Mcq8<(ul2VhGhS4gWmN3rTaR46I|Q& zJ3z}N-8?N7ake;xjqJ?V_~2~JXzVDMb7d%|`mv7yS+%WJ{2QwBz|nYXy&}(QIr;#G zppv(R%oI$O08j(QH+n5^sj^=`U$giQU>CxTZG?Ga4de}IpuG;@Iw`LVEVjgWhaAh6 z0Yw*EpmnnHe3S&hUHN)1*UT4u>{D%=V*GHrkZm74mX#EjruE=Pag3&EXd-K^C0ZGv zW|8eCR%1eo-%7!>d1a#cv4g{J&_HbOVWB>k1KPd{sk$e9RV&_urB7H)GM%bY{`yr`3ZP|@YuyIzmK6yZ#C6utSoRHGsnm$r$YOKp)Ekd~6zI-3du zWzgYIQbm&D)+2W@DYv*Iqb1Pd7FD3K+<9gL8|}9L)JSx)>a)5_S&@@gQ-lYR&XDYq zA_(GNPL{+#e-<^^oJOCyKUT^8r1-zULNZ2&a*9@-zV4&F-Zwg@d3?L^skpeV-)?z( z!wizoihocM+qAnc|XyLXNj2EmMKRhGu z0U+2weKzmzmsKH`8-t1?*LK`I09&J0Em@9IU_uuPzJ8asu@l{9tx4pkR^gQw zeVa`(eEIXkF@2F4b|cfu>FYk4Emww*RHdx}$Sdsp&u=wy&Tva9Tcda%%}jr!hGY*X za_0EI00Bhbe zIqg)S7fuHJ(=q0dobCsCG>i4&^?XKp01ZJaR%q7f3jDqA-5M9V_s!S=c1N}M1i;GT zp1Ew^{WYKGL#jx0N2i&_F_BXszv=&@JFGG6HBS8FJ5b8kdha&;<5zHCnD@KYU0PbF zOrT-;To{okSWy!6NSA!UmCmI4Vvn5QS#s88ZVye)AbKuz?O`b6egD|@Xu>(d7;Ty5ep*Hu;y zfWca|eS7aqGsebYFqLlD>kN@1QkMjH2u?tjA$CtAvDln|8la#MBvt3LT|C(Y)JEIh zr_f19Dj1J>;lV73oq$8R>dp^_SoCK|qG>)`_GFL5YJ4+YV|ZyDYJ9L-c4kmwnM}M} zk^rbH^X+nRlAnR`m>B?uF=6)8Sz?bEN5CRBGLzUOWutyJuLt`;cBQTVV&YmoC>gjA z=q0rR7jP!mRyeJD?Zh9{?M9pE{+oa0ZAd#Nh1GB_eY#686y<<0<;JJR*_l`;ditT- z7kWF8-B`fEYoqj?0~$MO2nIo~w7&lr|H~}44m=U7@Sw!fvub$cTKKy@LwjkzFMaPZ z@j%vHy3P-aq7NDY?v{mTYUUQ)<<;2HbqIyil{V}^vE05}V<%WOwoaWVzLw46rle(& z1NI0YzP;GuGcyhc9CZ4aD)t%&_sHIT&9IisU?Kq2oP7@Uf}hnw z*G4@X3JVMt*%%T_dH;+0Ch%X>H)K_6lp@#wMC)`ms~Ik6Y4#Zas*D-$KTwAewO~Li2%=%<_`IVb<4IGcg;&hk2;b|XkW#;B*{S-U|U~0ByUjA zjy*ZNeNRju9?@;S)?}|H30%!iUR7&Ml?--;Eyw_uDixHWvl(n;o#_0Pz}=t9IX5qM z>TWQVAML6dEkr3>%0|y(sg2Wa8?fh!3@P%V?(i3X5ZAD3bW5*8b$2RfVdsH#P@xQ9 zVG3%YMRu+2T>~nu&+Fn&#zOHZl+%luap)av#dGH|}ZPfoo!EB;k zQMLs*m|6&DMv)Ou>T|LnX!wkt8UhXps~!F_(r=5$nUI*6j;YEKqq5<yzHRrzM1kTMrmj@%;!I|t_OlY zS(!PWbZahk`09@x=(@-eUO&zQOWueC22Tcjwaa%#Cd^d^5K0%1Jj4n~hS9PQDdQe$ z9zHa>k1TCE0_r}jvx6OjXVxfoW|!YAyHr&}+kPvEBRoU6ffqCyRVFC|s}PSE+uEy% zs7wanB7Ol*JJO9(Pu*Ll{&|(&Q<)kAB?Xl&9wbxfAGEECs7F9m%V+h0gPJeC5LHz_ z=DGhCY=3+A!|YF6ehW+&qOi!fCq&Bc*4cBgB-j7Tm@b2E6e5DL{78MYsZvgz0}>Cf{06l)%??ioeA278GZhyvl9Z|VEzF9Gg3%^QIA-RkSr zx6~2{h;;f#nmm`7{q~GZ;1c48M4^bzr zLwNZ*pWyMwmC~Hn@8O%WKi#gh6-jI&Odm6*<5+pnxm7QR|F+FwgAW5T5K+d5vt~U} z0M%UpalqeAWGYrxm`7bv3o_?WF1m>Xs@dy-lBzpyHF?x0(3hwpIx|Ca51{M{6k0>- z##d)Q>*naQmG#&4md}x|PFI9O!n^_A*YB4=4Y2N3Wi@ut^egTPq3~se+D~+F5Wt1v z4F1Z5Obr6a4nVB|U>d_30pomsc4srk*Jh2W$Z-xh3>jyZnO+)GQ^RM(!{&_p$^m~* zXHGUWGdHCcCz15ZgZFNc*JJJR)pvQr@+My}_xFmLP1FsqkS1Mo`(q(KLgCGwPf3EU%)J426MBub_} z2SW+5&X9gWb8$HCKFZG2WWVb|yZ{Fm6;$fW5Qa~tf=$Ik+Q7z%0E_v~Vcl2Y4GkYF zOfa+#{~<8z4PO1AC#Nl8i$&7{?@IxM`r~VTo6D z2mfKUQ`|5Kb~!)!_dGz!cWHD7UKHt4&xlpf=cf#Lo65QW2m6S717Q{%&d5UCK7%jDHBykx^U`X4l4jsOgq-uNUY<%&9G@}%M! TaJvUy$N_1q>#J3$*vI@Ig{#y=6LaM(+U}8}f})vw zqzwm%xVK=LXgFT_o%5da{`sE62RP5?dG5Z?xc5G(*K93$xh1&)001w{%EBH1UHRQ~Lh`wkD?Emu<{O#?3 z@~bxwGhgU5y%sV@mqZwGZ=h{OVLe1PMXa?!0Yt`ywFR;Y%-)KTc8f`GENp9foo$PL zE311|?`X=C3SNage_c1ffa-B>-TQ;Ky#nj$_UZY~-Q(v%!2?5KwA}v8C!5exT{blH zTbYYI_B1oznSlRRJCT;#*9MgzPgT9!Udm42g!cGfu<`43mLG?y-MyWs)+!SBv!52! zM=t>R#k(puKs@p~9_TDo!%223O|VkcXX^{O?sd1dop+#ZzN$y*ED-T*j2Drtkp92Fi-#19zJ5rCe)gv*E74C%L7NiP;Zts= z@o)H0*$}HC&${}`#3WThfLr&cnI(%%j4`5CpbHdy_m01|b2$5i%Upy=7B|Ak@5;`Z zS)yRISCPToPf$pQ%Psz?5+aHav-3iQVwq|A>UlcDS5ge@0ll3akAQ^!gYf}=(feiG zPBi<(v027`&|)0 z@7-qZ8lJg?rf@I+`fFA08myt;<1js8jq#zPHLAInUP+j_(sGpof*Z^CSAx48{Enb< z<^Bs6#nIp6{3IcWV_nv@f_Cth^kHFq15*?Of!Vgir%-W15a^m;aSX)#L&kp!cCao@ z%OhU^nP8~6H z!uKe^hmE?sl>IKaI_lie3gKd<40>UfG3P8#X&`yXp+qzPOpncYgTKEfE z@xC$G;Eu9=ifJs6%86}%584#Tgst-)8^sO(ho+`vX;nc-%q@`Im1$^*8EK< zLaQWcborSf3pKbI-ody)fr8OCYIR~49YJs%1G8dXgc?|*#(-YsUvwaPF*jr(%jzHh z!Jw^l;;=c9aZInZ+LZxeIW`NxJdRP{x8>bITQhpV_y+o;%a{Co(iNEEx9*1cFZSBq zNa&U}+%{UrjZUzm;vXE3WLSTk%MPISy9WqFkY^}$7#>ilz?vIwp;LKHE-*onq%+qd z@O7)3jhMKfrKUTIzT@Z{v#@E!Uos(G3yE!wXdzu65R^t+?r2n6mkKMEg14~wweFfJ39+L~$L|Jx@=5RwlTua<4Pu+V z;}h%Y_$_5spDOTPipF5f_X_A9MNPIdW(_r=lgOu)6m>Y0+WAIj55y?U;Zt8lD4}12 zHaMX~t|J0|IV3u1%3n;oo?&|U$W-pK5)nYUO?y=@M-n*?M?e7@Vj9s;I);{r?ssJh zy{N-pvfm4)g27>1oHz-jlU^Y86aGZxI&wv2+-G*0ZJ$n|``$b{Jgk>%Pweet)2|!8 z?T2{8K@{xk0Kq$2Pmo6QlLC{B{>mjszvlLdY%4~=8d>!aP1Bgi4JBR{row$4y7C;< z#TnxiIlSM=h27sKgI|`ZAP)}D=XQMmT=rWBsvBawJb=_+>zc&AUT)zsZFtlXC;Tq<(W`7~sn=UAr~p&t0|b;~W=)N+d`Zak z2^M6nf=6aTpsYOmg6TZj)3eP@}`4kA3+CpA3DvHBpZ>hOIHU{^sdBLO9Tt)m0dfWOXo_xTiKQbDGUUMwfLx zP%wWabjt;>#Ev`|kDQ}^px7I?q8s9Hn)dD|X^((g{Mf8*D+Rv7R9hW>O1+n$@C32%SqU#g6llN`Dusmu z=kVfR0*dZ{ZDWCdXP`svl%t5b_5mKs*(XsKuvsN&n+Q(Eb(x%-%bLPdb{@gX9XSy{ zL`sS4gwMzWdaZj!r#XqweLm+z2EceqV`i96y?lBo!&)3f%j;3<<;n*|RjVQtYwY0Q zH^>z%QLRSx4!#(BTrS@pe+>%8upeYH$Im^NCA8bR*2QZa(2r-fezl7wVKj%Fk?qi{ z$-3X*k8Sh$hZ@UY%E(N8Vx6i-;-_iR_ZHSA_a-c2N z9d~M+tNcfB5Xg5r|%}y|RPtBv0>(H?#!;U%j zAWD29OXyezlGfLOO1Y{))EWC=33w!rt7fNDy=2QCnPoWU*SJlqs=}_N3|IYVo4e`x zvMs)Pn%xd2g&Sw@~XcEdtyLHk{8QSF1vNZfZ?rn zRA(V5(&vUf%jP|g;FA}JuazO>XV^7_lJ`bu81h%{Cl7y8uvFY^A>CN=BUR_X43;`J08iP7mvCb9s*lT94I z+P8>od;Wj*!GMQ|vg6-1LLlcL;jA5Lb=Iw`A+8C}fxfL+?XRLWzkB?x)q0qV^3H94 zl_an9yuiKSBNVH21d%y-8AQoQ=T6B5C{T`&TMRE!N_O1GSM5B)Esu{r=cPFzlAMOU`l)Ce)PRhFm{r^Lmvk+(t&NU zdY#Owd@JXhXvMNjyE^UQJ&(SWgmg32E?qEH&F;|gWdO%8LRi4KjpcXPJev%D4%$7N zasJ9f>34_vd)t6E{gG3=&mA`!-s}hAI#c~z_n^`jtuTwe2mCxK`U842Vj=obP&C|6 z_L9Mz_dTq!u1RZ%)?8zgvdq_$xa=KL zFWN6OC=&i5^S7>x^PE1-y=iYILWh4XVHa^KsM|>aHJ9zrro;*#NzK%dT=_Mre*;AI z93NUDZNRH!Uti47z8E@NcxOIex_NuF??R|i!Y)JJeYP{p{=2{q=9%RdYd$^p#?fJO zUq_m2AHElOn#-HA883zUZ-V9Rt02Ztj*rjD?*^Z7`QDV`8XK+?s5bUO43$_|&@@u4 z^ZNzQ&mZwqd?l5mJc}0_-)OsG>E!oeek>*kQW3F7xl~HJNB~|aliB#hn`CpolVB*A zSvC*X=4dZFG)ci|6oJlYi^hVIq_6?OHD`j2gF!nZa~zPcf$sCyv?55Q=HtepQ}`II zA)010Sh;TJK!xcs?t`PO%Rb$4nS@O<-6>>DVc3!_4O;crhL`SJnVv&zcYYsVTOaDyf;0_MdIK^@Bg8f{*Bvw2NBWd|FC$HMn)?><>U@ zOVF;d1P2)r*LZ~J3tI`xPSlXf^De(~Z5$QZX66@V`D@ckS$cI^gS2k+`2<)R1s>Lt z%tT$?0#N;(g9Qa`>8N-{Oo?R7y3xMR~N2)6#V~lZ_Dya|4 zM~6}$Muz`wLsuFFv5G&F5!WtRbNK8?hs@-@RwEQV z6b_KSF7n61?T`QdhKFPIV|qF^sZz~scF5*#cO-&Nz#mi=h2KXa-lnEnOt=>oyu69I z-Y-FO%QIefOl}%~77E;!NwiL9xH-jf0JFSW!l|kc7-kM8E|hwvG7J{ED!ApO=%u&bMgvve=;BXKk`aY(vp;l`g)>M<$5`#IAYqL&F8$v zHYuvH&VrI#!buz5PBU;C(QmSdox^YGY#|(?opkKAP}%M|Fkv!l69l=ekkxy?T)z5V zHtYD%d3%Ly9jZ^qE8v{Rhr+wJAK1RK;~Fz< z<{_a0N2L;h6Z1G0!fsL1_{|t=`k^z$!^1VITG_`t#i;?z_s{Gmo=cc$l@ZjZMJS_Q z(QKzSc+J1)c1tM$lKu4dfGHGMs6{}wpoza zEvvioS`HHSO5*Cg>D`K~P2svo?QPh}Dzz>tN{bzbyS~rVhh^%;r?TQ?*L0PMEPqhJ z%&(}Jlf$e{JKjiL%JEEhJG)WSNkHrI!OLxo&WVOI3oBs8`O%l2> z_m^6&$BF?ataLl0gzk5b>hH6~<0A<8lcXrNSwu7AsHh=Py{2BlD3V5JSZMUG5od>^RJ;xiuXO-x@kI6NQ+Z?)jhWQ_tGvm~Zf=LKO8c)lW* zEze8(46jemCi!*c;={;dQ==>n` zBD3=zxTkd(_RAKHl7Dhj_2*yNyUhB+K#YJ)Or&|A$4xf=hkK%(ZOcl`!*kAaDM1MG%Q4v0E zINPGT9NAyKs`D9P$Ne3h)T4~=;peP>i;}oGY!y`OJK@-e(_OAr-xFeb1o+LIAnc?5 zN#C9I384*-y&b(}6xk%kFmu%{^~89;;PSM_I( z_3tj%IxSf>^VffleCp%AGNFiuphmXIgBLJ9meMN`KP7l=KCw}!*ImE6T-|LZeo?}> zfT?HlLPoOw1}Ra|>$$HM<7sWQtQ!f}Vuk(uMNIYu&_{O;`7cyL| zFrVf<9YyUylww+e-(gqJN|DY^#4LHcVHR};blvOlXC(6E^R4ZV4ov;N_qPOhy+-MM zb=eZ$dG23TQC|r7r#hYTxL9+%lH`Z-doAn)KbP` zsYtj;aaB5MYsfx1{Y-yoe8hrP%Q=*Ulg>>oHWQz!qSh}1@e3`Ach%{r7p>eH`M>v7 zzRC#{T10wYcJ0KKgn-bHp{SXZtirxz#s7#VAsiN9A?lTdUNo}9T8Ld%?2Rbu27_)WI=jl?`Sv5_Vu|bXS*nQ*q9N0Q=)QujyIPLy|Ar+;Uc}O*&GCGA;&qDjI7u=XSK<>z@^k=3U5G_e#nG<Viv-v3g#*?QWk`X{DB#LiUR7g!<3ZmQ2d3!e*9=-c7oHPg#9hbN@kj-PH+!tX_zr zkt#YaX1`#PHJOfv@HT5|-6~lf=&sChP`=x?p&S^ybf%D{N%5B|)#Djc<6&4r(GwfP z0!5a#@6&q^w}*+y;{skhhx_`ph!r|qol+lnNh@}O)3^9z0o(Py1HOS#ThH#_K52hN3arKqF+z=OwwW@G ztUSJ`GkPCK(|0`5Zj`BLWkD`03%J+RBMMMFGH(~ih*|bOx#c9ver z(}q@5JspFA@0Q67bHk*en!&m0>B#_>n%vhHJcdgK3d9w!(~XN|7@mfY3u0LU_1z<_ zEMe$=jF8SenU~{_ebl@*RK$CL1J9e3OA`-a%wJXtokcgiC1zyUv?%7!;g8jz?rXTo zR9+nKbNrQ8G2eG;qZMIi3^_)_Ou}@73Db-ZK0Szz$CWK#%!;+^T+f%HA*&KKep2Tp zj&4}io>FqtM8t+aP76p}^xZp`on`~Mi(dhz>P&F!0J~3=+I~Az9RBLhG#L>{;S(uS zTy^)bOuzM9$e*Lcy1>r3L^ssom)6?Gb6?*JfAUzHA(fk5qratw@ODS?2WfSoT+673 zTuV>E>TP8H4AxH&W1*FmX1P^4!Dg3I$u}Ecq%xh!Qk3M)#jf34qe|uH5ZGd@86rsA zZ9*a}#haqtY!Jt19SIuU;FfSgO00$S2cjUbH%4YCsjwq$R9->CW5wkf@2F08J^0&O zz_?1J8jK1!R22{N`P7$Q{z@wlCP*;e8fp^j$j!q zY8QZ7%n3^6f92FZ8$llIum8s9v(|Xweg?#t=a+vL>n*V$`OL3Z8t)eABP7qWwPAJJ z7e@nmr*3B9pFV@E-clYe8rXoG1?#+A?0q*~OHD=fnv{Mxe@Ex}1Dh-8E*%xEsC_?8 zn*Fj&^GB#le7%${`t`CIgZpREtHTA}7kJ63HK$83^xI3(Ki%5sH*@`(lISaE9%m#! zwdo`TM8nV}ClPPscx7^ED;JuIVSY=tDK}o%7~Vj?W|$YM4?KO*^XA3{L~KL1RI#&i z*dOD#hO%`c7fuHZ<3NAEqxxDBhwM19v)#pO`kcMGYTe)VHfcOY3DaKC+ zl5L66Oml63z*Kk?G-2Vn#iysPPQgbP>n@NJun@e|l$!EK>&!gK5k@)+#iwiGJ*(vSNL0U1Xvf_g0n_@xOQZ!SijZwz3tEDge&a_D#AST;p}-q zCxdtHJ-P8BAX&c1Hp69L~J~if%B<0*#@U*AwZ7v=IS^P&DKMCs`RQzUo!6>$E_aX&XH)4j{YeyOWWxNOCXqaRL8oh2jHn`@=EWfNK< zc(!3C{)uodmtByqUY(uGulfhaJT!Fp$?>9Q>rABd;y3W@v~Bdo_?u|RV=h1VY9lSE zX9q5-4B$Fk@a=^iH+ z^6uaE_^j)B3E|W-AbAo3yCwUVQ~BDZ=okb^#8^#$6H`TMJ;ObPhNSrEC%6jRRv(j< z18b~CV31&Q_u#j(IcUh8AW5J9*lw5JnY&AaCNkJv`)-Yj?V4Z|+nz#T_gnmPb)CU! zT7hSRcfUl9t?a&Karz0}5{99-HY)_I9!NVkX8pPs-PF~6KT-8IbNyvn_41%4T+X4; z;!4ihzSfbXraUoCKK)RK!3Ig5U33Fqx?j;Z6~8*8R{ZbXpg_sykaBAT1ol8_XT);| zJucre4l}mG(`QxSN3LsfcZ`KHbuhwQNKveF(~d zoQ^PoJ}{{((5)xG+d17F%4faPzhwN_eHQ2ed!V~#ER<5y6A-V}Q9nB^?X(&AEH}0i zpuwDg=&IuNS4l{Rrb`Y^m%VM^7j9h{Yq6E=tDXE^if=9b(srFPot7)-kaQj}#=h}< z)Zm8g8greF{r#k*-Nr77T``J&RsF4G3q zBG)_GvdO8;55GN}UhX?4Vf@4>)11r*2!7X_YCUFPD;4h#83=+rvdy$QGwWt&L5;W? zScZUtMOkj5$t(|*xbI-+YM;*Do)Rw6Y~&gnd+L6w9r#|mxyj=!?0!dn$b!4knAe~# z+%ov_2&~3CKrp^IPZbrEgM&%rvvWjV;#oq6KlDzJH2{&BnoCuxf`}0TdrtH z-QvwfhhM~k?E=`uv+#xO=~9eTDMYx4=dTa`i9Xad^(J)~J$!bfdAJk*N+z(+fVx(4 z%{LbBW4*zD*1+zGEbP{D5D6I;C3^OOSgJK5h?*S<_?9fAp5#~kJd0O@xsQnhXQv2w zueaKPQ|dzcCLm#NWG={idkTlMpIAzOz{aG{ftQt~I<&fLdomQay6B+D6QPQXqy1?j z&7I8`Vvq&7E7NPKAk+|FcL-0I8C zA(PuCA(t!(!|pJI(|^o&uX}-uZ1W^-q{iZxhuaxmekqngsb?@k9nR>gCkP*JK_8yZ zitC?Bv20(7CH}m=)c!QG63RoJt_~Y-4Qd$LSZPlAEjwLnsn;ZpQw^mC4DHUyd`Aqn z))ju3wMRQ9#fA-!W5#36Oa?bp?K_697e^^InMavJME51#CA&zcd*iIfNUb4V{xSuh zPUyDfQr{RyAY0>Vi*q8#>NVP6Lv!@&u$%Fu4veq*lxX9^o)rToC7o(Jad4(yXwcKR zVxdiO)o9#!J{CIXm~=T0s-#^U1u?kuOO^3^Vth_t&&656)OswUipZ(`By`p=x}CGy zHq~Z0{lAZx?BHeHI<`@^&VMjM#{-i_%~`g#z4m(-0;0jAu!dIyTp;}vK`#{gNp~%0_AD&|HMtUr9OT^$w zO_1q@jEboZv@YzYnk5FGhe3($Y+PFBEx+DWhQcNujTnuB32-4WVR77)1+fz~Exm2Wz?oVCbcmpw~rvE?vpJ3mSPAN>2LJ(Mo>7LhqpL39=KD zjE0Q$jGb3il$3&t`kygM^3bX)?qU<~!SqOb?*eICbpyv3{PX0lHU0+jug;Untms6vL8O)Or zneTVde_BpcDGaDv!kiGSzf{a7x$lJNjtO!8$Le33Sn5y+##k(%j3|qLc)ahn*j8Ep zu$Ru9x~+d)Iq zdBE=%!%tEJ-+d*_{WCTgoU6I4`9&EWe&T-Q<6XNbddhkRKo(Cs7bTO4Y~nCHKPPT{ zOy^5PxeOlki!nP2KeaY`kEmaicaDN+X+F)2*b!fj%VqeM89g{ACx5<=_5LTw(;5;z zr+%iIxA9>ML*B$UMNF3yq)?I>gjO~I?zt9bG%m5_pSWXPLxG{b3ZS2Hh{fby8Ny-} z0u&7fpb~^o*Nou7-8sf*OtOGsMjEL)_OdJox4*_AhNY5!&wFL3FmyWO{Q3b1I8^fN z4cEoMCU7 zaiQU(_qAE8DT%h7b+~nRUUJEGC`L%T{Sq%Xe8d^?OqB4Z3Hbul6j7vmUD00uA(z3< z7p>2(u^M}W0gGI0^Zx0ceS5&wmml^l9+4PocB-MI`S`^M+IQ0>DpmLxhSJisKw08Yi@RUks8 zoRqO?g0W;w=4$l(7unItkOx0heQPysG)lvLE=Oa6^dw)_@R54+FEeG#9i+4@+Z^2G ztewHQf3!!M+`o5w9;dy9xUt<4UTk?R8!r;F#+0KkynY_;v{SazLU@Fd%8k??$7|v2 zlmjv_&|-tNUCjRfyltQSJj*$BINyIUV%Tu4tsuj25a1}=U^&wfwpwysjPOPoNtA{^ z8X9Q^7Y9webjQEEofkD-{#hzyhTY({w%Rdto`0c}5@-28eSovs>*piE#c-%tvJI-K zC@P+@ThuJlt?Wz6S85;7VRkx&ZI?kJ!fc`SK@DPx-|qT5kK@nazyP@~s*_M=EPFB~ z;!{!>6R`s!kWaXs&EM(7pZ+ezENH(X!m$cS{kRA0E0*XPW))Qz^6s(H{48m%_ydvOs68^H?2VGUmV95&Z$$Z`e_Yx|$AOclUbd9N=vV`35a! zI@`1a3GWPlRa2Gk-|^HsH|Vvi1ld2f^Lqr?E`@%yQB!3F>4a*Wr~rkWmdutX=m?T# zxGwrXk%nlP-Kn$#J)MqAD?>s!Z&|W2# z8lWH%NaIKCc@hbktJ`D<2g1X;Jz3_DsCO!O1< zv^`I;1@9mZ;wt_FV&#v5{GE^t#&VOc+hj#W;pXK&U(%+A;othbznAB;XJ$~yxCQNN zNU&E@Q`g_#WFC@Q!w@YEeFA$NakQ(Doi%UL-)uRv{4=D_jpD`yKl|`b%XB@>w{2wQ zLO{t`F^#4nY@l|K(bnMLRu)N0qWGCa_*!mAU-7IlD_r<-)}r<{mrMK@;c1$@hJSq! zLO8qZ6G;{eu9Dh(ooMU35m*}8RD9gr_rP&!rX<_Pqx6Hq9cjeUD|sXjseN>N?EC*6LqFJ+!}(VWt385cGv<#TE;5tjEI?Q5aPT7<$c(|c<6j?*)wP;m8_Dy z67I*DA3WPhJrT@Ku_}-!X1!yjq%%wmu&*>+`5&1ys7^;Va`=qIYwznAfN{KYWtLrv zQAxUNaM7Foq)t{N?(G%itqLBou2SAjiGMjCOJ|+yMB{`=A7gr@$5Hcahima8OV@f` zPDfzU;JRdU@kFf$@K;1UinUlBbpB~X3|&&ixyMbj_MDXR^jPwvpa*cLr5OQ^5m$>> zGrW~-P3B@6DKm0Y5>0_RTeafqYzJcD^WY|#kQoei;V0#xAg-LH1mp(lvh#qtG4*KT z4-S$l=&sri{QGMo4&k|FXYoAhWTe}k&x#x~a2f!2^k02I;1C}-j!)H|o##3*MMxTDR96Y4` zbyoqMMXcJ=F9;#xLkZRU_3a4avVg|HZ={fdOMg$Nnvilp^2~k|e|fI!Naczl_rf1S zhAC0H>CljmQ!v~6NrVrSXXjOs0M=!@O#mmxy0^0L2%w2jeh~iXv&{u3#HhNL#78C* ztNhCbhc8dMyd#79h)VBy#BgF6SB;RmtP~vySAW(0(FX|BO|>pRYJq?ieOFuE&rr$Mo4QNq+jXl=8L z?%|PWDwS%*ELr=pK}7+Z&RDy%QdI#Dm2C2#vR$`bnO3*(<9Kk(MvG@cHu@RMn?bA= zVeLIcGK-UxK)-?1o$uBzV2RH);#BQEPZrEH=3NQw+?8t%pz416VQlYU5BjaM7x!K7 zG`#%;IR`+!;Q5O7VHh?U)IRxVQjn<2wv>Y;D{Wl-?&J4z=*0Rh-oW6sIx^@BA3y`n zL!Rz|y7dYm>4b}H3(m+)cOmCxHA*@CcYuoDogn~1IOj$#tK)xOKMDEX?AY6HMn1RS zzCg%CW|+Sgxm30WsCsXensD%;mWw9i)b4H6yJSr)W3kCJVdQOWMf)i2JYAq ze(f@cf@Fk9h91Iu+K(^j6YF=E+21NPL%-ZeqaXUuNYhn_b^lbEZz!px^Z^j{)~-&%(d^fSfVDb1ps?o2Y8EkKZp^ch?_!ar>tbZe%EL5c63Vz+& z8G!hZ8FK3N3*GEIVUfh4j}58a&Q=!a%Fztd3+pX-^u?1Cx93{H+jHw3hrZF70D)rc zOOOfAP~~KgGks`@CeV|K%ZrcV^!sy9rjn=SzmHcAaUXewr;gDAsZKl@fWo`^78!rW z6B(PdD)#6v6SB_veji1@{xSPmEx{Ldez?|l<7@iJPQkds`cw*4CNSJ6A>uVDGu77U zruJ`ZZl=Zk;ya)dB>xOr{GxF-4As~z8@)fJY}d8#!cl~Yc(GZNHS#C){z5CXrJCN7 zkNFyOIrC++j`mR_K|Q*Z8{TynjQM*C(5JV#QfbH*%TwVL=9wcJzU=>5yk!Xg)TZ7w zrj*0;aHiasQ@qGX?fS!! z^~Q_Gg@?xlaSxA=7*jJdo6F48!0{1vhS(8C>}Uz-%8Y+RKccz;vo`OFmhyiNupN(# zyjPbdEgi4HATo#>?G6wJ%~U2^Ph_@ofqN@+w8NNc>d1UMg^|4Z5H3J_D5uU4Td{-7 zRZ{&wHrs8+dRrx=wHB`EY4y56eco^x#5r4=8r(7#WUkn6kO}m=%#uLtWV99~5Pt2! zxea|9_#C1vh(qi#I6s)9iga|~`*SkAR5zS$Hc**hsLfg?#`UtE9L-z!9^p$EIiVo3 zdipfeW#6$Lh)Ej5!CN(AKVoI{WaC@K3U-RzlcOoS-lYa`+#t@l=bs$eCM zey-7<1{`fdU+DxU&~!X46{USTF+E4D-w^@I$Gas``oY4KfF$$>+6QrmXDm^dZ`gyj zIKS7+1o(DCSeqzu5(MVqtRn#UyS>JO&?Ynj7E1ynZ~sWqU!NG_5mDp>i< zC~6nW=5A7FQkWSv%PDOawRQLi7)CYk&~b;l(V+>2`nl!Zr_D%FKHxVXg-olny&tz5 z7aKuT%Vzk3uH+kUh1`_iRjg6x4L;n%RrtS7ACArjMK5{}wxMyE?q~m+6nxq~(0stO}wi7DROkYV}X=v^cHSHLCZTo8(>Z zogv+m)q$NDL;%axs!4XjivRMjK%H_Qlhs zX{g?`1iY$3I*TZZyUhbXE12T={)Q=zn`9$=!%ZvYMDsv`QDKyngu@`SWcPgU^yB45 zP*4ZMfuC7bt#_KZxTyu&%$21Y@GEamT6D_BLcyPhT+JGN`MJG7ZP|c4 zGoip=4X22V!hCZT-u?wfkVk#;BL<-VRB$-4DVb_7p5o^k^A?@7A5h=&g4$a<82NO> zo9tV=mi_*ECicFs3Pq*pAL>zlOM|!GcVr`0vU;G8w6}<1l)-J+X)|TwK;2sH=x?=( z0$4RDu)_sV3fNAIPL7j}AWmxhs&DCW3P)vPX(x*6L#%|Sn0VDwt|Ik#Mpe@5d7oQ( z1^Rf~ixkTvD-H@-&QH-)nDpC^?q=xRdoe3>TWeSv&v`B+m1FY<;%418?E8oM;VGAk zOTp}e{{V@VgwOpDu>KO-TWqeR(Z|Q-Vi%KOYQQ}gAdC)~3MD2qH86K)TSd$Y@d<59 zVd)N~DY!Fl=uX@-e~Yi8xHlZ8MX7399+t?VinBthJ{0EehSOAgdPBlgdtH@D$QX>F zz!TEFt;J?}*+WL+@1OoYaejWS8lSMRZaZBX!iS*7G|RD6e!rIm@rWIKK9%3N#M$2` zjHW`t2yilFfJ}MZ5}s3&FQ>TV+^;@|Fq-$QCsg)VxX=*XQ_NC!wiHWKca|`A@?_vO zPz9$RrY3{c<*TUp>nCP7!36=1VidIT)n*qVrLRMkQrP!VYTx*ujBkaP4zcfZ4z7f$ zU<>BY7shDU_;yIfZK-+i{DbP1;#Wj-+>2d|Dq?9+3&5NUil@r|<0tXdaA#Oyjm=WR z^*5ZH;6HPtJ|E-N{=Io>mSGU)+pKNoUVO4?A(XWd5`DkjHaX6>;#b;;p0xvJ?bFW-3;L=u2|D-NF<|vv$&h){t5W7&7y#_Dtwoi&N5cOB D@Mf8N literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/rotate-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/rotate-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..43bbe7541f6431da0788781cf926698e9e8ccc03 GIT binary patch literal 4439 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 uaTmy-qXKWyfpai>+~?fqJU_2n`g2?~28lxg z0Dxh{&^I|;~10sEIxTvJv#5?6lA);!0@!!LqG`qvaXLWF>^ zAqru3#Q`X^6MHHK0Oqwa=n)Bp0~3SEl7wAeT~pTmWGJNFg`2!7K0s>0|42Tj*i!U& zN|sZbE1}(jztj}t@*1zANfn3ZFKG8~n_oU$(yCe1P+p?&EyGvnZ{c&b!NSkNHDmbW zSK6*n(%C)ek#Eo_W2^D>p0gu!M)DYy?8}g?_`02mdUspQ9)+_OUPhj@-p_|%tYZ2& z$@HLf4SvBKyRjG(;AR_h1g^&+L|vk6{ImP3Q^%0z zWf|A4PiPccB)@%LtKg>}=;yj>PT zmJ*L+xo?R&%4&lEYjwg{gn8*9Zc)n1Ka9QEv2IvzTi<-uJ|+%h~KKU>&T{-#(dkwaWo?P|4P> f?SmEXPuPLrSH(F2ftkaOLIW64arEX$)`9;3cL7(F literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/search-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/search-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..7d532ac56a99a7f668c341289b78370a9f7edd04 GIT binary patch literal 1526 zcmVe zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00mx2L_t(|+U=apYZX@*#((b+ zNus-?L5p?~O$%C~RQw1jmR4)kg(c8zblF8e@ITPtLTE{|vWv8I(S-$f@hhSAtAO&MG&P!(pfznoR!p3i=wnhI;GmcDM>B0BFrJxCJv?To23wC6>t?;Tf-y$ zHt>p>O;&SrP^B<$0~0ka49>m@XK(i6NctEUEZ71%=Nr%krqqs?=Z+s=G zD?!-MiDI>TN$XH(4d>mtZ;i$*V|7cDEbwnBAt5DUQL20BrkAhiL zY10P|WLP^okb^+23pL#5fp{QB2b(3mC+UQwEAH=vyVe}z{(+3e>07ALw8ilIi*#z4 zq~kGoj!Rm$2-p2Ai}sa`b$TG(715cEk{&1EdMs&U1mCWVy{EH0Lf)TpIv6*zOCcRu z3)}#j67V$vH{88X<~*gg#xo2I_m_*4c6I5G`0RQL-s@GinHJsiziguiH(Va#HAg&f z9|_@Jp7GFXG)cRG^C?vR!_1xw>A;MKJZaXP}QRcgnHbe;YA$5rreNDWsgxw zA4pmqA;@a?ozaSWyJ8A@+2_*-DV`fwHS^4~=HU$h7K%5^X#d#?3 zXBFH-^TPbcbDY{8o-24+VzZfD5Am84KsCEPo;R~w<@KEMCGi$;x*+0QleB38VZN+V znA7FLJmEQxyrpavDFQZ`*)PuaFMxNd&r^Acx6Ewaf{}NGI7>U&Bl49=pr_7->4`ex7%Y;|og~|RFi#WxQHMez zhgHQ8EBXn&O2j&`w{%i30O;P@R*%(zntiFuye(t&O!Z24!e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00PBHL_t(o!`+#&YZO5g#(!@w zf`S+#1`V7NRBSZb+=&p7Xs3n$g6V@GqBcr8Q7d~>8Au^Yv=M>`0VN<@8Zm{1qR4dy zV~k3~OFj!HVYBYt&Q5Z7#;@AhowxJt%)Ix$d20khQW+=%{Xid31UlX0d7uis2Bv_D znN?^uBy~v|Ryc+wbv1*SNg9__)A~_!@3M^|Hz;XA8;=D^gX<+XqUK{HgjhjRMXf_c zQX!3t)gf2`O0*W!W>!w#jMA314dehynak}QqTLuwU1I0Bc4V=kuzz#E0a`wh^#IcJWj&@$sufSOxUo(R)x_<%+9$&cE%&MNzV3&JuUMvCK zW;VCtBo{o$Edjkra*|4tuDdkWzh?iK%>v!P&zuAcj??NOKDd=2wqMdrO24;~jwJeC z4O!<^RpQZiJ~3d?!{%VZW;TFhIdYOI3(phnF%O%EiS~nly;zQ%p3A~yY$kRBCp~PA zN$QEUrveD}M^0>J;a%J)#{j1jaWgOaBBzA2uqAe#$0HYG*Bt=_i&0FbH^Sjq=y;lA zfJd?G0|5j(BhQWliS|7Yn+Y>pZtxB-n554@);VF>%nC6_*$R9BcGv0u1t^-?_n1x1 zGgHMe7kO^pNYazoGA{x>z$j2l^t})40e-~D-3%c2$FU@h0do|wyPfFU8mW6r4NS_z;r9gxiSBf^4q2< nU~Y;MaJ!4>whpo_`3>f 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/settings.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..e24421bc0a011cc6933792ba981b86c136b80708 GIT binary patch literal 1079 zcmeAS@N?(olHy`uVBq!ia0vp^TYz{X2OE&gS~F=okYY>nc6VX;4}uH!E}sk(;Vkfo zEC%Yh4#JF18nY{ag6t)pzOL*K*hIt>L}cSuhchrRAMtc?45_&F_OAVksiiW@%U-kaXOpXDaqdq4>$NwL z!THW=<>yKB)?KLIl|E1MbZF`71^?qO__`a5_+0fd-+WLrX^WAg&X3kn%5yiIJ5 z{5K{_DW7cgydNOE=2N=NjDkOckHt-Z5+F67b1hH)zVgD_rKAmd-wMp-oaw~TI=Msd*9kU z@4a)Xt9@ej*zmE?mn~afM^vx+{^)&B=-bt+cCUK1bXAtNzR2Vp<1k16)Bj#a+`boO z{X_nIxyi{z8@Z~a_(HGF7JhHIZjG$e&A&z2xzBH$uFU>D$tHVE)4VqCzY)>d+-tYa zy?fos{@1%3`*y3_Jhwfj^&)d;MCkPD+v<~QF4WF_5xZ1heP>2Y)4bC7Z|lyPtKGa9 zef#3u-OnOeY*)*@h;99U?rOe8)T?i?#X8xK*_0!SqocC9L$`i%TV(4w@1@-S+xxfs zZ8{3_P~Ll`y7jxg{!e>y)$sV+mwiWdkB9uRNc``g{7p7{t?wU2kL_h=JXmdY--lei zSjZh(s&-OadAInaIdM;a`jsD7cu~52O3M8#_K>RwRnpzd@?)Mxn@O!+u>5Jv|Gy$@ zw_cCRw%>lOZ`-xJce39n269$$*uA!m^ZArC$=7q<>8t;b)!41xugK|mzU6*(zj^PP zuiO83@NeR(Vvu`lYd87H>~|meJ@36=Yy0S4#0BRKH>y8wj|t^}ddmODyVa}WtB>0z zhBV1FEsxH={o8ugtKCz@yY6-$J*skEdg_Aq1jUmluibk5SS&i5U)}O~nezqbqTosD z>T7a)<9W0)1WbTw?Xbhor(a{@4eBawIi!F|&JCFIz!J?1uAkm?`AN)~;0yoS{hlYS zYqDDhOuKna>sAGO@?~ef;wyiiw5?k5lu2~d1#nP^22A-VL@bi=Y XYwbI&6}&lNpv>jz>gTe~DWM4fwmj|$ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/shuffle-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/shuffle-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..8dbadf6e31e2da8e249f4fbeeddd772a21c2255c GIT binary patch literal 4873 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 oco=4Qpvm3UTzphg~Z z^FXfP<>=RrA?t6Q`=VXHb_4|lncCXeaDCe>ORR{SbvI*z+J$)5P-cHVc>%uucan^M zKeo(n`0ekJy5tzqybWT(x%-Ph_Ss^{Mq$+BpzX=D7Nw1Xz)4Zt7LoQV{7w`|#c+)W zhvHBH`f@1!yrWu8PSuojN7ip4qg*q!=vV7OfqdW#$Iz`0KaW=X9q+thAl%vn9nx_& z-%;A88B<{}_#+Q7rrLd-<>l!qfI7#736Ci3)E>kY>=+pg01wpIG=5ui7E%W4Y!t$Z z@R+az(Ojhnyq&fTLblr7$3%;4$zw5>Tc0$ZZiH9_`lGOO9>Nb|=R`JV&#IU;-Xq2) zms>(IM0!P_YFn`cDmCt<1bAg$maV1t%~_UOX+8kJ>!1l93m~9qX+6c&LvbE3 zh+Zn_^NC2p=b!1hMx^E9Rr=iwkqsY%n*zbY6&x~gc^4vCsBASPmC-VsW=2Kth|<+~ zbMF;h+4_LUVAsS)zhJ6iHKc*42;nIfO<8EIeXo8vfHbVqoW6*L9||SC-&DXjKLR~; z2>$U!=yjpyAH>k@()E-vaJoXn_AAqpDnOG#dGjkq1s9&CzmJ4WRa(MR$0k*d`+?R` z=GwY^nU@1;|Fy7v4V>VJy$j24t_>XM&w+W6?$WdK^8<~nHKS_rA+e|VXPnBEmNYEI zB)0?!Iheng@$n;}GTzrF5l`nVWiEH-bq?PIAF|aT#_IN+jp2&^{cNfG`}^A{6zW5Q zS+GL*MZjtt74vo%zC|dRtZdvbXi zJqd9{m@!&?F!2HkyPDg4ScN>KWhUF9-w0OXzPX7R^&mM@b_HmA#@Mo1-( zmP_b?&h?%73UM~8fCWFFz-7XxP*5!k+Ki&sv&WXifELb7pR)&t24XYX3`X9JaNnrf zi#*g^>k5;3zR(hhiRq7t0Wpo&G((+EY-nosj=|iO zO7J0I&TR+D{j3UMelK!?y0S*+m8lS4@*g*p7d1ScvSy^nXKyaxT$eU_?sG*Io!P!Z zCsaZa|UwDYVlvld9^?1&)Hqx*Y~!AV)vOByUbg?lDn*|ln8&48hsrbU~?)NK+%;=-9zWBG`l^q}R2x~YtPQCLiyFw?kh!Y_-tu_LwyPgFMH8k1 z^kcQwfjO8d2V*u61D%)D@EOhxvPm?FnD}>IwWnC7ml&^Dt)`YxakHGuZLoML);ZVb za4-@+%Kl+dgjrxn1vtD~Rj8bwY;nJGEsa8hpQ>on$Y?7X3T$R~3h{xobni+}`Y8v! zSQnq%dKnuxU$g$IX7NV+D{3WJdqKSf#dsT!(zO0$P@r`_tr{F6l91^+GEcwssXznh z>GaX)ah(aRC1Qk3Afv?i-8BU;Fb$qy!I40EG46c9-c>ai+YQU<+4SN6(B#t@F8X+F za=kG+nu8BukSQa+^V2mamYPeIZJ^%PO|_rt?uus4BFQ@0doznlSF0y@H~ENWGl@YE zfXXSKN_B^@;mH@xyMuKy%U&v@wJqtuh{Y{B0-m+R#QsK50ApeZ(dbZ7GQy4j@7L#l fzk+h>u1RkUzRfFzP%jdzKR_E|p#DkKDdv9wTVQV= literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/shuffle.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/shuffle.png new file mode 100644 index 0000000000000000000000000000000000000000..a67dbde2bc506afe873fce3eb65c2c1dc3b6299e GIT binary patch literal 1407 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/square2x2-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/square2x2-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..66f17a8c8cd7e5275b34e37a35c552d75b55cc38 GIT binary patch literal 3445 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/stop-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/stop-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..50588e55b9aa8df1f4a51361d9da919ad0a2d83b GIT binary patch literal 3402 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 TP8&S>dH}}yW_l%P=ZOCSs^NxX literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/stop.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..1a8d4d9f7672d15f4097b0051ad3983d7d4a69b3 GIT binary patch literal 474 zcmeAS@N?(olHy`uVBq!ia0vp^TYz{X2OE&gS~F=okYY>nc6VX;4}uH!E}sk(;Vkfo zEC%Yh4#JF18nY{ag6t)pzOL*K*hIucHJ`Jqeqdl=O!stg45_&F_U^{q!v+Fv7yt8= zpR-*WSz^<^wbg7ib8)5@xq$Ynhjk zs->Ex#NEqxCh3Hhihg;VROkO`)!NXrpFH z8+A`?`gdVsWRJ*~Mar8c)LyLGr8aZxmR&!q#cIEAntC~B?c7N|o_(Htzp7?MPfF!B gWX2U9K=I_COiQ-wXWv|~JOQN2)78&qol`;+0N<6QUH||9 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/subtitle-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/subtitle-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..5584950602a5f0cceb0832c126626b4ceddc926b GIT binary patch literal 4620 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 T)?bRP^FVx0S3j3^P6Hn!Inq?0q?Hm zNey5Jd2~-#3%LAu<+puE21h8p?pXSO9^d{oA`PLer{EyDFI-=ne2J0`svw(7c&-Zo zOpS0Y^#@O9w{wELm`vOIUwnWuGBV&Lm7T9r@>g{&n09e4uh`vs`wzMQ;xxyeuN=Y$XIQG}2 zk0a>J+o0p8FRI=2{=sJM#?HaU?z1sW%NXG0{eRk#Dt|kVjpQc-d!o<=epWQ1J$t@O zLCD)utX;r@`o>SStPW+a*^}-#h4DXWBu5E3--Ih;a!6%S0|Ws&QN}9AuU$GZ-7&W; zf_omyDAPMLyY?)huW}#o)71$ZJ>=efnA)jB)1^luwYi!GHGFKA>V}Fg!Kx!{_}K*RVMNfk17t4WptK7z}4eiO6g%Vvay_w zuL;X^GLLASMG+0X8++x^V7&%iC_7Zo z#gAqKE|J_rE%PcPVwNiZ=u3fBF*HZ;p138H)H3Z zB)~mTW%hBB+j?l4^lj>!@rgRQH%f!oBNTbQ;rIu43;kS#J59XQi6uQ^3cQiFRn~rm z35R<%Hb?_H2a^)A&ud@&8A6S#VteQmN~UZSjwO>CW$xss5{t#MrJBN)ZCCj!oP<7c z(LnM(4-aQ&WM@A!)X>n7@|t;HSy?GQJ3E_MQ&STx9&nFJCaH&BYaLe{=F!*4a?NGv z3m*TXsji^`vme-YoeOhPT2N3hx^^(tB}w`iZd}Q4?Qcj{8ZBwO}D9%M4iZs4OJM-=SF`tt@f;F!hir#Yky(&IgLIHtz5ZHeh{V;8l|7jjK_KCOnt)Y{!LbA*n@8 zGY0u^TT4-Yuj;MwyAE64Za+iJ!dM=dCG?awP5UCQpo<^!@2Cm9tV*^E>+Q|eoWQ;_ zwsS`#a1lBjiCV({`B@byT8SmFQ@gC%6)?k6>{d=^*cCV^-bb39OT1O-T7LT#V*{WaHpIUd&76b7Mf(7z*XwAHd^Pg&|HV?j->T?FSJ}(c#WTpW|ULL zb#g&pUw>E3vIdWEadEK_aJ&kr!Qt>v%e`;<#cZ3gUY#LCc99M@*xPRUtCs(6s;481 zq>!q{bwM}a=aiBJl$`k?kK;M(hpuPGzh*Gzl{QUVIp{?N5@5XJ#bx-|?aNlD;dDuY z$1HZE?)B@}7yy{}Y{;DWduWG7%U#iiva+&%n3|eu<1){L4ibm#42W_aSOhXU?l>AA zrz!og-zt2;7qQ@(&$zT^ULX{DKH>O*Xkl@2u|Du#pEv$VA24P~$QT*$OFF-h9> zZ#nx4n$E*qX(TScudlC&Ctgt0|6=PK#$MHHsk8n0+3{b@*xHu0iOK%-$?p|j9t9Ns zhf2_KYyZHp8i%P!p@3(Pisppfls=BgS8-VIrijQEdS^a>16Z0exBuI)yu3W)*`O3~ zcDy||I5c$0;rBB#GP2hsUE8=PA|gU2h_JK$s{Aa1Tgm^ID-x-&`}-+G@+(}2X}d%k zbKN|`+7Feqz?{^$dA8eeS^x3l$BT-FMMW~83OP~y8|u>DR#~|-0Q><~T+V>G zc&Z*xJDwHHxol3BF7j(e(ma|k%0S-dj}wW{#;y%@K5K4n4m9Uu0K<3g627avxHvyA zEG$&Y%*sNuGBZDi0DJgkL%N0b=RwH3cL&9%RL53+7kbV&{=U7_ae1MHo0v$Jl9EdD zL7`gjrHSQuuk^)Q$9O`Va9hLj(%aChNy%*)-+JG$8lL^Vu$`;-I3owtOiiaStfE#a zd7z&5|3eCXb@e$Fuy;6NNMBJ=A*!dZ-lxn*5#PDjoW6IE!M@kpubc3ORs3RNm+-CQc-HL_07^}axn-W#!^N7%_w1~!X5}--#s&u1@)8pzRsSe+(M3TuZarZwPL0jWg_9p- zq}c~IwS$Br1v&@citJjoKJ^a%-u|5Y`Cb?K?nt)6fuV7_+>^!ZtlZpS-d#7Z{0#R_ zFoWER($doJ&3;>yKnO_17*TO?@%6ce-KEsjR00Zxx?qb4m?+jCi|0{M97=&)A@$w* zT47D&$=DO>UkS_m&%5UF5a_)+l;$F4U4QHHc`@>p^|NH1z|W}siNP(xL7b` z^-!Al7^gI1Jf}aN_cG5V@A)x308D%^A*7^q))f{O23;G=qaOhi8*4%DdP-CIxwxz~ffHm1Wgp3a3AWYL zNU=EEwfhK-56gc6CGN7Vy4w5CE2w~HOTa;~{PRDDsh~v0LulBRtQ$OS)s2mfKMK7* z>1DO2X+PU((GPqV*Ll9PIaL;~n;n49lyP&Gq=EfZQWm{ne=^ey?kf^A>eXX;;C#mz&=r5c6jFDIL z%6pwpj(5LbT4TOtJ>9?+?Uh^B($&@1^Khs>J4pv6u@#))hg(BNP@0<@jY&E^sk zXK9zw>_oS3l_N)iZR~UpDG1l{C0Bjf@EB$vEf<$h;grdAJj&@X-}UjHgSD~mgJWa2 zeenZ{nyPubtic^G{7GFcu!t{Tz^d>Q+$LS#pW^{5W1^yum8q#|?n{TSuDW$@q@pwG z;qp6O(k~iE`xeD15MbE&IxO~lbme#BShj*sSxL!yw}5Wkv-N{hsj{*%pM!$~-Ea+l zi$<>>Uy6&1e}W0xCRyHQA~{Hdrt6xSo3AP4OGoLu&hfA-aG6J5Aypq391J`xh*u5# z7qbIga?b15um4ww3Q|&1TF!%CczSy7{P2?ZJzW3N{SrcZlQd*LCME`Fc>C`m zL!X5*2%6t(c`t(5fnik3LX)4LAI84Lzk<;*MoCF&tOBGkBQOjJnd$BAW!~Q27Oc`F z1!fZKn*?!YjshNOJjkJxJ9Big*rU!nbA&fla}@-TvLOgj0Er4*m>d$9dF6~dmY)!uG{(-M{oZtmcsPALs(Ni)Itqhq zlyH9(2Iu1}bx80RYn&b)zvkf@p4RvnQIW?|al(&Yp&O~!Ob*lg6ejSI%Ywwe94gnS zS(}wtw0(_uCc`JSzI4I7+(84)(xeI79lxrsG;6jnPK`|*D!#K|g{RwQi;~?OEanZ7 zJiBU{G@8dUaC^>SVPWAmDstMWP*m&f@l_8uy#a>gL=p-!g9k#C(YG&7R?@hx%Q7LU zn?wxpif;gKc`F2=iOcmduklVhxKD^K=!v}Q@ow7e=C+&s-2|!(iFjN`=gk}e(USS0 z#o4(z^MJO+D{&9bC%=3#UOPB-RXeS@X-wj8LXc%rPk<{CzXv#=z+dqYa`3Dr1%tWV z5ET5LoRE+(46W6*wY9a!*44>?K>TY*=8(wXB$`jVhO7-ueaS8zV%Gdod$ewKF)cV1 zr|;PhtD!{*q*=~o;#($f!uc2(C+AJ+Z0ZQrka57tJYb7>_9M}lq_$>$IxSz1uhb)6 z-4CqS;vIM44muphpMPD1nMP_fE2lHK7C8dx3=YuAvDGS3%@#dkGfD@V*%yT+lfc~& zx2{_Q=Qo9#YMC7#W)Xe;6I?g65W?VkJp}p0b*?{UKWFGY?Q0>vc-uXTSBb;}cZhzj z2fYt13Dpai<1x@Dh9MqgOvX{K$Fk&C+jyf9nd$swY;e2e$`rPhn)f{(MMh$jz(mN)Wkyv}pPy}^|?dn0=a;TlT z>xvE_-$!l~DT)Z_mftJWrpJ+`HjAa=U6bhe-p8;GkiPo0!|;gP%dLwBa!~V?j62nr z&h`eeURH%zg4}N@y<7E=WGiC!&f8B^Kp^M18j%R2#N37fmYKYe zB$!9CoQ#KaUf5ldzJ=4;P@|}eUH|gXAf*~b7cJRZLZ1j_yyI< z?}dS|)m;xU&)!$3-YpcVM}6AfnQ=p{ao6s1dzb-gvbSK%<5sG?{#Wjli_xPW9}C>Y zkj?&DU9PgG=G!S<+FQjd5tBz?$jQIDQ?}AJHU2-AU2#bc*LkTd{^@WG{H+PVwGFf? IH5|hJ2bi#DjsO4v literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/tags.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/tags.png new file mode 100644 index 0000000000000000000000000000000000000000..4ef59db7e7100812ffd9d175cf34fbf1280bf906 GIT binary patch literal 1601 zcma)+dr;B|5XWuwd|gzQ)=8!LOf5x0rBXB!Lo$_oW~mexAf?qQnex!my5lUh!z|M@ zN{YICrv1qGd0CdCkzpvmL9Qs@*mWqHs2t7Q+~4ia?#}G&cXnt0`230w#X?M>rh0mM z5L^%@Tvr=(@td)sE+4Pt2z14e7>vc}X}>zRm0zgqn4AuZP1PwRUt`4{r_yv?(};!( z2{ii4HPjAOw{SIR}eP zphtN_7mXi=ABc=Z#z&@cIse@3e`ni&zsD^X&gnLHa9z!djg2%%BOj1TmYa&Te>{CO z)Gw??DCSZt{HFSRRc-PN=4jbjii7TmZ!?k0omj`?jBC7AI3>rhev;m6h&y3R+>DmM zMn>&rVTZR4yl1DM<4)GYYwq%Yc5i+iGXXdbvNzK@+Y;|uENtl#LKJw+N}Dlhw)bW) zyt^4hwtr)@an%JbTBL{8H-N11G=^?TJjY#;ZDA4#3AYroc>E?a0JXPYT?pNuL%4|% z&Cb>FeC&vnKJ6adCHr_c>PbvXp~B7~gyUJue8S1!x2s$`U7B?=pBTu2fGtQ_+>WaWhH7Dg)F@uq%1C+9G-T; zMX1!8;1cKYsY2GYWmW5*tfLI3M>`If8}vKE$n@}YA&d=7)GGN0Z^zzd{Mi?G14)UK z>^o#by}&cFBc7>)!=gWybu_iy>bN($9owqxE=H0XBteIqsXX2Lrf0+CUV7*Yw%2pwUD^;vd0Ltc6dtSh*?CJq4Fvdc4qxig*swoep zAcpU&SXorYKK|CVx@U*nTmMku1)TjbAN*_+7EA#3!+7wK&j50rCt5->8fknNmO76F z>rA}bk86} zbf#XY=H8U-1`8g3bl@N|$(aV>19MP~w!+xTORVhjI&x6lBBZR$cJgq$=nxAqKuFl{w zn_eQ1ItJ0*`W}1JdUby4@_jbPa9T2$4S0q81DdCew@p<&SE|Ng&-i#Reqve2b zEM^L3^(N3#Rn)8YcWmeXEq32sRA6;*x|?r1d*GwObZ>CU_VJ>XaT#RANAl%H=kn8) zq9Ye|9Qg{A|M{|8^dDbB2e_;2N(VPona@P;A`%+HMJLACtk-ZfwsTihW~+W^^|MA8 zwD~%Ds05(kCa#FxsP3%U5(ww5XMphAc&VG>K3>$9jqk6>!N4uPig1CUnCd-8vi}9v CjP~3B literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/buttons/trailer-focus.png b/script.plexmod/resources/skins/Main/media/script.plex/buttons/trailer-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..57bbb48aaac24bb0d5ef3bf034faa5c9f6322037 GIT binary patch literal 5999 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/0.png b/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/0.png new file mode 100644 index 0000000000000000000000000000000000000000..5ef79460d743b1183a1957776f2e5ffef6d87441 GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0vp^9U#oX0wkwx&b|qxn3BBRT^Rni_n+Ah4nJ za0`PlBg3pY5H=O_6J;|0^GX3uQVP2g(OQ{BTAg}b8}PkN*J7rQWHy3QxwWG zOEMJPJ$(bh8~MZ;7#IaST^vIyZoR!?=q*|xa_r&vcro2ZzC)sl9SR(CWSj)Gv2spmec zr(2#2SI^FQ;@r--sALQo0FG)(yWXtr#-Kn8UFIljt%q0-#&Wxeul&} zg|(Nw_0=t3oHm*LbI-Y?X`epaI<(vIiNsv~&pYm2$$I|rv3^IeZTdG l{ps7Yf*FCKf)})%7LD1vM&<9HyU#)DJYD@<);T3K0RUZ=q0s;U literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/1.png b/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/1.png new file mode 100644 index 0000000000000000000000000000000000000000..a4571b6ec4281accefa70372f253c38f66091b96 GIT binary patch literal 516 zcmeAS@N?(olHy`uVBq!ia0vp^9U#oX0wkwx&b|qxn3BBRT^Rni_n+Ah4nJ za0`PlBg3pY5H=O_6J;|0^G9M#u7e2A;}Wgh!W@g+}zZ>5(ej@)Wnk16ovB4 zk_-iRPv3y>Mm}){2F3zU7srr_TW_!J*KQ4zIsWmy@s3E5=0(wUI$k|pANT{<7N1pU zJ}SRZ=X$~dp0H-eNkLvI%BoX3i~`t#c4)qQmb|$A`Nw3z^OgIrU0!*4ck#Zt9`!Br zLoY3sD_Jfb`!eXc)#c8; z*01?|KBxLhC`)Jcw>7spKi%u9-fZctG<9W+=&F#dS)t3_Ojkyl-oLeHVP}S`V!^#y zxzD@29$uZY{POyM${X7|1Kke$PWoPxG^w!lwDL*$ zZ4)MMsWewS8FIq2Xx?vw7;90p{-Z@Doa-;Q$gKBd%Mrip+qqq(_6abgi3JVyk5~)& Vqwf^_EItd;vd$@?2>>4r%z^*_ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/10.png b/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/10.png new file mode 100644 index 0000000000000000000000000000000000000000..009f5be4a3274a343cee77acab82f0b44d2684e8 GIT binary patch literal 1500 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 LNkvXXu0mjfcemmP literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/12.png b/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/12.png new file mode 100644 index 0000000000000000000000000000000000000000..711c177dd53aa2462e687afbd383a0a81fe2b118 GIT binary patch literal 1733 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 IM6N<$g2e|{6951J literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/15.png b/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/15.png new file mode 100644 index 0000000000000000000000000000000000000000..848639d4072cd6d5b172c27e114b6c2e17ffd711 GIT binary patch literal 1824 zcmV+*2jBRKP)eSad^g zZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00xXnL_t(|+U;G0j35RD z1p^us!4Cv6gKrO$UGu8C?H-+Or@QLid{bTZ-p{I6uU@^XvJfy)J{l26J*rWK3Y4K3 zg($!y04ZGJ0;f2}A@;F{9c*FKx(Zf4D=;8BkU%?H(Ujqb8(6~%K3U5V0fZXRg-$$0 z(LF0V#}XDWZ+!_ZAk>0>^x{dDt6j$|-dUd!CZbYG(lYr;%ao+jaDdT4lXOi%&^1j` zM{a}BLvs`~%~4NI+7Rl&3q12w^cyy@gO}(YRy#XEYcz921VhjAdpv?^mSI#)2@bC2 zrdOJQ_bNN|Gnsroq;#=1gq)~N(aCE#no5;O`UoOGig7*ixM`uRT&58bQsO0ERyWk4 zM8jf{0VJkG)!cXclugNDM2Kiu-T-y`phpfJBVwe4qi@e0phc;8B65HvBn=lc=^qn_ zASp`{=RTsOyVOJykQzDV#_RkthKQ1~0ct{{Y56k()DU%t-IEjF;55T*LlctnUXwRNrjwQXOBX;SO>a<;BJADT^pI{IiML~6#I z(+&`>ag{&?V`yhoC5NYn&4D7}5?9$%YDCFh-GffN+g31Wp;F zL_0vZ#-{?uj8U!~AY9{PfkVcq)D94?@u9#zU;b(b2-kRDNXy?k?Ev8#?+NTMMqE2U zxW+p|3ZXS>2ME`A%WOkP+YrLK!Uikzi&p)EYrA1x2>@%1`KwldaBbJpTbV12`I}aN zaBb5_m~;pw#oHvz+$7AT14K)#T$eTjhHJWX1IPmV;dgBS;hNr{VA3*g(lP}ASYNQt z%Jyr~Ke(3b>HEO{3o`R$|39<Lsh?!Ez972?enPaL- zL35BU3iU@nJL zsxa4wy1KY}UoZ=pD~Q#~%q7(xD%ANJbHH45Z&$H-3c+=CqxWMOfO$^ED|gh!xSy6V-}{ z<`HunaU=B1y_Gdkdhi0zJQe+hO>AKodpN)mPH>J(dJUdG9($_s z172Hmxwy{kQBrRFr#aXC`v)IBlT!MgUvy2A*%>B57}}(xH=7+=rldax)bbIQ7WAVR zPqJL?I%e_C`s|m~mhZi#0bS_C(|g}LagHS{U_PCq?;lyg*%lHL6g7G8Cf_1$YD?g-cxE6vsHkKK8JKEo=sT|L?!fy?EBI8omDj O00004nJ za0`PlBg3pY5H=O_6J;|0^EG>dm|?Sg(OQ{BTAg}b8}PkN*J7rQWHy3QxwWG zOEMJPJ$(bh8~MZ;7#QDrx;TbZ+&NbWSCw%y%Or^YZCv(Eu{4B z#WMvyy?>mJO{a4+0(La7Zf@>inIzyAt>nQPsA3^uBGDw}*z#kGOToGCGFuN$_+7dG z+UeHQv)`XD_FtxbXt~uz|GyU|@@-ka{?_GncCVAaz5f5N@69Qe!lUf+U&5lRCg%#N zyx$%7dg-;z{wyb}*N5t+zrXVGPrjM$+q|YHbE^(2vuH+r&PZRUICED?ta(ZB_LAuG ztLv+!0?xPY`{U)m+0^yHF8Qis(sq{ROKjdhco{6T>=}FAv$@5K&XoUfiWXY-aN7Pk z6Q9gh7wMlJXRCaw>$j4dM#Ny+`%O4skM>bVr=^R9IFClhNCQ?J9XMT3{GTw(L_ z@Fk7Qg_E!B4Vje^R#>^}&jB&ZlN+{sPttMm3;L|&*%g>J!$LgLH!WFRGFjM9zj39S zXV>!UifVoj`xf8uns&YHi^@wi8#&vPNt-5pIm#F0&G$w7;_(v&M!9N>)Mt9lyHM`# zzv;+ZHTfm;Y(k|w=cR1=!M%Q~lo FCID|;3=jYS literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/3.png b/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/3.png new file mode 100644 index 0000000000000000000000000000000000000000..76c1403f686b3adbdb8345ed98f21e7752496125 GIT binary patch literal 770 zcmeAS@N?(olHy`uVBq!ia0vp^9U#oX0wkwx&b|qxn3BBRT^Rni_n+Ah4nJ za0`PlBg3pY5H=O_6J;|0^E%CMlQ@iA;}Wgh!W@g+}zZ>5(ej@)Wnk16ovB4 zk_-iRPv3y>Mm}+%$$6eGjv*Dd-rjQb4oMVg|M*{2s-G;908Yj>QDWP^A6y_j z$}BVfo9Cv)!(GR-uH8^SHK)|Q=TdgC@8myQ6kStNXXi*QT{mOR=~uq<(|#{KnA}<{=f~uG4Pa@;8*!Uv4*N^<1W`u6dKk^ODBn7>o9szG_M8 zJJ0%B{8u$t?>6bn%dP#~>OcDy-{9JIz3Pj~&)FXWzNi@QoV&!jY(mhx#yY)UQZLWP znjOA4x#yYR3+qMdGoRk>^U&cY*bJ?Wp-w)Yu{#JBtmRe>(*R$p&%h!f`KDr;e`}6b5+YY$O?RY7s zty0^u-)GX*KXaGqmP|aJx9cF6}#qR1?{|DE)&k@y;3-IaXlG!vUOr@#@a2zZiZy`T|IWr>mdKI;Vst0C<^I<^TWy literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/4.png b/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/4.png new file mode 100644 index 0000000000000000000000000000000000000000..7b126ab2e1b722fbfdcc8b25078833abf16b917b GIT binary patch literal 914 zcmV;D18w|?P)eSad^g zZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00RC=L_t(|+U=ZANYh~$$G`8uF$ifR zjBGG9Xe0_nSQ~T=LL+K)Dd^xqJb3ZgJ;4rk@L;fmS0N7}BN7BL41`Pw6U3NcWT2o3 zng}w+o(^7m-rsL(my$i-&+WT07$2VZ-?R5OhckjyP{tt+u!kLNVFT+}LlG;k^l!h1 zJ2OJ0${WjA!~#CKc?!|&V;0kxa^EOKvxEZPy055prXr(~p%9-*>8i~+ z#Gwu`)FX}tG$Mr-q|u5?r~2>*ymFJUfF$LC49JX>Ppp)8H9UMm#6+c2hGq2xDX(jM zq74y~l_B|gjFN5XfjuNAg=3^lNV7#LZ8B0-$uH@KMINz>q^FXy3sK_GN)K5f{wDq!m8=F=nuuv5 z?^U|X3hC6HcnXPncjz<5hm0%Xqk180eGUQURJuhWpH;fSS;TJyM5$y`pJ*cHjjX7Y zrjVjaS19DWN+}9iSLrf^Y^rpTLbg@9Kq0#-ou`m}mCjMfp-M4l-G?|-{*0^;4+^PM zsZ1d;J)=-ay-EiZ5?5)DLK;-sp^!$EwkRZ}(guaJ=w<+gq*Yp@kXDt7)=x5lpCPPQ z$W4`&UCFwT+bS*caCb+g1?w|N$aM(YLP9Rg*d8+XRGOub`zlRaA26ZUGA&ogW0jVU z{tw);kS8h?tPhw+y!@|)B;>jL;Nu}$N=%-~93LR^wOo~#5~l}32qAeSad^g zZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00UY{L_t(|+U=deOH@%5#?KWT20~K8 z$OcAjF(e8_SPrxeLL+Ku(X`5ixNzhDkl)Aw=eU-|ljA84`qM@ z=Q!D9&^D4MoP>j$z@Sn@;;&xYIB>i@j@VX6dd*r#5}bs)ts@x?WRfP^Kq7$!{kZiQ zX%7sW9_vW@0u}l?>qy49yFnnaKvk{7I+9-h1*lk8pd8(09Z1pxGR+vtGDZ+cqkrUv zF_Ph2<4?aVKzm4ryyJW3*Q~9qwfabMtfC3EXvN5x)=+A(D06 z(NviyvIH(cAbD_C2;@7sIDxE!yG$VK;4Tu#Cb$a(vJLJ$f$V}iMt3W2nM%Uj>c z1YSc}kB}SS7G1$QkXzv9xw*RyZq9lJ2{{g78%W538QVkVF1Q&2xd(2_`hW>NmT5Uc z9)Vjp><4ZcNE%$u`hel#e-8++hX4*eSad^g zZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00WarL_t(|+U=dsOVe=}$Di-OF$ifA zMmCz-VI&GgSQ~ULLL*{yDY|$N4_@qVNbq8Z4hlPX74i^cM1mj-gCG;a1TiKU7$_)$ zCW5Tt(_s{Qf4<*sb_v<@e&603g1q=V&*#TJpXc%9j7U$UB*$_j2eKzSvL&0cAq83U zivRcj@Xibnt@6dHEX$I7@)ijMbtnrmFLT~E0zs`vPTqK5rO~DTrbQjm76L(?=#(Z2 z#MP|!H)am;q)8&uEKzBdHi=88B&16&o$8O@%S&%oEJ$PeP)9YdrMe^KZ3Bl-0GP1$ z=__5Y17)(o6Kw#Pl#c6<8c23^Q0z(5nyUdNs~r}hbn8S_BtLaPEJ|ZKUKL74Y)acT zQ*|}lV--qD=cKvn?=x2S`*W h%|Ga%D2h7U`VC`j_M&OeqEG+;002ovPDHLkV1k%N#|Z!c literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/7.png b/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/7.png new file mode 100644 index 0000000000000000000000000000000000000000..9d15832eb40f842cc7170216af963a2ee5f5264b GIT binary patch literal 1142 zcmV-+1d02JP)eSad^g zZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00ZJlL_t(|+U=deOVm*i$G=Z+UjN{(}S%9kP@J|SQt(kdTiH3yVW zMILBFz$Bz!{$xS2EuFAu(k`hiP{yRzB9ulM%!uT#bikrXO!_lINy4T{jU+R!W}B=+ zNytQoq04|QjRq16WYt=%BkA%FKw;ei>F74=KoTC1Df&o~KB9rt_*ZV|BmJCf z{OOkoXb;JtcYV+NnzfO+Rv$@J2@_U&KEolGWf$ zQ(~IPSEXLiLt1qvopqB1E#OcQhsD ziL5A9PatWf9uUZHrQ!s#uGD=3*;MKtfov;vmq2!vx>9_s}keRFiZ|V|R8fP? zL(gHby{y`_u>tXU_+*Rfv*kFOn4g8sJh!LwZP>xDeBaS-MqXAWy`tmde zT(RBqkpH#uB0azV4-_XdRK$nXSA;PqJ=YUJZ{0X@OGshVEne5Zzd1nmF@s4=oLeSad^g zZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00d!4L_t(|+U=dsOI%kJ$G=bNFc2h4 zFvJW@VirTh(1eo2fiAiU1XDr~7j1W0ge+3%7x05yB8E2-aYs5GxcT zh+zZ+2DB)GRs^ww-!6pWx$n)4(#+s^zGwFxnep-A-gAGvd%q{bF$wOWgdJ>S6YE&T zGM2E2BIcvr`aVZ=Y=E%LALcNFX}pW31jNP`CNYk&=!1aRm_-4vqW3uI!K1|#2iPVc zHugBe9svnsly^>M4vEl=G+NM#c61<%PUO&qbBFr!TRe$I;USpeT@G@BrK&CE%?a*4 z31Cv}E`pYNdD%1cnoGZR2IrG zdYY*($vJCcXt3s88E*mm?C??CbakO{Ss zVYLwp=&FKvKaO`X1+9Cfdbs=7YTV90L4q)C~do z!>DV@BH>0rN=R1hil)guk$IzX0#Y>Ul7M_PDk~sMMx7Us6{F4y$eK}S1Z2ag(*m+( z)F}bkF)AH-=fMbj2c=p_5CYO{R7pV6Hlqkgi&5JG(rVPEfV3O6E+8F7tqMrisAU1^ zw3`6}k~3;iK)Q@7dSA)JUPE|qAzv9a7wvina?_|8E$+THYTA1SNjMJS8%V-|8Q)#z zwo#J;@~u(h-aAa@P7bA*Fy{rT_6g8=!#jzMZfn; zh`Od~ap)p*07O^aD^A$Gn<2<9!{U&kN-*5Ya>oFXDU-n=+b)Ac#%>0Otp5TaGKVxc zWFJ~Fnff-El?AcIA(QGVI6T{!%jmvZD)n3nLB%rctW@Px%$h|7cdBF#ubo9jyDScs zbvpnzGKNyWxUY6h0uKzY*0b(|DndB!9G5?v7eda3RnL`(=W!Nia2ltO#uore*uge7v5r+NV+o5W fVm{if@ALf&y_By_%O#f600000NkvXXu0mjfA%8uX literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/9.png b/script.plexmod/resources/skins/Main/media/script.plex/circle-progress/9.png new file mode 100644 index 0000000000000000000000000000000000000000..c6885f460a218e04886091666df534702d72b858 GIT binary patch literal 1391 zcmV-#1(5oQP)eSad^g zZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00i4fL_t(|+U=dsOI%kJ$G>kH2O&t5 zV2Ba?k%dH*CKOW#x+sM}&=P`V)9hS`3pZ~17gTUFS!7|r#XwimxCk&7 z1hI@@zEVQOUgL8_zkr?~KlUe7N`Ad(XS~91k%u7Ldmg4zZ72 zY-1A}SVs=4-f^_g;l&0Bi+r(yB`o5tw_re|9bg`_nDPEJAkvnR#VhYUF1zu3w!mT5 z84zg&X4q{&T$^U^<@6yQs!)v@)S?~@XhJL6(2kpD`sX)z=1oI`v5}8B!a3$o?J2J> z@$d-%lVlH{bL|u;FD|*G4FHp3njcFb+2H{68T*(m0cDCU8liM>tSFLC?1x5UBhy8p zj665_BrUpu zBz+6|DeZlv%QtKWv?CevMd<6aBbl__jRex@i>h^NM>6QX0EKq*g`<1514%hR=B$s5 zTOW}?n%yHe)<@Dd*SOQK1)v=yW6tqC^=sA+i?zB)vKB>?K-_5ST|*+zs{M5GX+klP zmqI-_4at_=(InIpSrw|yfaHX_Z9qN<)nq_6gt}!wwuHK2Kz4+>Zb0^gx@JHQ zgt}@#j)bcAwDX{c!vCf95XTHil~8#DQY}4-0jUw{(16qmwQoS`h1xYB4MJ@jkS3uv z4M?jD1{jbwq1FvZyHGjpI~m_=2<<)OE1_1rW9>k`7HY{hci#xLsNI7E9EZ>iB;de| z?jiF~sCfhOy->5-2Tb6xOwB#yiBQWY`M@;;`9Y|x_5ovu{~aK9Jw)KJ3q%eOyJA*y z)35y!qFqy!IP4;`1H`Vnmt3%GPljOWG9(U5sNzhwmU2e`v7}4_ho$WjI4rT7z+tKX z93Yk)QsA)kp(UNE?gX=;ryyoU9R?3QNi`GvxpESLhn~iqU+@=_`D-U8(T+CUMiXw~2Cm~8 xuA&-O0OWCmL+oQ0+t|bg){(=icO32W{R5FjAj;DmkQ4v_002ovPDHLkV1i_2fIk2L literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/drop-shadow.png b/script.plexmod/resources/skins/Main/media/script.plex/drop-shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..ca961689b8fb2f6a58b92c603eb86db5c855868d GIT binary patch literal 1819 zcmV+$2juvPP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00x6eL_t(|+U=d~vg#@fh7;`l z-?3!>InJ6<_d6d+r+Y}vA9%a$$M{DwbtuJjFGvg9?HK(Zx} zj3M6~$0!w&?a`|fA39h12F2i^$J%vXbQ%~u=onAO5;_449smO;9)~u8p>G5-8^+EU z@)#6+2*wN$IB2k$VCWlw;AGX{jq|3!w!3PelY!tQ)!-%|G)WC~A`qPLUJsPJabyI{ zawzy949Vcwp^DxZVyT5Xz$}G=UjPGdD25E<9|>h85N|sM3?5NV515GY$pJXC7dIWq z9T*-6PZ>C%4sK`~cz-Dr+zbN)3P8c|qe>ye$n9$isALP2*+52NV8`|dn8=k+9ot8s z3<0?|D9eitlHo0-V5iIChD5>m(!R+40(&0$-n2_0*trcmV3Z)75rs%9sESIcGp0;Y z32uZTUF}6Ny!G&cyXU672Q-i(@n$NNQI~ZWp5&s6pc2oe@#AO)M8){E*}pP(r5SX{ z6|GVTb{ZX=_#heo1EvI2V!13&9aT^R39rd;Thmo?ErvV-BMJ!|g@9xHk19&@J_xTt zP!6q9%e6oq5m#lwk)U`k44k-u!uA#hhk${rT!Vpk+}yQM9ia54IE2yxB?{yN0NL|a zIW3gZs0oF?%T#hrGQJi+!14W-GK!-b3AEN#Z2=I2K!Q@JIgS?Ot>5v7Aze3(Z~c!3 z#WMJd{pE_WpnwB|m?{te-v1rz&7gqd$~09(0E8f|bXgD_g=;W0IND$llrHbbsFj^Z z3!{bd7S5U2HkzRZsl9F(+6&szSRp+mDB62Pi9G;+m&&4%5{YDtHJ3Ft3vw+|hUd1d zo>mbc6al6-7U9YOA%H`p2w)1(E-WvIPf^OX*j+{3mZX}Opav^T@|J(6kOhD8h*LU>M3ON260kS5ft~O4H~szTtT1zB8^3WJqM?k z6&aCtgIk^Ljex>H-l{kXLBUB3-; z0Rxnv4o)0_8E&j>R7G!Eo(~*Bac{i49Nj09*7rIo$0}qrGmL{H{2~}0Sn{y2tJwO1 z3&5|M-10-!Ns~T3BYA~&kzxw3EB<&Z4+Dtw+A!z>qvN3HVD{&LWIGIqSNt4#O@Y@V zpG~O{xoE(uiHd-T)Kn21v{KNu(75PajSw)BR_0li+>=&YWqnpe9n(rhPf!RMi9fGY zr!_3V-?dZxdF|Y1q|}GLMIj{gRHT9c@9LK-LJ;IC5mItY63hz!ue*xWUq!&sOt-f? zmt|EEdNBCs6vv%ZrXCIj3@DMgA;&00s=`3S@X~8;xFW!?#skuC-=M^i_VH$~!Ekk2 z$D$|Jbi<7NrXHPu8JTQj)%02;YYDK{3HUtTOc`%MId35bSuSmPESXj0Fajb{k;1dB z7yx0#jkoeYH2@;g-R_CC%YkUdk3s_QGpp?vss<3Qf*NpN9t>|Rb6hVAo$Wmp>7TkO zer56^HUPWG0Tj0-xvI##5zF}Wq{|v{TLAHipH}^pH8+p~F6kX`Uj(t)y3^;Y&jtd} zHHEL}5m*7lQb`nwm%gZhURDjj02rV2xn#ut8rWxau3@BnpNugLIDT9+ zdJVWYFVX0w<)^4)HIRtw8Yw35;!6#t_#?*O_QTX2gWQ1vkV|W912PlJip6IlaAv|7 z0y3J*BIsMQN~#)1@K@tOuxG&TT%M`dz(=f?a15xLa(W+=Td{@KO&UogMTzFoyE zMfA9`M_{Z1(yNA9hF;MN`X_GavPunk%cBFKc%P9s1)F$`ylo!jjU|8b#*(v+nYUj3 zp>uc)0B<=h`mlySbguLbUosVvK(Zx}Y}vA9%a$!$wroG%{s3Tud$Jej!o~mq002ov JPDHLkV1nRjIhX(d literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/gray-square.png b/script.plexmod/resources/skins/Main/media/script.plex/gray-square.png new file mode 100644 index 0000000000000000000000000000000000000000..453a5a2f80c5b7bb0ffb8a3959cf447247a08c68 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V6Od#Ih`sf0~S^x72Xb0-m5?%$r9Iy66gHf+|;}h2Ir#G#FEq$h4Rdj3ld}x}e#mjIzk#UOZcEh_s1q`09elF{r5}E)~1SO;Z literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/avatar-diffuse.png b/script.plexmod/resources/skins/Main/media/script.plex/home/avatar-diffuse.png new file mode 100644 index 0000000000000000000000000000000000000000..f64652769117e76e864eb697e7919223ff52aa79 GIT binary patch literal 589 zcmV-T096}1W$Rw9U1s;IEX4V^g=X)3>khBhL0>6MI%5e)E0xdH;=QEI$pBE(^Nowokw9~s5 zi*1w^E68n2>gn_8N!lK4uZ-lZq^7=}rli@jT{N$nlMRq;2xME7H#0C1Iq#BNKVV1b|+EUbYLy8 z;F<#qfdv;#QU|C773`X%UfG@X7?A_dfxGzGfycmtj}F`g7QA!dGO*yK1FgV;X>!%Gwb$i zl2me@0{i(AQ^m5D&il#bHT^2qpps51tmsY#tIhDqLilXvd!<|7Dj$rJu!hg5ZPYJW bRm%Sljvt0l8(b?t00000NkvXXu0mjfpx*k? literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/background-fallback.png b/script.plexmod/resources/skins/Main/media/script.plex/home/background-fallback.png new file mode 100644 index 0000000000000000000000000000000000000000..4e3c9a8154ba2c9cdb0767edf5ebbc463c7b3d2a GIT binary patch literal 188030 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%0A%$1F^dB(P6-Q&TdMKMynSs^BgMoHxNz}n#!=itF zY>#_Br2NLpYev)-b5hyVKG`HE2CR-nCk(N6eRbfjps#!n6=-{3-(Wly>WsN{YESx9 z#-2!c3H2&?Qe#mxbm)ie6@IzZreqDeP%=k>UuevH^M+)<{0$gxaxE)Remz708gOlT z0TieeTuV^*{aThMK%c3hO)pvhjOV+NfZ%W~feGCHh8Zf!m++vl4RC~%e;Z-IL2LYY zbllOwcXn9F`)m2yp6^$hs_MP3a=Fc7A3I*=A3$02y!n;}-#Y6ySpO3_;Fiidn~$s$ z3~}5jen0K@Fs?~&Ja<4(nb)l21#RI{M?z?rP%~EX9pMaEuZQzR5d;gVU1q}?&DRp23Lz5jY z1BDgRLTq7Zf#-*HnDuTb`^Kc$SwedsLZlp2pSm+ zap~yQYSp-ZSQ`O`etv%k>2=TJNb`M2-ZSLPdfnrIMWL89Q4=sN!^)XL-8KHarCZ(j z{Qw2Gc89i>7p>tmqE_Yy8d46osxeqszjT1~&vg!Xf}<|x^iKA?pI&;nyCvjYPs zGKsGElha^#?j^(SGY8@*p5cc2@fB1_UVVh>X%;j$_|e>h_MFK$v#i3u1Ey^HJX5yu zgr!EEf1Aeq5U9nOixLgOoE>Fvs?hmjAxGHO`=Qv!haj%z8gNRw_gD}tfRsy)9G2NdGOqQxkQ<)nSYc))ifd%wfFKU?ED~Sx z9~`HCq#|*v7s=)sA&Qzg)_^VK!?iKT0(&iEIvDAC7n zb6q{}^oq&RqN;{c(bb+$3%wI{B>sLS-@~-mJOcqrCDm3&GmF(P1ggpx`(<;Y5?grw z9ZUT}-HF@gFiWD(J$1O|pCcEUgK!D>{bq1OiuAnjUu7iej&qwC$R?>_FH8{!jOyEL zK^Nano-*KR+0MJbV&mMv03OiNm;~g1^_~N=-B*E0=EV%Mw4Ft2Y3mNABGz1h;vThY zzu7eg+FuxSeYy-aTy9Y%MO|^jzv`jpGxa!fbfnF_t3+iGN>VJCA!6N=Tw!RuK*7Ty zU7M!xBHWV~`h0u-SBHsDo&;9woS@CuO_+F>-AQD>S$FSEvoLm7kF3eMZCft*j4#WY z=|&>J=JB5ZRN8R-bpgKXBH?rFbu4N#mFLF~5HpUb+cKecV6XN&&KlV{34I

An7~=yvC@Kd0=(ii2j?O?oZo*q+;l=pg3jfo;q{Tuj%n$ zxVFhil_^>Oo&+!{(;&K!RjMvvot?zeZgvRNS_TgEJ3S#_Wdx|A67@OYTF@;gZMD5c zS`Vokg?(!jK8-69E&A;M_Lx-$?smvZO~lMcDYp~smIhKuZN(0N871RbP zz5(pt+S=-p6OqNO9HoTXMiu>8GlyhLs*1s-&vGArjo^DPGiL5<-BMlDV?^8B?0VoF zNUeC#d~yG$oBBLs^NLUfJ^5}2Tm1Bsw|t}Y^I^a-h=!zEN@J6LN>abM@gV<>tr(%t z8CG|)yC(%hGm0$6tFO%Zi2yEiV}V~b6Qi1I$rPG=;%^F+e91{Bn9KWnX6F5tu9vGM zmJGAOsFGPu{KH{r`eH1%-~;&e5pU62Ub`bK&jn4g)KwWt((f}}2dezn&ii16I~Vjx z=6m&qO7C0319=b5P4sqWZDEJGsOLprf#J{fiaT957h2@s+^bCmu!veymI}WW0`O6z zEsqyds}PnRV7S_Kai@~yN2W_{*2c-MI)pXgK?h;(*Kh|#DxXb4?M!O9s3*o6WLmNY zDj-0m_xIP+%L>;Kkv3iitUw*Qf>*oGU7Acqg*k6SuI}nHIUqc&tANIN+bY5KGJ z%S`aig#?0WiMeGoA#v{EeArz{yXh_4+o@m4HoS`Z7BbSF zN}}K|+wCE9TKwO%=zUl6vxv9a?CJrVSifIxz%!qTepI*o5SHx-ri%uZ4M66+w}F+n zfABY8k(D#>02Nzp2Kx48*ru3xLDy5uJUyuJ)S*c-O+B08tUA8$*P6_8^)WVeD<^je zm4J2~pYvC$2M^%%yWR5uieI|K9vR6P%T@o;%Ha9S>OobALLcv`B>F=M0UZr(*_)FpIc=gi45TptS4>Kj>X?XOi}pLdHA_B<8ouL6E+6r>-H^B>`^qU+L%xgi_^^q{zku(5Q;uRx%4X%+`4%xW+G`&O}on2G{;C&7R08j&q)% zY@ktScDAI(*LOTW9aA4WJ}E4&y9R+q=KD7h6_~tI3>FHx!CbdR6zxeyH(WcIb93v( z$#Gw9?&uIcp6Vs7SP2SgC$~Wv8dl`8h;4^swqRhQHTo-CVdiKAk_(WS0ayqMh8B@_ zND_Ho``qMdLa~tr0LeCq7GE04jC<_O@?1daJ#ioBerr=oVRr;CBN4$zO%3V!$XYL+ zs6Ov%AgNsz(m$ZWp|u`d_&4YG&A)bEv=Ud2Bk6;KJZ~o^&Ya3h$bQPu_`h!qZcxi>6zb=<3W6{j_u>qM`g6x ztttGQ@!2IuJHtA3uIKBXEIuP778CbGFE;Ev0RX5!=4dB0MHpSdJoor|l=o*0@Z!&@ zS_=5zyAXFHIX>Y(Zh;PMHA+vG*`LtI1dVo*|9W14W?qCz&B+^Ffjy#o$`D4MZ{by* z5F|7BandD|B&tKpBmArFk&O3CS$7{SVr}MwV&bhD`q3PMwU$m>QWJpiGXG`tqe%@k z@`O2+PH3;SCR)Aw7)+JY5Q|g7Ce8U>eWL0$$zpPL3 z{C)%(eXi^G9}ITR**ot0br*mMV*yb)>kKm664GDq z5pq4L5WEFE07vhrii0;xpJ#Nm48?63ry+3}5SG&Qk9T@tKV42~;3MUq0QFuHyOqGj z_I)NsEVhue zzB;D%B0RzBr^pEDa}nkTS$HSJ_R_+y1It;ljoIL{&9)f?-)`|8A%hq5EqnnOcz}A5 zQqfy=03%FV`J*zN2c6BYp~eacuYK7R*2VO&SHza{9hSb}3LAZPckLX4w$!N;R7l%K zD#z!sO$|ulJyOrGFSOXgrK^#hN9r_q5m~Kk&m>mA|4n`gpEFM#QA_}F-;R6QEd=zw zySRLEpvmN8l;v~D`Z`nR3B;%6vz;evlx4TUdlk0Q)Dq<0xEE@{jAt_S{eVB&(W(Yl z``@3E3~{+ZAq^GQbjRQO{#q-PH`B^Veqb*zssmvVwv-91@r3WXt@TfShc4B=p-c+N zNc7#*19RAX2LcoIEOBGYGI51*VXHBRRDhOb$d#^B9WPeN4eZS)t&Z231uB4=ZIY^N z^o)jmEZL6}6#KEmLZ%ao;XGUGLXGf#Z9D{9$A&e-CWw*BB~ezk!VBn)WhzTk`)gW4 zO!_S7!_*R!U$S(nXDuKU(Rj-O7wY!xW+;wKzVw*%^ta2LF#eO`YKI7)JhltEDY9e8 z;MuL&lVIMZ)U)}=sJEwUx>oC7;mv@gZi*1F!-&u0fBMQ7N0Bu-W&H9;bI4>{=!nK= zx|rs6NaYZ_kj7)SmeNN+DX9QaGkcu*@xht-^G_5BXm5_gl$L`Mv@nczxBr*E+&<mOf=Ni^2hyafufEDFFUti8-2{0uok=(0qLIad2m--p2GeIXZ->C4O~fFc}n zGLIkNU^{q*hZU<^$kwMMNp$NRbYJCYezcmA>VT0?R}vcwI1Pcf)0qDtT}H|XZ*0hZ z{t(Z2@;fNO7^|>yTM*)@K^||0WRpOxC>`X%s9r;&1$1jSXc^n?bs>H6R;V6_IbK*^wa>`55<>?m&zVVj}w_(oc(eSx7!Wgd?fL=@^JAog^9 z?%M!NU|6UX%&7)F1bSwum1IXnm9tNTz;r(t7lM9g( z0PlUDd%u)5j_m>{=~%-5`kw+_kNXZ!VGpb8f9*J6FT9QYWgAC-sRhwf`s*4_glOv< zHD{8HbD^uCML9Ekr8a<2DRfUGWGZ)i+4&d`dts~YDm|A&QeS?)K#L6|MTB@1KT)mN z`LjnQYjY=U;lk59nPSRB_-MdQ*An*DP~-u$^J~(Cy zx2ea~SLlAHFy>Iq$s+oZ2na160FnSkTmRd79)#)1iK!;abl>2>mghE4ejo=EF$7dL zH<(|hgAM&$>nWCun*pXFcS;ZJgF%WC9KV5~t$JaV`oen;oZ0M{1#-vA0cdfFFCb#_ zE8qUXzCfiw=((PQYj*{q`3R~)K+a~vjUbTo3t5(*bEKxVpGEqxLc8X#%CMG4-t)4s znG86IqhS=f{l@~Joly6Dc?B<66nXkcuq3`@FY82~3cePA6bcB1f_e+~*#9!nOm_ zJIYuv42IZoIxf(tdtm*yel|O-v<4P2>U%TmwFCu~RKx*{w1|3&F$P$t`e~P&;TO31 zm7snxRAKuIX#1I`#>r7Ie0J8Eh`=!&92x}&HaTyX=zcZ4bvcx_QjHWDP=%jhM7yq_ znzxw6eszBZ6#!B#KpH410Fewn)`!VZ%DFR$BctI=FT*KqKIim)?Ba;A_a(3}rT;Lt*;bioN$8jV{;Q`oGoR`ADPdMQaCGLZFS;K6E!OM=igR z9YD=MKLmN-awvw05D*68{gAzMdKYH>s|C8&PK*<_k6t1>`%DY9v$-R}c|luB2<$C# z7!;?-mV`{-Op(zdsH%kO__ccYDzR_TJeHUAsQcdljta#%UINF`Dy8Z?A)w^eSXaV| z#npmf70G|mYY8c>wlz-l>A-i~(lr%5XVn^n36_jXuy&<^B33y1J_p~}Q(7QtjedVb zLrEACPg!7abLpH>PASHbTV@bH#UWUg zM*w@MJ!|&2+%Je{HG9+t$Z3R{-l^i$GYnE=@eJEN`o1NR6@8VFUh&_&kU{u6;0XY1 zC~v)X2A?f0|9%lhB_dL$4PSx+-PWqdH2t1;g4-B&z$T zU@C|z1}5AtTkcW~K|>~?+Sa(91$k(@H%bGMI^`jp6t5Y8iSgP3$pK|9E6KE80(DfJ zi7oAS5>|qM#fYpC4QdDHYylxEI~k+y6?yAcgDsmy*N0XLGrJ1))IM|M%(c&V3*;{| z)ai?Dxu_)5num*X3g8%kYqaHv`+#f4qH_!QmnebF7UH_&@I|=On3^8O;ywZG`zMl7 zAnv^rcbBou*BL6oPsWlspaCmw$YgAEz45RQ#5^ITL(9T z$=cVMlF|~!U_6#$ltpZBJ1MfpVBH2i>~kVd(N=4#DYa-eI_FgB#T8gNz8*gVRF5*# zsX*B^wpJRtqLaol`{E z_ICi2ZbsHfqVVZY`ai!quNX**{3gg;01OOag==(g3vvg>*l;A|(xXnKmVNoT#Yv(=URr_(=1G32f+il%zf0%tMxOYn8aowtb+VHP zqW{d%j*5(}+hIClAGpF5MmN9fTuy4CUaWFMZqa(*B<8i(6nO3z!;_b?sS#Kf7F1YA zx$z1D5XNAv%jXpp&}#kN`f)rJ%f%Q<)?(s0yBcB~VihN`L}_oGkDdXmLKN>~@TXiB zjMOM6-zk?{HZcOP+Pgpx?dEtAr2;A~0-6E=nGL|~N(k6N&i1K413^K1=;rBc9-pd# znu^?>s<8%=OT!7w?Q&IjLgD+8689pF!r~h*IE8x1EW>b4#&~syE)Ok`vPR4V)e6*B z6ekmWDg@ksV5jCuJ>UiLAykW2Pvgrw*ZJjEX^AZJ(|?0O>Scj^_5xBT{uO0;0UYNepInUKEOvGg1FP`MJ&>RJi zkzEJi$!|BHD?7*gWL5|lbEnfCiEZnFC9#6u0Md&iHL~Lua?e=jlbERL{#|xIC>V;X zPCDOaBOKJXmEfyKzI7CLyZ%bBBtq(?5!fWKrv=0!*#XJGp{C*VNR0AI1KI!1;NhA}<4t>~W81(|=M6t)-;7 zFoaTSWS^w9bU%Ug{Lw|pY@bZy2!Flr<|%JRp67H?3Ya` zeXz-c>`{)xNuxOTl&#&2-{p3sug1H`1ipY2*8^*b?t4DFK)x~if8a8GTD2j8txNm1 zcEoD2&2Tx?l)B3>=&+MBOsuX5$`x@nq z@^VN%Fo=t!fK8J!RR9yU;VIxFJOU%A&Go*tjfTlr8QS5lt{A5ac;dbqrxu-d+IFPz z_|$}#uvqJn-U~~uZ;PD$))ak!i3Dm1d1v%u5%lvB6qf-_xUFqWil#;4R-qOKK(}Vy z-XTdIS>LfM%@U(BfN5{(0+|OL;f!5LwP2G@JHGs6~QM{YzIRVeODKHi&qo5@qFdl=Qsc>G59EoZE(w`iL zy*JCxO&Ykjuq)0hb?qCFz>3YWCAJ`t28uePUQ3 zhUs?PQkmY%lzu!SE)8#t=KPvssB#f*`U1LZ7QzZ0=yc`Mu|zG0_E6uo9az*`)d~oS z+OL@8TV8%^32y|a`()a~1VDO(vNAE|cRX-$nhyt4WLRR(W=YWkkVB`z=UsAqudENz zB-(wQOmm&#(7*zg!TjwoK*jmvLTA$p5N|+8jNz(BVn+1jK$wZQfT95hrpWZK24mvT zIkIIEeSbxVve0UQ&EQzj@@JQSMX{TC96yUNN9OPT^ z3z7N$&gDmZsrKR0`2ug9p{^)GP9XWNzb{5Cx&jeK74lCX^LpA4VNbDQyAWY76TmDN zDmtG!;cLCCBMTa$;HR=SRMVZT25um>k84H*j|7TwY+5MUwQe6rt5TpP|3Tm4Yn<2f z5`bc?jxcDUEVh32!eshpLNegHBO!Ez`#E232fsXJKz!zm*lE3jtA(TJ%y*;H;-;!P`W7AK(&KNL| zBw9hij4>>QW}kEMz@0C<*$8NN(vTUBgYSR9f~2T~&~gpjW%LLipZurY2E3DAZ+<>p(p8 z-ULfu=kMK^6xjZ7tZs2y(9e?AqKna~;sn#!L2SP1)ibc;)(8*b5LD%~0i)*{VRtjF zrO$Ueb-#S-85A>HBi>>YUMrbor`4)q$0pk1)=7mbXaT?FSEhjnMgsUX&%u?Wf2r?| zhH*ucz}QD($BxFVroG9Tr^gvh6Cn6H#uoJ3H`NfNs|l%!H1J7U){ z<=j2|nR-_}I@+BG2y(5E%#rB=sS&(SyG&lM{W|w&t?0Qg;K(=NOy)-fSdMOD0=nltTb@KP)v{{~=C6q~@QF2UEI5X^=yDbx zkn7Trk^S^V(s&F-Vt8RO$RZ{OqfH;zF<`dbs(-S)XnoUWcr9aq0Txo=*&HO&j;t!L zCl!h0Nd#f5#6& z(CL`PnY6qNU|OLy1Rk=suJY3s)b*HNS*SF@5^~}D3Qt~t-WxR8=|^sr{d1CLLb)aQ zU=ZRp@)g-pe14{{mU1T<#&2c<;~p`KjNSNuI=Y14V&Q%lK5o|OYts1^!sn^0H# zsjN8k9qSfXB6wN6xVuv;coqf7P^Yd1vb=(hXVepy7LO^g9D}AWfdnsBbz!pxER9hClNb|UbxUjdaqTmi$@3UnMG%(m+V)N#5Wh&zz& z?5j-2Rfg|+m4bGHBqN8Pb^-ehQ5{^>B>ESagFqR8QQkvHJ#ubK6A|;U!w~A;L%%L; z^E{_SG|d3!pzS`mBgcIm)UFC{(IYe-3wbm&GH4|$vm=KF%DVMDRRG8_EXj|=&vhX+ z|6YqUZ;`ySGz5M~aymnRj*;vxCPO7kfA?gAk+nhKGofOUy?Y{0yX(6{b7X)5{jNi1 z-M%n?cl++n4Y-tAR_2RzcJ$;fZ5-yB=d%ySrgE_ZQ)(a;{OXQim8nQuW~EW%Haxis z_VRT2n@^UIQvnZRZu$(Ygq=fxup+=h!Dz!D+Y2*hIR`f0m|xj-j+@ciJ}>fgXoYLV zex_c!_pJjooJ&=hqY430g|<>)GVD38Z-_Vj=muZ z{Td9w>iO#3Odua)XUpwAW{NfB1B=ztx-iCm*rYu!;hNwtB@>YIx0|yPd|6SRuE7kq z!{0-R%kh&%$g3*1D3(DVPLB{!4Bg_>1mrTXWn6SU9E5q64PNArQ(c8d=V&rG5-jas z9a9Sygpy&=xI#`li>lCtM6*pvgR8fe3U>+!uGW!zI&#WZDYl6aHr{^Z5`Z!vXZ*mA z*#FcCBw!DQZ9G3*04R$~u4)!Yc$>1Cp0TTL{%fA+93=<9e{V-I5~K+9&<6gLP=z|$ zHh_9~G_#b~WgDrZi~x3k{%?V=`HNIj zDiMeG{!$FQz(%pL)>q(w0QU4`<>7P|)otdg+r4h0=1P7tgOwd*vB$&1dAKCw#uX!C`u^F4ogr+gK;2JYl07*Yy^pVlw ziIeyRQ2zYh{hR9c89!6xo!#>ps0McI20_+E4pxmh@;xa6${{>o`RN3}Y7DS{*tCf1 zrgs!s$GIA~Li7FXhY*LQ&2wp@TRnrXJ^qoZ#C@wOZk$1buKtu#Pzk#yau*AL9f8gKm&W`~bfhWb0hl*8r?~Zs}R7PZ9MvGmYkP zOZ!M9;W2k^hH{`Qt45w$pwu2YB;1sK{T#M{M6H(qe}Sy>W|vD(uhoBI)4O6@T8H^* zPvlq?)}$V^uvqbhqh(+V+E$d=_GCe$bXMl1kziQ>*~Pe3ooz~s+KU>n4bny~N(0ED zT`sP$uv4zGkoSxJz=Pw*k7&+QhD^o7Eng4sd_6&L+X6qnX52aaLg{|mRKb90i|hRf zX{H1R4&Ey}!gO*P*>t`+^6VGBQkKQ^K&0IpQy}+5VdmG1_OloXw~qplC}VLzzHtH> zoa~4FXu4^seZganTm~QQ>R5_}TCY!L48zn@Cr3}|44>1Zb+Q*XH1d^9;M0}iV^BKa z6r60owqszMM5uQ;P6ukR2`yvT3kdD)cq2cJm|5}>UOqgr;-zfZVlL`mBYLjqI9RvR z_$DW<_7-a$AhKBv3S@&y=D`;Gl(+LIXda3oCm|uM4BiONh__s=u`Jly06hkP#XoK?4>JNDrFa!{sN`lZU zQ#1zZrO$Y%Oe6(q(And~$bu}MRKiRFCOuzsST#^dd{PG7QgkC1uqv<5?C_*lO=vRx38 zhC^$*R49Z0-Qj;)0J!ecP7>MpR2jZmX`nK1c$9d~%;}n78DE)Lf9PjC_Ee4RC|AHE zDeqH`R&UvNp_v8gQS5RGTH;TG7Nq7*c}H2p}|t_swAz?>rtay=hqv>x?C zpacpkIQ&d)h11z7;_sd_9Tz$Qd%uCk-u&SoVer7Q9SVYKr8Wo=rkJ35mY2lvA4>Ja zYbxm=Hn$Kdu7aP&phz03kUbej>!gtm^HDHR5JA&uq?~z^Zqu^y>x;S_g2L}=-h%j<-SSWDB8AM<&b@hh0dV0Cf^;04E~5E(q4_uC=~4+lYi zc}Tx@zpJW`AbQ4f>lQvM@FUm7N23Lq$daAI9}4$&4NpU6I=FkB)JN92HSjIF7?v4pb*vF-zz=`9PAz49#Wc2qdfLy=f+02k3w`FRwgpWRoaRB!QW`?@0{;y?|xqRBmaaF&iDe+nX zT_)ABO7O}OdEpQ{*)Ar2^9j4T634)p{EO$`=qT7XOqi+cHxMj$rt#Vf3alu%amXGq zE|G0y#wLu|a;8k*`jBjCW&DPWK{w7sp;(f)bW67EM3Tq#VG1?v9^ejtY9T9}p7u^L zvmr;4YAj3r7xQ0Upk+0wrKf3)E-&S0U1Yea{il?7lws&3xI6e)?iqgNGww2LdfE%zPA#AN!EOb>|S?QJo{ zpr&}Md%|BzHV(s`<}>VYjVECJ-o#VRzY9X&A?BqY1~@kDupT7=J}u-=TT_2JOBpop zU~h|ewDd_W&ImpJtwEO% zPXtYe&l0E~5(VJ7;`HmeuiP&c&*6nbR@ zwBi*N`nI@y%}OGp%^#~xiA!G8Ow%P0%UY-7cN+_ z0`*pZFo-2W-&On(NCWvnPQDR-9Hgcm3STCGl})>Tiv95fDc|B1b)}C-TfbSLQ5l?+ zZ@+n;Bvl@iejHnwQl4dH#WI5glh@>uo<^e)v@PFMe`_#sYz2B@q4&H@VDp;d- z3n1DEFYx*r^vttZI$^KHCCC@kJaZBpH6I-DH&&o`>wf3Q8e07XnIx80$HhNTsAcBJ z=h~;pq}%p7dboput~A)Xd~orHLaf*$Meh(Pdnr6Q^;HkjRgnllWrn5-#!>j%(ZBk! z*k_+~;1~Ezy=Rid3K{9EW+@!nH2QXcrfDV45*zC=wySN*Kl1krr!9!N>a6ov@%X0~ zzr6(jrp!RkE}w;a`>P3R#JGCFO zTIOq-7GFH@>mPYnuYDu!{1}Of@H2^>hql%{L9d||-lCC~0%12}2u{~5gQmLBrjioj z7$lXOdV9(LhS&wxRlWr|&s_i0Nj0IHULOLQa=kyM+QBo#f2JFx>K^}y6tCF7>eCd& zT_60@d$ddL7-q7RAbS$v-PGrk)yMfcF?;a*&u#Y!lf0y9UEAmM@dcsQ&pam|5VECw z@edxIxngx7R4c-Yyzu39)QR z9_DcNV)C~ofs1n-<;k0GBzVk23u(7r)2p!4W_cn{ahB%xVLwvA5yhVg(*~hNC|jy@VCmSeQ83mI6g2@TC;zZ&NQ+e6o>@bceSqs zu<;3Azmy%orxv=GcuN|ZRzG=Y*)H_Pu&6kL`dw-g_V86^dLz5ql#S-mR@SKKcI--K zlPRr!{=Wb{t67!Y^;t(~6zdXgw0V^jm0a)bl?0anA{P{TwDr}C+s1N&)#Zry6BUbDL^&LNC^b_)(WZc7D@Hh+|6(2L_+^vAD?$0THR9u;S0-8DFs)MS|WTn|{ zm(Rw)#rKBH9nj`stAKwLl@`Vj;hI{OzUovr(!y{d1HfIFb>2Wk_RyCY1GZOJL z!_WV^zGK_>I|V2|o}>SRlzCUcP1$US}S|4j#8Um^v$}7{V$*>k*y#$(iupV3H{Kn_XevsNJ)+J{beXWS;sSF zV+P&%c&_H4R#osqLms&uo5~E3REgBv8Jc_%zH8SK*;A*e3J=N?P-*ZHFGP+v4U%1d z$qpmbN4GXrkc7w@j?IEB>stqj=4cSpiSHPx1Eb7Sah6{H3p{=)9Cu4Dj~v(jGB5h- zR7Kx`6Qw>gYAVn){EgT*?t0alEsN2Hvs(pSmqdMFLaNoW4Bk*iG*}9E=BCk+ix8~u zqZb!R09(q@#g2>BD61-|rRryUp8L2ODLNrREb!f#RZnD4kySS~5;aRfQc=$Wg&wu4 z)K&u2S+fQ6YNU%f%4Ns08o8myo+w=>O&*n?zZ`YYuvJTk>7x=nPVLm)J8ISzp`CTj``Nek_+bEMFGq7iak)BvXU=e8 zhjqj-0JJRh%>QnNMJ*AGrbJeswq4%F)~%k8 z>r=<^O%cAR$?uH#RL^{sdq79xvo0~*f708WwO1#+Qf?8hb7%Xf<`?CXb=UI<>5_4+ zZjd5qXZG&H^O?azY%)%H-Zjm*qL0Ek4s}vdDeWUWb18DH7jXqQeI)bjtZt$ik&lOw zg1MopKh1*t^RAG=GNek4u?n6!+;oI7RoDcswai34Ui8+)v3@bsB;X&^T#2y$Vr4DW zmoq-Def531pIv>50mY4?HBVbJRm79Kdkr-_6lV5QRZyoLN^ysS9xzSq31?+ylGJ%O zk0mGD-?T7Aau*?iwS}9fG6G}Ki=I~RW#2TJ1V&S)pBf46wAILpd!oJ$6m#T3xJYWX z)ZaibbHIGpknhLFl9a7N@gW-?>XcR0pjuM``S5pm_q(&M zak2zf-WgDDx_?}!MS^o(2FugQPCJNtYkgjJA1fM@1tyHGTyow%WP~+U!ZTk0K%4S`gGqcbmE0F?S}dO@Av{9GBWbpKFQoP% z7F{M!z9QcE9@wZ zFPNKM;q!WLmm8Z^Q`oma`?g>#zDV@K?tm=MM<-ia!!K%cM^*y#=3|flEODE5ft?3Z z4_LexiYZ5sZ7mel37Er)+GdDpfhh$_s1y6JhR`{F%UjlV;;dfcBJX&+&PY^1nhhT41l!oh$t2 zQjkfg7+q*o#~ND}n^M;3+q%rZ^(U;{Iqx=t6rxa#ucDKpXWynG5OO*4qkYJQz7#n@ z9&MW>EZqT|JQhXfGc3~lNq%mz0sMlD8)a2UtEt!b#Z74jF>%}i!8>*W+73jR5ZY?1 zOD+(*7TfvgCj*2$fXW@D51Ed|p$6WI`=L|&hekou>6 zXMjq!DkrL47f&4v&!9x7FMzv0FcAOkZ_E`&GDAuIa6HdV8 z_3=WwNIMu~E??tg;^Oe6Y+?eRIa2F|-dZpy#_yAyao|xH4z2K&yNRcxtT_n=a)@R* zac3g-;`VbCA(M@FHM9PdeG`_p73Xr$Hjt{L+B4Icu7#r)Q-< ze-(-feKjB?Sn>jg)A9%mc?h7E-+R9bU1R3ih>r-6`%%K73iqAb?3cqN5{;Nf89J{O z!5f)lJ7RRRb2O)&Im)-1K5B6bHPnX*3qDV(S)yq|w|gduDoF|ST}&F4tx0d}NaGP( z6A;qyn)d8{eCo3G~6eKe)5-@8Yo$}mPL`!JK5 zPIZ3^Iv1aSHzs#Frgs}0p(M^|6rye#aA?VJfA0M>+9sp8k7}`Bm8bo#v@11W=(N`7 zT7Bnlr>kh?bn=6$L^N#Oix2f{FXdO1_rqxADs+dnL&^>E4*YbQ3_60(>(kY(@$Z%j z(_`<+yK)Q_?<$Ge|61mlRuw#+#lV9Eu-{{1%`V27Nkt|jq(1Dbdg*ahuQF6;%TfNP zI|MQ_36hzLkt^NZZEeShddLrk##ZTLNUEX}p3_;%!hQ@9(7Z$VLf>vV4Q&IXz!o-_4<2i#-~jk?FoJT3b*o7vW@{{m=KY@S@6p`~NXQ zI4V?rs`-3oQab&~S-<7tqMfqny0Dr|3ee4dBP!VtRR!#lAKyG*k^l%PT;vRTfA5^f zZu(g^9My9q6TCOX(3ZMeHYyEv?EH6YqD`TBwvt6%Zo)S#j=%9vvYAHsh1~e0eNn?a zgLT--R$?DDNS}{xnCZ#<^#o`KaiD^sOX_xWQw=NWe)!WL(p^(N7@^YQxJSu7K72%# zwOfF$arnSteW{E6mw~WH=zp4TzpMP7_UK(Dc)B2DC9$p-=G;5?UGmavNtODdS^{-e zZ?$CQ(EV7`ri;;>?fjMbnpXH$FTZ|9RgQq9 z{$ZBk`K1fRi`?ba3#0emOW|9v69j(t2%E5}taO2NmjLhM@6KbeQ6YXVJ<`Ap?kmy&< zJmQ?0Rl^Kk^o;}t7}p;~c;K1^8^G;MpYx+Zun%ze44D~)oyLmowz~KzmwInd092={ zdekmmgmnBZDw3?R{I9{3|A}8asNz9^z_=eK@Sad=ED_)|#TAl2jV*rfa`n>xjfzI> zds|!}0_+#3O9UBf4eyNgm^guixJ^IwZo7UX`z*NWGPAzm{hH1P3(TK?$mak~sE#sU za$z`~y-{kpm3;M_+bp}CnH77-k*JDwPxjf8q-OaU>%j>(_Ux~_XI>w~=fzdj-XnxI z4bsvQx{f0pS0|L*hL+^jq6Q8`egB{qbT6Vz3a$f(tqmK737qFsvQXUj8Sx!_zcV}; zc36(E|B@6YNsquM;Ec&@qS8Cqp|5u2+q;+_BHH7UD)yu{69Xbk{-jBc|KW;SX`IXb zcG~;xY16|O@5j$)xqMY4e6}mcrh9Hu3*-}WPWK<&E%#V2(5V2iks$fc2(ADL*CHCs z9d}h- z=-sVvqO0yQRI-bk?Im$@pH&;s=paIdhRE1u_={|f%GR}M}IX(I2u>URj+v`7`?>Ug?i+3!c1?n$R`Xz1T3hpCq(bkZR zx29bb8WpT0i<<5qWR=N}-av^u#&24eM7QOg)>7K~k)ngqgiC)vvZ)4)${O_rvz!Tv zd70~kDcciDrx9P$yr;n<5!L#8knGf&0kDY)zBfayOh0x$r!dkG`&nNZ+7FY%{b)zy zVNGk*(adq!kCX`+mibq*p7gvteW;2%sLas^NKkgsMXmfv*~R0TbhE@r+k0B&9nM>~ zbyLs8>aufsB-TeyDa}EdXvXxq*v_+(^?Q@PY!&`n*aXWljnSUHg;0~HLWwg}Mz_S; z388(UtNB&TC?>gdqRSG`oz}heRS)eev9w#~A>B~-ezI$%&2L3IOMAn{)Rj-3fpE-# zZDb1n$5*t+X{Ubt&oSeDCmLIQX-iX+OmQ%TxwGc=%%bu6`=@)gXd1rszBIM1R8`eG z+DFf$8jRq=EzuD(p^wTG1p@o{@mWj2*A~JAu-ghFTh9K5R<81iAIQG3=SQI^vH#omsO*kKcDf!xIVJ_0=Y)K_I?`c%4`e%26on%0>|` zX$j7Zq9gx;{D^|rqNM-%Gm00!ujhI5EsKYS<*Ufdl`HkqwTUG@Ko?UMhRy+#N!-3C zjTV+DNSv@KVv+{)$EU?2*@q7k^rriXfk<$>sSCA-#ZmxC=wIkXgmt>B4ZflM&yB-D z?Ez$B{ZAt}={UEAp8PGnc*+JIVFWkAN>g)Sv2MY&^f3qOD``6jKTBc%<~IcB=?<64 zB#Ar?z;yGEzq?dg8K>1k_camvCbNL+)KLagrSr{ColJT`l-QNazt_$em1kbZ{}MT7 zLhfH|rNTo9q$0lkJ@V5QL4-V8v2gJ>FJXq~2?Ua!K}DV-+CFXPD)Z*DIfX>_R({~^ zOmb#<*wESV&9Dh{HQ}{?h7!G9spTdo-t%+TI?N+T!cb_;u1&%GB987>?&nbq#Bdd4a((`>WveP4rE0@vlqhaAqZH=Sd4HN*5LKKHv3i=@4{fVLZ*EOIh zCLFRL<*5KmL{6!AN7Z~Fz9;h>$D8iD?|&*Rw4R9Zba4=nayab^uq$Vfx=y`3yNFcD zxRrpY{keb$N0XKpE(z)N3mI-?D0NwZXFdiP3bze1?;up}eTG{;@L@)5^#rw|t zKj}g?gh63Q+oa>7?GIhcG5Tb=%;_7^r$`G`ROM>ei(P<@o`KB|sbpUwHb)Bo341H# zxqdQvz#&MnGG5!9EN@~yX@kKql3U9VY>nJw;v*Ov*w-g_S4F+($0+&-YOpwhlqm$2 zU)1NH#q#O2CCBc)DPB&BwK1rwvo7bU?^b!BdKyC`#63fn_QAk)=@^SUSH^6~q;*Tp31W=Q8EUhmNdnROAdc;R*t-jOu}T zBU7$6;ZBp{{XNGL+5DQP6jZ@L`%#I&QPllhmopgd=Wm-1{PI)d@sV3KZ*BF$9@BS3 zBv4u>lwyHf)H#4`(xWx_S9WJYdeH`+){S*(1G`t} zeC0+A91r$|Xb0fybRJ@k(cEqwTfF0q{D*+db%U3AyO(uL)4kXAfLjwGf$Ui7%9bM> z!3l4uaVq#>?nsb8X`;8mt6oW6Flgq{7k9+(p1Z4O!3D3($4FieIeuzP^NBdyR-Xw9 z{^m^ZDSX9-a(cOwJ~!fHvd&$6EUB&N%k=KAD&d9+gXFjDmHua86OSfaMZ#ABRjhXp zY7fqx{!W);8*Z1#k6_RCrixvOnSTEq7L#6xhxx$ljt z%HT!i8`H*cwq-R-3{?{$qIjb`SMxdw-%f_XS@dN+u<8$o$4u`Od*jL9iXB?m>Xmv0 zZi}uvbO8oozWae^xoc~tM)xP9jj_RKpCfT3__Za5q&fO2mS4D<_oHftq>3vk!4tvNx4wT8nDmNmcxFc z4J1;{#V~Ogs|$blfvh?J{Mqcl>NCU%yKDQjyj6|!Scvm3{gp&AJKHP1Sh4jo@m)TS z>+`;v^4~3!WcJ>Ko+$+}1HWNW&seT9TmzI1dTk*nSa)D@u8pv-8T#;Vec%1^5YwB) zka3=bH`#%#8q%sfcaTortU1ct4}NsfbmB@~+=yR2Bjxa*TZ=4OgDE>m>j$|Q`G!Ns zt<^=iDmPCE6xD5+4gKqjX3n_mskZjaka!626SH@0nW;6=c?;>ex z5)niIX=Nq}&CALUO>@}G*2sTiN7kM)@<9t-Km~iukWfVg?Q&tF`=-g^oQhi&-(nzy z!V=Ob_(q8J`sL5A z{IkJYfk&K46=Dr5WM4F?->5sjOE|8Q$h26vZ6R-6iDZUd-Ki#?HE{XrvjCr!b(HHaKX%vx_3{<3Bluwla9&21lW!Q zOMe|B59>R`j8><1`@cL5?Ya)mD}_3(SCtJ`W#~mPatb}*J&3k}C9^HXy>&P}U`w<~ z;KA1x6}axEeN&PN<-cwJ#uFG6RCQU$p+Dzw%BK1KeP`e3R0&JHGQ%cEYp~XB`qnI0 zWz!04+3L!CjI5&}vL*7A@#c{)LQg)l^XfohkEM3s=Z+gLkuobzG}|cCgmF9(Z5)X6@tO-rc|_b;XlfBGZGKSv zgv5A+ky;^5ePoICC-B=vvVZ)g^_|Vf2+p}T?$)SUxwLuk5_euOfv;$VY)P!# zZ&&GDn8YRZ{x=br{a|Kg{D^gJF)G%xEJ zc@8+O`aQaKeeQLm?@Nlazj^#_uYUf#SHyy*>7@JzrL556&F*H3FP<(YT+C`6tF_aY zC(ix1n0E?uA3m;t45VUP-U6;!6{-LrY2@V`WfO8w<0!+H=Gpjm1*LA%+;pJ$@B=;s8+dsZTiH3E9UJbODGHD zotliG)F#9NG(X-EXK5UPV_Iq1e9z3K+IQ-&q-6WunaN$Hx;&|Lqmjbkt2S9hR0Gc7 zAWdL6NLJX0%^W&LW)K3BC3aiop~w`M$96nR6(JT_Vys1g&=liN(fF)H z6pj)bfF&Tfxt(v*LNufXj20fm`21rqX(Hf$4YWG~Lgv|`?Bei|XS5W$sJDW%hoV}k znWqb`D~ah}HNpd(zAAhx+l&JZ8cE~W;?6F4dSF#u?M+M~MsPwcbF=Oy1ocXT9HRLl z-7BiATOp=qHvThxwaUYzuePzRH~M9T{xbgZ`M}6EQ$QTBww)8SR%@#ZniLy{=@amb z-Y5|8G}n0e^YF^{cdQP_}|mFUWs6v_mllm__OQz1ZrLG5htJZ(XQKH zU;c>S>Wu2YsQA~~vMcPypu-QT9z&EHzKMY($(;~39wzM01oc5rfpAVy+ghG1$G~%4 zzJDEcHdBA;Ud)Uiz$XUJGCOb zT@Sblq8M*RVGUmN^Yh=;1B^5n4jn$us^Ig{Am&L3c^NK@5%_l+7dY)^NEN(r|Cjls zDm}@(BzRfut1@0Mj()fw+thIgX|HE-XpZGZb;{JcPHG`ZEJd2m%UbBmr6g3IPP$k^ za7`182ndsUB%o@qWyw$SS2>3V7eYx_Le_SI%9gx!HF zkSjEAw|^s`-c5@Bu_FY*uVd5nEQ>0_^=^ob`@jad7}$haW`pSW>{F@b_wbQa zOa{*j=?E-8lbA08!h@d{BA0l>y=X^E4#i|^w{Wh%?|EaU8Gzdf^wbCp0*tBtWW))e z0BYVkup=#nXHg^ES6Iamti1f84(kGM#z;Z#jM3Z;Dl;Tys`lOSuZWlre=5EE<1W1t zQ<0+RuI$155?v1ec?(j&V_+Si%sRKmS3S~z`b1IUM`gQq0q&jnN|hn z@C0vHJy74G;MKttRbduriyyLXAZx^e%grW0zuj3kL_Lo%W4{X$@Kl zJHuAC>3(HMv7Tic|LX_pcLQX(TFI*QCr-*tX&iUb_(zJ#O=umk&IwhaOG)E(J;Lxg zf6&((JL%x0$o@6UtYg9tPh;l=Uoqj@C@N)UXS#!t9X${6%f_z$v_v*mI#} zR6^S;&wF)cmj#f*}Cc14r@nzC;#qg!JyBc{2SLSQT80gPuhY$ zmtfkVlAxl1w#C~R!bxuX4waS19e#Cj6zE0&yLk(lz!1@}T#$zJt;(P417`xlG}FB5 znpaxUo=8-kD~`CI&&k0hT#xYMl=4R`zS^4P8IiEJ>TTJ&!kOsh9_nr#RY5DyW~rVR zwxv$(J$ZE0S>}cYSv6K6hLCzyky6RdtFcYGql-mPyuW;M-aDZ8T?@W)h-fz6_quXv zHF?;=CYy~L>SP%#DIcop`Tk8-?bY7=l!WS>@YmX{1fY@fj|l;hNuXlBX5C`qJ5-2XTSaD9gMoAesJHHTzI9#VS=;>?n zCG|JL`+$jFtyFpM7;p*R;zuwjl865N3+Y5H>!nljL*&+`n_r`(4T*JLnoxoaHbFa4 zU;VGfXq_w_`lwT5HM8TyzwHI}ah?@Z3_c%EmT&>j`ai3!+y4~Px5=8vdx7->`~PUV z>ZqpP|F0k;94#=cGskPQ=iERS57VsYpxaA)*O+-V8Ql(14}xp4ta4HtF$?z- z0VQAuiH-4{UQJsUQ*_!y20!$#p=>0CY0laXP@TE2P}oDz19yA+XbzxxTv7t?1m6vX z75jIy6bO`dx;`X=XSDRtj;>wvlr8<4iyq$(E?^%e2|OrvFUwAVW|m6TIHV8fSmP5nkt43tnDbex^i^feoBcgLtg62E82nqPo&Sjzw;iO?EwXB1A7?M ztrXJ{y5mbMa=w>hm6fE#sPW46MY}%a%`gT3u3fquzI7tllH(k$*Mcy=TsHShyG~*G z+18tv8z$$2w7S}czi5B&ytq3wotc(gMDH*UG49#6bMJ%ahxbwZ5Ij(1_>m)YyDa_r zuC;(|lkpr6VQ~?991kLYnkfA%+XoeBLb&n=? zw+p+rd3^(p%4NWbZCBS4*S8QmOhpY^c0v+}swu6^F?e71-3Ymosvyzhs&GVQY5N?l z6w_UQWat~ZZb^N=$19-1tQ7djy=Nz)z=cPWAHSoyAjhT?_ zDnYJP1>yCetmH?NDdWT|WZBXAJ_mPB8snQRUeJG?j5Oy*%sLsFb$cv>2Sc&9od;I9 zLjm=~UB1-zky>B;axTpr+sQ6`{|4`6q^ipsrh3x3^B#h6}o{tScj`PJXn>NOCfXrm!v& zt}T(+nV>3c-zVF&p4%vb^V5*)D+c8-1^CD&5`tY~>hV0&JYK7#$C^Xv@S?V{TZEuI zGf4z@3-i4=JBzNkXF6GRr2X2>qkh0^g~Ff7bVNA?3bSRCA7(gyF;YgDD`~lmc>E{X zJzhs4l=ZHkh%+P8T?7WmfS>_qH7$Q%dM_9Oj@p)G`=d@=zJN#9gyjFF%A!VVruWW1 z;c$Iks_54;;>DDTyISz%T`#;VM(9WX12bNLZtu45LCcF+Bm7)U)DG6t6~)%tpY?ReSuLHh zs%f!VKC>YD54Dn%=PFDDf8D^nCS&m4rE%oM95Q#OcQDpLm>q&wt=nZh7loK(ikRQ! z^7#X1LeKWkfCjYG25A0v$M}-!zbx%H?kdM2`eIJ8X6qEWA=;Lzs4bw;LsrnU>4xtD z_vN*N{^D0x-=RX4INg6HLxQ~KwI$bhRx5t_SyXFy+jd@FA94iO6i>P4`nR2}(KO=6 z3>SuLZYSw>P4Ph2kvLYUq{IORmy7Db#aAlt|0%bEmIK>*X@LyQIAAF(|>GX_8lvNdy46^m91_65?qTXNerm0r9RWiOWjHv3$IOxNkhA+_-Zmqhp1( z3K9Ki==I@oog?i8^K|_=|7VCWovdUUU2NZ4KiSb`$X)B@ki+(qDuRHcskff-_a|KG zM~-BrlaA8ogb7+4O$G+c&hLKx6gGvZyu0)%jJHRcf8JM*ZViJlA@%76P-i&HKSo^UTAY+35o72^zq1-w{SJ~{cEL;) z%J+fa_lJ*kS2!d%KnKn+5KaJa@xG*IjTP8162|iA4vh>@#K(gr0vq)8-)gqMA6&&z zz9t35_e`U3N0liN`t@Bk5ed|IL?UoEnPB;`>iklQ`T#?==ds)OzmuW*Q-S5y z-mgxm!p9rJ^k6fE%tsS{*+5P`-Ka2vX1RN7 z1W+QAC_m@#$v>`(zq)ka;Vu*ao?~&RMLOFm1eyH47Dgkm`GA~|iO@#m$=!L1cjUgm z)SH|dpL)P89VKOi2wOy=kHuo*fPXIIM=%DOR~s2uoXR$E#xE3y2=o zXj;8j^ndBHRTn;~lFb2e?POVKr7&ADSMX~jpqjEoUMYZawwxtkJ#-8s{Lrj)hC|tc ztJ7Pn!>5&}E9xNIU*ynGH#3jwl5Ug#qE5(}wfxAn{xtr2oriPQ)SNSa0_U^K4YT93F=GM~Y>czP3-#A%C}n8mmMMqmm`Yy2R3U zGrs@4si_x(_jD+A%~(wfa@mEOr?({Bx1N%YgB|^+rzEib_1{|hTll4T`S`QjPQ5c> zAt7+o`Q1cT%ChG$G}YXMof_rjf~bk|`gp}WfeqaEz4;U`cx&Q?-+QqaH^+0aO@l+2 zG`GR7^4swkGf>~w1oB=4A_*xh&XY^>{dRI-5{= ztr%?RydPBlMpSCgr_#qQ<+2j)1lPo{bFTJ~V$TVFF z#e_>`Hbb$HB=?E+db`yvPNSXzt-OJJDVmfn(1M#2#^B!A&07Ot!6zQUpYW}TZwX>B zh4oaft$)pt5NiNPUJ52kv^xN=zWR-RoU9%w8SJC@IY8lBQ3#rgHBu}81`Ri&5choV z88M&DC49vl&Z%uRlH!ok@p5jrh_pKs8G5kV(-9#Vl;bvWB%DVesitwV{cI(Usm-0C zCiJJ1;7P-!NRDLVB|pCI!(UJK)($<-qJH)G(ij!T8W)L*xHdXUgEUiAqdN)p%o~>7 zQ}c&E#+rv}w(q5w_R4RqZT(orq-oV+mNaLHbizFd1L*43e8SrT23ESa)78HJ{c^w1 zy8UU7*JeAuW#QXT0?@VdIDP8H$L~?)jb^auyIh=Kwv1@I&cM;p0{1OqGcfDUVK{}N z)vn+}&57Cg!X=6({sP;&K5q4$5Hu;uOf*S%l~%!^`_Ut%Ul zcJ9})#}?UCzNdJ)O^YR2mI(56Yo~*e?{fyy0=mtjA#QVx;P1S9<2_tbMJnpo-Onv$ zG6E9=D))w^pMD2~)8E`$3Bj7J65kbK`q?mUuZncM&aF6Fz`$d&i&ritjWqjN&wf*e zfFTf3NqkS?z`rHZ{1uXmSN%U$#=hJYh*`POzWGimrlDp^KFuO?Lpj~cBc z#C2F|``?U_#PC^X<;^G9R=Ke(L`MGjHyfR)tW6qZKo^XLNHZl6-cn3RpPJJvkXWpm zTf*aljmU-*4KfwyHIX1+kACF{QMb@|9TZXBrb~A zYrED6xSaaHbK7sr3e3H|Kt2a~=W>pebv%cesq^_?5xc;@sdapo8vL|a_t_cc1$y}N zRRUMS{?#npYt0{)WeJPRPK|vVI7J~$-ZLD1<^n(JFK%87O?tV}8u8ln>K1K&TQd`r z#~IA2ZOPSE6pGMQ+2nD9szsQMRv_aPi+o~8b4WhxzXjmOap|a>h9368*V5$wn_*-~ z`mHZHzIn3oMBkFp(@bx9qRcUA+mSq!)6&Sw@YeR-KEpJ{l+$eh@v1gaU)TK@!}i>w zI9aZE#(H?0J<>xi!58Uq-S!s)bUp^(L0TdS=G%k2{<@bDrhWSk&k!|0(l3=eQgeQL z>Wq8g{$I41)<5v8%nn_3AFAuWs5YJ7J3zoigZuzq#Md`weng`vAxb+bLf;;9sUg3n zY9>zJD#wFJ6*poq;7ej@>2+HKV(YQyq1Np$LLcL|9jjMYRKh{4@7iB-x>cBtN(`=b?ymg$p|L`Ha4><{dccIR z-+%Y=1ZvE;QJa_@FfIoMzF_{2yq-*R(*7EW=nFx(jVi-K5H1QbFCRX^E^1L?>2!Ao z9EgNPkMuD^n39%-8hhCv2uPUw6S8g>Qv8OHikUAcJV|2&?ovhN4K%t+)((Z#nt{CU z5qn=SJ2-%93zX6WZ^X!Mb-lqPwDi<4S9#nZ7pY!u1SagG{~bNhDDJGx5;;x~!|Q9u zi)Ar4Rba>PN*mbbU1Bk^-22jHtl@b1mQ`FCnJV=4h#Qn7om z9zZ}3C`gp{NI8yxQ&V)e4~Z0+{1MqBl87Vgl#$)W_jp65;QA{g6R+F#yCBH)1^(yO zdv7r9t}ms45 zAU_o2o;fmT7;&}*YRZBZQO7ijg*6_oSFKz(m~1@+x=(#d?6S#@z$h$ES@dmc;1|FEY>ofY_)$qNJ$sNmR;THQ!;aDAc?=K`IO|m8x^S^nM31-{&IyGK98COx ze}1n|QE2|Y>gA9uk&j3_P<1e)sCikB^$;>r&mD4?sROOvXR^ih36j@F41k)xaU<3- zi)Icd>wf=wA1DB2bnH?egvZ>>+FpJ*XC{KSy`8H&w7qo7=Qt`+#KEq(bsVMRIS&11 zN+*-rq2j#fKydaa(F-2nG2b|izO4`5lYSosr*%;Zla(I1%+NHNV#!hhoJY_l*;fWsn+&UnYgAJ zT>=ZFkg}$+Iv%o*f=Q0_D#i8R_@U6X1MkDK-0)IR)6EyRuIw<}bxwo@(vmUppmVBW zu-x*HpwLJF3c3sZCfFCH+_iI~Wr-|&?7JAsqzri^`&@B<(&`e_UltF>-Iq1DmGR;f z{x4k>v18zqft%5oqdqbXfDueOynub&dFu*X7TPfbE)!2}uh_&FJ|hY-`uOpv_%w?w zl(P@(9q=@DIW_Sp?#tw%@n#B$@a=t9?oZ6Ta#7hO(KQ7{jtXwYSgx zsz-^XZp*hhel=Nq**obJy#Zt!=5bgBvaM-iO97h(`_LO~1Pstcu3h%Svs4BgwbM?# zzOE{)6%@*X&RHpVv?2XN>`HB`m9k-${@n`yUh7H%)OeNJ4ne|6NLVTPM>1*19X47_ zktxOpqc(AMsRB8BT)n2~T3=WE#V7|E2iaf@X+?X@gturU8|=5ffX#b)obaP~O~986 zJTem&YuViSKe%X~I>WmhSH!rDE69GVXSa^CC6#TA$Jhza#+!Z~3k-K#)a@{QoIMWx zvedW$j$s|adHX7N1xFT!Ei3z6Ru=6^M9wEd7O++-b1AS|tQRx;A5G?_<+$+IcW8bdzjb?Txm)xLcp>DXG`)eBf%=3f^zxY`b zp0!nBTuJ5RCPFwH@95v`G4H5y1i7QF3~s3mSDvl~(p7>W22jmFW^`DAOf}0y#zVLO zysQD+=8u0PTMpX9N@S>0=3yD$U0{$$^y{U6EDLXyum<;zLsVaES12P1j>SpQbxr!F zlu@SuxvFEQR7K|Q32wmJzszkwS9H@cg6q4B%&5v|0|I( zw!=@fRT0HvQO!%{zuzLF55n`xrSu!h4a^ zjr0htY0<;9`IY1gvm9+^=2*zV7o`*QXy9p~z5H378l=Ti={06VfrQq->ZC^cNelRD z^5>E^;`immd&Mb_6{mL@GU9CC?Q-_TnI9^$gJ>5c ztv7tD5K>IakDXi%qHZh(TuziiE<>)7r!KYa1`1XhVs_TVFv{zY^dXHLp@`q>Ii}(MsNLWgG|3W@Y;e870%FOwr z**r2F{jPl}q0E?U>-lB_J{#t3(!UNH*>TYwmgLkfR29;pp5-#i6&tNjDYSQ5Dx)e! zW^{>8TzHOkGEZ&|Z&)pt#)^xm+m1QzQ~Z&uq+usI5$aU75ibl!XD8XDkJOolf4qs{ z%T`9~c2mP$S+H+@eX00inOkL#&f(9A^?&go@;G`}!oiF^L$ zcgL=IwI{_iw)Ya!NFkBTc9*|ghA&WWL@<%~UMI#@Mdd@fLVWNVp>~Rd3WgxntJRlU zVa)rGJa*Q6XWG^+dtlca(WF`xM?8|UhqZ^aBahLnO#5l)M#}oBkW+1IX*{}+8flW% zUwqMqmW)hMhZYf&hXQ$t*2+S_01^03-PI3HRZw|&Vw=2G4UtDjfIaIEV*yl#se3I$ zjF%?^WM!DTS3KH&?l2(5VpW-PN}R;^KeZj4mm?hC|B-9q%=$Fd{geHFEP$;xM6U3m ztixTQWJXSZbBUJJ5!hF2;oY{NbP(+F12u^y%O&~oa|=#zHCxr)=nTK79B|$W*`@Jp zOAx>xEY}-BBJmPt27_=3^S7mD*?O0Sv|lCpzGmXGJmKC8l5Ho!BjLRhEjkRK0GOT| z_$|@D3^7}aM!fDr7CpO2bta+!s(pQ*o#L)mg;wwi*Gtqv8&L>#nWQ7f8p2yg??hFg zPVt80Bn0SD^SS`2$xc%zl~4aKgIfV7i@HTOH*UvY<)W`DTT1$f#*Q1Rj?vfbD52AF z;Cx@LJW*}kPj2_|Uem$bxWya$<2b6!CuS4v{>v-Qk0%`GnG)d`lCD)P%Bc`L!hS5juIBg0)gAP3VMX@DEjRk|LS;y63*z=vqU27XFP!t z#36d2YC}Qo7O26fU$;7_4D%fKQcL7uJ87^9yEY<1WrV?7f*|U^4|E=DiF85}(|Ua?O6OXQ0lg&bRF+_ua-MO(*kku?3w;ZB@_Sk+>Iy3#6K^ zB^QaDS`G=6cb@rY3TbQdCDN@a*BMTXF!J9-Afw8$0=({?dCOn2B#I?6vTm44BAoMT zW#Z?T_MCqrARFov7en=dYE5Qzqta!%t7uH6L$I#}a=v<^PW?i9j-1(KEB04pg$8Oi z$V&|yF7jRNqTPWM&@Di=j7UtzDDm!6Gl z7y&%*fw{K2mG^tXB>Q>n7tYmN%uv>k`8W6Ot|Z<}+1EGGKK(d`4jdIIFBC{dVtsQo zR2L=}jN*&o+F7Zm!&SZ|pCKdz((o}8Ou4)JUP%2BGRZGNCuO!_Zl4QiN~I)#x&1p` zRg2_5xd$xRr;TTDV8aCfNkGCee4}Yb& z#|8Ju__-wbKzvv6GXo1bn|;I9(*3r%nWCdG%8X%%zg3C^?y!ztreRL<<{8-#JOg@{ z*%02hT&15GSILb)AMh#kdcm-=r$Gx%{?{qqGrO+OW_#}UuHA`5%3esW&i2CDj66BKOlhq^Nu!MYl^lg7pZzA|*{?o<3Mq{Tm(G?n90%h~m=% z@o9iT)fhO2FKhi5fRk?}2)I^vM&O3-)Onqo0w!P^;O)O-f6%#B(j@vj@X$z(px-Kb z#oW}rN&LiU8hP>gcmXH~J;0n9z$1B_`@O%tOTX9r;w;2XFKg!K7ijOcJVQp%1w7nL zJRKPq4XNd4Y3kP2-1Nxku#1a=&G#BZs$)SAexLS)irquBFAFc4w9#K zQ)(t9bg!%&A;%P?LBY37dU4v?T0fAj(_m7=T3c99#4&iCGyO6_WlKEzTs<2&pxI|XGYoZ9#cg^ zB{T^iCeOJswl7um-@ymKvL>oTf!KqGMG*!|yt>S;@f%!UOr zAo9Q%_-}j)k*v58?8_>B=t zabZRgRz7|#=*y900g}s=*j>J0F|1g_n7!lSvG1%bot|4#t%x53a)#z^WXvXp7VkZ> zFe%)UX1?G~ABQ3gznquItUQ0ot#2ud_3~0a_tNLLpb9_A4a(taT7CWR5g#P1DEkbS zXpgrMEa!thYT{9{=)l(5qS#O&%|$#C#AX~V_P#fA6fRq$5lFZ4xH6GcdqWN~@|@Kg z&cu-nLlDP{HW%LL|JE3x3X~Z0i$SZBuRFd6IEubH8L~a2z&g+%M+iU z7MxF~j0viTq!b(Kx)CopnjO1+IX;tk^MF@sULj`v|IlwzR|g#DJjT;}rsVG|JR>@2 zW&>6`mr326p`8LOpt_vr9sTfHZEk#!w-^~!R!>I*1A6b#IlY>!G;leY73@2y!aAO) z*sxdgoqiim>DBxbb4o;$F)>V$CtH`nUaZjgq4(+Psrjgnrg=@?n>^DP-IPun#o}0F zn5*o&uv_bOog3B&$s~68r~GZop}APScgR6@?x&k}xlg53YinhoJG?2}EzD z(IlX5-JZsGm@9B_pYqB-^>lVjzVIe#Z?R@mucXP4^g!)fL(YSD?0q{&yoN#eHnwWa z>49|VJkXbPPux=sJW8HOm^~;+^b}<%qO$8Mrh~sxq&cg}Hm}@15zzkgn0R{9CpOS+ zM-8LJP{ICmswmj{mIABk?Cb*r`Wf<$n}sVp=kMZ@yr<1n*R#&8OQ(G7-u?R0|9IVc z{6|f=?AyqzCT4^DDN6qP(5Y`FU5Q z&+s24*o8%k-!!eDmpjuZ)reff=ezYjpSD4rfsRp3(%W48dmAd~5^Ci)fpdPx9q62L z&d}uhO$~D@~i|=XN|+yY3gc#`*l!SAB31X&|7QFncrWK}rC6l{^6weqgJQ zSPfD{o0pV23Q;y?>&w~DmAOL~pF4rlXOl%={8OP`{7!nmSy`ToGc%T1_K$5t6h;VS z^9*Myn)<;miZjR3scCoPO!SBD^V7bj%*QTBlH2d^M(lh1O?nLd8!V`|(StO8h|(Q{ zj~eS4mV>3buPqYxv>6tohHp8?ao2eSF&5FL!A|Ub@CTMV*Vlz)$hvNH=g08bTOSD) z0>;Ewg3!Aza4clu6?4gR98)y%~OyQ>v6YRI{{E06qHiE8>H8WU1EaD2Y1fc`32`05hF3o&IqM7=L^?6nZeYlhm0Asu_=pX@O) ziLkc{R)#XuL2qmO;4EMsBcM_I*(rcG5p4n+vjo#PKuk*V&ZNP2jhPM7;2eBg@8!VT zYmUyDAGBPp_t*7&b6+=z7eeHenh2a+Zdn=!6Iu-rsTNhwkyuWzW{;*+%^n@mmd^wR6 z@_fTdCb1>VI&9K!`<^llkdEvx+DU#!6XhpB(5?}Y+4&6b6jGZBI&UtbK<{k6$rD$l z3UIl{w!|IEJ(NBaBR2TV_d2b(JHoXp4|8AMuLq|&hDegiVEN%$q2cEf5Zfx}*w29r z5DfFa_R{JnE}Y}a#)Yj9x$f*ly3qu&JUM!afi*B!fn3mGZuJI7PIIikGx>f+A;wY7 z?t!0i=6QO<%M=D)AR2+Y>5Z%<2*wCd{>3$VJH@V7r3|a?q_sh2SrZR@GiiBe1Zly) zYoWXGAr`AYW}EzYOuv+d^G;}rPis+sle@stI8Fy8{9Ov2h{)p7(1xX(y1xR@jKVTU zERp%Ak(XG;?u6FQmk=VC%RQImAC*~E5sBt~Qp%XsAH!(kVOIFbO5*!Ua=dnc{zEIQb{ zq?dGT0?0Cg1~$)E?FW$wLgh~TU(8B6C}0RUFSYx*MIQQM(KY?0$Cyzly09&|%J^H@ z%rcuqe!cUsLDRQz#Pa9aIisLw`i1SB;Sanc(U2HO`HY8>j7d8`RH`L46!LNkGv7(c z1Waw+)6{eT50|>xatUvOe*&vs@Wq?qBairi||Z+|VBxz`{>V9wh+XwLl8@$L=}1cHs8cGn0Y5c`3cy8cg0O-jTpE z+XUj&1|dD29HPQbwO@rLSfy>Hh~btFKw15InK*$z@!Oe>D$tmv%Lj=V!cSzD$OF;! z)gO_0CAv}Q)*UMhB00bp54qD9z=gH^<7cx(s)-4M=PD;iok52$>a=6JJhX^&i5-+VU+nvs&ed9%O{% z8BovG0y!2xuEM#$ET?lmYcU9yHY?Y-kgvMID?ao1f~UQEw`J}4*!lEGYX_(AsWQs3 zLAK^*xT*Xs3zcTb&D%)2*E-Vhgs(^^;%+=nYfw=RI27O&#DwT;%b+JWuRdzZ81{<+ zT)0*JsKat?f;CtR31OGRPnMsM>+aqb$Zbz5Vk)on*N3USRVJw&5y>w}jZ@(qU@Bqk zVb`|)mz(KgHnptgq+7S8F*_FB|5KM?s7MFG;)9N8nimFf#_=vT(RqLBCacMkUhywL&oYnINg&;%%(J zHLKNu;|jYCT3p8+Og!S5%G9Ld-y)@?nO)zjejhLLk>tu5H!|krUzHXnHBq= zBnY-DRT+uiB4wI`4U)^`+kdx7H*(;zxQ9g#h2Hi5`Vk8{owcIH7&WxSJ*fRl@k$Of z10|PZdAVHX7fNgfdC8&rRTuic5`C~`a5B#Lp)3>iL0uCsNoq)dxj*vrd?t?C`maD^ zM;bsn;^@9qT4M~nVO|Ou ztkImw+VLUcUSOD*@+PPKFpzuJPDkGFQ8e+JzkTSIhvDZh{8~55Pmi5GOl(VXXJ4zY z$nIMVbsY*hyEbHUFJ{>}{Mdy*Q|^mve)tK06MPVxdWA2xsd#Fav=x63f5_{`;&AouAcI7WCcV|<+WX65l%elt%cwfV{MjPnRr)=NFC z?xF@=F;t+X9Z9-ya2CD6Bi6{c??WEXVvkD6^sus1>M%lUYQJ>TB(a;_4~8etl6rsy zBYJBTyRxD&^DCJ9KTNLon3VI#uuHDr#m#WDF-3iN9Bl zL_!}|E+ds~!gI2-%ueXKl@)Tb#OQ17tlGbgg_}PmM_9P}{cW2d ziqru+f7Z2@htFn74SvnJgiPBw(iow_T4M$0ZZ`rKO;|9|cXbUe-2EtJ*Wuqq4}L%z zMJhnIfh{g3)0~$X7t{Ahnz+I^S(p|vKkCZeqixlo42h^#%Gk{<=`}E6Al7-@jf+@@ zT-#~7$2s5WToQc(yZMI9@St|C-LVySSOu%j_vgKm@Ngt~B5u(~M zl@KCoKsUhvoTKpFoHbGt-*SFOOpm&20&5hmpJ*)edVrod^R*9+*_}w_tx%S-GSXiT zoU53d9#zxNR)QX4VPOvUSxy=wABbB~L6?aKD*sDJV>R@!-)*GA<}kuUKyX{-vyPS~+~JEKx^Q z=2qydUg=JG+gQsm?037ToDHZWJbhs7xs_6c9_-KmK35Wnwj6C&S4vyUypQ(RtQzRy z*iP0VCy;76r<*P%@lxeDa}p#Bfkos`!yvWq&YlTp%K^GQhiw^)$C{Jo_@Y0n-e3Cwn9I`n|MtPVpO@`Zqg#>( zJ?_%aU@Zi}k^mkfY$|?K*ATVgY_5EYGMDxgV(UMft)VzS4~$rs03j9sXGB`NO1P4# zi?TsB%v&E$XCJu$2AB$s0ezeihzp3t456Mwp#|sp>AZG(*ZKT!9DrJ-avitNT>73C z2qavY813lk<}m{*Zt6+xJ0)Y*VdvpeQUW+Kxh^RJCbrySYDWmqczXgRu*c`0gyp~r zH--WZc(QSdLeoF|UX!?wenyA#l5kOxM!yvJ2 zvyitN?F{u4VI&mwIEUB{1}4^<0eWoSm0Ac(rHG!RX8~zFY&08XGSu1$Lcb|}tEuWAxtc1%TV{hPcy#=`T z*PA_M4RnU&%_1;!)Si9!A>|~X?IVy$5toMttGUdeiDA^ky@5za!~I5jlfqB9e2@V} zY%c(Gby~Wu2O?X3HA2WrdzP^Dm7Z)El`pN#D_}Hy;g*^XDSiZ{#Zlw9Nu943BEsKHA2n0pr+e3ke>;do7O&! z7KAxGNP(Dw^|;s0)R%>u6GT@tHKHoSxvOuHpA6pBwFu6a1I06Z+Qn z`u_DS_EZk=7tSQNB+F9SbA17#BNWNb<);>~M(r^E$WQ|3>MyxZW~Vjy&*#4*t&!ta zQ!oMO1$E2^+NKAyG&u=Gp@~aB-`^i_OUm@O*Os_`bKcUhXr}$+9x-|L@5O|%lr~7i zx%ZEO^5oCDsmf$j$913r^zp=JYu;e63aUu}UC5*L4`=~AhtJWdirmCLxEfwN7Ow0! z0|QZ(;GBXNYdJ3M*y~yxAq#`BdrN|UU`p&h zLh%ZeJ3jr`507#zf@X^ltPde#tv5Rz|7s8{>{^J4_4#6P7{oX~^b6Z>vsJz&g&g^J543bx7Ed+4MdHWXNLI}kGOlW1i0~EaGC4M6L^&-S^ zeTU;G1?KzCoR6qUw8_(3s{)^-FWi4k!=iG}+0Sn{+Puc<-c7)tOe=R7KVXQ&SIa)+ zwCh>c{XkH|L<2y2Z%GZHx`ok@;MvZ`{LNDfq$u?_Jd*y7^~JnTM6kE8=z+W!F7(^q zMTn!SST5#pMw571WsYQ1;aN4|?CH?3@@7qi+S7cVar(F`uIUP68Q=RP+?D(U`PNymm2Jk z?Fp-rf63@@U0QH)CtO|VBWt#_`;A}<^qUbK5dUs^8BaFPItpSMMo-y_@%Q1)J1#)? zVWDj{KXfmP`~$tYY6gSrcQ^;fPprKcFFzc1E@?(u)P|wGkWnR)n)%TKO`UaRO5~<^ zG#57+PWm?A3f8b`Ne6%Tf)1=}?;pn)PUR9unG}5gm9SSuCl5nlBKp)K032jgc+ZGJ z6BsFAW`Gttc3fQp(D^A!z!Ldk5(gJ{>4a0JdAzB{%LF4xP0Q}W7*GB4e$d0Wo;%vE zkfTx|dR+3ykh!jV5V?R*?~x0MH_fx|9#Qh)bFJ5w0%+Dmk3!D9M z6#8dO#M(=Xx3*zsqR9yRLr@VFul!>#f!9HOxIPaO`4O8b%8;kO-nVIbzXKxHI-o zd;b-?=R;8tCfZ+tEEi7{i|5AE<{>WYVFqgz9N_T(SOD0hbSNPJeNPrrn5c#c zcgq1DNo*7kvkDK-Z}x}#ICoZ=;=xmgu?@6e)+u`{z`;K5Oi%o8-%RWFnmZ~8oS@8&xst* zcN+!xKb>z5!Xd-(`WXR~>c(S^%Sqvw!*zD_$(~g~Dj~&=x{%IV&|FCG6BM`6K=*qY z=v$@0;)!s!DX~P&lVao2Zb1O2vPTO$wLfw>LlE`9I|-U%+HuZ8eeCSn=CHwVkVbjyJkCM%V~9xr-rF3>iV!Q7s% zP6ap%O|QUw{qO}*Jydr(vgkbfV~xj66hARgZ>dh}{olMt0#cb@=YLZ$ z{A?R!KNGB`YglwwqcAeMS7Ujo-<*J?M`AQ`GMu`q9OLTk8l?|L=@yC^C*WeOb(zdSyBPdHVQQT6oBP+zZb%5p?XnCX;2{HwK|U5uxUeIg zm4o8z5wc(hS=V%@DDT}@FTCqNW-H(Nt3xw()BUh>7A^LDl~Yom>D(GECFtH*nerh4 z>5+9R(pPv4Etu%;vXCwtt&%?cF|2j5CYXJS#`MZjKdoC20?q(Pb~+aC-#P?32!oF2Q_v5Q(OAJ)jl@B!=KwkeL>{&5rY5x zB~~y0&V+#>5zO6n)>~)N@F*gUN2QjrTT)(7fsFmQ?fJa|{c;>p0+(YT#(Y19;ijT@ zVr9kgQ!*cZxS$p0v+J!booTjLP~KoFR$6;aC;o&zFiklPga6X%?nNuM|G4r)7x*LowkCp_2ISG} zW9BKWwn38QzU+RAxohX=)x}(r`FW_mdb9IpvX2=h_R{OpW!ed$jJd~E2`ziF5hE>> zdyO|nO(J5$wM)B8%elnwtt4G!ZvmzukFMvPf5R2^MQ7;S{|9ztl!ZYRTkLI|{91!`9;=oqpDN7D!?s zdl&RZt?X0n7C`t&)w-~|mY<|1>gxT%nA z)(<`3*$em7&5FpmleYsfp&sTMtrV0PFyRRzlLF4cyR~lo94OjKVk2OU9#OQt0Nyf1 zH7xV%)1Ir5sxp4${Ny~Qn$Y0?!V)q#8=2e!Dw|1jgxPp$iOBp~7Jyp3`&PvaEv6lo zV{1q=5m{0g^tf4>id80O|8x~|#=-Bsol+G}vb^@kwCe}{`IS0Q;`1IaP=b5_0=y+> zP1ND;3e`))BTG=zB!+5^|07&qhKxonZS)ZoTe|llSswzJia4ps1)%eNdA7op+-n71?M52V zd28X;N)(d=$tJjTv_51-QuM_`h>uw-<*+ z!w^Ua&xB@ay-M}|_{`0Hz|Y37=!|-MgO{9z!=Rrk707i^nIFM)m-!a@@n!8MBFN=6 z;CwyYLW`h(+!N%A576+JgAIYiBpTSu>3*ZBGFx7`n6quvyA)1)7%cb5`Ban(nyWzs zDoU{#d)qUrY6_%E*xR>{{-s>Wnyzg8pJd$2-Gi0H4E4dS)tF^HCX*Hi!G9#<9Xu$- zlOU0x_HajO_QTYd?GccWIdxB=a>TXr}rk*+gxlI0P+H+=Dwo zibH?`L5mk!+>1+b_u}pniWW+7ic{PnNO51&eEIpV(2yTD<>DOJ)37Da3Qxl!uZHtnZJ&bBwnlZ7fG)g4n+Kesm{lZQf$PgF?V z_9>8f;m~>Aj-OvD1mnux=y9WyEOboWYsaythoj~Qp2{i+z_Ui|CeJGS1vGtmLAZ-I zo?5sUe7uLETdm`#@>f&M!DM*vJuKrK3GXZz!c4*_>V(8kRKj%fHa0xc_YdE#be}t5 zKakTf8^faVu>;`NGz~YS(-!%H*!LB^UqItly~xTZ8T`8ahDY)zeS=t@#xVz#V8daY zGx*w}h#1%ua$Q-Auy15_hlqD8i~XSPMk(-_vRg&&wGxpm1ow@1l*orragj|6XKWFL z-Wna9p{~Bly`j}l7o)T#Um8aro?h_fC?(=z`8y6FsxXDAz`vLb%x+?*QSL_YJe<{! z8m6zoj>d>li}lIVFsqe>vwKI}6g^ELCjn9}H~(s%@g-uqaai_YGs3&>6c~Frxa!(N zu8s|4(od-g&qSICnZ1*TsDJm0*3nFW?PoB6tfx_U4^Q!H!#lU-Oz5@iKs{XwZT>}K_l8>076 zWjJ-XS-$477Ww4jB6vSQO8n@$sE{;i)l5d@|2RP&(*$6E`>_zbhj%oOW(+M5IHYs;cU)S`Ss@llu zm;vMkUWE+c2;h!71a|d4B@4v>QHomxjq_Y-N^UZUKx6>{l4DSu+fB8Y+$tcQ?MGpBzyJ^g+Hni$#_tjb@M8FY41N5daTmB7wJ4;p>5xq4 zrX`g6*hYhTg1&v36(OUD3li)u(G$ z#7h}-UN~C8-XQ4?q;=Vh-Qz2Faueu=1n-Io1X1|_{)h=xKsU** zN^6Z4;8{q_Z@ons;ZE1~f4uupPPUX@$uu3(tHn_8z%PKIlN?z3SxuwhZ0YZE%9q2o zS~$u~Uj4Xflc@bS18EIg?m2}HS8VvLL=n}IJ2CDCwn5VCxL?Qe&0GERvO`tLQo#5P zifK%&iY1ibTSqNzrWe{x;$E@z63@O+nSIGtlSXcLUyYzKOozK`{|%20`ulGkdTmJH zgvcJbDXOljs#nkWc|};c>*?+uBbWkUPtFTI^}+m?fby(Kvpk{TPnU+f1ou)OYZ2T* zlSh4c(CiC1;J$DI90N{w4+n6!iY#Ru8EctHhM&jXCj0h|0Ezvh7=6|-Jti2%>sT<= zy)LqSo8_Z$ss*#ri=Cclo6v4`J?VjdNk>a5KB|0uF-Z}Rz#2bF9e3HM?%-%7?6q>4 z>$EuJnj!aOBm?tWQ6B4g91NjzrG(|i$YgLUtAzjkv?_fZnjYMBOQ^DR(?%b~Dj^OK zX(DtFI%j>7`FQGTEVWr?3TUs=8J7)l6(R{z6n1hEHh27U} zO^dccA=4UMWAEsH?3x>Zeb;mAKRm&D1K+YR?M0RfT_&I90G!m^KgOEhpRcbFOI^c$ zn`kKH2*XVlL?OahxtW+)SxSRb&w#X(w&tYmSn5vdbQGK|xvR`-jJydd>O7QO;n92p zEW_cq_R!F@e`3}P8#L#eZge8JSXd3D=smsAVgqV^=K{!={5UC>u^iE6Zn$-G0t3;< zIX+V%+{|MEe$_`u3;5dYsw<&3{RR#`V6gsD%Xsz#KDJ2M4D9>4Fj3RNtYXUc74kQ| z-A0XlNQ{~AD}sr+HY1&K<}aXIM}P0MTwps*v}k^lNpT|-gHT<3wC9@Q{IM;;9l&han`85`y(TgS?Naup7a;j~p-ppSLN~ia1)imq zE7U-5&D7A83f;~QBxF_L$8Nl(9VQ4hwMkgfipjo*+fv4V$zo`zU zoW6+XJ!_7P0Qa;?e%?-Yfu}+UpjFRy_iD>fh*GLunGAsPWTOuP@p#Q)VzTU@dHq!?mm;_uY5Fa9GqJD8x^uYrV9Rr z`a!YC>O*%8?t!_HJvHEa6I;4bpX;?SOLKa{`l9(al=^D!yY3v6-DF34^i=Yt`^|XD zp95+aEG}m^#A41D_?`GC@o=$A?J^iZNzdRW$KnY6t;q`iNCA zZSe6}JG--WgxQ#LJAWS~u=a_r^W>Yi@q!II^zi{7)^d-eQs>N9sdR9Dhxg9xT9F;n z8AGnQzeeVKatB8$8X&|I_`pDW zrri8y-xjog$7iPj9Xfv=5{(EVJD)3r=O$Z-Wju=Cgv@BGEDxd^%x;k^%VxA=2q8*v&CM7xBZwz}2MrV$z(U@P= zMg%y}ddfhd4cW__L}>pzV`oo>Bu8Hf(T%_CL(b(_2k%rnbwgg>#5tYhwQx{yq`6l}8nY&&u^(nHXoG)F8t0qd`dORZOCbCE73+LtqDnb^`pUnQ3}vS| zk!n9mRU0eEwqCfEWf~gGGmzYSPkI#*n7VEFnFP+}>`icW0f(!dYF+52*y;aHf>m<> z9=#p5*Ag9?&TGO7o$DR7v3IPuExcE+~%VKXlV`5LSrbn3?MG-uXrY3 zy%T2Lw(%DlAm4$XT7q22!#BnB-H@m}AfK)c659u)?*=GxeI9BYWZ%Mn$QHCVf6c@H z_dZ@pgLl8L8ycbzK@oyBc=LfYhbkShz-z`E9*M}6?JelUPr-Ng9BpIiPqPS;RQ zLPZV*@hR2u3He?B0R7)(2t)Cd!d6R-7Wci_Nd{WhQxl6f^6q!?=YNqD3aZzw?@#{f zg8Jn_=r$8H=y3!5`M;%w<)Cn)l>)q~mc1&J3K|nCAut?jieTXx2qpP@e%LcjAGN)> z;I+xl+PwB-LYzcTACj2MG0)GWg=Q=?^DEMlEn}`B3SSlFMTFCbl_+qJMf}^4-Rgms z5oETu$+XC=w_)f79=j1{K0E*s>m)CEKQThLm?x?fIDuL=G^T%z7tNm{6?a)~O2N2RG$e!$8C;dh z!8f8o;KGetcf2z<-M3wyB%j^mu&L=5K-|YPdGT+w*q)+f70(j{UcFUySh1h`s91l% zctvo_&=+{{vXI>GX8EW>UfjcI;MTjdZ|klQJ?=9KJf-VFbeK>zSRxXzSiQN7i|Dhr z!THXdYc+1-Bk%pWfM|T2+4MOSLVcwt0AQS-%OtHoL$8pj_)WPG<}?J>9w%tP(ELq@ zqj^_HD_5aWV+V;=nika1TZ`8;J{u!lav-;cygY90?(Iyx8VrOhQ)TlQ@YOzze7(DJ z+JQ2Mres_E&-mF|%FC-{suX zT@C>kY#}5sz(u`fnaSMw{D1KWubL;yMn84TmpGRa1@6hg@9+M=2lOus$%E2Wa zKKN#o4o&h&4sU3-RM@iTBTcU zF)Dd-+~V_8j{3{ZKL?&9ZbA{hpQ=)(0t`wFemI%H2r?rZNw3~h)p5yE{uD)E3=thH z%QlETYcUA5owuEjW7s#6Ih>fjy3BxT7h}MqV%uSWz8(&{XqMWK-C>fMx3gIT#Wdf4 zaRMf#IXzRo`wyeRd%r7tq0>GK5VYrZR)9;=u;~YC%o#Y4>$JE`Q*R9`!%A#V$UfHPS@R@ZUReMQ<8^= zJ$}*bU?bm0^!8lpAtA$$QPG#|+|<4h7`+WU%W5yiT=>f`srf!Bw=udQl^|Ni5<#2@ z#v-M6g_A5{r;PIUU3|*Bgi5jJAuH)QSgzMc()p*(dn$aI>BO;0lGRT?tdp+|YT?|a zaAA=MJQ^<^WbC{V9{l(2gGB$vUYCvHaQ@P-jxJ9*NvJSJ8P;{tAWjW3O!`@x7L3a zd_jP205Ms;*@;V}P_3>=C;3Ji!#-##?N8`J;L)eo-sv*4oRyO&H}zA6q*ha=nayi+%|6TBjaR@mRka zcja6Wf%X$>7Sqmo_?+=QldMjYpd%;bR}9uJY`hYZ$l!Jn5F7i05gtludTSy`r{e3o zvxWO3?qlV`M~FbNBU}AZ(Ux^E_;*Gn(u$WkER%@Sf4v43tzAOb^U@on(Cds95&cf0 zs%KQbcd~$d1NF<3$`YM2tTs&n?~MJMslsRW{kzs7n?^{y^I$ZS6VK_hd|X@4N9Q3q z*{XR#Jqxi(QC@2XzJxQ_8=B4tf&-awdbBb6&8BH|B?5k5@{^oK zoShgaoOkBImdVFqHBmIqg$eM3XW2)|`G+NXLjm-{fMOO96g z7rAo*AN!$%&f2UrfV(P305?-g5MTbyh|Gm5L2KFs%5leExqmNu=%f^^LBRLNICe3) zAI~MK(*s+54+9*$?v;)VGatfpaivbZZ)mU=7oNay-0USZ0$YR=+kx~uV}Aa7!RJNw zMJ?dfwx*I)0MF|DWrsLGU(wVqMOUAJnN%25iwqrnhq~3$soF<7BPUyZ8`E+0V-|*r zM`V>%++$LJ&J0h1y~T+otp`eqTzPN@s9VwF#_Q_}NF$wLmYQ9&wqV$4d;C%`4|Y(G z;z>iH3Me(ykNR-$g|0~Duqc*UQ(&!!B2~2u=U+I%0{A{o)b5>o!B9#0390r&z^;)( z*yUoflq0IC*@|f55SYpdq8*d9756HG^>YIp3Ha#v&rv&X01tRQQXS1tda0TD3i~Tu zru|K`w5i`ou~C%19azczp_7lt5>LJWhYMy&nQY)%+BL@UysTB|~!vJ+_D^ zV=VSVd}kQ#@H(p3n-~TZnUmXt0VePW2=V##GJL;hL;|v8wnc*F43Wh?OQUC~c1n42 zJ}p$xB)8_}nveLFUR1?NkUeLCezQmZ6Gc-r(*KwHJ%1D!SjxRGC0D!~P@|yN`K)Oh zV&xHK20LjE9Vw4)P&0ArXd2ByQQ45!2vO66C*M=!X}z80Gbm7kqKP)zmJv+(DK+EY z%}U>yW>9Z86=V1?fi+7%*G;D(!7~W0lgryl-TXh%@RihK&&(X=k|?zbu;W1}AG>LyS{B3EVbV47H*@lo?`9OU1{`C|u?Y)gxj)$f) zZG&hSW?u83;mUWyxcT9SvSKi?F1x|Ndk8FvVl|-o&~jz3Yv4S4oVB@qY1@L5s^s|n zD!(p})hh0$-!cIImnmmI@>XQmyzg4yp5Y4lPaOOaqShwTSvubd=f;^kQ#kiZI$DMC zSK3Xf3ptsB#Ood}E;hX9FpLY&-sOy>GOR{vc{{%Eyu4jv8)n=xy~JW{fv5Ll@!Un9 zDNO zxbDnOMeLIO@%XptKzGwnLNfG}pZQ$K)tZ0%h5DR;JT@+#{jkqLL?yw+CR2rtp?kSB zy^5F&Sc_EPskBVb`~$P`M{zSv|H)5Me(e25>t(HP;58BENU%{^A)#|wf0;E35I@2u zd^1p}8!JS5^4Ax`Yj&J+v`-s5pl>%*r)l-E)FM!nHdSFGM48w>CQ9(0$x0jMZG2Jlv}r|`#t<>@y7e=(ZDBcC!BAh5NRVL3)EYAff; zbo8}4(J5<%!Er_(ac>PPbD&Ws!_b~DU3ePjp{9A~f2q!Sv$u@%@efYAQE1$I7@Ji^@K&OBL!%n#;n^Q!?nnCF3HPJq#c_)1k|cmfN{Z>JNVI39 zL8SxzU9WyNX4PtoUWY#_`W%mLlWqQv%*gu?TS^Na-mYTE%MBp1wY~l6KyEAo+0W%;&i_hW*9- z4g-1P;90ja^&Rt#1j*M?Cg(WhI0y%&KY8prO_iQd=-i}5!r5&@?64z6jSopbn?k30 zE;}*TT+1|4qkE*H4+YgW4e{JycAT%yz8&_%t>9X7o-I9bF%F>;ZW5ejEPT6CF2mg4 zLgP!Juhmw9OgpXk32_b4M&m$!_k81Lzgr~8rX};=4}Mat-OmVaw^^Zn7f?Lm$#(J( zcSfu|#N~&n=@tSi6~Sn9lpm& zNl|6Zx6-s@|Z3G}QPN<8x+lzi^q z#Dymt;iHSm=-|Hjg-?cE$^Z@_2E<|AFo8w=kgB*h;$0*3i*V{rIYTZMnMT+NWep~g^&Jc-qX<0k^B%`R5*6(t^H7k~{m1!s0UzL8oc&j8{6VJ$?VZT-D^yKSr z+j?&F2}91l$gMUz9IV7i<_5O-K1bR6{#cEXfFo{wAtL-pG597^RxQ|lUaJR1C7bks zjIo}}oC@@((m>6{`I0rec~G?Z=6J^>E$Mn%(d!nE5d3nN z`|%q;om8iV1_7F6<-Wj&TiQy^<|1{>#vF<>#Op~OgIDK@{c^ZeSBMe97Ss!HHiL_`PDQKen+q>vQio=@N%=v?8Bx*4+CX7r_eFN&Z~ z+IOpnH^=zYSoI*Wn@O=kru)WNX?I?B4Z#rMpIc&6TD6 zQl|$9Vde!h0|(pRjCyisE8)NV75s7X*^wCcbsYI(m~mEMrLTLEm$G`6mkf5#oDGjx za-sr8$QAvKl6nka*fzBfe2joa6}>I9U_nD#ol6FL8*>IQdqC0$T6~)-Zp}Kz(Z`kR zRYpC(p~b8|jzyj{Kf<1f@?xXF_T6s|@=P*)WC#}G7L+X?%$Q{Gqz$D{d1N~O2(kwu zxAAERetNiQyC~R~#cm5kgrc}|55`s}XF$#T71=b23o0XD%exJG_y=MY@i*thhwboQ zsiZs&pQ;c=Qs@~ZqAXJA`8$#${h1RRGpSLfs(!mV`yT5@jk=Y(Di)aSJXL!;3v^3% z>&Fmbd@~cKPk-GU>oQEbGPqB2Stq#Mqm|@;ydom<%nMt@wz#OK;oPsF+3HrzPHbX! zqs=X2QLt{_B@gL{K-tLrY$?zkt_=H93KX+f{rE=y7(i^87%9E;RkWZp+0k4`g3mDZa| z%0yX#np=bA_|*TB%%~G2|K!8Bz@=!qt7>@#enZor>TlS{)9#ZJ|NIx5JHE#o5Eqpf z*(c-`=cFapbO}wIph$GCxdBZ*(zyyq!zjIj&_K!1Ik+u>pSR{i0rN0|mVT8iA)?bE z7mcOYPh#o3B)F*@3D`4O6R4c8m+l;j_bnfEdakx+i1oh`)n=+lpE8d+qJ62rm4hS6=>Ut=_FNI4MW_8l zL*|x-To)>m7^>_nqcx)UO*mbicda*v0#{$Z6>5<>F`yX~7i8e+wg^K0ve-=4@c|b7 z#vBhabsY;In82sckip%z30Qtg_R0c3kY|^Ve)WIo_^sUiE&Lc~H>flIjaY4kKGwQ? zV)U2X)Tf@;l)BcJIZN{MF?A1l?e57Id$2SC8Wnt}vSRHPxPzk|cGg&P5O`CfG*@Gz zS{9YHUWZYn@TrKAYz4Zl@ouEb9UTGON_OmV@LNKNq6RVj(w<~}J2m0dgtqDSxc@v_ zNcIBDtM=gW({8AY$)#78gfA8T1CuC%RLeb>fgt%xTTNLYts6(?0*xpp`tx4;q_qNP zRSWm%Y6iRC;EG-zPoz9RgKJD!*rXM!yo3SqviLqERFPQ@Wj2@t=d~*;iuW z^iXgsj_esTs1D#|@KqsL^?`tfm)^$vkGxAn%?*rq^46#KJH5h0ZeMp0hh!GSQ`Kz4 znvo87pRB3Kbfd0cQPrYf}kBqOcTP-;}wv9$AF|<>rIJNbVsz0oY z(O)=HlirjIuC5eZMN_MABSYibv_GuEexmrG-GTARoxNyHJH2TS>U?bgdxT~TbaHgr z0`p{`U9`+OW)2({vn^cF+2GVcDxlTCNO*N@NijF~ZFI6MG4B2H4P%w@*XUobciy#5 z_1}X^-qI}x%8ul>zY|Ht`eYJU$;=2=@_#UgBiSG|byNAr$xun5GA@9KV+?GK8pyhuL5Rcj=5 zPFht$M}|l3emYXf&ob}4xAY#u-mjWhRQCPF7-5RbFX9+_@FQ{Dtoj>@6M`cBYvT(O zFNaxp(U*3Gp0CVHjUjQx7<^<8j9(4oyAkqJd{>UCTju(MzEeOrl?3K>64gy9KR57v z5ykjeX)5tv@?ezD{Vkjul$Z|CHQpC@r^XwOGvQ|aJv!wkzS{M!G z_gP>~i`J)L@j1k4j%e70!6?7{+c-aa z#&$-a8c0T|T9i3Ah=}7XtLAIGj|`U$IiPM*p2*vLgGPnWz)D)ryrOfww9H^_Aj~EU`@23iiE%oD`occm+ha|E)o(-#(&pq_A@r+x?N3r$nxJK ztDMG<_dT_F&`gYv}A;|A-pUg`D4-JFSFRr9o?y*3}!aOe?98_ zI}^(CL#<_O64bu3{c2UC{fkJQ6UM}QQ(W#ZdA8URY29yc|4>W_kj2@pvB$Oey^H_e zGB?$pe@BfeK^#jJF+rL~g8&s_gQ}z<=Y0M8?=ryOFFZUY)883lt#q0Zw9hp$N7C65spY9p7Aj;+f;tq`eIQG<`6hj8H{39QhN1i}Vf!Suhs1A4G{cX#{&ko#>*G$c&so-jQOsGfR+@$+h4f?9jJGSdMt^IZD#6ZJ!D-n3jx?!~{6$lUq4 zAoLp~Z9IleCxd=Su={5xEdsY|5jhe8e;2eA2ipC;mR>HHw>qVt+5sPS+p2+N-?R8Z z26&q+!Oo{>mO^9jC2=`D{sic_{Y@FBMU49?zvk~oi`2u<koHvQw^g3jtXr!xV& z99u8r`Hmnb;LrnNe_h;;1j2g~)sq2Ba6=(|H zF1vhr-OCk3CK`6VwW;FV{vY&i++xm)maqn0lrqZsWO&REQ!wY1Xr^vbV0+#YbUc|VTA)79I?z^+zZ|KT6k)kvz~tl(cH3WC=^rg0!((Co6fa=PW{P-@Nw$mAPRl;+BNpCQF)P$RdmQ zMF%=uhFVUB^U3%|ufgnW=S4&%TSd}HuA2HHAKN-Pf29+#A+wS}i^id6)+M4+wnLf1TvVyjEUWJz>{B-=VwkMB;;>V$VPJpIbu z)$2yNB9$hKgz1QVhmu<%&SpyVpT%J$!~Lns?ygo&Vhw|Y%wLTfqP1^|k`3j@gE=E#CxB$!KJe?;Esw(zsaR1g5V&&tcv(wfqI6^bf zlDMyqKdK_+y`dnz@Lvkh<E zzUNW|RoWN?Hboy8N+k}r1~+h<<>Ol7!$K@8`HeDbYrdvSvjXa3E_ZQtk9~tN*xv62}O_cZM$go|65^eOmuvAL$B5HZ{@O&b{%( zL)~dq-S>5)0i6*%z_70@uNdskMc*b0c%b(5c-7D3>g1c&Q>^&rGGkRM_Q(a(MIusk z{YPW#F6>p`tt;jqBlaRoZWp{4PsyyTlKzVBIK&%_h{On!AbLZYM-K$SZhNaDk69udq1MY8&YLF)2j2Sx(f?7+;*av?me05p1tko_a=>YQOginyemlng%Xp&Tzx&$ z*TNiA?8pkmycttEJLZSG&vO=xx~5h9uKTWihr=1GaXKzi%s)_rnH=t zClp9gc>xbL9F#{y5?UHE4AbalRMESI){cMD#HEX6zEFPJK(xb21tu&eJ0?m{td1ax z|HY`wRwKAt9PD;Bd~Uo&La}(7WVU#Q_dAJ$>bt{2?6TKQ!WPHT;k$Y*fr~igxo?(R zeU}}Q0CM!v&3=v0G8eSN_U;}>au}}gR{Z#o>vR(70yRc@qBYb;@3<^)bJKipIbIdF zQl{x3ZyGhwf2u&YpHozha{^;oXR?R=y(b11`n9((lZN-N+s97H8Pq9mBJar$O5C5~ z*LyOTS04rrIU8|9U$!BVzB5AO`@Y!T%-r^S!GRf!S{AtDc@fB;v8zC09`{Y*AvYCd z=;PyDuH+VQ#d(Y2ydV9-b&CB{I%IkX(fz#|LP%Ohvk#2Z#E_LtHMuOveLdrR(e&S& zSqH6wnq(U9^bFwIyyR5hYeuB!U2u0@c-&KvLGs3Tn7}-LBGUtwX3`OavJ>MusxtXv z&`08CY+xx> z)#}Su!p=|LwjIjJ!ac(Yi0Bo!1isZU)&$F@92-g#PXZ~26PDD{+l1q z-J-A*I}3>OJ>cE-51G5Wi1GnMn5((s*|1PUod+CVq@*!7HMNHRwkVnEU#3w2?O&Xd zn4|srQ_cw%s(@q9Pl-3gaWOGDUP!V^$vlKrhc%~jYw&nH#abquQb+ZD?gxq^W*4M4 z;h9(3QLT|I1T(+^pLuZ)GB)xegmrA)SqL}60|b(eS0Oie`WpnuiVew0L3wV}=9E7H zkSx=XP&Q3{4Vr1bQz0#|do~;M4F6u-WIvU`lg6HQJi6C~J7!#Bu-TIo zLZzj=x7zZ_94F{J=bejLJ2;U_vzmFJ-S4Ebt@g0_ZCs4lHD#FdNbkZbwR4kCiT{dH z8un^E-n#GzS?S%=(R+r0M|6t%24rZyn>69-hn-aFbWIV(GAs|`_|ln0`q*|CuGZF^ z(@;W38u_)0?NNN3H)7+InbqRw=IK`3boIZxFE~Y17#k~CfS<$Fg@FxZUdYo@XDm@c zMGr1z`d9+Ob(|gkcUz#8aRK+(oW$c*Z^GF_;YLjK$(*6UJi?jL-9cI9#p{cXKHB5m z-+<`EQTl8@|L>;e=0(Npe>!0Eo7fL4?q501ms$D_)7Tm_M1NeIM97NqG`9BfdB<-q z^TN3-zMK7n&p6QZmvmP#qC{FNHdBpIYr=d^M+n9(60pC23? zq!f50@1)}PablIm!;&xkhW=O@!MSyON+*FfF~{z_@U(sG;+YngjjBu}kWjGhc^Kr6 zJ51=E?WTB}kfNtHv7}|G(O)?0-s>Xan()^EPcx;#6GYB!6kAnxCbbR6^Sya|CDMdwN(5M)j~ zw|p^+@A+A!US6f9iwO`A)23MQ!rf#+k7eup7l?RBC1EyB700v z^-6}x{ACuaE=M0ZGO_og&d7-4^m2jmm~(&~TeUY&A! z(O<~ly|?xo`o4Etzwi@$J9g7zk@@2w67R`T&@c|7{2 z9L>Cc=9+CGZdCmCt-PRSdWfta5A=s;7cqb(#qzuZ*=v_*YHc_sFl6pu>T>FccI9|x zf8DGy$?__e^_dMa#qeP_X1}Ot}<~1K3WH^nWR;u4z4>=I~_a-cCEb zyx(dlx7_mTn?|)Q2@l>HOx|nOD!PDmtP*(f2{^_kn=ZeIY)88UgQls+G4 z`aS?Zgd~0&Y8mVj)j8^MG7|G^v2yk6;#eOQraZ`}G0Ybsi}20DJC1&vQ0NOEy% z8Nz(n4dWK<KhyGa3fcd2RyF_Lp8Jk0j+PAfVxL`op;l6kLr&64qy;Qx zHO3N1eJSzVZnX(~JCWOn2$gS)f^k#Emwe{n8~}Pq4k}V?xVI!5v`=VI3bPr@%fXAP z@JwMmE1c)spD(I#(@IBA;doU35R#%>B|fTpL3w~HH34=rH#fh@Cye0O${%R9I2i;2 zfsSdyJB>Ghe{g)4*xd+-9FY!Nf(Li~1oQzS3GH}~GzY+7v# zgAlF;6&e&SuD3>USCa`JlXUVz8xQs9fI!zcvi}NXo+WVsi`)l*!)#`L7z2&vH9qX^ z{W3A{v-ufbmrKkbsbCMKmwL?5YDUT}N1)!)e_d32h8uC+hpd15Eyd$PU^1wG^dF^H!61cCdS+<3I>VIt$j=6N4Iyf&KxS2T zOSSy4XKQ5V7bn;#n;5;|?u*ccCw%TFMnsP$tR3VFSI4wTL|Ng(E02k3`v9vV@t*vF zST3ik_aOs;nvCqe>VNbAs-3Ov`3j07|6g&Cw5wkml5ID#gd!fm`Q^ zi46bK^-vDbY+Q_6Y!Be>|30RPLi1uc-CI9;r(f`T~E;^uqgLXv@O}bb`_M*@owvg_xat^;1n)2AKjuYJk=@5*Blw+Nj*BJ2 zANqgGlRVl18ChlnTsBi0Xn}C)lIhtl7#$c>3V=Xe691#*3-839>v-jL`2V*5YZe~K z|EQ@eR?d*7kF+Xw^oPqbNG6-rGher;D0TZY2Vr=fp=z~Gc^15BVh~*Tm~c<)CFQ&O z1MlmR*o^vUiO7F1z91!Y`eGjZuXkfm$o2b`vTn@Yh&c%Q-x6|x>UiY$Ve)@OD7+gR zGfJMl5kFcVA2a%e@_)x+#k$`O-j}w18@QDIE33#igQHLX?T_g4FKO^)%2H**lCOu- z249I*d==QE(DwCue3<6Hu_FB5Jm&X7vPbLFs(z1r+x_&K@gZ1WYvG}l*CKOK&bmDPZu92vw)ALv8uJ&PGH!cYd0zMoGXaAj&zsCT_%stviH(-tlCC>Uw#4ErMe&eaN5w+v zn}sSPj_0P-+4Y17dWrE%!*>K<5eG6|1~OjPhutuSxd4*BYxiG-2md71Tcv-FCGS;n z5gLhbV*N1GpcmiubN5&ig5)Td*KTVbM#7Dm9HS1kzHLn$Fo*tMbz8k*V=Df?&GJMNXj}4SJrXDleBu zw{9S)cjLAC#{pT{z&HY8-#ml=xK*J$IjFp%kZty@&8`hE+ty}NgEgOs*W(JaV{$_` zk5^8PIo?G(%PRvOuAOOf98c v`5RZ|S;FIbf+F%jY(MZ?&?X?Pj^-z7w$U;P6? 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

F^N4bAHlJLA;zo{R9Y!xEJ+HLCN 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 M07*qoM6N<$g4b5s3jhEB literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/busy.gif b/script.plexmod/resources/skins/Main/media/script.plex/home/busy.gif new file mode 100644 index 0000000000000000000000000000000000000000..0c0828a6c1c0d7641cd0dba7d76063b11fe676bc GIT binary patch literal 58766 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

-RGQdba$zd_alDAg_ndJIU2vnkH7LRU$@Eey9> z_n1m$eb6RB2&>k#E2_-JvRv`JZ1a^F6)^jbo8-sAM=6u*ZXNO{gut@f)DPD9LyuD< z0r(jGi!KG~vc3L`qw-H4T9fu{gYDifgfrxOi1SWV91S`w$cC*$iNkJI+O|mGd!)v)m93C3xt%Unc8DKLn2R; zlz5>MP-gQ%E`Qu zg$Fwu3r@EeK%h~ZB3>6gyF^is66;=of?~?(=xuBFb*mGj>D6ydUR%2mK zBRpj!c^|F#4!3Z$swkHV>>(W@NQ%F(ORiQG5=EhP4Y?y@#VgeOL2Bl9R>4hF@f2C~ zj9Bd72!9!HI94QjOB4l(;9Hrib)XXL!NSlvLnIkf&MvuwfxliXP_m03tQ1d=G_mb2`2FUrrW{J%SL1FSw$$;cyQ&mMN1OI$#RjuBY~rHc4J z*E!X(_FFyFLev5RPVR|2C3f-e_V$nPj_}t}a!$Ma;NeBpYuDADwT5(@47ge2BI)TH zh=^DP@jYb1qYoc*?2LDL=y?24dpg?D`SO+vyW79_&MoC7I_G|+(e`|fwEI%+1ssam z^=)qVss6nqb7vmkx%kEn8aN^vzxv-DLiwf&^08q_?R`&A>=Ef)P8Ry0YD3_S%6Lt3 zi8oF4_m=wTdzL1(-t;r#eZYjnO^M*x~DM*B6F-**|}GbBI^MyL-nN9Y^k#nftzu+UOXp4JvNE zcjOp7`EuY1#{(m$Rf(D#m~lO3vs;Efm6Un;#__HSHjbM!FVSv&KfCL{U;>FXzWA!v-@bbAm@jz9eZG1`DNeRLmOkA zcZ3|Gl|HW&2ku>$8aHS|(Oa!7&$GI@A}>m}GP&BZ`p^mOR29E(cN;cYdOTwknYbJ6 zeijvb{l8un9}zh#4nd$Jl$1z=7|>Y^^(fozr63bh6Gn7=#d!lD)_9IZhhHE)fsBr| z*N&|ukL{}5p4W-=65|+)z-s+IT3T0HHQ3I|nxQwIK3sd0!UH{>`#jWL2B!^Ejl-?Q z3Je@ZfT#W8NGk*(A_)Sz=Veeu^`!QOA3nMz%j^?*#xtelDD`cs>BvD7#f`WSpoUKt zt-cyzHdE+8XgF4Eq%4`)isCjSs$a>>>^K^XEfwT%1h$}Rlp(B{SZR=IP}Tb%HA^P6 zI7Waf*^y9Jo%GVwgK*6M1VYV2c}Wu~llH;9nT)v4I@hNz`c#od*>tX&F_B<`fByO& zQjNj1KBa+78voo@XG85jh@|w+lH|C+{u{wjdt=Z3fLX`49+=!N>0AD8Zn2VuAGDs+ z+e_YJqL@0ciP8JRc+y>ixsmeip2~I$1BI7y`vws~uM^C#S3TK&Ro2Qdp?i~RlSRv| z*Ev`^%wVufsNrUqcI{zU*hd)N`G8aupmc(ibjxxx$$iM%pp32|8?i3&ne&NHJzZ}v zmeb|zo0@(O|27r_W05BOo}*j7PS`&Bq2Hao^}`&CFJnLCVmEqzT5h8p>GwqkH5TRz zO!++wo%%L6-ZJTUu}4o9KK;>&l>d$x@C2FT~xqDes^NHab2Eedj!|DY{5o?WCGz8OpCI;Owwu-I- z8O5ekGJ%b*DmnNpWhfFSH%M0;dzjP2^jI#I!c;OKK2_3<&Yu(F8uf%BT6KSZ2^hgg zq?u;*;mW~{?uyhNSV&hCe&-+@+jY4>L;~d9#J9*nU*S6^+zl{dz+yR}NJE*ZwWB*r z`>i-Pg#nYl$^txxX`m?JovvxKgx=aCw}sK8IM9CAA{tyl`-dPvL*TBzH=!WD#n7-& z;<_%yMmDJhlyB!^3~2tadb=|k-x}`i4wH&D%tfo7ugq2<9>C;_JgiijhrG_~9le>x zfJ;b2${Gid4j5zN>nbqJ;YWoC7hxCi?Y?jL)9L|1_u0L(zVQ`Tj|^*>{BdRZtW|wl z)f@(@DA3`ugWWJyc8t|Q(?`L|V9BV~Svi(u*g#qY07YaP@=zatwY;(Tho(xr#|*J~ zf=?5#UY-B&NErG|ed8jqA(C|8qD6Yf(vSgXc>jNtz4u>I|NsAg4qF7p3C?iiO5B=O zxUDR4lr}6hOEW7nQ*s`Lie_eMY1zP$qg<7%9D&=i#IiJ>W|$32D=JHyetCWWg7@cg z;lgiR_yI2G+#a|4^?p51&U!C$O!gtwNt%6X9gEi{Uc2jI7(At1sM7v>lxdopa?Ac0^Be-PqmdIa{T;>cbd$d*2M=gwsMYDF z-t>KkTcaFD6?6%v-O|2~W+lAGa{-6CbkEj!D_e_Z>SIGkUQc9)a|% zcl7ByG?RqF6}En>5j*wGBs3EX(c7_(2-kkKYISiV&f$HeL95M90dtVsY0#efEV zyuTLQqwd>KF(Ze=+%B%GeOa9FTxkPCC|7?8u6uerJSvlir&8ZiZ#$z;@Z#MnySqw`PVr?8DID2-@bO71DCgbz zc1zGNxpRo)dKKjN*xZYVZHMh~!F7CX3kGP&{BmPMr~eKu_p!@e_VriA?*l$R8_!^H z8vm~B0>cX=ath?dvj-#}HoW}x+@CC}yOz7)u38FH#IzP%PKBWm4gbk@8{xWyx6Jhd z7*6~Hc9?vKOk{(Sw57W}od9(Y@dbwj!e!7_N|x3$LnqetR6H+nJtUD`{O`?PMnLjq zfFYBkGQF9Zu<4JC-@*vxB!Efu&e`%$%PQ*R;FIa$pwj=CEWuF|yY|_rk1ZGyfrH7H zAhoLQ440%LPHO3)w}jF#?!d9a^|V=~LFZd{q~C~9TKHNs!wTVb5&y{NjngTg;rZ_~p6;Ws4W3bMctgk7)>~FUl9QP)4?a;=>>VG8RVIFf8e+kXk_3Ik|Z>( zPM7dN9st&S{xh>DKT)|Dc#fBJg9^~E|K90-J@Ibs+XII>PYH5x)JEfqMh#A z0*74!{t{f%fhSq6%jkSwl2sc(g1Uf?m7nmjf6JHN!5Fi(z-o*H*-I3D+apN-@_Wxe zfdkBs3ZMn)h{5!>L|`E+2~JN2CZc8g9$RE}I0V2TpeKq=T28Ib0yc@G5kk-h0zfJN zqsrb>Op4Q&ir8odYb9YnG9S^L$T6kJQu+$}(z~=@S?snf;CO4KI<&!%1pLb4QmVP8 zq0sWc31W4+f;8FO8&r{?JoAz2(Yzfjz$luF^ko~j$w0?+AF{9bT$&T>Ac6$M4rapg zIn2R~xa#y>(Hu%Bo9L9%LF9cno^@zB3tG-PQk{{&;yRErmlNUoLrao))a}^ zZp0{jb0OuhT_`Ygn~s7TZn)@LL)G*+XgM#p^Vh>Ntz7$Z-+(g1jU@ZEZuf0xY~uJxc)&W_ji>T@ zWCM$-jZ>D!d~0U;y3@*?hd=7?{6rK!;zI}}`!R9Jk!hsk7$c~-48U7d$6-JVU*S2F zS)(;-uYalDc<|zA)T*?dwKsc}cd{Uj^mSjzFvvc3d?$!VTY4IzQjB2B#ayCfE1_sq zp4L$>;|pP4zDw}5^|{L)E5xuiJuoMOA1Ta1AqFoeO3rn|@oz7AK-zNE0O#1oMS5gd zlir;^C=f*PD5`^GSZGZzjVzUif8xO!$kk!~UKgwY=} z-cd!UXfNAOTh8H1H&n`olfHQm1?9;BpE8e6k2 z5URZ;D|0V{7M{s`L?}PHx`bYwbY1bqFQJ>iH$`lAXFwBLeWj}H1_trdGR8`EIpF~h z*Q+oF!Bh+68&~eYUYf!bKWf(UVf_8=eKldMk_Md3G9aQMH_&dv)Qd`LFJmV@SnFF< zGmZ=`C7ryb=#J5=DpK$G6E|FETr&PJk0wT5$0yHoaUp;uPcg)`1_#>tN^ZgS^tgVy z=}HpW8M>;5-x^wv{s>p{j2*SMu?UqMpYS;2g_nCXZEbLGuL-Z<9 z3vYWzd2TS#Ksk2i+n9TBn3EEX03I+mCFu>kN^m^fgb;68oekTBxN?W!iBmuj8hx0`cnd;1 zg0BZ(QHrRQ4K=(gtk&Wyit?~O>ih`pUulCt+TWRzBHruV$ozjRkISzh>f!gc@j!(k z`IpPx=vDO$1V|18327zKow~WcLqp!j*FLnDC(l9e{n074RL&=y8%OlfJ%aWc|*Qu%F z=C8~!jYw;rG*f?pro0Bo)U|WZ(eO1;OD*mWj#kn@2}?BwO}gK(XYzFDwDiFI{&m0d zb1cZOv<%o8Z=MF=cD3zY76LHu3dxz&#l4C@^F?kOIVdOG9(|D*w4G8~!R@Ea=;?0Q zxX$~m;_4Ss76Sbx9ijlty$IQ8Q2;$GDmyX&v&v@8P zYQdh>eBS{IiwJ zl9=zg&76oIB-dN4HQ%e1te_t~bF27atvV%HVO8k&>PuTQNp_ni#l~>ORhW6-L&8am z6k*fgGEIK}rvE0p)LUxFK-g^tys;iYQH$&L9Bs$Sjs0l5tp-0DqQ_B>F0B{VS*o0O z$u^CZ+@0vFS7#8AA2z}eTCCM!&G|3z9b@gM8Se7h!s#EGMfE{6E5ln7NZm6L{&C;u zz&8&t^7)SUzMncQA3yZcqmYbNzrPWOhu7yJ=Xf*yxed%Tz$N2Y&q4WEjKpY;>xdefRe0G@z#NPN@15=RzmkZSSKp%j>-_MVM zBm#H)`k7}q7UzaWaijKWpK6Y&p^ev?Ys%iPUAI7szv3D?i{C zy0fF)(6OJBBa1(b9lsOhTCN4@A@ zPi}7ciXniXD)+e&eIaOtD6{=UnYcYaw*}VqS@JGDkve~A9Yh?{`GTSTetP@Uu?xQe zX_N|zJ!;KX*p&(>(NbqDk1X|O(dJ#mrA7uaI8(L;EJ)|c-IbNJ3k=|%j}Qpd`Sd@aNesX2&w<4*3l$Woz^7HZ%he4jZw#QHudQ_9N7DAnmyP_J zya#~~pFrST4I~Fiuv&t(u(nkYQCqlDvy_}!mGn9bP;6vbkrDgLH!6$M6qcdr0bu3_ z&_e_;3^r*l-HHI{F@fK$>92~C^q8#pEY{}%)RZAgv5jL+`Co*#B5|n`sYDjw(3YNQ zvI6ylq?}&@900E=1lPieH<}1|k$}~d)IU}16~~m!q9kD!OP+T8(QD9?l`&exYktS^ z=5w`|(;Z1^@ap)MZ~p#JMs#ShEs3j1;_9-1nk=BZD2b7u_NW4Npe@4#!}V^<{2j&n zn+WJ&I5kB`qwoGY`B@%=86*E&qe=fYwP~e zH8PIAq&1fV;QjPH$3iC*c7q4XtG{$RaCcrv{pZReb>HOi_aZ!O?lXs=As%+T^H}Hu z_0>r#pSRYszLa>M@^G!Di>%p7XK3=*X4!I2hBC}Tyt&2lUeyPeS`N+sIQ3|Ao~zZa z2{|{0IN#JFxW;{~;yDke)x8(1;?_ncmLk-9k=xcgQhQZwhHs%fj|1 zvlo`fO-Jke4j=pZ^TAM%*K}uaBZDpd_W4G|{pxoymCHTRbvV-)z+kMwuG;ZvBP<&IW3+HT>Qy1y& zYb5L0eHk6_H}|>TQrHw&;x}=T>HlL_iPP~{ef6CC883q4(Xx>aiLl$iJCwHj1lE_{ z7ae(FKNP@k4&s7aLm8f^*V>N(JeDNf;OKbBu6N6c8p!KN2YyZ;v(_(P#O7DXOgq@s zEZy*o&BfZ8-cavG_*PXaH``=)>$#Qm_M-#+(1Ar@7O5-_<)5;Pyik6k?@Z)f=KzF5H)e-f=xgSYgvsiktJJ2BqD^uG z7YP}v#-SJ3N{N9NtMbC~yx>fcMgWAqP@^F!IN2}fu6o)G6tOiL8Hj5JQ!G<%-za%M z3sFq%y?ChWfZ6pxN-0k@Xv!=Qg}0NM)v{hyn-sM?&Q`$suX|oucyyzZmtr^ScLu6o z!4tSOv^qKJ_D(ZePwr#Q2oSwG;y-T7l){Z(Vn9lOJAHOPt^QWSm69sN<>q8xtX!^M zL;2+7$R7gIr+tJLi4{F!$2v*Hwr+=5Z0#!edOMKryE`)w{qssH&QthVd7vfm%+&(C4WjlAiwg}U~Se!=&wz7>JPlRgmBoC)uA~ZEOTn(D2M^W`M zeLCEg_A#?unEBc9fo#S6!5*`2J-H2JxcaqyfNqTRB!dT6OLy=#Pn}V)0ro0O=w8m< z4X5m00VG?JkMpB1@~nz8Fv;8iE-e7Jffi0?ck`V06LKT?hWhf2gVJhA{@K^1q%{K0 zMpV@bz_)vC>_WS*@JC#bZtbqTal=N>e!`jRML(5Ya#;blY&bU&SWM{ljh-B9@D2`( zPPxF_94A5!#=B{7yPpG*k#RG{a$eB{ESlIO1+a*E^{^;FIJ?Q0CP z^lxAGp~3tv(1Nx}$(6LtHL6K#%m)wdJ}Q1{AuO#w zwcL%J{sn5!**7>yj2XmHwxW>M5M&v<+rBZ>OG=a95h~iG=rUnI5!}jdqlH`FK$85_ z8q9_8Xq6e*aLhAQ#nbMcYVDKmW3=1mL!d?v|ih-4EC`QXnY_bgkU$=jf$I}vWRwU8~9sKrU6`h+jz&Lu+_K; z!ES&;lUJCaCBG;c$0LZSH|3u+IrGq;dSU0kwN&RCbJ(9Xz-{C+s};@>GUwMTJ@k$V z8oOC*=EuLSozITb6yn6w_=8UOI#pwNHDLv-M9Qo`Z!Tjt4P0E{v?JZlK$nGimv=?#YyIpCsjZW1%IB)Y z3WlBYZO$FPgn0d|S>!*+F7Qd=n9MuL`tI5zUX5%OC-S3x(?>72=YsctIe-TH0rMM+XjbO8VAhXj3L1pG@mk`4zk0BwZLS0zrQzClrnfJSqP7trFeI#y+VAK#ULu z!?_qxOJV+PP4%{&2TbeL z-Y)S52*DD>F@{j3xGp+qJviw<(Ou#73W(k7g6RLW18kC2-xfmoV@__J)`vb|89QEV z`vA40^AKxWH^FRJ5b;wd#58Z8wiX}1bb;VB5*scdDbke3G<6Lqr7#>zsIA@zB+vey zdAZsV-a`L!k42uYS@R)rLAz-zm*Fp4AIbN7?{>C#V?f zVu+j*!V>6g4A1qo(H^0k=599Ami)%=nhN^tmIRPYmb10XlIxQ4oaw1(c|PsYD(3OC z>%+l4=`4kAGfNDnWZ~xSUytGb3o8UN8*jkOfb|o2SefSN^l9kz%;E2s=l^_KH-2~I z5baxnMz{i$xCFq+vEhos1&k9+dxFX~YwFmtwOEK8Wb)1!0AFRQEVw)MJC?okNqh>99f%)ys9j~eL3C7Hxtg3y*PT()Y*3&>T-f@^l>*J($o%AkY@0*vb3Fe z;UqwBIo(Q}{`+0}0SYwT3P_eRM7E3^5%4({)ja<;xDo-T)rdl6 zZB)reL^z#%Jdg#G!tU@--VNoO3}&u&LNlqL^V|j%G72YTUvx^{Gm$$I>c{(&2)K|T zaPTC81e%cHwm{6X9n44q-ysD&d}Cjc_^+4KrxNp`+W@-+Fn%H!MMrJSM=ZW&DUoF? zN`#LXq*D>A0`}PbzckQz13Trds;;j3`t|~S)TOOhJ3QiluD`R0^Xk~G7fW1Gtycv0 z#>U7lq?{~$tEy|%4G!HvSlD4lMsBM%x1jE{cOW~3BEmEQ>1tQ=zkuCf5T~px9&Nhx zbo}{b*Nc|~6#|9eYVZ!&-WlWF!*NT%P7ZMf5px48|yj-^I9azS*zQEDmbWS*1!wLu{VIhc>KB=a0jmU__5LbePSDH>q$ zw)W8!nt{oqjd;z)MY&+gQ1p{mIvLC66M;v5?cTE8d~3{wR^*Ci=vp5#_eJemH)Y(K zrq>$|DsCRD9ynFDso4L&7?un75l+eUt+4^^XZ^DdvRBgPxmG)(O_^xuQ!aJaE=M>v2iFx`!UW zZ)P|fNE=T_)Ho+d_~A0IRvxyZT0frfwy*o7_9(r_@73thsTIDQf>I{d3|Gnl*R8%) zmi%MJWIG%s$e+Y%i`nFCBX?&{Z8KH+K7EDBYermC5*1#2LvPS6FVH=^5_{B8I(c!< z6eN?*rw{h3IvfXtiKN`ul1=fdOPY+uS#~ zdYYq&)+#$|X0B&2EQu_ zUv5&3O8JtZ{N6t74Ix0F)Hf2av(8g>53cn1Iptwjhvy-;4>cpAe)GGBww@0APL#p! zUK&TMoH(k7US3|(f=GkpWN}V+eZa9jFyxG6p zw>xXU^eJvnTt}2oEa*bcZR)LOe`q{PTQjq>x6AW=pm_CmwaOL2Z}s&Uf0V}GUsqH# zZx$W?^QHY;UCI`f+Appe?FAx)N~izn0>nUpUdjsbzauaE)Zes|*w?#=j^zA!vlpf+@mcriyCT_QV*1OV2^Zy%k3-}5s>Ko^3fn0E+9Lq* zpj7q)fLPU9$sdQ%Jey!KJ8?o+RpQkhX-Lih3)zJI6vX>xg2q-ssX`P5Zd@(N9Ezp^ zttK9t-XMR7@=D>rGTcyqR#sf?#+pwcOG1x3!ra3+s6yjOWH)W>;$047ng*YFcL(_Qmxz8}HRP(nsH5!^7I zfV(noyO)_m(=~lpMyAX8 zv*-2~vn|v>7;*V)kq(t>$R^wf({;z}BJ4L#|GBA6;|aln3bzf*A9la!h8uD9gylo% z&0C%zvxoQVy^;~B#VT^E#fG}FV0%=ZgPGg)*7@NOQvL32?EIxD$7|VJO7GYz_&B+* z38VTSwwdvN)xoubo6&8VY=JL{>w?yU>CDjth?&Q*w9#B89= z+4@L0iYYXKK{LgBRvG~CX0G`%-=oDEK{~AXG7Ddh0uzGAe-K_co*FFMmP9wQ@w+z$>*NOCP`+FZ#?rRl+<&gx*NLN$#LKmm zi7%fRKsaV2M@`$UHuls9G;T0Q&Pfjdo!nPk#UVP2YUp&edEfQ4kgcHrn*Y#3ZES#B zC8IXXNoI`oH91rq`St}J+P(whfL^ql{HnQw(fg7SHTCMst}Iwg;ym>JP$}L4VykZh zc9i{iimER3M4fH??=1=_Y0~20w}~^=CM3-_Kh7)t`7rE@6Ww|ABKDnfBS$^76@O@1 zcrg3-#Pb^WR*6>~P@CkSRM^@f^!gm%3~(nB*fn`nT1tueo!ego4UTPW{0=cpTTs;2 z;Kf-%?$G0cpId|;wnC-D5=hOkt;4c-b<)%M>20;b?wV^>eSQqC!m)`SM?w9GL(sG> z;G}Fp26K=E0Bkz8j}Yy_37eWx?`^|diaGdUC}bOr(dwFaggAK3QgKRvRA{p~^B@^c z63RR$PFd(zT5l+50dn&dHTgj%S3B}K=xzM9s38_^5AtyE)yDt@0xbDa4%&xF!|lk2 zE4T>o3gkGgCMI012(EbH&CxBh}71-pXNUk#|Yf`*IW6GRo@&vfU_pr~F z*tfa{=O5QsHUYkpD4K>4Y2xIjuug|-@eUYOfY>!h8hKhp+^4RY&9}l<%^A37~09U@vp$gdKpm(v_eP!T4x0?1Gv? zIpDek@AIgRkCW5BUqM2j_OJg9Ffq2Vk5OC|ssu6F-%_t5oF_$#9`es~+Tbu48=fL5 zTt~a>Kfhp5$o2);5P_5rKW_`YT0HO6cU8=xw>}5=e+$r1(2~{NJ71&xTL+(h~-Ku0+w zQ=;Hp4ai-gvrVW1m_p(&l`XW-F?)CZXT1!ZL-oN{hRsSOuK(`bRn&!n3(yFf*$rH2 zgc(CJo%Ng}peoz3y96p)vH-Zc4ET0sBTS<2J}A}Y@*i}3-|2ho9F2A$ia7PdFl0%L zX8ibH1AVsW&u0(XF9)Fzby#*ZxzBDjB;Lbu?-VaelDHKxm&%SJ@n}1krWm<~$#ZGr?#ASOHObSZ@YDowKM8m*+S^qY ztr;l!melX#+~k36HV{fv2-gY;x~=?whC5Co5O@u|x3_`%Wp(ANmkqp&3M#9rtIlZ@ z<1H) z&CAU#ZSA9v=TKOS$&VkW5ViPk_ix>v#kO?Z-TK&dPCo`?N1nOZ&h5+7yD_j3WEmx< zRCt((d0r~26M9pm?2?X6-_K_oBp$q4pN)b&la;~H0~jiod1(kUJrGjf?Hs@V>s9{) zu#k(a_cq{ZlwE=DSEmuRwq!%KV$TDDGOseZTgCzgy(aMVG{d^!8~v(twhA(bk-hcC zHu>Ev_sn`15An3OM3!Iis`>h1Q>z>qQ_r?r?NhSIIB?deD#&^F%H#Uj=j!g;L@LI# ze8w`hgB4b^pYf$;&s{-CmikjOlKWdZ3Xb>b(xD#}I0Mx`DmR~fj(JeGr<`wD@G2Aie4x=OuMrf=)FBF}yp7x>PO;O7;Jm)x}o80*K=shcH zuj?=od22L(ddnG5PFzJ&co_XWTaxJ;Ep0#RvU8VDk;6|0r2Wi9>#EW!Q@#DzT?uIaYhogmyorE`nGJNDZ`{9bBo#g z3fG97OCT#rU~;XXQqw!UOc%|rxtf+VM>yJhhIV6cAGN3ScG-@3LMSf4sJ>~t#I2#J z-}*q^Q9rkZqxuya=Wh*1u#vk)5*$2k4fV4#TA!8WABs|^@2qQn7N|GSmT4r6t(%Lm z?(cYYYkn(S$T|42V=sNCq3p+_U|PqY2sb1K)2_h`)WEqR?<-Yr4w4teaP^`x*IbyvX?EiSWfRkHZXOd0af-?-Df5po zM$os1>)RK=QOtJ9vBzY=sE2AGFl^_rcabbh)$uQyRZ+V>=AnX;b^1mEDFF==&q=gq zRi;mA@6@r7;RFZoip@(?Q4cJ=h7)~Y-BZkwu-=(0MXhD3_9eE{tK_WCWh#Mk6!mnY z=Zw=U5C1DU;2zh1ZL^P(uH+!RoYFEs9Bk_9*Q%_t;mkKZ$@5yMCJ>T7c%{tzCLXi^ zVV|mHIzm|pPDg#If~3E{-6M)ROvx7Ef4@&yS^qT*9sBh6$62~t|H|^~B7fBKnOvnm zUqn%-*BNf4>8<=(yt>k5;1zifp%FG{_4jY?AdPsDCWNUIup0rgL9TGUjYX+E+)g4@ zt;XmsOE{!OHx&Wk)*e7mLgw#T5r}!XUl4qi9}nfn65->RFjG&28pgL<`C>lW+O=0X zQs|-kI3HRk4OKu|!}L_e=(P*sL`^-mb*&`fi7gw)qj~A=DuqJw*{aF`aMKBftcsgO zwGdJIg92VqZ5d%pC`LCw90|jeYri4k-qy*I^I*BgsIOOs90z#}SE1b_bd{5R$h(lO zo88!NOxZ%vBSez9LRW=BNq*L@S=DcCD34g$%GqN$H=VscnTCe!9H!8a5Gmm*lk^n? zmkd-l55Ub}qQa^|H#0@kJMNJ6d2kT?^ooIYA)m#x4I8NvzJQF(o2W`#j^)V%=$)?~ zb2G${Eu4vXa!#b6GY1$H(1(MtdUBn12v|#vZHqmG(E&K5Zqv+Tflt!-gl-2HspqMW`&XK7H%u!7vZB($)q{S;YlHI+;2lS4q*@UWavH?o>00QTO*v$fz(VG`Lx zrxx>dNN@u`vQJ(@a2}jiI)M{|XYiLt-@ z?VR*M%X70J!wg8X`H0t9!MGDPZhWjz%&u@c6m76W8dSWx3Flb=kT^o*>gcBmn@&}e zc1gy3X!g08jh;cRMt7bb!0TYj}vF7+>NJX40~(7Q_m(i^=Zbd=JKPVp|Csvr86f) z`c~J9HhIBfOr}69pgI(C^sdcghm`RhCTE0|CjCXMfl$2R9x9P{JuV6adWNMMM0p$X{u+E_D5;BV1Wg zh249z<xEbDQ9`(SL#=`@CBUV<%7PMqcRl_+$ei32=v1{7ReMY=v#Kx3*7~ zd&bVyxSXXzU#^oL{IR^1kEUe~P7c6ro^_*d(cY>>x}nn&zMk58S4jusoIBI^RsQb6 ztVu0?ZS%0Z)?_}?a*jQc{0OG-DEGZ0UDRF!^u)FMMXoX+3*n6(=T532Eu%}34vg_4c>+O@0)_(N=tqiBZAT;9A(kw!6)M8#omz0PD0v?FNMF&j^@P@&8KICU(bBslP`5>qJ_MVLgsw*m=hee4T$n zZ!7TM0&eCD@UK-kuR)tEB?sbg+L`<=w!HBGsLLb=oC1808@CP`C zg7kk`AdbNSi{T^z$C{B;LxcynGOwGYxiMp`BM_U(D{&u}()1YdTGebNA)rX+xsy1* zs?v?4IY!F}e|pl?Kx*PR#|D$;z(g^A7^4UXka$>9nGoZXqRCJ3#Bd^6JcB{NAIiir zIsO99f2|;rk`XYFWHX59d1hiP1v{6LXEND^#Pr?)wwG@vNj55K&E)eruw|YzHR%*T zNq#(TgT$v7wzsP)!HN;zKL8Abqzw7+_c?J4X|RLEng3eBai1iTASZuo zn>t2>`#B~3*P3chN2uvLsE9)lhiEDN1MK@z>0B1SoX>eWkjX4QypaK0YN4vrQJbVP zEQ&Ygd#ckZr+hBms4deGK&=&kiX<0hDoAcbCP)t>DV&cih7Aq17J|77<2}Yq{_mVf z0S|#NH9c<%loVdMDk$Y&EY{G#S66Bv%IfMH$}1|XWr@4h0Drl$qqE?Ak?C!GbBlqU zU7X#Wu7{7Zh1aTj`v>gQCzRt1YDcCYj&?t3ZXKLZSALJh#%a9#+)&Y7-P>yM_PO%> ze2h9?3alTx=v_BuAOB&|w7OfoN0^n5dTf)qAh??OxGwW%La;>Z@Qt-0TNJjW;T&%*41L=t7F>*0TYE9iAPBC1 z%WUGi>W3O7Z>#!E*T;l`wV?+|%j365h7FJC@3XTh-81!8de$aA6ug1ghN zu*o+C5)OO|wNDjEBdOp=kWL_%vWw3_6&)a*MX0uzl%Xujq=IZvL#oF$zcmUcbK=kr%2Udi(W;(QRH^_GXZG@FoeVI_Z8=j zA}5S!cA+P(o!`5EsQUtN0or%|Sj++AOE2vN;N?TI1bNBb=dE_sffB?f!%Jx?-83k zL}h-E6dCH7>vadmjexE6DsS@hY9H9PAcqW%)wb@9EgVJ_>Ly2kYR0Xxw@{|ZXF;vt zu@378vANbLG$)10BkjbMvcs&cY)}|qle$F$2O(K}LSF^Bjb>KU;~uU)ebnsJ*DXy)51#q~OL!UP@H{P9$4vt4 z68F5yb)5E?3FGQ4BTux8mR{|pDSQX`r}g^Y39`EE0r}y-b|TaAQP$kmy?TT2N|)5B zNjxR|_s15lZYJ5e;*9s=wwWVGF@Ckpw#%1IVDzs1>A>5T}-G*KYH6yfA3J-_gR6-aHb zNV!^(tO!ub@-j=%&?1^_5`ybB~q{SC*Q{w?! z^jJX`9xT9|Oj|IP!pG1yWNZN?d-{mHNXT+%NTEZw%n=ay3uD$n=3k981u7h4O zhs%|VPpYtma_W|&1`x2R?!FWNU4`qdj)P>3TP^HRjDO-qu}>};HW&F?VR8)+@6HYg zBEXb-WrG6#x!N@!-8ZO-P#5b9p!25=VkV#}O^cSAh(`0>YMXe*g~yZ~X;HfHb}mRg zTdFr0Qb-YxjbPny5pA5%fsMR@)P+*-)N0>s4OvN`=B?az5Z&7t+W%^sAmR|m+DIw0 zEvK-u&eFnTRU@3G;R|k_qoJY3skdehO^Itinn;VFZBCU~Q0CoIT6~OmP+*i{2ZtT$qK;io0SVQ$B324XyzHVk7 zb!@+?!5>E|U6H2!P7c>YY*jU4Q24VqBpUD*g{Z$aoCqVH1 z%O0o0psY2;q6cCB;?N}^&p3Ix;K19%h2;xKV#~GDYpQ#cUN7vmNCZZ98(V3O&0+Qb zJRd$V4Km=Jkd6f;|0Hz~L!)PT&O`F))!g!VdY0=uXIx=g24S7toAruoVDwM%RjcT1 zBi=793%VPcNzYQG>_D$xhM%8b5hAy)zxZG;-`;{pKe$VA4dNI^1lN~BTSCaN-Jwte zXv2}0h)}C!8^Qk=3!dZb(e2xsd0WYccBimQ=`9JBot<2CY&)#u3YVY^4TY#maBGBY zd>(_lp70x9xy9l3n}-Xi^@cb#jHvF|izB=%3FwyWeDXR=4gtp5Xnmr zg$kbQRyxdtuUIw-kW@&7l}Y%Eth8UqStX1g{D&qqX^_KxkBQqK{y4nq@7&QnLTxiD z+A3H8+wJ@JMW;-8Cvyo!5V<3}KLaEu2D15{2)m;(Su48qjpe<&&vX>NB+S!rN*_-m zKM3BYSqVPMhXM`PEZ#gWU-!Kxz5B&p2@)N@3hv04H4$RYB0TNE9a&w}@6qBWs7sx@r0_>kn;p}(zwKOwauBr!1rk_Gl@B6oKqC^1QU{SJ6j zw8C{{viJjOqE;4m2^~6cI5vN8R{;FDL@{O_04u>WGC~}TrqG(o zT=v8p0-wuEWX+?~z48Hav>}p=bbwL==J?2o90fYpnsD-VHIn7)%bFht$#nP=zKH=9 z86`yCTt*-Vlg=*ZSVOsv(aE80un;Or_DC^P4^V}M+#^ODZ)8bAxX#ewz1I+-0?;)- zkN-sH{~=r#o;zPueBolrrOW>d*Jb4u*UlplmDg`%SDTtv*WS8b-=NWO`;MU5RHF;u zdbj&xHKOw#9`B8>>3LMp+@&#e-`iVbkhw)lvlQp&M#T)SbKa)LBEh(3id=biszww# z<8?$&*2{_1OHP5WF$E(j+ke0PLiUn3IA+!ee7kUq@8D%dxGvbJrn&a=HL|aVzSm`g zr@;Xp?5M}#_=~rAF@_ zD2Sc~-GW7B23v(rqSGoB+xSEWbqxR&y3ppkf>MUPf1QVc7Vt;@s|->j)nI<^lPuy87-lmHpS< zu5z3j4=C1YmO(WI_ph_dxW01H;2rhHP(zo4hp5tOc>4lk@UfnyPS#O+1rT(WUaN=P zwdP}M(T?WcO3&Dxd@#QE;-}WHAjAVEbjeVM*Q=OM!xIOe8u^6nxsjhV!akY9;P4p_K_C5`bTH8Bf zc~Zk|)JM_n*fX)`*EKv-@(VNgA-`09gnKAQirrpLb z+k$4h1k10Oih53f*2G%j{b)2@zYj9$T1JAcgs2x7f%YxL(Za)bUoqkG-qRQy1iYcO zgSN;c<%jRS7jATO64w`L-I5DMtV+=?*~8$FHKn?o7Y_d)Yw!Ng^#8~I@454lId0A) zG3Vucsy4@wYL%j*M#>>&O3sJp4w$IdI+9c)MTMrsL^UHM)heNb8YwE(bfTm0-k0x> z-(NnT%jNqA?5Ay)%l&?TTyNJ~Eaa0l&FQjze!9|_XmNd3JRs5!@9_nZ<_hPU!L{92&O~eFH-iPJn8!I;}Bx! z<${0Ryk8I{0FR_`$*$tRttcB!x}xAEpWOkE0pM0DgcJK|w|lFDp|p!&{znXJ7MnrB zWuQ6z6~OX@7*t&1?w)37vip~#FUp7k)F|{8unR_$t>a$@iNCFTY`$nl3Ye$=RtOoU zrWAJLMLF)$G}3m1*7`yw1MzmB+@y2&b{|i_=4lGT2H(7YU7EkKIH3sYxP-5jFa}Bc zc0mi>d{Bsw)!UdL#8AKkK7%o1TZjO)B?%hZAE!y&7#vtLyFk>VvMC>f?pzO~*z=QQ zR_8<^i$@O~AytH#=Tkz~omcGB8U=JHg?B7;yN)%ay)kdjL>tx;0WIkp-1G(y?RxGi zdy(Aff%2})Q1h|f_0{HwX`#OtKR%8o!cLtR!?*ssQWYq%vg@i4LTe>Q_u&{60vU+q zF`@DET_nZNLaO+2W%&xYhAD-a^)lr|({l)FN~hRNcO0ehrfzvD+dasVodwI3{Z*g- zJk({EPW{~nwIOTr-hM^Ji_bfqrTGPMs?X{RY@Cm@^RYva0PK91_OPhfY;qjGbH2-P z?IuB=7Z17{4~)eo$xxP$foD~#V71D}izml%#D%|d|3X{Dq%Ra}c#RED2<62EDS@a2 z1@X86F4Xs6HDzi`Xd3Q6R~Ty;>1Ij$4_)+fhv)mA5{D z9cO{0FO|<8fBFvSjdsDvoX%%Vie|*LUvjwu(e;+wxa==4!X_1XR3yG^va5k(R?5YE zc_VFJxjVT-@nX<#q~oZl3)ZxG*u&{+ZS2F)PiQ$Dp}%5*aGV1B`@Z}Zup7DyRyDektb||Om6E$isl=+=s`VoI zkyadpxofq2nN+1$A&#s8LYxqfMses9 zxVF75A9KGq8ZARgGeDTTIvblT`>>_0YdXt;e=weba;HNzj+()Z;S3bpGv^tfjcm;^ zp4{QNv~@cxF`f$IKJM^TrriAA)W?QRea`#LJyWRPVuo^1bj@Dn2qt~ZP;41MN|Pbp zUApl)gq9rz=2?uut{^o{iK%!>{t|GXHK>j*W|pW)TRPWBgdmNo(=kw0@&8DXdn36& zQAlqh{M1NRLR+c{1dI~FpZ39ZC@W?u085qhAbsCt@It1vIA?z_S6|5e*v2*SEa=aG z-z|m()x$!`c?ostJKIug`w-4bppm4hD}rC%kYi2Hv{pdhl3*I5dx!jZLt{Y++g`FXe0U|+I z^n77Keg3V!e8YaOI03eixc|pU?m$~siZGo)ff;kacQKH)kb)DQT)pX>w)y<){iQcD zbAQz3R!-%nRKO!yFr1s2t`Zp{UYpbDQA9=`C>`N`ia78s9u`tBoDYVRh$fBBP^uUn z%i_}Kb4ufjW=0PN2@95i2p#&a=Y9}<5o9eK0aOUDkCw&WF}nM$w6zh>IFX{NjxziKPVK`bk1Isl2K5&_g|cM_ z>=OH%+1y%7Hz+&Qm(4pb-m98_GkIs-!PU$q0{IYISLRh@_hx3&h5YMn=|1+8pP);rg=1MGokSLDU6qh9DeagTQlm; zg~r|=yRh1ZdT3%QZNF0Boa~t2nY|mbF|+guaDzxd3|%stIuvz?2i$<6nNBQ__vxXY z&@4s$aFZykz!RS4TI7E2eHgJd@6zJ6jDq*ytz`h>p9gavEGPkjD6zLD^4??81pJq? zl<{H$#RAU56I8)Faq<*9R`)o9xBcqW{r9>7U9`W9Wqv>ypFbBv^%k`gn?WWr!S zMz<{x!l1!I6U^aE5CV%rnP`T}`zMbRG~{5(;!ya>LxM>0o8t+Uszv6D>^)@=v?=Xe zLL62uKW;%wl%LL>K+!QD5ZREbd+Rq^n+dRgzN+)0-D`yx*Eha>|DJ*j^PX;i8f4o++@?3t zp$$c78Q%P;_l1+kHFnaQ`mNZzp#Pm(^ZMk~rr;h4kIMRZZPE&oq`lXHiI74fS)V$5 z(T{j1UufGB;WLJ_yW1_$YrC%AG^OcC4Q6s2;76Cv%H`ifZNX#4R*^TbIYmbrKkvm^q~800m)kifi8 zg7Sw<>%YbjV~cM^JmN5wRR@1+2Lj?@IEH)lxy$Gy&nSZo2?diJxjiN z0D2SRN#yFRs_%5}(P(X)d*<5b@D1YRsl{#VcBgfZ3)>Fx?gT47O2=L}E^RP&ksO$R zLxNFyU-5iWZKc?w=D((kchU-xZfL(=wHBA~6S7ir*WbWJvFz8!S*Q${TIH((IuHu; zPF2n7HATqny3DSV+__HyH*k_tKg{BzYvig?yORLsfyayA&{f3z#08k~(XGo&hBmM6 z)14nv!-Tw%6^ceIhtm0T{&CC|%1U1%qg&mzzL1|`r_(tOrbx_8ROQzho!rglnKG!U z=n6>$N$Gk>Cwqc)_~{h2luHJ+iflW&6oe~3Jg-h57U{RrxF)&$E68#1XdxT06f5Ob z5JdPBHaf;rjPvMc+#%FpR*_>cuwpsM7vLYWVUUaHw<#J+@C3^MsBNa-r-u$uT!p+^ zR}9r_5$#_ez%ED53M?JPSs@LOKRgZ<9oAe%ud*tX$s`th7&Bko$(AiWW!d40z z6tjZ#CR5QTTmqoeK~Se3P0+o2p*sC>Jm)RSg(C;!EKNt4LL>B->f#4>4x?8_s(n3pTlE{EP|!PSYPCd}DYx6%=cy z;D6GEz^9H<1OH}m`&=zB+Lm#iQ(k@t9Vw;9ssX)6>U%UR2A^0z?bXKt7O9o<*8Ss{ z<@>v%9hLA+OeBBx*PjXm>I?DhIAAv~Mvg*2J zi1z_5?}h4t=EC+y8yHgt>V(S(=}Q2^Yz2%c?Yfu}Xv4Zdc@iv$5ro{1S$o&}fprxd z8B`51tWgZhdE&;BK$}&I9s=i`Wexd_GR$ciXe@Ox#?tw^*~CIqd@CwB&>kJCWQFAo zUAAO>v|TL&hkty(Hpl{vYQ%zP!@~r@M;pTzbcFR99_+}{kG9)bFN_CWP+nw*CHAx; zivVu>{R7an9A(i1`G9r^r7P*6DM>qgn?efu%#ysBs)#`X+RM&NBzs%^Sq>$8?*-JVuKait(xl+)D z>uIFtd9a^q`G7qd^AP7$H4|kYgIk{9T(*Eh3 z1p04;<^6%{7~3amle~~#o?Yiml%R2o67?{yP|K5!q<+iB#i@6&wskuB_+6wo>GJ0tMVaw^O-n8Y;)EoQ_%KlhG)ap;T2fiQh%`d~Zh!Ets@p&^z7b;D~U1ZEf$FkM0aTLA}q#DMS-6VTU z{yxN+WA@yFYE{b843uNvSJE>{%3Pcm5$G(b+o%8I2KUODzp%r_T#av+bB&Cvf0_~D z-VmfZTE}36&rrybV7Lhdp03J^0JHbSXEX+L5UAbb>A->YxD;AJOk3*jbeL=eDk?Ad zodI_T;qGeELv4nO1Q~1;3XM#MAVU-YZhiqgkAeq?vsa9yWsD$@bFkDRT#yREo`QTG zfqqBjy3=`^=(#kSx}%h5FGV?y0<;9sEt2oi51vKA>5zQ761LA8mN1{z904_|$LUgF zl=;1XhM}v41;;XSk4_cXjq;%Ng=jM06^(p80thPL-c%T!0$V!Ie;dEYpP1RthB_-V zEttF!{jBhWTz5r*eLs&ahUI61E>z^xVBzy%^+z&FJoD4z_ryrH$tci3TJdT$tUDs> zcX{r~1lZtQ0h9?Appj3l%L+$9Z(;V{V7N0oBLz~bZu?4A0Dp=KZhI8^)fJnG4h+tf zZYIO!o@KaEpuVCIzD+2+*oM#%?^l@|JncVFFnypqlRpwKynsf; zu$f(JVBsS8?{dV+dfq}`t|Pjv#&bWGDHKFzZ{+~%d(HLPt0IVShNRej9$>0?NHo&$ z1emS>LcpxiFH3%{MUoV-I8Gju2;WSFXQ&WsMOklaT#o(!H<_OeH@Mn%%)%OANNfjp~(?=_qHN}2l@2s)We*}re zs}u)x?6D4`HSPZ}qd)T1^1< z@B7TV)zxc*!cMNbLZgEtha3tq?boS0heHB1(!Pi4y*_X-Zb9>eo6&`$Ti2i(^Xm*^ z1ESjZUX||?z}_$KgoT@W&b6`F=WU$hn6qekM7Mm{%IeYR>RvTXovL zZK`I(`<)5=Z#Vt=8g7R$M*~zn+naEwh3}!bNbLvf9Y&DMhO=$ko?cD7TCwGsh&P1( z^#0yXS(dp{Ubos~B4SNB>FF&C#ZobU&d)|(>fx6!_zFzm-Hz`1@zf2iEq|8WW&%a7@{exCB-9aPu-%(~(+4%syVN=+l%sUa ziyHlP+zpj?6%CG1GL_-mz|4DWCw2L{A4&Z4t(7iO+TSAL(Pcx*Dv=N$~GIhz*aXLYKCG0&d`C!R~;Y1 z*)Fu-)1k}7HUp1}&2BCsYfyj!)oR{nrvOoVO)1be){TUTF3 z+$kK#v_=3<4fIXcRXmMj(jJFZ%6vYJp;t%sei%dH=~c+jCrEm1q-%U zMA-9fbo`5Lb%qIaSW4Pi{e5Ua2U~;A&=pUs$B2*XA!XW0pwR-l-yOR)qKF1sIAsKV ze79r)dEe+Tu!9~N`Y%XRw6wiur1_L5KCFL*7?YZf-1FqtQz_8HvLq#V2ZX)74SJy3^$gs>=(h{%U*&xRo#W zR$mMks7-)!LJx#zyObN4GHS4>Km5GQ-|3Yl@6oVHc12&@WS|Ep%vf>Q-e94Ei)!7p zuE};E(lENmkeAI9U(v1CU_$jTuLaHVF_)sgC#}4I#Nb-eV5EKO86}gyZ8tqLZV8Aj zA{MpDuU&FE#jDZPLSEhCigH*A;P;4Ngs4D3u%3&>`oL@Nr(H5S8lbJ7H!qyly5hxw z;N4{>tC%tviQKTGn-wX&KU98HB16?=^Iay~t{G8x=})U$QSjr?z8iG%jt|2$j$X~t zY4Mham9S24CDMZfYS2Q6UX~uMB>E>J^6o}W@qO)`N{8)@IecXkTkYktX4s2)IF@;* zGO%d}#z!z5Yk}~l@6y(bD8Ap-H z?+&oy~N}QK@pLWJ4 zL-_VBPhsR8fxsiBdJ6*J(W|;ko^s+;2X%ErIWq3js%?jDv~`+SjvH+ zXFA_3A^yDk<3WQc}$VmtEP1+NrCYIYNLpU+j^+mG{79YbedtPP$C_1KOe>X ztG3xsdvEmZ*}dA`U$Gm+2_|vo=w#5*)^LHwr7{_qwL++2?9xQXDT5J=(8YR!5^IY) zIb zNWrx%i-FP(2EdY(z~Z!V)C#KKed{go{mXwpSp&8x9*T-+_0RPPLce2r4xDZA=5O8x z@ifxJa})}IXH3(HgLJ`y+A9aujnsD5r9Z$00N7|yu6}uWGSRb1MI@D{|wQpq!&4|b8*Yn&o1iyVSFnW z6DG|4Z1>;ZQ{`hbRTNXJ6gr_=>C}U3ZP8C#QQPjdZ0ou zhT~%VK>6%t1;R=MU^mbI(&qewm6S(+jaMZ<)JGVLlcf;#a1NV1zUN}!9>+S^D^e!c zBmZrDz8{#cjwOEb$o(>ch@d0GBye>|@V7_$gSxB-=i!Mgn2QH4NQUhFk%laWubIov zC&8m=3*3qL`~XhA8W{QLk=xw||CWJZiE>$VT5)8I)YV~;f~H!(=t&CpgkB)ro!oTVRr_? zkAtX<%%xCy(W3of!o6M*P;HK$I+GqCDdde5de0Z{pcI{&FZpB*zscMm5Ls}jT*z*N zC(r<7y)J&3ukFbVQEwokob_#`;`!3qctKyW@Q5|SMJ2r4#oo-y*^1tb^c@A-nVBKV z5&?C8Pe##~@&hZx@Wre=e>oJv0XD139**)uM5XWQ4hASoKT->R6eEpUkd$)!JuJvN zC6G)+Y*xTmiVmKk!nfAJNh~Ol4NarEhW_8q+X8!o6Kde(kg10jU?El~Cw070KohX+ z!j-FsvCGUax072sZxp+Ew#%Dt-tI)$bq`qe-V-A{1|IFa|D+tt1fY)wHVwZz91nf| z{DmB)d{?%fEPwO%GUol)B3tR3&(BoA+He1Ya`q7Vk3D!nDELaXC)a=0^NK(e?oyi@ z$M9=`P1}>_SsT%oF>AxaMqY!EB17}aypIYsrkm;Y-(5Oj)t8z) z{T@O>_)fKZ-r>9rJ7Ie#ar{urRG9dAlY61M1FhuZ*IeoKY&KhQW@Ebqa!KO=B+7Xq zQDf-hE_FYG{;9H@(DYB90GX;>8E?_UCFcB%J@CBe4SOenjQ8ZQi|^b?T@Ahc#nYrb zwdii8I^S_;?EY~0jMOk&7WN3{*YCe;C3n27CmnFS>2pNcgZVt#Ypp4aVdS}xCKgGT z(erate)p1Tbol2&@z&&3EGrn;J1shsiM*~4MebZOx&rVa&Wi<|D`TpimbL45?Q1si zl$o0SuwcNo8mufzR+TZ=?{CRHbf(1qdMo8XOOFIBg;h#nnD4XH6;N}_JFyE~oGQKe z(A9Z%^kH+)*|V9raNwN1o@I#Nk#NV7p5qt7Xy*=ZyhD(>PS2xYRkxpJ@T{ed|+~sxITfP7(vATx#onP*|t0*>>$+HW$vA7zP3=;3P z#2n5Z#of`xPD~FP=+zUcaK<+wh z1JgQ(#D$FpGzJi`5ylK%D<~oY7J7;8t9ms`+t7N#QRzQ_S8M<>54!c zw?K&5*f_Tj8+F7FgTyki?-S@c?uFvZ`AV4V>VF7VF}Gt?40QXsB-U$YiDRc8>XCpO z6(Qzdwg9T%FOf$ZY~Il6x8ZU~g8;sa7TLAC^=eggm+2#K6MgkU<)SU{7MaYr92XbUk2e{zIptDcY-a6{@eh^ zY=duC$kHy9MjYBv1H`JDGJKv7oi7?eWY3ftijBq$=n*$uDxisLL||yFAHmzxQDbt` zRucgUlda$`d@SFZKr8-R9vk^=3P+=hT$I1!+1IfOQ8a& z`IF=S-lk(m|MuYJxR>WEJ-c!^5}cAXbV$KQnr6bvwufz7cvjIWmdUXeVG~*(AQ&@F zSIM;*C`mB6*aGcO_EiGpzESzV##wxS4%U7;rfWm5vvzBlV5yX?8Kq(*y=#ut%VeWd zC@y93zT5D>+mLyPK*P{Z<}V=bfNRRSF-Qoju0&GG(}y(f<4j=P?u zJgk$_&zhOUnIvRAI=YI7>k+{<;UnbfaE5U>hr4R8_fUxGx5B%eq-{|$MDaeZ=)*#1 z@ls*+BS$3>U{{jtnRK#*!}W|3k5nPQR~-3MHe=+*O*$E^k-#WdUiff`+x9g4>5*d z%Y+P?$H2A109+!yo9wsj%MzBkvICjXRSZccD83mP$aoz#2c{BMY@X7$hF-g^fwJg_ zXeUu|FUe~^_;=AOIiL9)c_>|bGz40W$X;k*3V4jtb zHx>cf*Jn5;A97R3lEXV-fM zY#kl>11UH)m+MT+s~LfZsfxLoytvW4`1!n|Q9*uNnk^fuiZ@sPbK>am#EkTWk%9_o z379E(J_nO#7Okc2zm@?IDaF2Wn2Q)520@+fD}EfDU6oL}S%Q#GXLnHZ9mq%`1wgji z*sHe=5cznjpcW;JX6KzAwJX~x=GD~0ZE5O0qQbFmSOy812+5CQm&QY&Bo%UN@K5f-Z;2@ zpLu(CW8BTYex7z5x#xaEozB@uyp7M*rf4sq9OV)Lip0-Gy z5STBzj*Q)~KC1nZI4}y$7N(x%qUcAUJ3YmthaLxKX~zUqgIB4b^D56PX<4F0rf81? z6EoE#c$x%+RX;GrCrW zGEM6kP)Z?Aea%i<;T77EG@cy&em? z?ncCErt!U5U^l#GU3Y<{EdEu&?e#Q20TjW2^4=tpVuc6}Ss~C0P{m|@)~gF4Ss{nI zpj#AmHHEg`TmZLZcpGR{IaE<2{MOjv(-B+9-RC@Lw0DISuER|E@p!9kJQ7*bZY9#2C&qiQAa_90`uvUNRXL`6 zVdBhuOf9}JbRE6WlC8XLOwZrQNH}1z2!Ryk3xT>yPm$mG{^>OU?2NPGU0t9kdl0>E z1I6xy7i3dRX48G1y!=d)m)%99vPwIr_}oPMQ`ZKbbxCeWL57CcP?r5E67BAa#y&rz zkL3Xyjc|x(q27%o&rG|!aD46Wcc4-(TE9^Yx4^MPU z`(jzKva>_8$r>8po~N{siTgR08*`J?^YfWKZmCq7=ge%kU9vs4*Rq?khwAY{!Wgjk z`7?0mkfR&!9=QXYZjDz;mqEB?>&5e-y$2eoO1{(XGjVs%0LTLT(JKQ7Srd(;}Uw!qBLDcT+Z?;}a z{fcyGP_=8Ey-Mkrsq;{|K{iT0W%t?FCBq*DmC=5yT67-W9=OqVI#Az14B3lZ6kv8k zD+qtNnG#vs@CO@}G4}qBeVEgYg>OS!SFh0LXT0*$_Z0sJA6%rMEGJB?NLhw^cUh7D zE9y16A!Pz@oF@JNPBS#TwYI`ppmuqGpmD5%Xhp91w~XR%kuKRZ@66LbCcW+Gmq5%E zP7sZlz4k-nrNaZD;gBf6J$-h+P)RrNs^`Di&OoW}VXlLLFs$dE|29p&)}Kv4FA`}T zDhlwkFcKCMHkK|xk~p>0Cz2qCP_Vd=<8Pwben%6|&@`(szG_by*t8Zry6Grv5ni#( zWEwyb@H`FgNR-JRrwD?&VkDD&cg@AF+>&`eBHt@4!a^;rNPxN;1#-9B9)Ye;c>7Ev z2BcVwS2p4OP<%>Q_xAnBfwDU16E*|3$u3%f^eNPP$O@Ao#t{Y$#&$jyrq#dhbWIDy za!7JNiN`qN&0!EloI;P#67@(h&Cp7E7*NYNHJS!k@Rhv1=@5K;!cnz@h+meJrgn_L zao&>E0q-Gr9Rk#J^eNY1CIo7gkhmf`Td_L?ieQu9`5$7TO0J7x-nXA0N?`LYV)xY} z7Y@`}TQiDII_h2Y-j{?@aR$i-U2p`IPT&nZI&Mfmn?x=|9Om5jo^eH6-`-cy+8*){qDDa*a`th_p({3dT5^j<4*Bma{{5__=^C>5SfTM@ z$g}>+VZ`~55aZgD@TurvC^C+GSfvTQ- zN^dXSNWUM8oGfh0dRV&URX*TQ5yOC5(UtS}=dQgLl#>VSq8|;2Z-uCU1>;=ySPKz^ z>d*l!Hd*-*>)zEYhFJaA27}J3tLN{Cc~@=@z+I@^`n&9Dx2sR@8E@bpt6Kx=p7gw( zLH;7x&Ot2q??Oc<$hE~3gl-y$2ZFzM+H*l2K$MHF5lRAk`&VX zO3X7?BU0OBe#VFMx#u<2Pbvv>9bUwgwU2)f)zy|FUQlAferG8?N80b-{>VAAz@A=9 z<>}t16jG(ts0=f{QLm_|t`ES4M06qKV(5YSa%J=>*?T{I_5NN*wzU<7{ zgQKt94BT(2PLswz29*1ZomId(=O~1n&pwZUt>3#y%O)*6e$W%rwSy86`QW z97j8!cl_hZeKgY)!HjSFZv7rx^I)!S8-U}P$q~N0=P&i0o}4}1hP-KKim6x5Eff11 zT$iMuo_jIHFw1^8M$dkH_B8h5Ey%YEO}t>jaBL9n-K)gVpj`AF+rLLcY0N1A0O@@!jfU3vC> zYwp9j)Zy|>^|4him|_nB)+i7@)<=1}gLwh*Jp6RNEqdPrQf5>9zD>nYBr(g_4_K_q z+SSIdj!0WWD`c04TuR+{?&pS&ZBN`VWuj8`F)>LZQ{Cs!xkM&fEZ? z*1_SfO}Bd+bON@hO{wPMYi+H!&a`#jylKwZ-Z%ELNN0!THS@v8w;oGxo}L*R9fjg| z6JC99a1FJ5gOdJvsHm+I95Woy95>d=W)U z&r{oi*8{UU`P6wXEV{1jQ@X*-=-q(+le|pdu#NXEmlx7{Y4aY%(+Xf^nps)R3R3LL`n8Lnakfo-v@{K858{>Q+w2Hi zrr#SyS2jN=S!2)-D*uoLgeL=={|k7-5PbXZiWbfAoWrA z*;BoTNTN95EG6DvCEI_plgZ0@o;b(P_HZWm!YrrzUoRXyiH>}PtkTPxfP49ZlmD&w zMUFA)VP;uqZn0P1{?C$)nfMRLuRc?5q%8`pz=hM#pP(&cK~GZMwT3I~Hb~B%@y%Yd z=(N%CE*U1~PWuFAgR^9jx;^uHHFU|*lIi`N?3gzdhe9vLpti7CI}mumzQhX4u<;8; zF*MeWbH_iOu!Na542a=m8pRew^3K)$y*Lg zLG6<;@KK%zbTl2Jq8*T4X-ltO+*CYS)F1PT*gaw#zl8Jjhh^%u{v}8E_-i~#M|k+V zCbI^R4w4mfL#ICNdH~O#5@(K{5axD2FUrtCyx#QUM&{_UfSV$N@^UB)&z)jjdiz}_ zE_`=<>r3dJ+Kg>I4~$;_c64;u!DGk~5{9 zOIR-`e`k8SMTPnf^W}{lGFVDm4JN~a$$mp z43**8zJ4a}!NB46L&RwMHr?n^*`hGz!6GTd%qJ4%$ZSS|_HcM4S>W|cQs~FDG%sWK z2m2kurTIcNExm+3^O6P8KB)!iS9b_R5OZ*CatzU%-A^G_ABfiFQhn%s)ID8z3-yg4 z9fN_YX+;y}Hlmb1NZo+S?+CN9hn?v4hPWJPo1vGt)(s{(%ORI)x9fgjBR6OtfxW(T z-ZSe2+KT=d-!tilQk;P6v-VaEtF?heCHK>YzaBsP+XOIFKr#>Sb*D?>=_QFpmT3_5 zBD(2v5_WY^?fCIIdn)Z71irSl39yf(`oF$_##nZpMn+p}4YCwbhYv#RnTbJe&mP3N z%L#3Go4}AHq^D&J&SS_B7sQ4ysy}+}Z(4v}5H^eg;nvd07YqcD`~7Ypa*^;oI{frZ!4V1dOTf4QEEa0|dtpFO#3#Xxf)P-8j7!*KcuG~4aNs=6dWm2C|WJ!)$#glsS%uSYsl zplV$z6vKpEsef}R`~Y#(pAJewJR7389FzsI3*{$Vd&f`=d0eS~O`r7MKLnf9PX;VmV?TcB zOLKNLT3|(ylzH}5XDOffNy-1?9)n|)>8D&07rob)w&~A1#FhL;>)DUA{vAtMD9BU5 z&1ls)tNr@GMLO4(SaIV<)Rdl{)&kOm*XGjucC|Kb!dG zIU3V4-@Z)B$LG=~^?!?TVW3>>8wfKc%OGx_B*lB}V@-Yh;1723L^jDWq(vt%n?W9y z+)({}+0#3$*5=}|OAzPPvCvJ9PKQn?w|f`2^6vrA>gR_#t#m|{gwuXm%8; zTNJtIByr*@pDe}N;ioG-*^^cjg9r7izU!;GY%^U3thiMJ7+PTSc6gi|F3@NZpKaJ# zRrYKottjoHb#!tlX&egm3ZTf@s zBU->&&93wu-*p{z^V3FH_G8s?{}e1_hJC4Wbn|?x_OG$e)Br9_SMtR&hz-K&6aWFq zx_)YxD&dUR(2a417H{Rd+=6k`Rx0%NS+T%0po>5PL4@l~G_(vvAu1s7qJOj8v%jBy za?iTr;{x?iw!i6l=^?erM=lopeyfH}42x)hDI`j}Qx8zDwmb~_)U<_%_oM22usy}K zz+&+F#ansE6RWG(`rgXXXu52lq8DEF~neVMdO0gx>$s5h^;ymHnfyT=`=$mH)}; zb7p_=zZuijzx&VZ0xzc|z+jHLxR<@*w7dD|#pGKhfJ=h;mIm}%Z* zTTbU(rVcCJgSux|u_IOqxV9DSmSmitLIx(}h0_tKERfpI!}bICX;5=CQ%9V?qc2}w zF|m7U@i8S*f26>CG-EdrjI9tL=Cf@<(1DucG!0IXxVM7Sd?jh{#}I@V`qw&d5f!wB z2zj2ul~PcODm+l0&xwTWYW2{E03;Au(1%Q9@n8u>Cz!&-OyTMIl691{+tvjSEdYcP z$gj_4PG`%|Ig(Lc(!5|-J+POGl1|eIvSdS=nrY_QQp--(7dc6DFl@-#Oh0=u#7dcJ zsGgKTZ4gtDvrdt3A%p3Indjo{{?7#*`;%Oj?+Dh=@IgbNFeuJxi=NSrEaU%oOkT8j z#V$)23=PwQ`9M#dfp$2Z1^}_vk^tjHO?L+y5YZZzXf3qQwf6R|(>J@Gb)SayoVLuQ z-kX{(!mQZhq~)af1pQU|{h1Qlb!r??PW-tw7{&~i=n)osq|anp?>FR;9>0I{zVNcq z<^1RWzW>%|16l}#zxxDW*{hM^!<6OB@^sviVOxfty}fi~sytTIMI z^BXX!Sta+EP-@&xh%=uw7$~iJIZz?tHCfh07n|!rX0^w;53#|dn?yaQmyb8OES%## zo3n`@YcSfk8&B+pM5Yn)GqYIce(;tZr1QDe+7>Iaowq-$daoHSZQnGj@wnqV`oOKb z@)w!(SYRA&S$5d-7i9b0V$FSb)E%$qr47eiQpP$q%gBmLmdcH+@h*NB4zClvYiMjB z)9J&~zi;epKXn**O?E9}hbtCqFipF=isUctw?4VC zFK6ykf}oFyUDl%xTp-C5!FdW@r z`vJ|?^24OCFa^ZhhEDN^SDIv5>W5;rgYaP+ln9JoMQ~Lj;qbL*Fy^4-&1&NwR!zl1 z-t8Kr+Dvt&Hvcg3by>J09jdDYtfAUfvlzb<%W3q}m3;3I9%+qfWK>qP+V6pL7Gzlx zxBHEQ;_}0fEHQiwA(fbPG(?C9RweqMSVLpmT+$0y(j^Z$18)f-&yvtsA2Augg$9im z!fw8WBp(qpC9-uhYhu%5};LM`~(G!?Mysvy*LYQhD;`_kRZWqxinQ z@6UT|A*NO{l(Tk8Gx9C?CH|#Jo#aD3FaozR#nW~pcRVf6gKtupms;@9H#+YNF?KLT zM4H>ePa?j~8S^=s&|fD)gf7fWC%6XjFyM~L$o5Cy+o#g*af4*Hw(dDT(1oVc-!lmC z&a!{+i+i?1FZ}FNH(HW{)Zy@fjV_4s!<+N>5IO9TJ#DKSFSWm=kH{k|Pq(l>y_q(> z*MYCS^6}UB4sPVN7Q4p$uvgA?&qLpp9Qu9jBD?W`c*?JiHG}T?p=@i(Zj}Frk0Ta@ zS>9@~c{}?J-;xk!`m{xpYuUNo2KBRf1-RFeJ`9BY8f=jV&p^kf!H>!dm87Tg1rAfu z5oomlx&k8r!64ds>IvBCCDGT-$Ke}6WI`6QZ8<%dAv;BK!6JxBV~7*KsoZcL61y}y zXRfvqvN<0rk7VTdYgGo9r#eh>RVeE^8+Nxw*Yi4s2>yDK+&(TeupYyb-rMMTE4yw| zLxk+Eb|cqT2)D|B<`N7U?&E~GoEju zuElAk(a5#dgmH<-_i0(~*M2JQzL@fMYCi|)q~KbZ=|KB|iu4JC$k^MvD-vc)(@U#q z?F>=WIfN`aGSTTCw{JHL>MOg1gg{2W9z3RZF}Tnv>*pfc#AWkKrHQWFYPvQyhaOCi zJm;Cn8At>Y{_gY^dI!P%NzIU6-++T5D{=W6E%m5d#aZtj^RCqJ)7T_s;{Wue>7z!5 zshq8t?trMpH;fDuD$cn)F~7TI^oxO)<~(5l5DAXi5NAb;Ky0!);l8IBmngEb3XHY| z+D{Laa_yuXv@P2h`_*3I>D?!F7af*cqiPmL9Fyi|dY}Dj-+^LZ#TvnfPcdYml?Ff} z?t2@A1M|rms&K#QVXUX}bu?)jWp4bnhWTnfnSAwOm}snK(QHO?$QTdfzh;OWOs$R4 zU2ktOwA*x4#qgShcIqhX%h z*(P5e+u0|_iC?`lM4w{=*|(K49~UERKfe!xQOmRIHv27OJEV^_B)@_a@)+@t4z59+ zItwOLvDVD>=Hq0Eka-0I9F*{tbz*2so-Qax2k~4@b-XL*nH#Z%a4oUJu=t(hRY^kY z)kMLzasWkh8N*Ox>a0#IL%&?w(z?DEVctuZq}DVM*Q-;_S_$G{MLBUhTY&G28$#EO zwXt-{qohIA^BN;E|jr_nY(|(+_$e$92=g9y{H;?J2Mqv*n;C`Z}^=WMq zuNkhuJSr`ulqb<`mf|*2rp<1!HqFaEP=M@ZpjXH?p}abg&_1QKfQ7VhuEH+ng=IIC z3(%9~d4YjU6@ygC@tT#p) zs(;ub08(o1Zpz+C+GOo@*k_&0Vu12M^zYXy9bs92WuSIpEkQ07V z1p`z;&sFDI4)KM8yk#Ny#^wxF4<~is$^@bl9W3+>7dp|_L4<;qhJqcUJ=cD?<78gl zqnvkJk6R*FsRG(Bkqha@8jU<6HLA>c(69>F67j`34wch{qFW~Lp4-(j| z469Xg0gk45-p_@R*(wB{JUX#tV{7N$IiC*Lk&zY!zC9Q{$fcBzXYcQP937Q7Q)z4;e^XdhmFE{`W@rk!f$bK+}Fupu0AZtQ@mPKUo*vy#Rl5!gi8_RWmxz zJc7oAv9%1uc_UlI&>BELnFSbS-$bLO*T+Z=+S8RY-yfZ;yG?_|`(poldvbOL6}s@3 zU$)MKBS&DCvIL%ob*>@Z%>e+(EMT-8_+LkUD~z7Zb6_DFbUk&k`S`8rj$6S;X6`z7 z?(QFH?5(+#JsD2Q+#j(yzhfaU-HZwahG;NC0TZM!Nt>ti%P-2xEImKV^H%OnwAG#d z(>Akm<6E-UozES34eAo!Gvxw63c2`$ZcNyN4dCcPvNq>sVRlkhrYRS!$?_q|fLnzb z@maZF9CNB;1%p|F`3lfk3c31&x+!uj7aIKmlXbQ=cD}f=jomP5;!bdYeetGyV4m3}dt8-_k(BjKnD1`?UFr6tzXBX;ofnIimHw$5;EN~ny zIX5i&msYfrEkWJU}4{npGk<1(lMc*dMo#0N4cJ54cGdV4K&b0kDX*|$dRwmBtt z*T+U-JFxmuam%d?8}8h_=&;zI;HXd3*Z=2f)X5uFgj-mf4n!0J!V)8CgC9OhY`4TvE_uSjY_GxpvH%yxX*HkKTItZ{K81#@4ZA`>gUkW-d;3U5L75GL;Z?{DRTT zO(_O}2ISDH(AxyWy5^Hz9sedJ#HVC`u5RF>9i1lV>l5zYJ!RGMDqfjAp)|uPotOV( zxNFBhE(j|YB{W!Idm(?>!LTizcdVirUO-tD6ot0$N^blPSAKn4`JOQVN1FJT1I`z# z)v3^=?Euo7enINDd{2m>e9lVXcR%_VplHuT8m>|I4q z;oW(ONuqYNQAJ}`f4Zk8>Mf^(fXz(9Yjmce9wc>cdxSH&%pr)_vs3Ti@%tP_2F zg!M-DX+gVf9%*^|%gB{h9*jLNi+VW1l5@4s%=ZhF{OW*4WlBO#Z48hPcZfaK5yFg<|4If8u(aeSwS8|*VZgt-u-sU$ z@i@J)@wAk`H*^zK1T`3*hGz*cY_`8wf$z}5cCV9{LQHWD+LX4>H;USEA(5*u*^pOJ z&s9JVQtDIVU@HUDjSV)4qBlPhou-kB_z3S+0it}*h$_>h@gPJb|e+A`N3WcuRX|6NkS0gwx;>q z_8U>B>anZ$w%9HY-jVqNj8sP!z=IzV<+4AW-TNiR#ykb}vProa= zd3}@V#zT6yiRm%A(QN;!Q`}7>9M#%7psuPzEntY8rzA{0^1s7DuZ;g$mJ;m6Ug55vw2ClGR8(2 zkn)oBIJ?vR;dGh{w!>f@rz5!A0K@c$ZvDYFn@^4%Sb`0;`9_Vfgy92Oc90?RCvzzp zoW;n~+mRkWJ@G1!A~)_!JHHx?lgx9Q84t96gzcg74jvrHPP`@Mi8hS4qZ%KEIQ^&S zkDZ1IHSb>;$TU!B$AP?CC)B7EbEF$DM0TAh&}|&U+`p1>kE@f&Q&asLuHHYsU{i?G zdYxgj`rxt4RyKi-tAxB2M*5E;6Ac6Xqieekp8RR-Xm(#ch}%(h6x(zzRH(Ws7)N10 z7>60kiddQTcdJ$(2wQyoHmaz&>Lg_}5Ne zx4PyR^@8CvfAs|?(dAUJ^J<=4fe9oi0$G+ib9=^9zPsMfq zQe9ro?O43nxrpA|q!b?^Z+DDA5Bus;Q7~kj3*31U2th2>hXnngz!#yX(VgG;slsO> zw1t^rc(3bj*S&1jUq1}iQa+j1S{ZrjIu{^g*J{vMk9 z@}YjLk;W81{p#bcFJ#m&&kpQDbwlcHrP$SlPuwCcDloYx1YftSu=$^6^*>(LEE?bt z_DJdGy54fF8`xm-mk6?L6YIH;b*-gAEup1YzZsRvaRXF1w@pk}YRNQdn)QvTO~isK z>_*;L8P0}3FPGng`qO?OU`uCFkFd;e|!-9N>E~L-0HPhAd8#bsq34Oe*iK>=i8WEw^}ZKD^1& zP3~nH#<*9#uc_`HATZ}-^pco}8n02I_0-dc+jPu!aQ5*li^GABbhXO=t2#-%VnbSz z=z%F7MUa_6Py6aKE!^bErdME6Dga(SLV|o@7{7`m#D@oL!7GAB`=Y`wKY>yCn?q2q z^rn#v+5613$4RySCt#6#uCAL|b!WAPPj72Spy96>MpIu( zFxOu#(idXR-Q~~Mc4s2BK5vv0Uyp??Ag(z7%W_gy9KWy_nBRN#(cE%fb9>t>KmFg9 z&sE^%@&vRk<>i?bGCr}I`XTQ122z_|#_WmcQG^v`@8}ywq4|IcSob^{q8Q`(>ou1V|Kw*j811~Xl79yAeobIF3%A%0Fnyw zreX}`0Gdky+07!h)x|xE}`m^P_+)18^+Bg$vno zfM5n_Ocn-n05nx-ET2W|X<-9hFPtK`A$E_&Wd45-05XvCEvw*XPu|Q{!E8A&zg6JE z*2%a6A1dU|6?#a8c)5@~EHuW7LWZ;ME)nTfqgMigC$F<_7DBq6LPspTVpy<7D)!|H zSIdL}y4w(qpP(w&bPu78sEWqx}n4aUma`IF2jyXM#b!LIWoM zjUUwSC&}9iTR#L)aKW-+2~R4B@fWB27iD6FbSAh*A=Dc#G}Hnp@Q6ycR&u^ty(z|Fsn5#_&Lt}`D0dM#-mmewi+b(EqWh4@lyseW&n z&`_Fxj}4=afW`o*m=rz37CmPcWl{EdGD{{V3*R{APc8zyIRKejO6x7VMblw_(OR1D zs8(#!3+4P+<;?(5Q~O4^&;h25trgs6@2{vRGF8cr9f5Yq(Y7oA3J@db@Bcy*Ug3gv zYT#N$EQx`@Q-x?)e2BI`ScM3rVd@{txZjuje-OGMZrc`5W?%qu_ijf*fTL^RoVDAG zO#ja}5>BQ@I1`B{PI#O;C66ZT*4MvD3?e$ScH-;%`s-||Og~4xXvd~jqT{LPN`m~R zKB2uUNEH;HWkDKv_g;)%;Y+!9j}jg2(M+TepY49uMxY=OzFU{Hqk;@2Y$c;xWca@~dupsxZqC`7hB{QJ za{h(l+&qVQPnjC;lRoNWA^%A`b4y~ikrQF{&X38)Nd3~ zbDc2?TC&Jgdzux9Ai55#PG%+C>6XV`y?Ay*%wyhpp&pa#@z83FDqqvKTskdB2qCaJ6@R+{lVZpxj=`nhYpAXwD!tCXeKq-?2V_3+0MIknkJ|-L+ z>G0eP>tes zx$8trJq#9xf!!&qX*Le6TE1z#M%__TlKFbx4!@^z5f<pQ1*;9Pw2;l*t^?M==aAnbZm zM=z}$mCE86IH472BZ6${C~*E*APjuEF;z!yZA`i4a zGrN}ULuB=O>^U;$1W^lsQzTtLo9G5NzGtfWlXKxJgr4Wk52s0)4Ig_gE}-{Ky<2*| zwsvBmn%A@cMu8kRRsD>&2HkRTyt!(S@_tEZL?m3GESd8m`MfvL z-_?+e4aH=h?*emVIe{=kKh8j6{409frIi*Rn(0O85s>JyWt`~K8!{)GQ+yGI-uL>2 zxF)BGWV)yGXloZ;kB(g#y4g9E+HRv4Q!-bIB*F5(=p6MvPb7l8Pq8GT6i&?RI{okA z?(0jc2Z@vuRpuSNi_Cm?%^K1euw~Qa5->$$fCoY`4+|sK+)u++u0oTg{!8Q0s@0`H z2xdTr{FXt*UGTQ2d{p(am!1ao6|d$VK?}o~j3dj8!yK~SESogHVluCy+Vzscd%J_J zUJ?L#2LYlD$%e?s>%vVhOK&Bjse}?POs1PhQ7aOPz9WT{yXAM+C~Tx7b!Qz3e8>w6 zV(-_zHZ0iFo$q9adq(5}BDvI6I(C{t4mG47Mec?8EWHe|)yVvN;0OsY*4dujlUaK| z8)n&L+%m9tx@S)9Kt%M`EOmE6r$PKmk3^I{*Men5h47(jZdB0K6&^|(ML!J2%&YOW z)*558X8jdWhx&XJS5G5X-Wo^ghKz!?44n`4-)<=9t!N0{gh?PVh{P&UH9iEr_1l{{ z7H=P|NvGB$Xp0bX+3IT!J`IQu+wEE8#{j&F?7(!|(7;1=;>QTZtGicK@-RkLF^D5R zb;NoV(i|ItI+`IiwXZ?ZvagW0QCy9Zw#Q%FP<60o{Vj4l88zYr8F^w;c@h1hzFONB zu?Lj4buVfRT~6%XK|;}%jXIC;aV(uIs5T$1XHc&_z37&)Og&nEn9(*o50Ra>_PJCP za(%$$lZj^dxm20Zti9uA{%{%k*uz-c7`0nICiq$NpB9tF>QDJ*Z7+PR*tTy`4YQ&v zmJOJe&4ew(0*PN+!pHdRIYhnb{K{Wr8Fgb_w5Vx|?)XhfQvWXN)Jx9AvT^r19hUc| zl_m}p(|FpRwF>(FwFl6o2Adv#H^IRY25i$3it=5PR?L4p!E6I>ZKMed50k~NW_+L3 zr@D}BZ4;hm{K5puB5?Yuffm5tXK9RR{!{(7vV=i00tSi+3O<84etz0vHl6hHwyNdbH< zd!MC*F{n@OCxug(TN+Xo2$t?)Ab?fM|TJ6^TjEG|B35E=h{0^^*amKu0xs0e6Bi9eIjs1 z#*ja>M9GI80r1Q?CAOW6je3)O26#o?_>&w=mQ+^lMN;NMy`9wE`nvSvJlT(W8&29O zqhMn24*(O)OWo;5B|1532Mg)D^=T&&u8zL?@_Ojh?8w{L0t80YHhpyEocBu$IxUx~ z_=eoJCnOCpRQ?gXbm1f-+r6Erh)ltY#z<>gt_@FbK+j&^t_hs<77{H4vfvVW2fO!AROMb!cXJ+<~XelSW7 zyf;fqR_6})~fsCi}gbtXeuM23Ld=k3=p@mT_z<>)F^5Eb{0FGKfWERZf z7R;sa9jN~Y>2knM2KLGKvX0C`!EnB%j=`}4cdXEZCe#7EAp;RE1O1s;q*^q8N)+8H zVy(t4m=ylNh(i5E!Ah~QT8y6(>%IndbSRu931>)1GKo1^yu4y9i3;H~u&y4@04qdO zp_OilX1l zlF?z&EM+~33O?{JtD}_GV@m`TvJr*!IXiJa2Wct?_6`?wC{nWk$(7!HNTu}1-%yXg W)RZjIITjnG()rtXAtqQL=>Gx0=5yTu literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/device/check.png b/script.plexmod/resources/skins/Main/media/script.plex/home/device/check.png new file mode 100644 index 0000000000000000000000000000000000000000..c6e2c3d22f138d4b2a5304f8460c95e194c1b5de GIT binary patch literal 520 zcmV+j0{8uiP)AbMHO(UvHiBy#MF?&w1YG;|L&SSSjEH7}xFP5UvJJ`NIb= zSuXJ;aKwLn0yBUlB|aoXWKTq<0`@8qIS`RlWlX{qBC;zYX~&C=#ue^u+&BahaR_gD zgpXA&OHT{JAiC}ycj`v#Up$H)CBzm z=mj1O4nM$L2;pUq@Fh@d@)Z>h8@}|8WLOIx;VYod<}W}4aN~HuJ1}B!o>$Sa;TouS zMJ;#HVmNahFTjB2I179`_!*$dcVzlar{(N(cm%qEX>}Yn+yc#E5;bV(1D+iZzE^|6 zhAhw)wn|LKA>fVZxC7dw^ak6;gy#!Q5$THBm|UA_Pg3c*&{Ie|_7Qw_`~>tDIt#*( zRvqOxSj+?rOWX_yzXHR>j^8Nc9j)Vym16csAt!)+RS6~e@%RORMbBn5AF7T30000< KMNUMnLSTa9(9`e$ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/device/error.png b/script.plexmod/resources/skins/Main/media/script.plex/home/device/error.png new file mode 100644 index 0000000000000000000000000000000000000000..c60c200177c78292c8548951330d247e0affd91a GIT binary patch literal 1217 zcmV;y1U~zTP)Cq|0Ggp<%mX@%-zK)%p9Tba20Dz(>7#JA9$jAuB$Hy@`Itquw@q15C z&l3RO2_c@LlScA&l20<3%*#k5La*0L0EXP_^)eEPFr7}nAo-MJe<#4YNPb3=p-_mj zEVI5vZMhJFR;!hvP>3X}BtIc(Z5Qr3$saULqucFn8>*SR-EL}{Mv{+6I*r0PNbW|X zQQGbHj>9$FZnrZUjgn-NTf(^767yGTIDoxLU1JmSsa*WV6|t0@`dgL$PF8W~EXoki31WI*|Oy z@An%%L!AT!K)>Hll8;XUzOQN8KZ>GUI-sH`Tw7Zs$y)#*k?g8gs~^tK&&!Qcb(vNy z7BM$Bhgz)`Yh2#V3Rw|W{N~MmTQ>he6rIM+bb*6#@V0&n2 z$aDtN>GaWaI-NG1!NI{n0Qge^@Uze7GhL$M@i=r{hpy|0$K$5sjg5@~z!pfpWu}t6 zDz8_PPp<*^!{u`AsjAwyy}jMmY9}Wr(bv~^R5>gb3-GSz+$6~RMTAho_bUxUHmg((YxK!7B-Np`g=e+-a(eu3JIM$%w~f^H}t_g$%ma%Scge|mC0miR$e00000NkvXXu0mjfEw(H9 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/device/focus-refreshing.gif b/script.plexmod/resources/skins/Main/media/script.plex/home/device/focus-refreshing.gif new file mode 100644 index 0000000000000000000000000000000000000000..b135ff2971f29f661e89552ec49c22bda364dd8e GIT binary patch literal 6211 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/device/focus-unknown.png b/script.plexmod/resources/skins/Main/media/script.plex/home/device/focus-unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..42d85bfc7be614a2612d45625d034767ce869c61 GIT binary patch literal 561 zcmV-10?z%3P)oXLQQ7VauEE$jkPJyWsuCh;{4fswj2YCSqHy}>h04T4V0B8V{ACSkhX~j9s zd=HEZ_-WZO_#SRJ&xr2SgHf9R7~_jK;e5Bk-{2+h-YLSzMC5!=G1) z1sFU0K2Y<3s>AtLsOEr*!|{sUmpN{LyF|=O?EM6|0QM6x6@Vej`gPMz&WaP&b?^+m z>{(}nhrL|eLeIlqux+9LFBya^YRq3^285nAi>ob6a48}qBO(}Md~7Bqbv^^f840g} z1ATu04n^cEevZqyYf@I50>!k3)B5Ek6QHrKWtOq^JS%w!6xQ}+ox}&uH_T>={XxjN zxT2Qnf-xq*mh&pMa8T5Xcw^J4v8teM00000NkvXXu0mjfkKX1^ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/device/focus-unreachable.png b/script.plexmod/resources/skins/Main/media/script.plex/home/device/focus-unreachable.png new file mode 100644 index 0000000000000000000000000000000000000000..c1912ca77c4e8b8cbddeda17373f770a697ff829 GIT binary patch literal 506 zcmV96=BU;BPvL39)mjfnjl`dqMo6pzG(as-B*juAv_d#yG?`T;p%pb#RBFY0QBJ6CC3n zxnTD=iI`%cC2ZrSBJr%f4IZ1u)E+M(jGiiq>1W%ySu^>-iI9p*Qei} zJ+4XNSiWO3=Pc(8o52ko*91~j`i#-QyGdB=_=~~yVH7!=gf;AWeC%N@VW+Z>o1XQM zekWn8Li`-d9e+8v61EaHDugfNi)}Fuu7r(*l?veq>m7f+&=f6J7Upl&OVoK*<_#FM@Yn+8|HS=$k%YxxIu@iuHXxY9K~ zPH}0S7IyL*7dhw4obx3vf*Zmqu2NL{g4+RcyQ@Bb7PpZzw{7|p`}o=u@B$w@ZTca& wKI})%ryDp=GBRg}{>dCe|G0MOKl*RWe{=xE&@G-i8~^|S07*qoM6N<$f=4>rApigX literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/device/home.png b/script.plexmod/resources/skins/Main/media/script.plex/home/device/home.png new file mode 100644 index 0000000000000000000000000000000000000000..d4c50b90f87cabda1ffa3cdbfc293ad3955b2e42 GIT binary patch literal 367 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/device/secure.png b/script.plexmod/resources/skins/Main/media/script.plex/home/device/secure.png new file mode 100644 index 0000000000000000000000000000000000000000..da0f2dab0c044ecd1c69b5559f6e145a10abe45a GIT binary patch literal 674 zcmV;T0$u%yP)JA+(o0w%z55CqUOX{N5FNEa1ynNsLe)D_3-%HQ~ zmTjE{@}6q~_zr9U6?rcUQ|v@>BqE5Dz$4%>aGKt5fq7s-n8N+-1eR@G0$u~Twm!62d$@+vc0!k|YARFDrbu5%huM`Erf@qJ%>~H;3X27t zwu7pv=+ioxnGBhk4EnT=s;M|_hr(hZ%C0$pgk@Vpz(*kE)A_|^`Q|bJllLdlP2I<^ zZEsUtDgrROGE3@AD$J_$ij41LZx6p7{<7k@&%QqISPxP_Uirg_IVp@JkPG(if8MA1 zvf6FeR%;^0Z)F)cHxQ)CCBqan-!-YP*Sqb;W~1ja>+5w!uZ@OH zU?}t%irifN!iFMKL%&e@FAB{=rt5K_6qYt(;s7v&Dc<-Bj?CW={_=k~z`YK6RLLBdB{Lg0Vr0pD8(A_v zO7g&y6RJ6ohl8s@^2k$#N6nC&%#caZkl&PKc$ej|r5VNX1HZKN>f&c&j literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/device/unknown.png b/script.plexmod/resources/skins/Main/media/script.plex/home/device/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..564c2864a5c595225e6e44c11c29f9e9ccf1c1a2 GIT binary patch literal 664 zcmV;J0%!e+P)5i*0_V63m7tn%`{;M>cY!dpy1SqU(z(^^z=J_a_%`d!4BBAeH$o;o@3w# z&<8yE?g=5zw{ax45T}3!@DjMiZp?ub;8X}P|Dyxjw(kQiz$6|%0d*n7$FMTFM*a+V z3)~|IeE@s~(qW6)Y(}%$1fW){VHm~=gXej)+id_EjRu)a zCaP3-71`hEjj!|H9T!pO6oc!k(eX!?iE;6*(361@FIP(36Ma zUt{i0000 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/device/unreachable.png b/script.plexmod/resources/skins/Main/media/script.plex/home/device/unreachable.png new file mode 100644 index 0000000000000000000000000000000000000000..a06aa49c31b0c205e78de77c7b5a4d8edb679a5e GIT binary patch literal 651 zcmV;60(AX}P)nVDlCFaJ{&_*ck!B_K185POCe*11UmF3n!!)ep)?sX7J{cj z9wMU73)C1AnheRHm`YK6JLK4?t|Y6F^bZ1E-FwgH|C}R50m2|qz&fxEYylg*3>O)x~^LmuGUqQY-y>`@_^bls~N_u zIt~rnuA*Q=XUe}23zo&2>rU5euFFEkqY^CJRRh|r)uxGR)@qd#p`~%n#gc9FT%IMn zvRzlUbj8-ZlO50F&En$py(0QrT5c&4W4KOJI-WkomUmI2X~ zeqLybDOnfHhHemsWJF2Vo+002ovPDHLkV1kFH8q)v( literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/plex.png b/script.plexmod/resources/skins/Main/media/script.plex/home/plex.png new file mode 100644 index 0000000000000000000000000000000000000000..9a94e24096b26273c8398858395fa77d23b08bd1 GIT binary patch literal 1579 zcmV+`2Gse9P) zK~!ko?V5RPR8$Hk#C2bDMQ$(w3<5?0CjplO zj{%#_>=84opa)}8H7&?r0wm=?%43d^W&0&-3b?8%KzI{yrR(H=OMxqZHD-21PbU8O zMO)S&?m~uS$mO+}^>qiF8lv)vz@-H)^MIu9T^H?n1n{Prjq1t7SM1pTHi>UgsM;OQ zFWvYAr8$HPs0E_<+zc$Dz@+wKFmP{ACVljS>zm}5E@xihiXU6TfCV{ArvfJzaKAuO z1ArnD>FvM^!RvlNB`_YC28<5NCBWg5)^<}O-3**lq?^5xzRdT**LPMfQH+_fdwbZf|XIlTlv*?hHRTSKcEnqq%`er1r#@?x>1EnP|appfz3dkg7f zuW#5Uaf5Z|d&yf17cfTBw5X>?|9%8e zsu(N2fIuc52ld}aG+=?k%?sj#NsPNMd)et`c6LW%`n|x)toMz;ZeU%|fB9eFhb03q zaV0h>-7+`Kz`nQta;D3w_wS$M4lJ~TRl5|+f5bp(v z!ILQ&J~iL+D&X26BK#wXv{xeKTJAT~f&0kz>?7S9pwgE9$2=6};wCd2)<=4g_~!0G z=a}b$wkmIpAG$ZfO*yc*kMtt&*?j{C3N10yz6zy{d9akdf8a-J7KSyo zvT(7Po!IGyR~KP|nU%C-{(4D26_`_MW|NBa*C^?Oyj`=#_+l$zXq!0h)90VSl6W^m z)p%RT?Z8FAAz=j-@UWRpl;pdc^at8Ge{Q~{l!GC_TkSYOSLF_VaqH02JgFJZd@I>5 zN99t@!P6SP3QE-7W;PF47ICfPf*=;8n)C7M<#~n#Bnpe-nsv-+j5pZ z4ZKspeNE<1S$(8uXT4O@jb=86oJu82<=%Uyk3XMe&VkH;S)?CAN8N=B`bf{hM>h|f zfHBX)6rQ$6M$XvvVaQ4N)1W01g;{1crjK-B#d*Y>Ssf6^=TUij?5E~EvH1mD%?F}d dA_?H0zW}^GpnTlSyl4Ob002ovPDHLkV1oGe@*e;I literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/selected-section.png b/script.plexmod/resources/skins/Main/media/script.plex/home/selected-section.png new file mode 100644 index 0000000000000000000000000000000000000000..9339012e6d4689e01b35b438ad36247859da1052 GIT binary patch literal 6642 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/type/artist.png b/script.plexmod/resources/skins/Main/media/script.plex/home/type/artist.png new file mode 100644 index 0000000000000000000000000000000000000000..bd8e0177fffcc4012f480b4f794ab3910266fce1 GIT binary patch literal 1331 zcmV-31e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00f&!L_t(|+U=Z8Xk1kkfWPzd zrkOTrt*wQbhSG|SNi9-ATvTwOBHh@HRZ!5K(2Y=vD?vmM!Hu|aRk|rc!JWDhbR%6T zEl4dG8?{QbjcMA{*q(V4MtAkOd@0v#X6Or@nmXl?&phe(X zMkjz@fS;`#7m=mA*?B1X5Ss-q1DCA42>f9{CV&YMnQr&xJMBvq3D7d|Cve`;NnpyL zOaT`~WMMT{A@_KHqT7Hj1LsVCGo3bT`5TxOk=eYhq89-*%qNTiKbih+K4Tu31Lj3! zv70cu3Fu|uYa2exz>4Zyp=VUOmT zw={rTo&kLynKM4<5e~qThdLKXp2qhjH-T>>;6dO$&%{9mQ`Og1^+pcYdcw{*x?O+dd8!0B2{iJ~%dns}9d1W0 zsy=SBPnx)Ur(Q`vGXuN@>=Thmclji$`YXu^alYgL@L9X`r<{Efs=Cqq>Qlg@B&S^U z^WS!>8o(KnZ0E0l&qZV|TUT1)Cmx5_rPO3Qxrx^1y|t!&t688&z^5Ls`H1IWZpB>% zx4|N^VA^N}(_N%zE2)|z&0EH8x3Ab@ruC$%PUi^cimJY-s?v=OHD8dPQ`NIMz?o9j zmsFG8%2L2_AZ=IGw^eoK9^o8S)#1{>v1$H)afLbVD)0pGH1IgdDVa6fIjq<;c@4Ng plH&ah@P#cP8);oq?8Alu_!pHt_t9V;k^}$%002ovPDHLkV1mnWPeK3y literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/type/channels.png b/script.plexmod/resources/skins/Main/media/script.plex/home/type/channels.png new file mode 100644 index 0000000000000000000000000000000000000000..c03c9be48a4d044a5c49d1ab5314d50faa721399 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^0U*r51|<6gKdl8)Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPN2a7n9K?X}#K2T`8r;B4q#jUru7xFe32((?4Kg7{< zNWj35=b*-$0uGTr7ALKH%e7}spJ#D#-72lzEh;zV=FOeFMmJ_xKLZmBM*ssO6N^Rz zkQ8wMl3WTvl2rgmGI0P&Mivf%1$m{RrshS{ZBKsu@McCz7V8CLqeF1@5BBr!w0jr% pG;U2%UA9yr4kOTPI`H0#@rjkVqT1I5nLsZvc)I$ztaD0e0sscDQilKl literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/type/home-selected.png b/script.plexmod/resources/skins/Main/media/script.plex/home/type/home-selected.png new file mode 100644 index 0000000000000000000000000000000000000000..023557b729888fa35a2c187c6b65f4ae26ad6387 GIT binary patch literal 7286 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/home/type/photo.png b/script.plexmod/resources/skins/Main/media/script.plex/home/type/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..4d528852d04e9c887354e54a126d777be0d20456 GIT binary patch literal 1252 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 _{S{`l-46Caq7$4T|&{zvx9E&Nri? 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 UR;T^M1ONa407*qoM6N<$g8xJn*Z=?k literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/indicators/chevron-white-l.png b/script.plexmod/resources/skins/Main/media/script.plex/indicators/chevron-white-l.png new file mode 100644 index 0000000000000000000000000000000000000000..45a6bcbee09268a2f99526a8006f539b93c9e1b5 GIT binary patch literal 1127 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/indicators/circle-19.png b/script.plexmod/resources/skins/Main/media/script.plex/indicators/circle-19.png new file mode 100644 index 0000000000000000000000000000000000000000..9d1a852dc0d2c6bcf10eaa57fa3e041d606d4c69 GIT binary patch literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S1|*9D%+3HQwj^(N7l!{JxM1({$v_d#0*}aI z1_o}RQf^^JhFNnYfP(BLp1!W^54gpI1x0^^1uX&!NtU=qlsM<-=BDPAFgO>bCYGe8 zD3oWGWGJ|M`UZqI@`(c#E%9`546!)9b;?HGLk0q__jkHYNmOY||;L5^sO2 z1#LfXK5et+fj*fs)*EUkw=IloC~bNp^-8vbWhUzm)uVev z7kE!9WwlT{*|+n(juP8~SdA>@q#vj6pP4E3^0Q9%B|C{XE)7O>#0SiBafM7VIsW?zbvcxr_#5q4VH#M(>!MP|ku_QG` zp**uBL&4qCHz2%`52R?Rr;B4q#=W;UHVPgx;AwrRZf+8=bm_vhmOF-g*%sNtvo%<) z177^y^_k(m=O&%@CI4!4Zdd&W3aqR$ndv%t35W3pk-P_An9@)2&Y5D8yfVadcVp`H z!-;0?(I%UDc7Oda=Q8)6_lLP{+9ZGckc)|Wb9n2#X*&E3-i?Pr8WIjPFfz08NEo0p p{>6WJts1od{mW14Dy7Tc%wrLcNd9mByb$PM22WQ%mvv4FO#rI=b3On7 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/indicators/dropdown-triangle.png b/script.plexmod/resources/skins/Main/media/script.plex/indicators/dropdown-triangle.png new file mode 100644 index 0000000000000000000000000000000000000000..ce90adcb8bddde66db1280b48b6613a34bf2ffe3 GIT binary patch literal 275 zcmeAS@N?(olHy`uVBq!ia0vp^{2(?58;~rMGjRk`Y)RhkE)4%caKYZ?lYt_f1s;*b zKvma4n9)gNb_Gz7y~NYkmHhz=hX6O*AJGTRK%oVmE{-7@=jUEB^mB3)VZHEM(WFhn z%)v4JAYaanj%_;xUN-bT;40u2Ymp6*5UO&@urWKrA~56p+UI-BKi^}S|L*jjL&1|$ zCxxBb?0?CBQbN?`*H6~-SltjgWGdJHu5r7QjZHPntcW`e@fm-tS$WnSkhh7KRkqW6 zaPzF}g7&+dcNRr&aq02{XE)7O>#0jHF(j>)@&&t?IIBuiW)N}Tg^b5rw57@Uhz6H8K4 z6v{J8G8EiBeFMT9`NV;Wq&!_5LnJOI|M~y_e?6NOlN%7UDYCqfwPW}q$o@}gg|916 O6@#a%pUXO@geCwI@G$8B literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/indicators/pause.png b/script.plexmod/resources/skins/Main/media/script.plex/indicators/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..622f04c769f793f3b6c01be6ad146edf46c17bfd GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0vp^ia@N!!3HF~9)7wGq}Y|gW!U_%O?XxI14-? ziy0WWg+Z8+Vb&Z8pdfpRr>`sf11?d1J_DDBA%;L9$r9Iy66gHf+|;}h2Ir#G#FEq$ zh4Rdj3dS j`}^nZYzF}ha9Myo;wXm)Z(Tqo&>RL&S3j3^P6J#6b2IL&Qo@;(^4ry<90ot_?F6{px8>y*vi9o6pY%lqD{uz7vnr6S;U;q3dG zUpC$fGe7;aczC)%i!;=9QtktRA1rGU)?ZaF;GGk4wO>WVVUqHL8?{#N_pEB0`oy^4 zsodEuk)Cb``l3xP*Q!=B*zIz)4xMD-9L+n&K}6UUhK{-j!jNI03k>;)1cK0%@@}KD zwr>G>a~7_w<825o&sep-d6g8Sc-}>q>7k|3#oL?98}q+BPb=8_VSy3juOh`)`WwPS z??2CHKcB!A!91<%gKJph?sU8RFHSn2v48Nrq<+<^`{}kPBgMAA*H1K8P>GCZ_@sVv zQ@G{sqmuvHKOGI-Wv?qgsb{j!q(5`^=HGoR|O(w`l+X literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/indicators/player-selection-time_arrow.png b/script.plexmod/resources/skins/Main/media/script.plex/indicators/player-selection-time_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..fe5e15a2e84b3182ae41b2e11a46f192ec2e5ed9 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngk!3HF+w~DI+DYhhUcNd2LAh=-f^2tCE&H|6f zVj%Skgc-HUqBnr_lz95OvOi!G6Vz2uWBR`kC?r|p8d2h$pPQSSSHj?2l$uzQnxasi zS(2gP?&%v4-pD5oRFvrH;us=vdFt7XyiE)OtQYbZZspyWEGm}3ahRbe>0!nc9Y^n{ ziv^^Zn%3`p@~-Y5tLwgZp1Gu6R&{Hhl-g0;tytyp zX;%FGgU=7xwttqKW6w7=|3QG500006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3Hks43Hkvlc3ZFj000McNliru;0F;BI4HfHKGy&M0yRlQ zK~z}7)tIqsQ&AYjf9E9x1A;|#(7{l2j1F}X9a@kq4i4S*KM*=4e}cI9Clm@D#66?X zg0q8k5fLdu1#P9!QbRB~4&GOuS^D11ZH#A09^`#F_ws$`oO{I?u#Ker`vR~CtN_bE z8@LW!00zJwumfxZTfk>Yhm&=pU_1Y;+1{|dZ+q-=7>D0)*sc}p#gb{*?m7*+wi~g# z(XxHuv^cQcDz!@mA|2aDJ|7&}?vy3esn8d(80UnF&;*fIn1+j-KaPR6q}{*Bgzaho zUxCZa4nKfvz)%udVgA=uUXk<$xC1;%&^wD+Fuf@pjGvM=fhMpC3}e;>tYpD` zqj5S3(g1i0+ydT3lv>V03}9M9xo%4OBI#}*_NhXdHnvY98m@JgzZIT)C2O7#=|inD z?q4w8XJ!1V9t5nJN-%Oo553g1{R((oMo6;|6_XONUAO%l_+F9-z+OGL^vx6`fST=l zKp(hNvCK{u!gGqx)FAzYx`R=Zwlv{ ze#MpCxBUTl0bEVc`+Z4=v3X_$)RO0!(10VLSK;N9M0%1&#iTbM88|mONkd>Mr1n|h z7+8`t%#AjiaNk{Eb;?mMJIbrYW6FPVqMVPj_T1e<{LA|pl_4~%o2%asQJjJZA

O00000JC zpNr%fIC44mKo&!EWnb16IWX}N74(PPMKq^>WKE)L;NUs%{l~q1C6JhuZGjXpEqli9 zZ3AkQfLVYfsioI6Nb05FBby0Wcv6zKNYyk*sz^O)TnN~BUSd22-Sz+%HUf45<(Q5n z06PJv2$`A=Bmk$ehQg4k8$=9aJ5Sp1BWc;PZfrEMv}f9|9<*Q;7!6%pP*Lx7Q`-Rh zZmI{{u+PRs_77uX?ize~k0ga}!cKZ3TUlEWG$&c$&s;cKV-xLyDuG;LRLVvvoW&^8 sKt4%&kaR04vFo3b-X*e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00a0*L_t(&-p!g#Y*j@R$A5Dv zA4*#lBvw&c5rax%Gyy~tB_VO)is09VxKI}a7RHj`+PEYV-ROdiABnC>Oyk1D7}59< z7nn#0q-bfuL|YL`izcP~TrkgEANSsOZ@qo*{gapXF*E1bRhuQ1>i0$;SIF>R$D4 z>%*+NN4+_%t4`9-s*^4reph$?Z}KU^z3O4xhj-MKttJp!kY5pZKAZG^T!_KBKNGkh?1O`A|Jm(t+1kG9C4X5~Qcqo$Au6 zCa5k|cd0WibX-)Il@;2jju!~KqQ2Q6ybwo9?dmf1Ep@&?-!IY6S_*rw#VTw`^{vDC zQ6Fic^KhX)b$7wwGwNWivG%_cxLchl(Eog%fLqn6f`Nl=IE~jA=$}+qXU%xHz^1oA z+fs>b1vdZ6bvv$J&FOq7+F?6LH(qb&aG7f!@LEpCnNs1X{s}BsFXwRD-{_R6qdA?P zuG<+aIO}scoKC3;>QFpPnlT;^3OcajjYH~e&Y?7z07F1u#`vSaT-y@-bOLov=N#~5 zMsq(flmOdv#*cJ@bQAfJoaXHbkQeH{p!3M%u$gG=*MTlUj)R^|fPswu=h_`j@}diH zHlukU0aj)-oKM+VCv6KWtT?_Sij=8+sMbRab_)7(My-n@3-Lm6D>W51}Z%(4K1F){} zsJ;q3T4drmzaI=C{Lp;kc)4KJ->7-j_bjj=x-UyuzxrFjpuIJd|EePC%j*4k!k%g| zc(^WSReNH=v@FKdr09}*s8uBR4_FIq0=5AU0~;z@*X|I)$7SMWdLrLMg`L9Xn7y7(pCd^LTYMZC?jZ5;5W?xo zhhHk%+!G(FUa@}6#%R@(@ksK;TJj6^G4+$02+ybo)H_r1*Tu|Kb$&4tvo-3$_*i_Z zHP;?(T5Vlp!_EQ0000c-?_PV@fXCHe#c#6Xjv3brPiryn2z;*Py}|6# z9h0C0g%8ai=P+*&tkBn}dobJDfKmIytBv2bTeIJ3U^;Vv?S;a&dBMA$IWx*Nobh?L zt|K5#%UD#fsC?#4gQ}9V?UDg&L)V(hUW^J}TRP*+Z~OeTZ_6w4FKOR&^H+0tw{G)} z-z$<9l}88`-cnF%JLn}p+352Y$27j?@P|sQ6-+v(i=wuiuKl;9bNca$%87NGPEGHB ddH?wzwse+_GDd&nHv+xE;OXk;vd$@?2>@uWfb9SP literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/indicators/spinner.png b/script.plexmod/resources/skins/Main/media/script.plex/indicators/spinner.png new file mode 100644 index 0000000000000000000000000000000000000000..6ddb4d4ac419e8f4b881e049e29a978276fcee6e GIT binary patch literal 824 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 MboFyt=akR{0QwtzoB#j- literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/0.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/0.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff39bf62c50285bf0086a6d57b7fa3d57d2da1b GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1an)5S5w;`G~thKvjh91R99<)xH=RBc#j)z9EF>B$zB*(^-|j`3>&RWf+G`njxg HN@xNAAHgf9 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/100.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/100.png new file mode 100644 index 0000000000000000000000000000000000000000..b25f1dc57a9f4efe2e83831107e229b3880e5755 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89A7Mq(@QG4j{!@;1OBOz`%C|gc+x5^GO2* z*-JcqUD+S7aEfpVo2UJn02Goeag8W(&d<$F%`0JWE=o--Nlj5G&n(GMaQE~L2yf&Q x2PzWtba4!^IGz0G|9|_#8WOCF6GQ@-85mw>GX3wl=n68K!PC{xWt~$(699hWD1`t3 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/12.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/12.png new file mode 100644 index 0000000000000000000000000000000000000000..3cff5946998d143b5555c1a938369c1ff35b7681 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1av)5S5w;`G~tjJymCJk1*(#+zLK*dlh-mT7~^Nj?^77AEf(#qL0b44$rjF6*2U FngAN3D=+{6 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/14.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/14.png new file mode 100644 index 0000000000000000000000000000000000000000..fef67aee2dad268d38132bc235bc859e5acafa7d GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1`Ki;O^-g5Z=fq z4pb!P>Eak-aXR_W|NsB%+X4?9IC0{Hg%sD~1d*Pmg)9tAyIGjZb6i2jF?hQAxvXT5fsA;G#hVFM!rlQ#=fzBYddP$`3_tDnm{ Hr-UW|(lIPc literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/22.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/22.png new file mode 100644 index 0000000000000000000000000000000000000000..b79551d567c2296b4b82c7330a70dd6609b4d032 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1a%)5S5w;&k$#|NsBjw*@+wC8VUJ$ndrX8gRKCbO73Xn}zAcrt6D77|Nqyw1v(fXIC0{Hg%sD~1d$%5D4@;JEKD!mvW^0kGI+ZBxvX`Ki;O^-g5Z=fq z4pb!X>Eak-aXR_W|NsB%+X4*~8YWJhSZE^Rc2Glt^$8OL!)q2MEoQk-K&1?xu6{1- HoD!M`Ki;O^-g5Z=fq z4pb!X>Eak-aXR_W|NsB%+X4+V7?qWkA7^OvGzA)P6)-X|WV0~wCGAN8DrN9=^>bP0 Hl+XkKG@mMw literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/30.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/30.png new file mode 100644 index 0000000000000000000000000000000000000000..a0c9aa4b821acfa6c11d7b47ce63a0d44e4e343f GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1K9a#5JPCIX^cyHLrxhxhOTUBsE2$JhLQ2!QIn0AiR-J z9H>an)5S5w;&k$#|NsBjw*?wJVNh09ew?Av(-dg1iIL&|8y2Roi}$Yts$}qV^>bP0 Hl+XkKwUsYh literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/32.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/32.png new file mode 100644 index 0000000000000000000000000000000000000000..e4224f7b87fef4a85958e46acdc5a7811a6d5792 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1an)5S5w;&k$#|NsBjw*?xkVNh09ew?Av(-dg%hmqlb4GU9*?vD#Vl?an)5S5w;&k$#|NsBjw*?w3Vo+9Aew?Av(-dg%g^}Uk9~P!%W_N&AF)(<#`njxg HN@xNAvyLwQ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/36.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/36.png new file mode 100644 index 0000000000000000000000000000000000000000..74889d1562fe77b4a2bd953f172a8072eb609fac GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1ZGi?{3mPU)oLFcg;&xC&LW+UmUk?kD3P=7a%)5S5w;&k$#|NsBjw*?w-bujb*!QzDmTy6&+Ff#m;VPSGipY;o7sn8b({B$NGBPl5G#I>;m$LrxW5Yr#c819+m77_AvoJM_Enf^&$>8bg=d#Wz Gp$PyS#4Bz9 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/40.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/40.png new file mode 100644 index 0000000000000000000000000000000000000000..02bae0233f4d89308b85bdbb7a696d75a3d52f4e GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1`Ki;O^-g5Z=fq z4pb!X>Eak-aXR_W|NsB%+X4-^Rxn6NN=mvrCyMki{bFSJJBNj-sp;Q(pi%};S3j3^ HP6a%)5S5w;&k$#|NsBjw*?w-W$;KyN=mvrCyMkiy<%ectHZ*STef&DP$`3_tDnm{ Hr-UW|b#yE4 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/44.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/44.png new file mode 100644 index 0000000000000000000000000000000000000000..72a4f4c132c9a395c591d108d13f77badc1de21c GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1a%)5S5w;&k$#|NsBjw*?w-u?ZL$85#Ap9nz3sUBb-pXAcY0zMbA6M=*H0`njxg HN@xNAoo_7t literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/46.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/46.png new file mode 100644 index 0000000000000000000000000000000000000000..6e7155e6931b206442dcb29467545c97f46a7501 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1a%)5S5w;&k$#|NsBjw*?w-u^A?$q@>93wgTA(j0}HlSeP;&=q>{)W$<+Mb6Mw< G&;$TWzAI4x literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/48.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/48.png new file mode 100644 index 0000000000000000000000000000000000000000..42a61770e3e4fa82d12c9c4fd9a08890651fdc0d GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1an)5S5w;&k$#|NsBjw*?w-wP_}#q@>93wgwu+Ff#o1VPVSC^q&D#$>8bg=d#Wz Gp$PyX6e}(O literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/52.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/52.png new file mode 100644 index 0000000000000000000000000000000000000000..353fa36789f992e1ee66614f97f7c84917d551b6 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1an)5S5w;&k$#|NsBjw*?w-xhW*1q@>93wgwtZVPyDqhlOdOO7LBvN(N6?KbLh* G2~7ZZYAovj literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/54.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/54.png new file mode 100644 index 0000000000000000000000000000000000000000..66cae819efe9c84614ba61c7a19b8e5bd85e11cf GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1a%)5S5w;&k$#|NsBjw*?w-xiNAjq@<+C@U{jT++bw*mBYfs@hW^ZP$`3_tDnm{ Hr-UW|mAWjd literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/56.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/56.png new file mode 100644 index 0000000000000000000000000000000000000000..7f806034c5affc951220ce53e0335d9d5405713e GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1a%)5S5w;&k$#|NsBjw*?w-xiNY+Oq@8e&_u-TpaV0*&o?Yg3sP3J0F^R$y85}S Ib4q9e0Lm>cWdHyG literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/58.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/58.png new file mode 100644 index 0000000000000000000000000000000000000000..2aad245a9101e2f192e816a694b686eab515b2f0 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1a%)5S5w;&k$#|NsBjw*?w-xiMa4P*zrcoT1UfRK>vXvxbG~+)~#-pi%};S3j3^ HP6 zaiAi3PZ!4!i_^(}{{R19-xg@V<;EDxpscL?I76d{DT|TeCl3o#me(^Gpi%};S3j3^ HP6`Ki;O^-g5Z=fq z4pb!X>Eak-aXR_W|NsB%+X4-^+zu{a=mCPo3k|qBSQ&owurNJ6J!1h-DTAl0pUXO@ GgeCyS5-(x^ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/64.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/64.png new file mode 100644 index 0000000000000000000000000000000000000000..228dba450651a1a8f911c69544e381be2c2c4981 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1`Ki;O^-g5Z=fq z4pb!P>Eak-aXR_W|NsB%+X4-^+zw7)>j8qr3k^OoFnnLb!gQ3;t{te7!PC{xWt~$( F699hEE;j%G literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/68.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/68.png new file mode 100644 index 0000000000000000000000000000000000000000..0c853000b74774a190b4eee39d21767e2fa128da GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1`Ki;O^-g5Z=fq z4pb!P>Eak-aXR_W|NsB%+X4-^+zxJF>j8qr3l07-FnrfxVM;bpRR^kM@O1TaS?83{ F1OP;~EWrQ( literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/70.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/70.png new file mode 100644 index 0000000000000000000000000000000000000000..869f9d751c950fd8f3cf829f8f136a8abe681ac1 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1`Ki;O^-g5Z=fq z4pb!P>Eak-aXR_W|NsB%+X4-^+zxiI_5i`+g$5>!4Bz&!Ff}@R=mAwSc)I$ztaD0e F0swMVElB_X literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/72.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/72.png new file mode 100644 index 0000000000000000000000000000000000000000..e9158e62821122dc32cb3fd98391973f145b1a37 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1a%)5S5w;&k$#|NsBjw*?w-xgFFvz$76lDe3N<_<@Pxn-2?<77|Nqyw1sZU<9n@H0l#r5=BE!pii;3ZD3=5OuHzyvTQU*^~KbLh* G2~7YkP%CQy literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/78.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/78.png new file mode 100644 index 0000000000000000000000000000000000000000..2333dba5c81a8c9cb36bac9f0e605f8df48f04f7 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1a%)5S5w;&k$#|NsBjw*?w-xgFG4V4RSWk|M*)dWwPJ%N-V`*OP7l?P6f?boFyt I=akR{0Nk}N6#xJL literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/8.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/8.png new file mode 100644 index 0000000000000000000000000000000000000000..12472cb9211843b3882671706690e8033ec0cd03 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1a%)5S5w;&k$#|NsBjvsp2_0YO`!0hilB4GC5eMg~@H7A7(O^Iw2U89ZJ6T-G@y GGywo~b1Itv literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/80.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/80.png new file mode 100644 index 0000000000000000000000000000000000000000..873fdc264a6ee2ccc8ced2ed672cb813a8fbc36f GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1K9a#5JPCIX^cyHLrxhxhOTUBsE2$JhLQ2!QIn0AiR-J z9H>a%)5S5w;&k$#|NsBjw*?w-xgFGyaA}x0ablr~2nRF6mmC(RE`Ki;O^-g5Z=fq z4pb!X>Eak-aXR_W|NsB%+X4-^+zx6;C^bx+II++~M1g_f^B)$b4;?nkfJzxWUHx3v IIVCg!0C>GEYXATM literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/84.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/84.png new file mode 100644 index 0000000000000000000000000000000000000000..86a77bcee835d7a139b9e3cfcdbf9c5f0d1473dc GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1`Ki;O^-g5Z=fq z4pb!P>Eak-aXR_W|NsB%+X4-^+zx6;s5MNSII(ca4^f8CH7rc2k8XqmRWf+G`njxg HN@xNAeMT;i literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/86.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/86.png new file mode 100644 index 0000000000000000000000000000000000000000..bd940470064fefa355a47ce8f03ce3f38875a445 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1Eu8E|NpOV3pC(zJE$SS*f4S8#6pXo>`Ki;O^-g5Z=fq z4pb!P>Eak-aXR_W|NsB%+X4-^+zx6;JZzXaabn?$ostZn=CCjct}5FBRLS7!>gTe~ HDWM4ffDbN^ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/90.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/90.png new file mode 100644 index 0000000000000000000000000000000000000000..528fc988762ebf6790f9842ca6e3757c438ce55d GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1 zaiAi3PZ!4!i_^(}{{R19-xg@V<#td*g0+HCSy}mULa{KzCm9x|z*n+GK&1?xu6{1- HoD!M<=qxQF literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/92.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/92.png new file mode 100644 index 0000000000000000000000000000000000000000..565e15edf0b48473d1789ec8e55e375715fc8443 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1r9dIc64!_l=ltB<)VvY~=c3falGGH1^30M91$R&1fbd2> zaiAi3PZ!4!i_^(}{{R19-xg@V<#td*f;ENN&CTst;|6htk84<%-rk#k7^sxN)78&q Iol`;+06Z%&7XSbN literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/94.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/94.png new file mode 100644 index 0000000000000000000000000000000000000000..5653ff0cb87a5eeb35478774066c61ca708a9f12 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1 zaiAi3PZ!4!i_^(}{{R19-xg@V<#td*g4Kkv2MD$pNi%%3VPVqu$k6~QW$<+Mb6Mw< G&;$VdGc8yE literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/progress/96.png b/script.plexmod/resources/skins/Main/media/script.plex/progress/96.png new file mode 100644 index 0000000000000000000000000000000000000000..6bfbd5cccc592eb04fcb98296c61ab13f7c7a9f7 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU@QQ#89CU1a%)5S5w;&k$#|NsBjw*?w-xgFGyU~T3zFfuZFG?|^@gAWVSVVP|UfJzxWUHx3v IIVCg!0F_iM-v9sr literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/ratings/imdb/image.rating.png b/script.plexmod/resources/skins/Main/media/script.plex/ratings/imdb/image.rating.png new file mode 100644 index 0000000000000000000000000000000000000000..adce94124530577fb8b910c9d05072d671fa17cf GIT binary patch literal 2909 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 Hu0mjf^522f literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/ratings/other/image.rating.png b/script.plexmod/resources/skins/Main/media/script.plex/ratings/other/image.rating.png new file mode 100644 index 0000000000000000000000000000000000000000..a5f83e717ba8b8e71c0d682b7cc0f39b44aaeda5 GIT binary patch literal 662 zcmV;H0%`q;P)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00I6 z7lw6acV>FrGz`>qbyvN4MZfBSh+(^Fdp0IULfkk990Jy=2AGHh&XNq_hy(o&Xg2 z_5HDEd$~kBC%`;#9N3p~D8~jkKO|rW@W3AD*t@_N*%ojOxLA^js5Sz;1-eSr_9Sov zX#7VY2716_N$>ul*Y+fEE0iUvIr%QI3fz~pnOEOFkW0W4Fj-UbEnr2`i$RBm9JlGf z#?c79Ft83hl(d?)KqJn)fSbT+V1LQvJHQ9vfu!xcMJgyhmw_uK0jx-RR+kd4SD^oA zol?A50YIk~070rxQ~)p&`bIPZXNUN5@-2q+$zX$eQh$%su{vW^-NnJ_K z6cyWKEmGs{Br%;l4V9s_TX{Qtewig2BuO!_qk~{^X wC+Qxr4E!2#iOB`9WP2|90$@+uzMAL%3%$jq)J#TR-v9sr07*qoM6N<$f;|Who&W#< literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.certified.png b/script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.certified.png new file mode 100644 index 0000000000000000000000000000000000000000..0607c9c1150bb087cf4ad2748d75c2dc4dcc2612 GIT binary patch literal 2754 zcmV;z3O)6SP)ECIxUS)MWqw02y>e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{017HeL_t(Y$Fwv$9(N}ZCq zdi$UIN7VmxuK4dqbz)W1Oi5c^@R8MRa^IG9PSw(On?vt8^na}QLN`p!Kx>mAJ_|li zqs;VivR9w%>GNJ3x@8?aKU_KsW1o5f?bFe6{jqzU`ybkD9@zVk`{lH0g@1G;hv`@B zzE80K4aKv6AUSvx>Z=8R`L~LaGKK56X>Q4fx31K7gbn|;Xvn!SFd7{|y_L8sC1<{O0d|-u;1PTIRu%4t151lm&ZtOQe93h+x-N#ZS-1 zcx-Eqs$z$Yt0iSo!BiZAe!&~Z6}RR*wrp^XmTG-_Kp6|?hy548@;(KQ$S1n>T{||a zA6MR;(TArz1_nVXc%WNQRVk>e(;2tIe0Z~vUwlx&V#YxFBuy0-ri7)9f}AZFx(@fP z6JRRFrW{dSXlxFd;_|?#F$7ulpWyB`e{FY{@%QyDnev&eLv2h@7=l$D(B7tqTYi3a zrJR46iE(V87Rp5tz_{;nB-eU6us}G;)=&uN01^U`6@pJ zd4tXa9`d3={v(5ugrIVzLm;BKF$RMpP_@KkYlj}~zpgLNCklVHXr(+2VAl#WvbNRy z$ItCf`vXCNm4UWpP?s~w{-~JzKNa8`(#R-5U%A8$NgnI9Sp7+kkqU#ZksKY@96~n@ z==Wg{n?&0jYL~k-#3U=*1a);Tlf!{7-Oat+cQcdGAS5v5jz4=;+Z%0IAQG~S#1FeRC+i_#SZJ}OiY zAq^?er3iXTFqQJS7SC|<>M(t`#z=S?SEd~HA9#&_y*NyH+d8tr00rv!#3{H7+*EnA_RYTmI` zS^wxbpUj=3@#jBh{l}L$*Le@)r}|iS>oh}sVUjg#NKWUtdZr)E7h>&G-=+WE!-!Zd z_pI7T&(IX!;3Z}*o#%3-o@H0B(=vIB)93n0B*xj+qR7~4E}a8?d>&P%#ITmjEHy8E zkE!=18*?!lYs)zM_A87Xe2FhUu#BF!Utl<%q$3t#@cT#cEE_DB8qbH3QJi%gl!8r$ zL5ps3=*?GY2!)AClhMns6Wi>f)kldZwc+Unl>Vy`rJAe6X>4QXUpy7T(+fx*3*b2L za7UEKJIk;`4sFY7iTJ{}3mI-M50D+PiB2p0qaOCGhb|NmQ<70&3%I|in3RA-PO$xc zlaf727AAGBO}VFsCX~{zPu%g!LgAxl2Z~<2uT)?~U7S4R6N>Tb6jvJ)l!gUv?;_1^ zl+n=~zTdmU(QA2jZwjy=1%+!AP6mP(O*9QmDe+kvmJrN)3V+n0C@(oXAeddSj*Uzt zJqd93lvGS&a{_cqf)s6^;Pt73H$*Vv2ScAi2%ww>_+Y+I&)WAt*anm-XT9$Q7EV?_h zM$pHK3x~$XQ z2s6VLA>puYIo!UUWBGD}N57TliQO7TsF209k1woF(H=?h$OfC#%?wg05v$N>s3mpi zP3vXZvA%lCgMZ%np64?|hEz<9I|PD)l45~hSN{&j1tXN?)23yN=l&4&VNYa~U5 zg3@Am?rFHtV^QeE$>3d)gONW0m60wBqtDgQP8m4Cq|( zl?jouv2%*<=B)Voh6Ek$8v9-`xs!@e-4MV@JJ$w|-~J;3(73rF(6O;Jp_K;ocg`ir zFXYf2FJ}g{TPp8Pd&*1WsRfCMYlc2&FF0B9stW)8x^LS3`FCgkpKVy07*qo IM6N<$g89Ezx&QzG literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.plus.png b/script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.plus.png new file mode 100644 index 0000000000000000000000000000000000000000..57758c6a2a1bcc16cfdf2a4286b0e6a194a00a58 GIT binary patch literal 462 zcmV;<0WtoGP)EBp<(jPn`e&02y>e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00A~hL_t(Y$K{r>O++yeL}!+Z zFXK+40~#PDp$Q@c6R}^n++Fmm6Op@7(=q?!w2SMJFal1Tw zeBA}I%W#RECMY%Zh!6k(02y>e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00%BfL_t(Y$DNj2j9pb3$A4?B zefB=rIcH|hT-qr^Z9DBu(GhyV0ks8;AyEk-V!hNC(HI|i&?qmypwA{g7)VrjA;AZX z#F!X-K#2ho1uCgvTPP_AZRxahZs)T1*?X_GJ|E7R)`6leD_P0jYwx{&`}=?Y^{r*N z#&*lS+df|0JN1k9SoNrXYh{^_(Db!_aQ!DncFfMzzZ#WGTlk3Ws-Vs3idnyoQ@=BL zdHM9#_gYK4Z=c%rQGWcYKDhW!x3O?&$DWayp=zM?f&5InJ$KjCPe!Jyhk#)BXEv3t z1sc46Agl)}TeGr$fBUz0PkSf(hqqL|zj;^VRIMI;suik{YRT-LnysJQzA$-k%l@(L z$Dcp<%d3T|D~yFZ7A9x5?-`qFZml+hC^)3G+GjmYY1^nW5%K!NCkUG*ng=H{0(mye z{KSz5Up(+{SiKskxzb>1qC6gsM0abY?~hydmP#WW@&z57IM&52Wn}O65Uo+8MPr-g zZ9@eW?VcZ>*>~gk_WiYTu<5Op#gpK!1uE@x-HSJG9hog}D&HOq6>7zD!1)C7(4ceA z8A6&jHkg<$;*G+LhQ(|moX^Li12S7XFubtoroHt_@{iY+PFBg=!9+vgSfFV0ALYHG5EVfJ{; z;omLe6(oUTsib&i((uB3*}XSxp6;CK-2e0=$4`Ag-ut#qY@IdXCnH{*DRF+J!2Anq z-1%*X z6gM615?By@Id>k=D8`hY^YGTKQR%3;J}A`hu2i3>m4X^W8r?8R-H=5ZlL?Jg%eKXo zJIiNVwh=!?5;)VQUR30XO5(k;ae%n3X*wG5&0`i zEA-2g1BzPT7&MF-^MDco0VN`Q_i}uaL*^jszlRlYeY#Q~%%KBvgj^s4QiQe_309n2 ztUEpAGl8_9FG(~May&pU@6VWfB+ikp#rGWaJdzIJvJvJHtU%5>%#(VdC&D?OUknnF zmk@T63UmdD9NuV@fXY1-bbqVQ1xY>9wMf??9S_MM+W(T$ieLv3_M{(OPdteTvG<&J z_DFCn&z{^_2oI}FkdB~?AU;Q|NA)}^7*rV7UnY_`q~)RQk)B8V#^^F2TL+3K834Q9 z(e{qlvh<1Ir7ZdLLR36?oe6fjp2q{qYDgUv9TE&&?F3RmVh^z(iO1)cP0|PUVLkd% zCgSOO*YD18HqTx=oo7#*drH;Z3Ky;m3ik%6zFbyN8ITGjKrGPp(D6uDkVNqIvLiDf zL5M}@iqOT=_MVn^tU1e?%ek1Rypd<$i@kltJd-BuiHdJVN{>#OU>~g8PM}9WZ-Xv9 z!RP(F<%56fA$|D-OeduvzTASLh zM<>6#s}OxBQfj+W6xL0Wt}g+E#Cu}ziN(`(j<&b7ZB9GSXj_}FI`_sR^5|dS5uo$` zj-UYiw9(viM^yesU7OE3#SExnJAie?6N{tkg^tVVSj(EtShM*`$J#fRMV>tczc~g+ zulC%#p*>h{&dr9=LZHdiT;h@VBGz`v02q YKejv;Z1I+dIsgCw07*qoM6N<$g1*bSmjD0& literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.rotten.png b/script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.rotten.png new file mode 100644 index 0000000000000000000000000000000000000000..2b7c9bcf4013b5bfc9520cf5fc15768fa3dc5025 GIT binary patch literal 2358 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 Ef=R|(NdN!< literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.upright.png b/script.plexmod/resources/skins/Main/media/script.plex/ratings/rottentomatoes/image.rating.upright.png new file mode 100644 index 0000000000000000000000000000000000000000..42597e48fd6c3e326eef67fac3d00cbf31557175 GIT binary patch literal 2108 zcmV-C2*dY@P)EB?84_5(NMN02y>e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00*Q=L_t(Y$9VWt@qz|&yGL;;JZ7n?C$E@*3i)XdCPIz!o~E4Z|u3^ML=9} zQLNFitb2h60p8hn)4BCx&FO4xWGbEJp$BfZ8vLAi_^HvB*Zz2CJl5C}HMs(-Hn;R_jU9RK)qU6A^^e;Cy)N^qbQ%CZ#BSdU{qTv0 zc0bzQ-X2X)j*>VsE@iQZT%E;_$kwUEFwOm2xbCJ)KC4tsY-x6y)NHu>g@O|{Nf5tn=U1v zDPlEjWhU|BnSpD69b1=qN3Cf8*^jRqzx3)WI~#ho;OZ&LxjA8rkmKqh%K1e~xid60 zM#;?PDdxgV#M2nLO6K$kq2MF5%oncyOmFQP(*}3|zwalH?s>Vr-EZ?dZxBYNNRA$- zIDZPSt{z=Tkt=nPITZ0*Y53?hfikqzkh0e z*}lxO8h(1|rojz&Z|!laIx} z&mN|=|0;B`K)F;PzqAa(kV&4xa%!kDk;xaU~C;3a|Mx(x*~1_H8Co7iJ|j zgDBgbIdit5v)cm6{`Whu)XwM|V-9e$VE<|ZPsjg(iXF_uSl zQy)j)ew*g5ix7GhK?I#&!DJUGjE&(=1_TfN9qY|$rag{1Ii(I;4bhubJdHT=Dqd3! z<^Fm)`@>iZA5rcRc+FkNTpUxE!#lZ5X8#0UevF8&r+8utMo&{cx{N+k#`rdNQwV*^ALU* zQCEjLc^bWxp??2ADU6L%`}IA(1MHDt*)Ad`U}iLOPA4^ ztTD!z@_~aU)zD^A^%t0PRxFu$KW0)j%_fMC7-Ni4vvVfZ*kKl$yG&q=IdJOxrGJ#ZRKLW;7Hc}NOHClr<2+P8F9!hJ}QU+}dZ0JNuMP~5W;5qpI(-TM4 zToSXf3lm7n=|!a0NZ$t`Fc`E}C~YuOVgPO1=x`XNH9ual1_}4fyMLnyfk(6 z=t(vYAca8A%vJ!di?(eP1|=m*DO7M4?uJmI5DI~uOQJ1->F;MI9v@xTEHV?5qoTbH z84e@ol1O7vwvBQelmQh4D6LTCGFpIgU8I3PKrla#^nI+B7V;w_!|UJ+W8;IOx(Zoa zL$HvpyaEK;b5R0h5FnMRjDU`KD5FtQ5u8~4K}8~HW6Qqyb&!BOC_-1S>13SOdwuPx2CstTCN6X9mWH_dYqjv8}zsDwQa` z{{f-?UV=!Za_2%|Tn{A#fi{Rp1U)-PIi8@X6?%M}iPzsa0VF@spwF7@^TG>trSeWU zpw+nc5h?LmI2S(9>KcY7&B01iDnlOafEPJjb15glPzPGY++3l mwf3P)8Eemk!TpIuY02y>e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00cuxL_t(o!_AjXY*bYg$A9O( zkC|bnjFh%up(v1)j}T*8krldNLE=VtCWgqQCw(D zNHCa4YM_F(q7(|1HpS9*I?QxBGw;27T)c)tq{Xx_c$1gh+;`5qzjN;YoqMm)+mQhF z0i8etwQPaS1BdX;K^J%nI7F_TGZ)4}z^xUB-LgDOW9kE@f_1|AcM39E%J`i>!DOX& z*-#+uQu%x*SXCF_$;g#FdQ#r!tDD4w~6nQ#bSUWeV$0uyDtV|@hs+c7VlB;3`C z^Ycx@S6k7vhxs#yzeo@>*9(~r@elVP!$rKK7jRAwK{+Jcvk_gNg;1dsVt%=WbLz(8 zSLlHjBH+rb(z6M0?{Zt>#?PY$QP0c@IpyMgd=cpzk3C(3)CFp3w{jwkD{3yZxcAPWAFg8ul(S{kw zqq{fYd_RcRCkgj#B=PQ#RJ*oeejP*C)Zv`yC)nSPj7(v! z6smX!&Y~-pU{3uNk57jXDGCt8uml$OyX!=|T5*qGMrQoufPhl$vp^7ui&g(5iG4pH zk)jC~_uK14uWcZF`&oj{cFfrkh%Ch3j5+J2rQ;&6e&lu=8+;JrP);9 zhy#%R$wk(Yq(k`nX5>bJaQB8dPCRV)yp&}zw=&JNX1(~|d=6cfz&+N7Hm9M^LmN}b z%~Fj(N+I6CbKpD3XbGl5NV%B)Nhk)j0}%xop1OB%Iz;aC3)V&>kNi%dj~_%0=-Mol zg6O_W6Kz{bw7nUL{^L1gA-51CQPkE53CE!jeI0{%CIqGwusd23!JAtW_$Hphh@F{A z(3!1FP(Tq;RKa)r1)w;D_HU-c6FlK}xao+)}V9>A+4 zo02Aa(Fn#UBt(~pi!Mscw6D0`ma_A+yJbEny1Sj3{qo+t`SGTp(P%UpjYgxuyYtKuqahhTaY*B5r# zGzwa5xN4hO0GI@TY~X5{+ySeyuB4?AQD=d0D9kbnS7#lp$`IafWu;*XU{#83?kh#D zfKU~Qh_e{FT0jd6i`xnptjYy-4Q`Ko0c(*q?7CwB@G$Us1)pgbl}SH20aj&2QcIbT zBVf%Hr?DSvC5jut(!vabRVj;aEFaE?R-wv0e=zjb*y%_HHMI6)T`^c5-Y- zTzd%sN-86@I00>Q4&62mkSIN?LP(JUPKR8qAIEX&(0EQI(uX|qqHrzx=Gz1kDGcuZ zfz0kcxJD1GT|5JGZ?rHR;orc$!&ow@>5}khlT>d}Ik419yg+`amMytCwFIBB=s~4aZ}i3i7(}B8zyW?+c1Y1beXd zy%XXAu0JxvY=M3*MaFqdl@s?RW3-X2nrny0ZykWym6-(Oaow1*ZaCf$OVe0gI6Uu7 zIvMmRWdcrik$811mM>8Y=;u=7Di;S7lJ#>b>i1%?z}s zs02h4??(5nLv0+i7TBqkWo6LzgId65qzZTvpfVC#0Y^`OfK(F%ZGoI<0XfkEazZO$ z?2>yVK$R^^E1>kviWop;B(ws?D!o<`RPU%=xDl5&dx1(o+lP7Ro_FDy3zM|jZWvh4@?@^^CKrw2@vNj$G8}J$r|n#;F^1!jF`=+*PsNn+j2;(4 zQhYI4F-eD~T}*4^?t+A@2V%NxY>uEF0}=10sEmD~#~c!1iDeW|*hE0+iZohcA*M5x zqG<6z)=4GIn_h^?KC+7mlu~9-QV(4Fxs;5fuQbf#I8T~KNI$WT*{s4&Fh!)uJ3x+# zvfoTVA;(cj8LnMFl+CoN!ixGIo%o-?Gme=KV~mzrKe0~MCs%lmD)7(|0mB5+=CT1X zgJ~q?z>eSw?p>UOEmn<2qtR$I8jVJy2?GHC0PUw_Ri#^ZcmMzZ07*qoM6N<$f(tb; AuK)l5 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/reviews/image.review.rotten.png b/script.plexmod/resources/skins/Main/media/script.plex/reviews/image.review.rotten.png new file mode 100644 index 0000000000000000000000000000000000000000..39f6870085e4309f383c9a02615ec8b7f0007e09 GIT binary patch literal 1306 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/section_type/photo.png b/script.plexmod/resources/skins/Main/media/script.plex/section_type/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..814e233cd96fc5b3d22af4f2afbfab7132ee4b55 GIT binary patch literal 16385 zcmV+cK>ojpP)eSad^g zZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{03ZNKL_t(|+SPqovu0P3U1o7qLPA0W zgXtD@1Ra1oqQimR;ePR-cZA%SlHRQgxBvpM6 zQdQmiP3Pp!Vdct|`JXFZ$VWv+-TpZ)f2zyB;{Vs>wdPk?pRqpc`o4AfRO|1}KdI&C z>$k%1R^)v;S0Q68ðo0Vz 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/settings/checkmark.png b/script.plexmod/resources/skins/Main/media/script.plex/settings/checkmark.png new file mode 100644 index 0000000000000000000000000000000000000000..641a45902bc344cce008efef10a66145fb44f7ca GIT binary patch literal 512 zcmV+b0{{JqP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00C%8L_t(o!|m5WOH@%5!0|g^ zt3bhEU>s9|1Q7wtt2Y+GV@pNgV3U7RHJ^yn?w~zVj5j5#fD2Df-6V z<1=P*#t&jIB7B75B4r2B>^Sh_O{EGC(TWHkqFSVIJ*%hPv|_o4T9&K5I6$N5l&E7n zBGAO+uJ|f8BJsz0Q|oVtkKjv0CTj_J3gNzUplQ zpROri@Vo2zH@vv-MzN5I|gW!U_%O?XxI14-? ziy0XBj({-ZRBb+KpdfpRr>`sf19oXK1%{+{w=+N?$r9Iy66gHf+|;}h2Ir#G#FEq$ zh4Rdj3Xa3;F+DRT&Wpj;8K=emiy=HzW>kp4|nyjoOu$?n4U0|dw#`g<`}ISmbjWLOt+^z zF|;u&l-i@bjxQo=_i>+?Jl@-W4Xufju34R|fAeI~j5`fqZ5YIrHU*x0uBUW9plb0F zbGs+jH<{XlycdK$u$q?Bcsk&h>FUkx+6(;O*%;nr<}ZHUa56DT=-nEhOTXue?EIfJ c^-~=~u}ELse1`L{fWBbxboFyt=akR{0DEM9P5=M^ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/back.jpg b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/back.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5ea94ee0177d90becb8c902a2863646e36be5f6e GIT binary patch literal 130557 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
  • 7r&%5Om07IxFD&~lKhWDp?=<>M=d4}6>Ygwg`|?%)7)5rb U>4v3EHU;HuPgg&ebxsLQ051Q&DgXcg literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/K.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/K.png new file mode 100644 index 0000000000000000000000000000000000000000..6d99e483c5caca9dd6c601266fed4324770cac97 GIT binary patch literal 3368 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 BZ`=R? literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/M.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/M.png new file mode 100644 index 0000000000000000000000000000000000000000..c15ebec1d334d5bafa3dd736778db85168cd77a6 GIT binary patch literal 4291 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 Dr0#Tz literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/N.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/N.png new file mode 100644 index 0000000000000000000000000000000000000000..2e00eedba88c98203e848ab246d427ca8c0c78d7 GIT binary patch literal 3641 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/O.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/O.png new file mode 100644 index 0000000000000000000000000000000000000000..c5b01dc2c106e8c6d7112f4edee7ad10ed978309 GIT binary patch literal 5231 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 SXH-TbpX*&R)On$8_uzj56#C=< literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/P.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/P.png new file mode 100644 index 0000000000000000000000000000000000000000..2a30131bf2216bdb4063ea9462ad1a57db640f21 GIT binary patch literal 2346 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 ol#PwtI(hm3i%i_@% literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/Q.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/Q.png new file mode 100644 index 0000000000000000000000000000000000000000..672ec0159ff0fe35211f7583eb48a38d67bdc8b0 GIT binary patch literal 5435 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 ONfW~p1_k=g;r|2a9J>Sn literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/R.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/R.png new file mode 100644 index 0000000000000000000000000000000000000000..438182e5c186477708e4024b35aea2f7362d2c76 GIT binary patch literal 3523 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 BzvKV_ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/T.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/T.png new file mode 100644 index 0000000000000000000000000000000000000000..a5a467b485863fb36ca1fe91074f19aba0069142 GIT binary patch literal 520 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST~P>f$_Yji(^Q|oVT|Ra<(`KxH?vU zK3{p}!NDdAtx&-~rx*Lz$^g~k1OI1ky>`pCsrt;BH}^i6?Z3tYK4 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/U.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/U.png new file mode 100644 index 0000000000000000000000000000000000000000..bef0ab8d6ad2bc811195ca5342a0e680e7a299df GIT binary patch literal 2371 zcmeH}X;>3U8pm058AL7*5Rg+5QIIep;gHBRM8bUvL?sBL#2w|32@r@FQ4!*?2q-L9 z03}2)5QIe_PGDVBK#*`K0b+s*f)PkI2~31QGLvT{mS&y`}D2O_~^H;I@*}sj+T3cFL%w1Tw zyj2T%=T*^0IlIXy^M;7S2Yx)r`jXmZxq!}H>DKKR-xBY5xwx8j;J~9A634P|+6U|_(PtPcsDDU%9kATIQG zzQVqdkrCbGj9BvI5A|w*x`e5VTg49iO#@?N9@rGD}2nGu#&q8rOADk><%Cw=?-g@>l8(T){wCjeH*+ICkV zGR1Xsh+cb5)zOc=c{*mAoNIBd3N+Ml}hyydua9AYn!=Uj+QcT&Z%?#JNQi4Y$)%| z%O137O|rnEU@_g7*IHMG!czES6#p@Y*x&FXuPiJ1Rn~&!9JK7t9Fx}poP)z)u&i+MHYcI3H$)wNw3+;%uAQax=~VT+j$Hx$n4K?h$5QFd32gkPy?7O^owj zPXQ|AB~q-3bIQl7hBEf_^mHR3u_ap}`D-y?><5Isz5SV0`hm3PTtRJZtp%TX`}m_! zIn8@VSEgh>kpGjTW^d=O3&SSd3l8B?QBkFavh>;4clR>bH_g6Zc8i6U1^Aia>`Dhs zT+^5SAy_S|ZEtUfmkxfZliC)dEE@qhx{mvgi=k(e07^U3=)pxZLTSaNym$jd*6t&8 z_F@$PK0AUezEsvTtHx8pa}y1 zpBe#N?yhZe6n8!=D{Go|jFG-P4d-6C@$YZ%pG5gQ8hwo3<8ibqsM<9{P$@{0L+nm> zrg*L+-<#bnC@6@Eh=}-#Iao3Zf+t}Dc~AOv^pVed0E4~mI?;5hLm-;%D|pK*-gPjj za)cSVQ4a#j4JNym-#07rFxR!Vv9Wp6!#foj8L6+nRaJyXB>j#7qCVybRzK_DnHahu z#MJH_9*=j{Ro{v*E%1>t5}yfYZW(~yW63d!2P6_{oBU_YHDJp0(D!2s`pfvIlgpfr zWG4W~Jc0%Lmk!SIm7W>mA`leYb7k}7V>q^L$~L&kZxT$AuKz85Efi*Sm-jqF$ZH6v z29>QY=s6}%|FeO~WF9lnROY)iA=WrK$m63|(s@HeLjho? zxufJR0IW*^C|<=sjs6xZ0h9$;&Ek$$*$_ic0Hk!KR;AUG%Gg|8WYgJQ^&!@~8F)Hn`d?yHVz4g9K5%1nLZyu9Xc00@2C!vf%DHeW;75kY~H8td_bEeqTbj z@x+OG181RAqobp>GFpvqHh@SZ_6W8=HCUBOrEI{W+y3+ODbB{qD7y_{K;Fc+bar-5 zPEAemK|6z`hO7g@|Kbk4=gGX?=;O2Fe(S^SZ@Za_&%i9VN5urm&rq9l^Y zoqJp1lspaOZ{M8vi$?tf07(*M;T9FD-UfJa#$K5{RSc=VK8R%mcDT}I7uemvV${mK z6uW@*wWX;xtO?*rWYb9s0TOo!d|@(IKr{kRnXXVM^r7oj%H{PHez?7Xrm6dtjn4Ny z7GsBPWrz+2gOMc+ewM^#w1>DW21_Baa>;e2GgV|V+3p=HPjgVM^*;Q<1Z}GI++c~) zyg>KI4Gj&VEG7obVwgC;Uy%&5_03sm*#_2IA0Sqc!3KNVE)Ivo!N6xBjlSp4KO-J5 ZHny-X!wz>BE(IyueUU-l&0c4&{Q-(AU2y;a literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/V.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/V.png new file mode 100644 index 0000000000000000000000000000000000000000..520ccf7418f3c177dd79eaf4403bc453bd706ce5 GIT binary patch literal 4241 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/W.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/W.png new file mode 100644 index 0000000000000000000000000000000000000000..8407f61dd03e0795cff09c7fe113445afb7ce026 GIT binary patch literal 5489 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 Y_c^KT7G`nqpV}?dkzha8;W+Al0Cbj={r~^~ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/Z.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/Z.png new file mode 100644 index 0000000000000000000000000000000000000000..64e62120bba6f0201195d8e04022214a712ccf12 GIT binary patch literal 2550 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 QK?k~bns~;f(#Rv>HxUBT%m4rY literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/generating-code.jpg b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/generating-code.jpg new file mode 100644 index 0000000000000000000000000000000000000000..84bc808b7b263afe3bcb1c4aaa77bba7eeab29f2 GIT binary patch literal 110012 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%0D!43yC3tiq^+ogh<0XaAY8o;njOeI8~P2=&bh-v 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/linking-account.jpg b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/linking-account.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6a6618ad20d0bbf54db4a30ae056d3f6f546d39d GIT binary patch literal 113729 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 KO84o1`u`7kDR3QO9iF2SgBIM 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 OG_Zo>nS!N%wf}FeQn!l$ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/pre-signin.jpg b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/pre-signin.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6b1f9ac544cc559c23a8d7a636bbfa119035e7cb GIT binary patch literal 309135 zcmb5Vby!qU+dewM44slvLrNnppfE#+F(4fxDLF_B2o5bF42_^Tlnkk~vFp6mCWKhAfq>ntXoYt>$RZRV-_UKc+ueu5Ybbo6yVU@#bTANT`Z`~_Xo z^mVrPcXmPqx%s;yboFncFXka{^))r^(8hOk^lxedy+I%d-qX>`kL)T4*Va`2m*l- zKr_T+$L=dyD ziLoYdZ_I#^@!oh4=-MGrkNclG!B-#tscmYSCN|981~4`QSsyGD+M zf*C;&Mlh5Se9;Z!0d@!i1%7qle|zzt0)di&VQ_K^N-Ch;hXDiz)((e}las@!DBJ3fQ5r0Oi)HLJ{j00epxuMo>XR5V|yRpLWR2yju8bl zABN^ws-2OvFUmtjR``O zW*qx$qbLp&yT8K}M=5#d%+!G%&8;}L8`DH)L!}t9Xc79cHKZ-ZL0lV>k-B#jX2RGu zPf9xo5FpP~7kTY>O0QG**g<||Oo@Tg$AedpArolc2JoNzz?d6PA;L_35d}|w zNxopr=$T8hy#SH1CTfmN<-aK6-Oa-(#tl6v5x@SzV1la(vllcSi19@6aEE6a!@ z6Cdpt*WUDR$@WcjF4oxN${ftN(I@vVo+%MMcJTkkFZ zjvI2y;(9TZaXs(P?b};x?yckWD(yPYutiCPgxC1@-Y<(&;ECT`%Z$Yr zO!=mC1vWN0eLR}B52P}yF{(e4V{cRjiI!%5zuUK3&+WL;q1h% zJL1)uejU_Snzv0{2$y}6B2^Rg>zZ|g{OWwdepH)&+rCwQP_|iIT|mg6XWx{2_Lfib z_rt)Yqb;+&(Td#Igsfo#fkWogLUYTz`_twUJjs7IJyVx>zS(}Q$~Vie6YQGoHkmN> zl$So?%CCHtC}O3r&eKbKGtJ8>ZB?>MT$WPa?TOS;;`RxD`4oR2f8a6`Iy-Er*|J2K zasBm^x400**#uf?Z4$e*gnCJo5muGuH3d@!*Bql2CcFe8pzt-w1;_vlnf~3;4V$P# z*cRDfXKV`f*xeS@O~Ra*XnC%8M|xjL3RQ2~MRv_KGx)P_;Fb39xQAcoktIDK^#CaC z%o=nVkJEl%ZN}cdNIrv#=4gh7kC401)RU8tz6k3!5%4myAcHxW1o6&GGTE1 zc#$qbSjy-O%`e30=dz^DddCDOulzct$B*Co|F4r3shs-!;bL=MAJZzXK25I)o@LS2WT z?wUYF)7e>qpF|GkN?7tuSkfla>WNLa5ph z=_&9YISi5=g7Edk?ubEQ4>X(e2RNF7tv2HC9t;@bOG9#i1|1@#IwRq&vaok(1tRM_ zDtVYvN0Vt88LW9!hwv8JrE{WPqH)XL5Ge&Qy%gbl z@Qw3DSP$DbWD^22N@RP4AoF`th!w}6DkKuP4MaG%@YJJ74E-Ta=|R^TUe%QhY`u?T zJ;G7Y5a_7{tybt?B+$>FG74&6y~kSvZtck=bJAl2?;?x^;foAJGp1CV_^KWJ*s4QE ztasodk7HHpgy|Efx9TNt|5yfaoum_(m{TyG-Bm)J!`Q#v;K^kqofCCyeS}`*mJ`)o zB`4ogq7#+h&Lp5sa=zxoGuVtHKGN*}_YDU9M~TQyA_<(e5oiiBI+<5-zVORIn=I`_ zP6tvUa*B25+=)i59Qrn*C}~MtLl&1Pel@XmVFl%$tvz5W%;7fmps@pANzJ|Upy!M< z=;<_?UKH(8g)4|J3KnvmZ~iO?rB-c~Yi&K_fQ5+`L`LZvnMN@8U#n@xyqEE`pdNcX zuz@O<^61!uHk=^TlNdOYYWIWaj!`W`r+KCRc#>gZ`64}s?)@;KNV>?B0+NDchq;ly zj@lXVNl?&aRG8)5++`@%`Sr#F-8Dd29*Wlzd&@5Sdh3nNv5ae-L0^@)9-51Vq;q4Jc!~R&8cpstcqve~M*Ginfg%erLyJ*X&>YCW@SMB{b+Vk7|K5 zO60r3^>2Av85yR~YqZ@kqOql)s;bY2ab1P-6tQ6;|G&3*WZLd{dJFtG+v$Eqe+QON zC0SKj;^yzAoROxF)*|EAI=rAWJCBe&arV>Uv5#K)La8|`?k`(*gd6&kCMkD)j> zfBbLa`ACgv6_xq-KD9cgnAdsKVWS+hw@|c;s@Kogx?7}__D;jUUHeO+8O}fM%+={0 zXXG8vwBDkc`uR33>7jngkChuDj}YE-IPPNFK#xvKNUF0m6D+#+Q=}nIY7s_+T#=`) z-&vM6h0@6KicD=Ia@>3;jl)c62TH?JC@FO($n^0Nk>JDBKIX!{qz)8EJx!Q;jV#MQn%!~w3 z07B`gLxld|ofUR*xi7*?kah}Cpx~ewC_))V7OK?hihit!y5+UPQLdiQE5iFx|+|^F7=CDO1j|km(1DxT3^qB}XnzPNE|MMDN zawCDFS4PSnS;86U`?s9p$a@0GD$xIR#9+`muR9VY)la1EBq440(O2i($x(@I%4nt5 z1N=Q7Kzq^Hts+-sFdm63s0;{=ZC=+5w&j2Wl{`wIpTzP|Kz0&9@zqN}M`(SNK+2h( zY!vhZxHbDZ94!rOs0rK}$EN;ZK1xJZk2$WZcZIqc?F^R^gc0dOe@39M0uIG(sMiEq z)YcbNhxfpV%pD*kH?qZGBwuL21dcnJM$?_f8&$b!JzX$jy^n_VfNao81t2Wx496P6 zAlaz^MKJJW=pjSK0Z%JRb?{0HR>JH2DRVqd$KnVliZDL*Ls*}S@a1K~e9uk!U*50j zx_XFvHy!mYpqwo$OYYFdZmu1@q?-We(RL%#qprm#JNWQ5eT+$+UJ7(VF;I{}C`e07#gifZv35H`mwliIUG?8tA}QqOD#_>)UT#95T=2c+wVbqUyG zGb{NeKllZGem`d8!_a5U92%@qC=wUpaN?L!yKJ(U>uTX&11oaPtzEH@~=Vg{EOip1kvT+e1SI z;iwDHFnL`o3)L-QUK4W~vkIB8(eHu+rD?srzK2cX);>$OCON}KXcQO^mkz9=%11c3 z0wS}AW$8)i8%PzL3JoQKq7GsG>cJXbKw43Rw&Z#E8k~JmZD6c75>*mDWCeUCVcubm zaW@4fmXOx>@k*gYzyJs09vmU0+Cj>Uz;D`j8Tc=hYC}6ilhu`~02PAWz?*RJh;>Ir z;M1Rjk7J-u*b&$HBmAtet+jgeb2z2-0K}(7%1I-d;Z+ zTjFW95Lg)b(Gso87yQliJ{O~qs2o3TQyS%`o%qtcMarN&PqB3re~gg&+fCU{_Eg4u zYzu|>B{5wXX-e(b|;dTXL9WAtr=A)p1!CtWXU6O+WP*S+Cmzki4DBRD}`wS^-HL2CM21H zItDz^8xi*$>^&Lr#2pL`48{SvtYdo;d+r2&h-`mj35rOJgh{tV3|=XL`r>cQRz~WtV zKt;1}B9huS2m;b=5r)9+JcneD9inv=?ROF7VeZ<&iDGnDZrz=wiI{YgJW-P%JQN6+ z=-7iZ{T-pP3#ziXXG$s2bw8!NvX%^q8gl z<>X}1)^P>DqWyuGa3B0y9H44w?%K|Eb=9rx-t$Qb$nFD=ryMOi0ec7A6}QDE)!ct~ ztWT6ZJE#lhKTTmrA{ZP-IFN|1U^Ztc&6O>@ecTud@sW2MVgEkZcVP~RxTn$I7uj=z z>(H1&nz6Z~GUiQwpkfLN%C|3i*DOdmC z#baG1Gjf7y8a)T1sOQfn20br8vaY%2Ud?PdY|6O~=Lq?+Y4(uTr{NM&cS>U=>*1s5 zeq~tgvunxSS0BTtEc2+tMHKG6@u-60-+%JWEELo_H`@NgKuA-1`jkfRrtiC*hCz%x zT}4M8?VC(8#_0vGclp~jG%o|Bb*;pvlHGHoc2ch@k<1fhz2)zf4&BYpEr^tLnATG2 z9Jau(l^uv^^SH@2nHy6kWFdG4Mv+e7z9`+wNkvIf?(4=G3oO&3pV``XW;Z_g)Kvp| zi?t}1@R3&_(%#|iyJ@M-6Up!QDtzkGAMm|b&bc=(;oCu7@ojOjp!EABYsTuQ2`!uD zvh<`hpRj5DPT10yjVfzN^Y2V!D>)kTxsQA={pEGoHqY(P)DF<6n-dQ+bv2zB={08n zyr$S%G)sPw_Yx#9}YUMuU- zLMO}Yt^LEtTjj~OO&fjP19EkhUn7?7F_^`>d6z2+>gzxbo@)6NDpazM>TR!Ot3Dgp zeQc6Ye5d~FE~?@?ZxL_sWm}p%jd`TGU35uV(eg&}VQ+&~W#n{kjmEphTy>M@7L&dL zgv}75$}P?3T^99^j_#TB7Tapv`{4Db7>i_6^lT?G$CEh=Si5IZ1xwX?wMvUo5B0I` zO>LFy7e_m9GMtq}Qj&QxZX!H8m4SQ`kY0%xq`0aP#fj64;tgQvr3q|C^R6Pud0#{{ zqwV2gBedTA$PkuTE(ZNCU;F2fz9(p|jy1?4Em4o^yBft)P9`-><9Cz+ zjgxYs_MXTDpAsO#yDo=lNm8+uth99q{1EL70bD)H6(mCX0B=c&#mLq_){1;FX_YTg zXsvtrB!t4y;EoiUF|M`Vz_dn3E~7f5F@LY1mJ2S!c*3tewuk?<)wytHF2rsyUof(4fRQY1odMtpD&xSgH6-~qNRGUzL^9z7a;n<+n$%)=hp(K*UcfvmHPc*q+;42 zSs+qvt;e>mBN(9l>j;lZB*O*B7>0bpfo6NWNd6#i5^yK)KScKQMFfQsXn5-~L0D;X zNdoQPJ*X_4OO6WE?! zwlC^N2D_Am7+<_&RJ=w(mdCI8i#rWH6p?rw_TG9A%U8noA_C2cxXj z>P!t4#}LW+<|0e{;ANcUrw!gf7s-vt=t+%`$ai}7tXKGw8SjI8-ah7Noq#>lfEDY{~?YBR;l81f~(%AZCi)>K)=+~8St{GTNx${H!uxA64mv65et@2`-% zR_|=b8b4GIkMfunmzPs<$LkBEf3nREziw`O?PHEw_?wrL{tqb3hQ`5}jRxJb%AI9F z!KCr!okSe&UUa0$@45g)UT^-e>>{|C7)EjJG%Rp9ZIxeksOWd~RP93jvzmnz@+TTg zGb%q<8$TPd_rmJ2JxPYKzf2ZKSG{iNql~y2N1jOJ3Fz`1^BT?_2xaRknO3E*7^no# zmrQB-wcS*J{Os<#w$K`?cBq2MeYRY_eqiOIU-m7-^_xs{tZcXbE5BV^n@Nsh!l>2d zNIooHnad4x<PoCIlXsJ!>aUnI=4R27pOmFM`NqG6nW^bGMh9Pirjwh) zU(U{7nROrBrzt%DBy!zkZB1n5dFO&?V!flU`M13(;+m+-(yq8heg-1H@cyASZ-Hh- zs>nUDXV3j?n+?WA59(W8=fwjxGuxlWzAtvI-W9t{61n+sVcnsGaKL-w6M`BMt(9k9 zQy)UztkqN7qb+r<(lws`jrMMk?_AjAvHjlkbB*c9VLn2yRgXEbwph3Rs4z7npU0aC zl2jMcSfcaZV0Tx{0JVcpcU{;=D^9eD2r@Y`gHoKKp`Dg+RXsV3w<+j4gQG9`#u*_N zegENc7zKbDWN`4BpdZvmu_>p~Y@<>?Sm3-i5#9irz|jDnIL5(JTB1~Oj@uywnnt|3 zDWL01`XX=4tYKU4yv&4b^42DjnIj}?ASu!t$Z_9EYy%`)1*C%0mH%L%WO()SHYNz{%OKG|DQX|*n>*3jV(;Ch9GhsfddiQD^5^r&Z^Yl_1eeNxz zHhLBr`7_JOKsn)ulQc!=&nOL{d7BK3Kdmp-+0CZF;FlH^{w`WVo{_y64_KYoXo>fbP#?F47LqmYfvEyNQ z25rkc(&nFSIKRi))i!UACWCMgvcpNYv-m(m_5T?-9_49IlX{~+nQI4Z50CrjY-pF>{kdXfbJ7)A9GGwe;Tp3DR)e>@)iU7x3AHW}s`S-$l9rZYuN zO$YmZi`IvMqt=OakPd-hWP)a^urY0SBB@ z>g2G!50S2I`@!1=%h$ZR?!U>jj9$oRC8jw4c<5a)UbPS`dBZ3~N#A8}=a8Lx(>~{2QC12e*o~ zA8ty`X0rreYecW0mv0n*x&VEKYqu>F_x5v|3a3zs5tj2IG8qE19yi(_U#n$xZAd8U zEr`AVy=1gMQ8GSQf9D#^$$j&?dM=M%DW8~Ie98MJ#i8dDH4@jP6{|DbwkEAczml8Z zD&fnI&9)#W7<^fqVdQ+-h;po<<3926FL_urWL6$o=tVgcqpekY?Q5}+GBWJu!v`m6 z_2a7<9-;xq=10c3Las&Y$2g%tkDXEG~W|I)BG>$U+iFQRkIa0)>-JaPugUwb0 z+8%i?s~JlxImrVmEqt0s-zmm$Zpy_|D9Jnwr%bgfTV>aCOZ*7Ks7am^t1=IipGfiQ zb^gSA39~jy_rR2|t7}lnJw!E5>#cpH?Wh=$zijp5Yi0?3$#M87WvJ05nwU9ci9i_x zX`MfnXo=Pod@5LQex*&+xF5f_515K8s2E2jiwGbAOY0y$$4D%#af}^@&`N93@3KY7VfF`a$hsC;1cn#GLI6U%-0Ob z2jX*B3S4!i=OeovX7-9DDfUi@61sC*l^E2$cU46>?WO{{Pf9eBgr0-6PYHajJ$daG zzjQ85S^7}ey4E^*wpoW*dr6jtP2Ux8!mX}CC2BI;y?auxwLD`pS~8LOcKuDtd`n`~ z4=uV$cqNSVm4Y<7g+%=!R+VJ>Rf@uLBt*-g4|OWFVTm z1jJ0ehWESyD0Xr99It-{sMXFL%4-UB*#Y*TJ|Z!J2J!9hFvu4HnAFoY0^|c2V?t#V z=jw+@Dx0dcK}&U?&mkLg{HWgA{-OGp2SQah{fvmliTVH_s1}iJMgqtcq9VGE5#Arb z`#65`jZ*+}+(%%>Td<6$0H6p4s1DSvBqS*sNd2)rLc;)fa}-H;BZIsE93%#nB|{>- zR^$b_;1&;bA&w=cqfZX(DNpkqywQ54+Z&SQSv z0Ch5AIpN) zcS;5JmHZg8=ga8mt@!qRa+Yg#c`L^ezdl2GU&PCV66BiUL9ov91PzmIAKPpgM(0P9 z8qOaY+HYfdZ1Zx+3KBl=}-e1?=W*9`LKoT z{+f>p^FGP6WN0;v`ffo2WBJ4aqB-%ifZh+esh%3oAhF@G>NmKChbFN%sy^OGwUzW_ zGjN$UUQzLDoKM5BQ*5>JI_yr}+dA(N{S`7+bl?Hxl|R*XBvXndVJH?kClyZ)-`tWr znz1#!`y-HrC4wwegv=4VlT3RgRp!1(m`r74HIaM(9i}U7ce+))LN2dyW@Z1G=^&X( zCTO_z+0a3U^&K9F(6uGZZda^${{xr#Ym22Vygc8M*_pKqBlu?{F$o*e$6 zokKOcKHL&f78_}~tzWSv~g?30>_c9@VpwQ~2gjrBPTwSKAC3pf8!QT=)< z*J&GKp4_z>xt~?^3PUQwZ!F~F(uSWdcrE&}qA|xt&STB3lO)S116LBSrc|c5zg(Np z)lcIVn1N)vv#OuHvO!xjPl^vbTf_}bUDp!|Eu2N3&wc);s`kreVaM#}cKtJn`udb5 z2lU7b=Kb3}%{4BHS5A$)BEPfTG0`$x^ep^n-Go6)xc+X-s?9RyTCjhs+uln$!JHGC zY}H!bT8dh-7z_GNHs7k(Jipc8x{#2ZRymyO!ssPbQkp9)p3DB{hvSCxx5;(CQ}@Wr zR@ZtdKB?XbJ=}KsKJx7&H=poW7N_5}DBJApK=GA(-~8XiXznL&Y<54jCL{(8_R8t{ zZyx5}L5!Z?9g?B@W**m@ME>koGH=4?T0)C%wQF(V;M=8yWDvwVpfiN^6&;;Utkp|S z69tAZbyrWRhcD%j4tXZM38SV3 z0;aH<^h-->?Zm}6?e@%_vxlda@JWmb%aywxRCj&LIl0H;gMKELNqyZ8C^V}NwnPj4 zy-K|zjK0yU(eFz^tSvKErs`%$Xxb;A5 zNQCz&a!QkK7(S)sk&{6wnmXTx46||ShQEA_> zj83#?`Vi6sS+YGWiqTZv$?Jf?n98xtubn-K4R=6d8bA^4+Y8LFj}hT}Q~{IjQM$HE zEJpE4_x)ZC66FJ|4tea0N=vKI$4eoinAfFBXK9#D=k& zp{wVMmvsA9Bq%OGZIP}$snkX(Vl}QTd{;gR_{LP3JZP|D>Gnc5*%mpv)`y8aNn93M@wGYN zC+CMPo)b8i@o8KOLH$lvJ+lf(DP(B*Cli_wBDE>@Ez+BreAgYY6Ms4#u-;~@>mvZA z#a{a5HsaO_?ON9bh=wSO7X!mFNJ?2Ku%o|Yz(LO7$s;_u^apTuCV(afiH13W!<;~S zcgZv$#{v!*S zM~09x*ireYe|fn!>@t%04}AJ#gO&2Yc?1yxI645AfpB>Qlx)I|Tu86Q@|tIY0oc9& zZ!H`^UP}_dCrr?EB{Aqp1LO!tri_zX4@OISkv)FO{1*8#gEG+j04Mt3+=*p*zSvwM zI6TAJyhNZQ%l_~Q?MmFGN~8J~HE(2er{>%VQ^A)Mk3$>;+W-y3p!gnjT3Tl&J}Cjx zb>5955NO&6*y#{$Q8YA~t5;Q2l1peUcs8)(%sMhWyg$og*4XNC{%MsxcdfQ~sAzO4 zlOJ|y&2+|=^{8L`0+ikUcSD>yV#taq^8%FN7A*GSQ4CBjd*(Xl#_j#5oxejY&R74& z%Ig7nlg!R^S4**%@3_MZJ4q?)AR+vIsQbueqib4@#fi1@#R}w+#~WIVTUhY zbd0_d7(O~~nyGo2d)m8}yVp`%9#VJ#;ud%{-!5Mwy7*e+%LBc-ujMU@hEG1MJt#f7 zMAbN{u z=3&Uv?b+#bT3xrbJ~dV#8*EbdYBbGfOiWy|`P)FrODmpCt^iitra;OsaSitnj=nlZ z7NUYmpPKF+p{q+Bk`p!DfJH38T=#$y9n0Uf6$^$2K8pXe*(Db$gIdX*(p|b^DDhoe zN5v}Ti*v4nCtQaWM=`rDOE1?_YPu#wWhDyemclAELX$B(*&WZF(&DyET)#C+Z z_e$L2BDiut{O--4y^{azX`bsowcLHux8`q+nZerm?yHtxM%%8)r;U!!%=;*nZx z2|Dgfd-a=pj3>0r#O<<9Qfxj`^Jh4&^;!s1jabkz;=r0n^j&f#zX`&}^Yz9!*Dhg`3a_O$yQg zP}~vvY9FZtVwiKL7v-B>jy-HfEB*;{f)!%9&<{dtUVVV-MBWLKg*8V#hh!qHU6;2| zlqMX$ndPj;SFU&4DMOY4MGU2vg&`42&btV&>F&t3%t0;f-1#ST2aLaczGetCZVe&E z*ZouOR0L=VYG@ffn;CbiE#H47(q~hVUW-a?AGxG+GqPJffNXHCH?rGtei?ONcMV^| zeoBZT?EWtAA&m0LJ4B++oebXlQBmFi$jK&W>*sBHSv_Z!A^rKYrVPpJ zEYB>TL_c1FjC7wF#z~nv+!)JtCU>S2pm8K|(*I~F;bS{QeB?`8(oQzf7;$vn7qRR} zVWPqJ_f>Mgp@M7!q6vfsxDh3`-F7(oe)yXLsP{2WvK;IV&3+EvN3(^QfFJM!IXNi` z`cY)qBK&VJlx+v!OGBr|Oe6F_46;ZMP!;9ocniS2SgvruDnSDp(`fJvd>Y+)d}3z( z_K2i{tIX8(M-{XI#OO$@^iTBFvuOe|8sL3<uC&F-bGLckff5Q;qx+1O81rw&AIcF_UYIKO^EewV@blG#BCW z`leYP2k>zMFd6t`_j*vR3j zHejHL@^c5&%92wFoeeC1bfdc}CGWH(YOk!Z@sQU{y&6j;sTscT3hnQtKeNoG>USD$ z*qt&e7IUHpWkwv((X`x+om*Wj7M{%Z@WOcb1s%RI(4E;vevAlmL4Lf)%t_(%%G4jv zw$F0aMConLhYQfqJ;Rf0Enz;c{%=w%hU!?<(n>RY)AeK3NMDD%#l_aC4Q?t?GGfGe zm8@0v+To?cOooE*wY01aElg=YC4RqUV5X&cmF8JcSk89WkMgnxKciumTL40kCGOP8 zVe^$$a=Tg5X{_pY<}h!r0bg`1p{mgw_bP?8i>%7e-$VBntw|GesI2d7;L%<8#)>?K zgxVK0#Yuft-G;2QW4(bMVWyf!TCzNrSb+sE6PWd^P%JQ22@ zR@b$ZwJaVU$sVZPO&R~#q`7kH4cdGW_UmqTQd25%rA+a%RrJ@I>&`pP+2&U|%#DZ8 zG-y&dKFFWV}V3Jl{|(3(QiNrF>qW(;CBsf$yzSIbof|GJxf+WIwp0dk=0()oOAQ6aO%z@aG1 z?XozvjHD*ab7Tvaw^`$-3?DzrRtX`=qOt}!grX#b^KA2J=K z)V!;UR$%t^bcQs)c$8v3nbfp$Ir-94T@Tk(AN%bdLv3@(C7-~+G>6TdpgWMZM=m8d z9;2-Wt}gtQ4&6Qy)@v|vU)NBUOpq1c)l&>hkd+{?z>O)dC2Kg?AMvF>R&i)4Bw;__ z;Us?Watc}iM?7eyJ zTIMfqdMb&Hb%b zRbDPeY%!HAkv@@7+pHiAI5TI-KAz#UWjgBRP^_0P>GwySh!~9|F;O^a7vO3MOhy-= zSl#XLo&e29>RnQ0H-#MFNSiUd!~x=l12P1yRF2&NC&0_`;R|Kd0 zoKFeSA8!VSuVE=p2?C<*f}GKH4^dYt=8!h;&C=d7kA?O^GCnxjf!&QNh)M}1C>F4=SBPUIR99v7(8r|!|bZv z24Hxc8^FHsWeFm{H6=e|5Xp{v4yEYqN4CZIh`_f@9mU|vrr5_KwC~juAhT4^QM7Cn zc{iG84HO@j{S({Yi{$}m2YJ4e5n(3el@Zkd3eyY@nn7hcs|Q5rD60weJ^)(`Woq>xiVc$YM!%vgt@s<*=t>*^=$OW))Wt3%R~!ak}KR$IjBO#l0HWTx=L+eB|Wg zT|&m!r}s4-Ay)nR)`TQ*9Y; zV!`a??Nv0Ie;DZJ8)exi-epVH@O#oQK9oY9+D%VJ-WE|5YY;C1q)3i4YqlSAhIY_S zM|P_SHx{b+C1mMC@HglAxG>07yN=bJ{Jw%nw28`hyq|329b|2sanhTPOIi*sTA~z@6Wzu;! z?%fu4c{x_P`h?9^-3#CRKDsqwyC7uxB|PJK0u$eoFZ7A~p6bX9`mcqZrM9h)O-T`9 z_%5U8pA3h&k;U`%Y6)0z#g$msr?G~x-rrXpNq{#sQub|3Z+P;&^yjKcRz_eAk(KoP z?MZoEmHU+IIiCnnbCx5HjJ3q<-)kIkFpC-*%&dEY^s*q!-E}O=#8=k z{3!78X}cTJzZzmxg97 z@;a<6uKpY{(WD?c)_-kYzVgIick)={gaXC=R)c^0<6PH<*H-gVXl!KxL4`w1kgtRB zoo3YB_{`?!y_YJJQQ0|Vzmk%oqvNE_)V@_(|7@-L;h|HbTiS46C!hDqI}81%H8Z4} zf38jgtQnR|t07h#zZ-ol>TL61ZeQw$c6yi{(V9NKZ_h#ozl8QS))3*= zNWP`?kSjvvmp3y-NM6(J+pX<)seixUYISpaZmxdZnqjxo=cNZ57 z82x;M>-`b#1xES+F}C(Msp3t6r~~JH2Om+vR4i=gGmWiJCu2#;1qickDqj^i*r{an zB-TyuHN#(*>`RZsDxNhQdM^%NfWFMMgqZBl3fCF9g~-P0t?=b@0GtyC%ZiLpk34YRMTZtR=(YrEe5&XpFw zpEETX7C+9)*ZckSOZ?VPse#XQ2hDX8#kACjZ278}+JRMU8^ERGmh!PBePIrEc-oi7Auz#-J{@@MqVX{CI;FIX^yar}CxRHWB~QyIx}a!zlBh2FOTw5O9z9(=_|{ zpEw9@Nze?XlV&noyP*{`L<)-Y|>ZQ~zmh@|tN0 zb)`}n&31~un)#{*t|~%Hlyism0}1|VAOpyGWaB}*=u;5ORpku zOe|Xzp=6y2_CCbl0BFikXCy+^5-kzUNc&l+Xr3Q++e`TlqjQVH;iLZ&4PKXKv<)T+ ztZhFj8Ck5#Bqkeo6N{xhr$!{Yc;m@FD*K6Rxc1;~@o4Mc6!N_Y9&@OO&Upsqu z@_@P}PwCb#H4~8Hvzfj5t(0DArly8AYvGIx_Jb zKCGJ#Vjj*`)sgwS_2y1ex<613O#T{!7a%rqR)JmX=f;=le@3GEB3++=wQ>P`lvXNV zc#ojl#W}AwZnII|&~Xe))PGV!=F934{I-X|SfV)U-ZgGCX%{%;;b)U*HB=OiD`nc$ z>s?D!S+5q)HmQB;vd(xPZBfeA^r#~f;-L+m+`->)zQ2sL4mSZP$4ZDV4*_K>8^!$+ zIJ%Ju4KIhDG=r1^aZ(s3@-@J!g|-o7nvuj`X0mvPS?f#-$^H`pd0Ui-%sPUc{zWA; zMHcIF$^eU#g>3agUuB=nL^R>mz2||mc0e3O@oEN$&`5m|;Q>SeQEA{Lk62h`VE(;b zW*T{)quA{i5sd;tGfoAQKmo)QE9@`S8);Kb0@qR|9PI*JKM0uQL>v6Yon{+A_?mqTs9r zSo9y9kZn)dPMRTE6wL4NT9g|o4o6>DGnte6NaTyi5?7Z+E#-3=-o1zm&}Bt{e=^Vz zsp>J^cAxyn{)~l+bBjqUQk!#3E63Lv>9Xl#h7EI7YPsH4WKy4D>p%MNrrO5`q%b7XNN+#n;f6v)7qhplIssqX72Is#iCboE#vo9zX-Gs z%tTRKHMaKZIb#4angK1ke^`@45BFD{#8=`#8*qf=psB0B%!33e}~Xn36`*P2>k-%XTeQ(bws z?tI;&cs+bjSHUDbl`U;*l|Nv(<&MHh-=7TQoL{XOaU|2kuU?@fP~I2BLf(woTzWv7 z$R5SB85UZjv^y^oQh8O@;+zZIWmkAmr+C`>BAP3{-bYd+-h_{z|8gKl|p~l zms&zJ!0$MJdcm8fI>(knbA;~WIM3Y0xsZ)7MdG0Fpkxn)R~%cNmxs9G+LN*BouWv^`-R)qvUnjy7T1d zrMnER!%bl-&aDruJ%amc5gBU#cc%Mvh>;}5b7{a2M|`GAAhzLSwa=HCZJtI6)oyJ? z!L+G|RA;E9UlS8gWzz34tnwdT5=nP%s#(yJ(7>5wJ~;TZ(|vH*6&o`hYFYlCC;8pW zW;tT;&W|_0h_}0>{)X$NYFu}Hf3v&&|4L-Akr4IUt;wg;qu!fTnM(hWdYaj5yIoLo zdG@j>>_?-^pI4I}KVy8A+&>+#bFFI1_sjzG7RI-K=w z+YC;F;=>-fPaL-JG{Um|tCR~~zQqZU;l<7fTbsIe(kl&JLM6a(7dm4-dFL+iLWwgHu7D@RF0R_sXT4}?O&XuUo zbdG=SpIIyMdXS$K5}`IA6mN15SoMUD^)h-dQ0mOq@cz?}hPvCRwmxJ*uYprX2c49Io1m*$dAMP0Y@WS+P2+t zIs=jUMwk==ryFCQp#>pfhv8S*TNmy&3Tl>Wo-UtU9RYhX((|`ZI_?ER0+bm`QxN}w z0XTva1bFaQ-bBd8v5c>WYrI9N=>44ML-D9Q2aF46VHBdcsSI`CHK}EbiGb%4!xMsV4zj4x-PpAfw4}_x zMm-DWCe;H;eBTZ|4A1-?3@kTzxDX{VbT9#{aUTo?!9+9xND|?iy`DgXjDgd6!0BGV zO5W9jFCOM6b;ZC9{%Z-ysIqX8<`%nh2p)WOMkCQkzIv9&pz+YHP~^&k>qei1Y?E}9S-Mlsw%2>YB;`s}4_PFvB%GjoVqQ-YxKx!$=4r76>TRJU$th`$9iq9j& zm{ZUH3xP~F(93`P%v5meC}J$bZ+Wvf*5!Bo)^r2d6CynTHaJ=}WQ z^|G&Xk4*aY`>FISYo)4-)yLrnQS&zi!m{HxZRI`!H(jXkfx?_c$D zUFSCsVV#KEN_9-sh>(bj>MX2C0mHTAm1Y6~Z}EOLpFY3#EDTS#;jt@OiMRoIHqzE$mG3YUltYoL zO*5^zJPRi?#MZYuDMF{6MAH^zJ4;*5bf?_kpYA3znoVZ(-wAiwJZt+JJ5@C1_Q2pE zDp0mU6~Bnq_@jxWU>>2A|6x(t5B7=7h+Bn$Q)!_G6lJEDcZpwnolLTOcO+r3k9><70Yu^6vtuKFHpM+Q7 z@M6xN7L>Eu?PRqBLUXcYZ?V~PE=s^Y z;1KyG(4zd#xZqR5 z9W+fbcgo}R%=uJNw-;3G95y!`tJ1E2l^;0p5kw!a@kfY%cc{1W8R_6%D_>9?aoS(+ zAnO>LimU6X0dfDV0)=tev4m&MFu?v(j%lb&gC=ML~63*Q6F4 zj*xz%d0t2)VkAdJWqGR0)=f#$RF#aZ|2o=4W8B1eqJI3(4VVu@wJFDtrsB_*7?BhQjk63AtsLjv> zxpJ5pwM*8K*2ik*y z>-l{&693_iAC%}Z7BF+Dk*#kKEr9N`znrS$a2OJeZTE8a3?bx*ZMU1B6px7l>E(8A z-chOQD;%{N=&h}(DX@p+Y12qd#JzYtMsjNFI&1Y80vr_y1w+0%{Ar$B>y6PZcb=uM zG}c&k`@V))l&I5)T$f8cek%>Hq8B_==lquaVPW9bZu1A7p)43%wyT2y&G@o+v zi=E79)5*AzC$_B%#o}7L?hqN@>94)pI8B0w=y^DN8)-C`1g>V4lWUs9%{TIYA@2Pb z!J0iAyaEK8cNC?B%Zi)DL zfrV?jbPSvg4-MVhSZ0RbXEiw@7$LmCWU3Qg zs8Mu;db@I9f!1v}c}le~_?etp=f3)*7SDV)U09)17&b`@jtwwkzwj|Q=i>LW`SsP)A?3ig zLM5lQ83=v7A>`um)FGp!2aD651&gNkH_xWds@q0AsN_~_Wb`Hev@}RW-hKYv3^~p7sdGy6K6rn4(3Ywy#=BE zL{wkhg!RQ0`Lz*XA#J?2_MC~Gq%tb|2NunuL9B$9quFZy`4x~$y4s6lg1 z$@rTSX?032`lKh9pVDOVMx^Cyy`uJaug09W4pU!B8v6QhZt^Jo3rNRFT2|IuoJ^%_ zCw58mC!Af_ABCo$=t`Nfl|;olvJ*XQaUbyO_HuRFb9yX40e@s4Gx=ByErwF~!s%-N zfRWhj@t+T?qr*(T>Q5_uV$pf-+M!-a(G~OOE}fmCA*WmX-#0A%-Ec0z!9RNM{H2yc@B2{(A}&v1B#* z3n{kWJ#yQ8Of!A7_x9~2dUqwdgXh1nJ3VKy($wid=5`+2-)-ygSwr}3~ zMQ`sumQ34y#ICyb`cpAke(h~#&xOQO>&Um$Q^Mc9BiJ^2zOX)gab6vmlH)3f;wp)m zZarCLlWg5OG+`LesAPky9&qlk$gm*^xEDccH1+GS7ee>)<&Ck--P^!K5W9IR-*ubF z7{l2&;9nUpr}ZF4LnN2xx8OB%nEnkiF&qkpxK@idfPv;ITX-C}Xh>r<9v&M(fOnP| zkC)BM3SINH7$#ufYQgTEXC5ZNBin_G+59V-pC=4|N^scw?kWAw6`)-kJ^@z&31T9@&>yDJOd7;!2xf55#e>i&#OyujAjIq+5C(gG7 z@fl`~H85pP5~W=a3IO9vBMbPUJ}v#uWaV(6-_ZDUl7Q9g$n*3i`lYiu!tw{pF`~hy zAEFe&P;YmUhN&>JE?7)8lKq{HzgePfF){#sX|CsI{>jj!aO`Y&%Dk)=z%8KPbO!8X zLLZEsmQ&*$K_x&GU*6bAumQzt_c`@fc#$&X-#<%8uI_!9?`@-IZ6+_flr zkd~+i$d=zxJT$-5h(KPtPc{Q*T#cx+S(i|Q$%u*$9t%`b+~r72*=pdUN#D921crX1 z#x-~zh_Ek!PMH|m9oRldI)!r!dVLCiKx5OKgVSTflLvAeBILVq0;1Kbjo4;(agUqp z0xW+iNiGSH&ZWTqLa42dd#SID5o^~HY?{um`Toh$$)EIUg+r6{#XmFZ5U{>le`SZ+ z@aa|bE&pYm&8x*(=O=HbB9yt(U%`(bq_Bvuz*gHcRxbmCSjMKM8%@bS#?><|ss}EP zIg{B>!M=ZK1VkwXp*{E`S^h>PY5ZYpDSms3tx(C3ICj<#Rf5i4*ci`Ypg*tTQt#NH z7?o04{zAo+q<jg+M2ZEY`2|4eyiph=E~3-^zckfsTI zc7B0WT=D_ZucDtTW}I=1)f-R3qYhifCFkFKtQUFFpG(AR#xS$t*B3;{L}J%!g5P+-&OpM<{F0|EnS7FTHN6F!C-1oPUq=U$;6KL*_rF^-QQVr{R{CKNvOFk z3sKeN**{m15D~FIawAwU32goLRQYRNqkky3UYRHL6hu|-yhwnk|?ArBL%U`?Ke%bQJLDy6Xje({Ly@Ib|6&$)A zA}HF=^hNLGjRwY&X&6RMU2!)%yrA_z+<26#c;`6X50^DJi)2;OTQ@ySTET3?bCJ#t z-EF8(+S^^u^Eq&z^^nx4QSA}?t(b^XkhE9|yT3D2*;`h=a;mM<_+VC@P1)GL-Ynk&q z`5URd-(-A`t~QC=>N7Nyxc6SsKI`Qa)Y6)OJM5FqsZHusyGfqU%zuJXL9+%$mU_lf zO4)%0Hp)NhU#>-Lw^ox%b?H;#u>??_j;D^?@syKJYhTtS@>Zi_b3j2l%a7_XE9V;< z&VM9-X&ZV{JE1tQxAB49=|hh(NPG&v4aTqBawta6a9{?WQ zIPe_e0rZpzrS9$svkbtkF-{nxv^)*Jd_Qx-Tm9sSrr*Q&(J}|I%pm=KkL+$=j~uHK z2QxPp)jhH$I0wK@cAMP8?>d9N*3~5wv?Z27sI$c5u~$b@82qQZz(oP6U0ge_J8}B6 z+#$qn2>lCTr;R;r7RTgR8>pc%6ZPv;)7H*Vs@`-Ni*3F};3Q9xd!}GYkRClDxz_Ok zKqP(+LsFe!$sdU&PKkUIDf$NirfLYYWSqELTk4{#;fY$7%2QqitDz$(Dp=l!GB<05 zOgEEyPpTF5qS%mvCg5>&YEULbSGE(4KLE;cul6GYHFh4N9`2aoR6Sch4YX@q%5(gS ztiKR#9RJ+rj8^KHtnWO19RUx!7GC96yV%?%c>p9~t*(Y%EsOA7AH|R&oo5;$ewf7D z-k+jN9k?U)*_XBu(61(ZXxfAo%!IcL@Dc;eRHG-c8wh-3_<(*agRZ3o#at0g021Of zvUB-FKtaP7HiF`1-*SLb^eHt8XosK!9R)q0A1~%t(qYV5$o|56oCHX019I~WU^Nk> zcF#Zvyja{9!59^8%O`NHN9cpoh_Yt35x5&~cUpcp3>PbeHAP!a`SkWOtw6J zwIW>zagxK3d%>p47@lA_SLMGWuZGZpL%S_?&S0naAXWLF z!A4nGdePlK=UaXjF9VUXEj+YKuu z7{2PNz@dwe(`(ZYGi2(L(XqJ|WYHANVcD8|ys~M$cg2-_z(RQCTfb#cosg1@3~@IO zaD9$$G^$1?Dmh#w3#NL+fD9X!{V-MW&8?~uqc$@>2%ocw}udW=i*<&W;%$hGe5 z(T)|HC+Npd6?bImbc!pA%1`1<;!CA?MHW=a)%y0yRy?bS>^Eynbmp~aH55W#-Vj|I zPB*^evyUyLtXFi5lh&DSUJzWV^|$zGrSl5m71+(7#HlmPFQ^+tm(4djm*wU0mHG2S zf%cxuRXe66fnVKd6xVGTwly;}d3QG&B){LGKlF}dV)=%iU|p9{B*&agR0{4&5iLtu47j9A|1Gj6UKfW|=$#c<6H zNDOIb2qtig-_QR7p0%$v%##oRGi|H>iFLNL4Arpz!8w_5ADSVX`+$#eT&^E-V18bS zQ%;1k!z7h3AI^XLAu<9h%y}Jo-4h;Vx`f~x5EdK2euXgf5-8=46@Ox)g}h7jNZaey#p+u_#P0IVyr zdXRimw=I@dpcTSG>u~BP!ZjpMHpjpeu;P2x9vDfUkj!nt+8$DF8c-j-506oTykxsS z7-Bax!->Zk}!e}ZNV9PZV$dT&_8Yt0iCF*$tz#ofB{wsjw&!REf>Vf$c zF#9+M*;((3DZY<}t9b>M0~}b;Uq}V!7zk1P_mRh>edSXj<6%y8d*KSB@6tIhBW?~; zUV0iBB~Z&JHXp$?d(ZPjhl$X*j2D;m@a8|qWN^b6 zX3ttCZf%dI{YK#!6`+@>lMwDiajQ>SsRM?OL7oJ-@^8YUjIpzt^oSKA=w#G*2l*qv zTp7k3Fcp;@U~jQtGKN_5o1Mp>1QN&Xs(n(Qj-TmF(LWEruosyYcm)bIWn6(t;u>O9(YEgpS~pHh7qR>Vh& zTt``7~Y08@(KtYgg>3-RdFKXeV>foO#sB^|sHoxuG+8 z<#96e2j|mP@xo`5y-Z5p>;3#qEA7qVlB=WNYF@iqGVFd;?Ec|=TH2sqqZi1c2$QBy z7&<`D|N7+D)?9?6-|5&W?AlP^NN>)e=RKudxV@gX7B}b~lKacoZ}FQDY1!+;sS^hH zwlE!<=ZQKOZ>tTl6G!_+6Qkw#guSAlUSCfb6o2R!IM~Sy)L{tudv>jMzT7gYB2$r2 zE`3y((PCl{*6z}t6=)u9r{sN{Hf$=)%wf@|@0>e&I`>gLt){$;s69clnqu|jp0u32 zD$cOEZ+Cg+96fuKby>VC*v*%#wFY;^7NBLLXzXEgAPt(& zQVZ_x>YffgF&2*iBJfj1jZ7r;g{lkx}N1Azx)HIiY%ezBS6AK-yS z`ZX{pw1ij`16$vhUmM`jjv|**-y^|gS)>I!j&cTX8D{dCTciW)4owX0uenvj+~S`{ zVGYZnan97S@)hp-NOtp0W$}q_xk-C4V8)`!P5EEHsu{$Q?U3;WgK?ewfzpcnGn2ko!<~W6bYPANog;cLE5imJmG>UrXTW5ZOIPF&}mR zYtZWQdtLVS*Ta0L*~b(kB#RPikw zp`v(!QVDUO2BEI_-_WF5F+#=c!+f*_>lIbPiH&QySfG>qJe?6 z(1<|OC5-@(UVK!_m1&R(S8f-7R|;Wh-FQT?)_G)q%Dlvwrvr*Kf8pm9>VDI4D;7$E zs2~k$AQnztvy~PDHVWz%HHj@ggm9{@mw7i9F_+oA^2dCgB;4=C!-*;iU#U%%K7t#P=l;R@ z$HLu0MAs3bfGj8dFN8ouqI=T4h|s=dqA@coGaMt&LZ(A=zVdmlMyCYb zK$&F>_3BX_jjxAquqm?ak(QjdA+M zUmVj5W7K)&Q4#VFPOQ8_-ekW`y0P?Wd;7@wpeCk?88_DCv{Jq3$2Z~#zlKRIUp#6? zBI?zRy{yb&x13Iu6lPSz7`8N|JO$P=zQg)FSpC>r+TnKu_+q5L1$f#jfS)JHU z_Ti{|cQb=^1e42L20XgAkua)0SYo)de^<}I#HGK#&ILRVKmy0LM@X>V`x-V4eyL2q$ zPx@?^IZn=p@uQh98OXx9KODBn^|Og`n22t{4ML}olRq|fmey^Vuw^PM(@%pYW>b*E?2iSK8l7 zhbs+4%1x~9JE*a*!8rj!-}PO*E?lAC1GTwl$LqYyz5Gtt{P}K0zcn)-PWX775wm5# z(W}RqoX~ur4;O~V&cZol=1#WYpXR7n{!@F-tdsGJsdPQqzwL#k+@0S<8LH(lU0r64 z&I9GKxG0aq%k$q(L(XJYd-kLx{JCPG=-C!^G!~Th<1&j}coQLNX4;LdgLMea@ zEeOK-%=iL?4IGRD7dk`~pPvuQ8zUOT-qR&YpyQ2F$e9^C9B5T}aj*X=8kmcVgG8ZV zn@{Hqt{y%T9uDiho5BSM{0sfaeh z?I7V~RTzHgd_@sczi1p2+MB}il4gEm)rDPs`<^cf#Zg%Pof#yZD+*X=`q6&|$;iub zZNb(7m$^zJ*Fn++NXW7t-YVGD0h7nZ{IK{V6J|aSRu(LTR|Ds^7bWJ_{%@!be+x?7 z6x`E6MICU&Sb)Ey0gkp=*doZM0+#>3!OhY<9Iaa_%apf4rzb1}a7>=K&0x5`47;A- zCBE4Jq1LVn3@31YJ_|j8w79`qI-Q8~HG>TDO-(bg!+N1lrf?3Rnu)m$k@#$5PJ|~U z&EysLHyUxvG*xf1v<)8ylfQU8LiCn^!Izk5r_b`&eZ|)-WPk!u4_+0QVw4-l4W^m1 z0m;m(BWOye5n7@ms`qMLzb)sW_oX6n#N=Ks8Zl)`zPUD#mv{_IwN zY9-GnH06V;{S#?6j8#GDW+BP5Oe!s4tn=9AHzDI{D0w*0V`^!8P=Iq;`*T z?zWy}h|AY1mXZcpyZihPM;{W2&wYn@1ix6>H?3Rt8#~rxrSwo5vBHm{e$$0B+s|qs z3pe3(@F9G7PeoQC-YiB6=GwHj+k!o%K>1n9^{5d$i2S3Ps!(j-AV>PcHXak1k0uFy zZ4X5_1+Wx6<4MZN#tv!Bv!_hcoP4mb&8E!EZJ6z_EJY}?a~V_*l=(h%Iw#g`e{Cae zap)TLm~| zU(r0#=FjObj!-9c%rUSLq>+{&mSq}lxJfa|vwQKWxTJ(YJXD7dYgoG3CU!ERu+zp7 zZIVMmt)r*jR35OO*6cyb0Itc^WoaWbD(8zb9quy~8*(Yt>4~m&e7?2qc6;LdfMsi1 znsNC>NB<@V&TPG2ushooKIarXMOrmOK|cLyO1Qnw%|+tu%AbG6zkEU8k=r^(HZ8#F zwFx_&^|vd_iVS^UCwn?OloM~14XDX%g5TpTgMREAeP!TMW%S&%?)Gs-4Y6ywF>|_6 z*Da@@onGXuwJ}PmYoW93-)EV|OeO`M6erjUDjD7%TQ1iuI+=?MG6hmbGoS0oSz1X8 z)n2PC=*gtXFTsAS8Dn?YFH{9wyNWt09;Kg~y@UX!qaOB)*LZMJQ$s_}g0oKEz8*Ca zVEXg|F#`A2LvU{xaOTB&w*(_)EN8-%cn$5rg#k+x28gq5vYcjM^_dsbFFm@F1cchv z(qVLx&2N+%8yGFDp&oVC;HXO+XJVP|hQv`7?Vlr@x5`ceuv=gs1)o%~{+L(dSIt?T zsuliz%B!KZ&9DTLeRrpnsxi9ot+V^ln=j3jl-LgGT-Gmt3%z?jQIp0s?W|4uDfZOu ziJx`vY>LnTICJ!M`0#Qar3ZXUxC9~(e_SIBa}>X2nZG)TyR2RMwTkZa?8$JszZYOw z1b32OMHwaI48M@_L@rvONlN6BAO7T1oi+IR(u#!fh5hxS{sZs151xfuPPi9<2ZL2(R6$kplTH`KARyebo{;!HaW-P+ow`@A;#Izh9&5jL4q_fK?$9-?w2j(SSgP z)6y}6d)>iJ`T}MiCS-yY<_OMF3kP5H=~Q^=1scgZvImu2zsv`$YjUhi%ryTt4IC!chuC)Kgt@$x zdLDlSB*VR42sxwCPXo#ENoPA8$PA9GiO(~Wd^>lMflDRN&f+mHP|Q(~Y#^y#K&2fR z8h6WyUSohiM);k61u$}&N9EXf&b+vk?%oK27O=|%6A}QH2H-Q~3XQ>n21UdD@`FS4 zh`=12rY=(d3ay97LUY`YahH()FK5GmtcN~dRig^#W|##l6n>1&!`!b1|7oqy{UqYS z-;*4f8u;O;uQcc$UZE(O0KSo3sdBYyzy&ZPciWB zv7Cu;7y@rEnqTGLKR4hNU(+RK#`u5uZRc*cq*wVjWfaPi6>}A3iwwjF&34p2zcxfS zJ^7-!U1N-_aB6ThK%|a$bJoO=jY{4T4b%iW{8>6}I11xrinedk(IK^NQ0;F!wqVKB zz0Q9y9a1;w|sFCcPb}0H}}z#in1&@sI6p z@6ycQ;}=8JGo`e;DYiBVf@+@+?;3Xk62-FPN#@neaT{JV=tsv$Z#4i2lz^HL4_TCI zrinp?AHyj%v;Iv^=g_{}v$5S>-+474$$Ep$II7B}x8Gaqsmhaw zt||&VZmlQFmluU2B=&RYjL&P_AFhm#7vrjOwZycPnUD%fy00l-$R2#{XKFM%fZH{< zFnhzJ^P*j9UMIeBqZmzWd`nv8NJz`$gxhJ&h%XM4?6MHtA9l%kpHd6gcuImp(#*83 zYis2q9BlltV&3>spti=`4rQHjl+k6B4f0mTpor^DtT>LJXG6~Rx$k#J|8_NeO#uAk z;1PV;dp)6`w3I=q^YV{g=!sy}C*Ukh@S%^fJU)}W7=YfsD*te*%+8SJPz*P4(`}AG zs-_pp2cW#k(|0!->1&}U`OkI%i(TA?gQTnXHMmSH&I21{$Oa+XAcLU01|}fFi(-Bs z0akmIi2Y^0lpgM%x%@dt_pMM~7c?6G*7hF$795IJj|xDjw}Z=M^Bz>d8KI~{Iw#8f zRX6v(^P1ogw~txUYoH+B>I0A&ZD$=WMd%bHVQ{c58thACc4y4x-pE_e39W43tl6!v z$-6SjatVG@*gDY|Iqq&PacjpWRchTdne~;AescN0rO+7ViZoXh$tYLIF4JCVZcO1R z+h2%OpqW7|mmUMJEQ5~zEB1z<5l;!O-E6~eVNXo8RdG!dv$Pt#3&@kR;?Q2|^>>YM zaQA*Y_;4r#fd!`J=IbyTVJKexIaCV85&)4qYQ$I=83rd*Abwmu$nWucQfTF7gl60` zTPnt&cCO3+Vh0AfLWEd8o&UtWfd@bo^8`$m{uO)?&9)tw88;~iSzI6( zx|RXc^75)2Q1zuC>^U>^xq9Vb1K-ku9@!jVj{-Mom^BDloPf8Fi$_Jb9FDN{&&O}$ z7LLS;b-whbg+-5tlRsz=4~e6|q>vb+B8;GG(Mu@HT}?E6*=Iqem|Yz+R7|-^CpWNk ztxqPME)ijkxqmP5+SGG~Ui6~@|MHP@9TI4b2D#X<`iY1>&S1ab8IbGuhvv|wWEIk_ z^V!9{8d&&}2-Ph|tbw3WqB|hBp6F5}E?1mV7*_}g^O34DS zLlKt?Y)Br`#l_C*4T_@+l%F~MOxS}ds@o~-_ses>w{eNmYC|I#2%{8Q*j!{TIX?a3cdxjy5Z^Yra8l<@8kQ=PvXv|0T;cTR~Dpb99mijvsE7jRI)Qf zB}#}h>J!#Ga&5+`CC-7(Dhm2fe=~K){HK#nnWK1M>IC=$Cjw4cZ%ZgR6kSPE+fE}L zDjBL+6v?x6lv)WxShBen#7ns}emoq}sVgXXsjfXYd7^qCNL(R>IT`pw7n)a>tNP=! zzaR9|#%QTe_H$+gJ}Z8gYmaFAbr$RSCO0k?ahlZe zil_HVo#1y612LlCqg9GPb$n+nsjZ;Y@5Wq(w@-C4G(q(Dl}WYpN7C-di&8A*_pNV> z#LPq=;l7C|tY-B);i+nW-P} z?k9-CyWg}vZFXsuTJTn@;l|z0M}}7H!{D-zLv=j*)5}H9Q??n$$O|3j>6~d{xXv#SI?lRfD;x>5 zveS*oZrfv<7}|qYir8%-@JIeA$yMV&#t+u4OkX|OyyPPdzjk0aKL+4$a5(Mav|t7H zA>F31YHzHOKNpd#VekJ1se;YQF$R7@o&S9vW$u7Kib|}MK}~hm^BU|KEtEp3vtU!A z)j`yOgdUd}pZ40%8g79qGrF=KB zPJ}Kb-nvGBw=_bE=aXC3o-1p2^I0d+&-E+Kbd^mbRUVSL4=umey8I4x+1VUzSlQ+y zlNY~9S>HNvl})zkCaJ7v&;B?S(lQgUzgFFSt8V`)=8cSu<+fpB){}@-*pyBjYM?=6 z?`7al;@kK0#9=cPTnz~7^R8Mf{By8cPe@-3?%t`35-sqQs_-P+1E-oUTWh`8Mm^|G&N}w;?>p0u3erw*F8# zCnUQ23s?$9uM>2nRLQ@PR*Mayx1;R=>zQr8`MCq*gkK=ua7?DLEftjU{) zr&3~}LgFw%h8==znP8E^$b^_REh2Bog`}X)Vao_IjSnD7PUCNnp#OJr=hpv5VP((S z{@acsM2NYv3yWjI82`5@1!D#Y1B)4*G&41j+5ZLudPHGW7=y?bh$PS`xgU1m;w1p& zCCH7tZSLor|LcTksEF>;F4N&QD=IVioLZeicT-9UK0M9hH-EqVet_)l3{BSgQ9{Q{5oEvP&p8%(OIjTV|E zXh>C)8cVL1U9h3_a;w<*Zk13N`+M{pnpd}>5<9V*)X%~KwB&bMLN{-(lX(M<{z4M9 zjjPkr0&;Xwt$Ef}veV zu?#w*UiZ=e9Ai?zqoGyo+aeZaw75Tho+5pfUDwz>z*XE(Y&FcGQLCaA;$t;y>Jhir zGt;-kBsr+0z!-RiGMWEq_CUv>%hs~cEHD#hJdA(kga&grk3EdS7Q+eD~IH);z^Wl55F(>$?{9tD@bhaMz zn8{;m<`{o~eEjf#Mtbwehe3Myr~GLyYId(|1d3Ms_d&{~HAMr$kbq`8B^BI#lg&Cu z==9=Fn?TKiZ82%6Y4X=d$@W&&R3?^c5z;f3U8}3=YW6j2s@nE?8wpgT565mYYb{vB z-bI32JK5h#l(AT3Yt&Yz^Yf9xsA-~OgVN;m+zz32mBiho|sR*S?X(FP0z!Rip}Pwd&FTmba3F-9mtezHK|{w$!VBADt4U0$wNvK zJCN{Wd0Iwvt6eC@smQFG!*+7XQN(`nd**r)YK;Al(%k0gb!04yMgyf;+hN<3S{wVF zfD%U;9})9D6Yggw2^VShGP?NWVd<{if!>%q?nlQXVw`bws+r$;eB^bB@#k|kD5)o6 zMWCj}m|4_d(=^DBTII|D(|7FYZoCM(a%@x=sD5BXr$ z!RA_-meS+fKS+`b9Qsbo`lJNySGt(?dag(^nMmw2Q0-ZCgzKI>nnZXNxy+@foX)SE zb(80kXAB9%8yig(?oudvV*^4rmjP9v(Og+DH6lU!S(1&r;YIc3N4LiMbF>;*$35m| zi))J~#EaFx4EA=}K_amtFlR{YEo}dp$buHhu`TDqgAGnDQQ{i}9k}GGtk9Gs&q4F5 zqT4uu&>6_B9!4O#8(6>-5jG8x5>RZ@pHQ96W50ZFT7CphEHCCt4lFr@FJ{Sw5`9f9m1^`CCNY^&OeI9IvhM4Vk zg9aU|0+O%F>SY#bDf~xY$;0nAO;MFb?vptSeRZ0!cI49fD3V`VjpPr|X& zhz}${2y$x}DY$?EsKF4KWhzW0AMS5h(Qv-FEq*u{Ja59NJz+qm1l~E5Z3?WF9as^F zVzJ~3?Ln1Dkt4qmPQR^7VEUM|(0wq(K?;$HV$KjN3<@LRdA5*a5b2)5xaSX=1~rUL zkZ_X>p22t)$;}39epF6{QURMJUGpxYF@d&>WIgspC>TMj6^50KWyG%$PTq~O#|Nsf zz~DJxxmMBDEFegbMSlq~8z1n6kbs;e0qfFREB5*9t^qQq0QVlMFT6!gUn2cU# zk@U}B*tCe;)B01XifSl*YGM4!w&k-73#PNMizdc7w8FfM^`(Y7zgPh$$E27lQOXxz zeyw)%izcksMiI^0hC6gk#WuLuThcO3ZS~E}vJP1vZ4%_bvO*hf8!N?p@045yhX$8= z0{eF5Usqou*_L8bxBWC`p4YrDojlHS!TZ889~n~qSVJ(;$6bZk&Y0sYN;xt>DH;FX zg>Vx~0%@D_b}~cZkDl}tLa@&<`Bi5g??ifGD}Lhm{r)|+*^N1Th#On;EWBjOWS&W& z&%(X+U@$39v--Z4Wf_{cbt8#r+eO|wQJ|`*@9@mS&`?%+duK&rkL!tBrT&?V80wF{ zUM>?ojw9`n6ibi5Ws!)_RhX6o+QhmfU4ylFHzGeraS7)c410*!^0!}Vr&PS_ZSHRchyiou6>h6XqH*s0O7WSq8I#(GcH`7d*aS}xBz zWuD%*U3N(JK~KzxP8d*6smUu?upSQ7OuQB~dCOPrb2eq(#Cq85X=^>(^!n}aj|VTA zB`Dv1PjF)5Gosg^NBf_rPiOXUNW`7FyKN?#MYQap^J>&*GNxj=iIa%sRsFo!3~Z-! z#4!ajSu$vX(D=8lDuD@!!#-vQ!PriM=$+X*WTA|I!co1Yco)xQvP}HWF z9Tb(;Vqw=V6~PzT*Fbkjw0I_`X1bwTn8mK zM^oNIyZ(=_FOP=$|NouEAiI(!F;hu)MG<1gz9mDHU0Jh7maIdHqL^d}VY1ZN%bImQ zC6TgbUnBcY)-f~g%jfs~-h1vj_uPLvr_PMt@AsJJ>-l^EK66IcGhMRau@)souI_Om&26OLS8>eDQy!O7vfD{uMudq@tx?-oq=>tHy>c0`ywN z4bW{lfQr%=k9Y~P`9=-^U{Da@ff<+X!}t)P-m0ZNw(sKQ9Sssou3EN5Bms7u(C6NW z$BnM^W9?fgMi8a3jd$~nzU-EfbW=ULULW!Kyo=6NF-VFSME`4~ZC-^t*&-@C(P7iN z3SRNYlM(>buvPz5D85(Kxb(7R=4P~Ldz7vHeXFHBZGG3VTHa;O<1>PJLtnq5`vJ!6 zWkJ6Myz3NMEYqc>jS&GrPykmZ$>*B^DNU!V1Fyb4UkHKm0j?+_ z7EEmp;1fr+D8fPL$f|0*AJhjSXbG&-LD~mhyANWwq4!t=j2o>$=O77kr9uO{(9`QZ z0*bzdgza%w|GaKa7lVchpLjXD^vIwOo8caFbH8w0She;p=yc!cA3|XTR~5xotdWK{A#Gzx=+bCEv9*3mm|^ zbgsPgxa`!p_;p)iufosUM2)@fE6S^3s5aT%VZ9M7Y0js#vF8lFFNnS+dZjAvwAH)5 zw(d6>=|y&O$Mgj!LGYdX*yQGHTGy$YrdyR-vA-1MN;O;*?aG40_Lz=kOHIL?ym4+4 zu1|j2axuJR7_${F{cfKZW<+IjoztlpJJUTc;@g=xk~7n-eM$3Uelo+?VWSqFm{rym zgs0&Ra9irXaOB}`VARHU2>CaGz_LIVaPmr7rfrgwXg;wzfJg1&2)R1BA$lGRm-6ARq( zHmQ#Q{bO>2LvrrEh*^_SCU|v}L_kV6Vgunzd4k7(x4AgJ9y?Opa zNW=;7+?SlS4-MGL%$okpjua0n?bMjk@E0n#29XI_^|nj z>9_2<7CD;lx16efEx&i>J0m9J6Qwl^`*H(p`}CF27Bt+jN@AzehTLT3!@zOH8`k!H z%E;2+b+D@|OiK$(+UUaEgWB5UeHIt`(c#JK?epC;dmcO;`y21UW9_8b4lVD$$8~Bq z9TazmJQ+UAli&Z2=(PMq;Q1jW@YmcoAcu}e@8g^(y`;IENox1fZOmnBo|`=;S8tkp z7XK7@vnld3e zx}#KQ1%9fWBv;R!ZfEJOJ)TW)EaGjuUOIEL(SB+zme%~kV8FO|HL^G3Oiyy-JnM~a zlgT{St-lCm&X#&L{SN^(A1m%RkM7;+So?h51ek1e(R8iv#6*b{C>rG?+@*(I?4}aLgd{mgq|_j3y}kCX>xY0mPv z&F?kklQ&YxT#?uyonONZszu&QLZ`&?7Myzi7=Db?)%@`C${)2O!Nib$h=rO6- z<`-pe6`ih}+nq*cXIcF8ueOhYACgg`iiljhjAC-PhocA;*6dYWusJi2UBklpBjS zX1?iiDvdBS;V${*>SlCT>)BIb#%39}RcfD4I2LdsG_H-Q;eIY@Dp&LbDoX8#tK=;;?3w539_+CJ zQ<22z^nPn>15&(D?`|^ySn5;?=s7W#yWk`Q%oz&s8Ndn_K%U|GyZG*7MpJwU@_+`` zB=19i&<0CJ_eR?0lCG;Pi5h>}P`#KyKlU?U6cp_9LqaS<;kBK>z|N6Myi%E9YvgsG zT9}a`mT+38NN@dbp>Fh^pPK561CWiX#G&iyz;Z4XpxittH!mR={65N;m-9oY3BB8q zu^!qL-VgFsDZoD#fby+ez_M$Gi@^m(>1ADFLQHrqW5Nmm`b{Tu!b0avH}3bv6wu7X zz9!w%uF>a1P;NMQ3a#cxXT9~g zS122nsTCc<1%j^ccCqBan&l?L6(#xs>trsKYEmIkmQ>G8bHZ^*s zX@_9?{rg0Z_#m_NZT|-p2P2)J(J$cZ8JR;$tSZ*ct{hQSH^rj<=;tkbwJ*&MSkaVY zTOoy(K5gW0?*6ERW>L9~6k4(0KkpmAAF2Oi|Cd_-GsEo5quy7w%}=PXb&Rawy`50a z>&;m_cFuuTH`X{>tqM<3*C?;io2TXn01*L4dr)|5nw-keWScA=@LlQ^tp^-O2}ISs zSIfXSsu$4-{4#A9R1bLexxlqDl%jW149o(uu0nWwJbqzUvb`tt5SCE zS!;ID)b&lc{#?@M&}+fo-f+S>4;BTjsSU3QzIEB@-lpf6kJ-E<*Fqn21NP7_0G)#~ zrr73EU((Kf*&Q|l``R~umg22&SIM-2g5VqZCWRB=%XLy4AtW@ zcB;l=gh_EMUlDCn=~}JkqNC-iN2uIzw>p-^DZEu)j{fZTdyi@ZfBODJ-nAt(G9+vu zC1!G=d45FuW-hpe3FfUr?YtnxM;^?wi6_^u_imc1@V*HiwX!Yb_V?c@-RgASsI`9E zbTg(qi#2C*Exzi)tG%p~O%sp%tK#099YWIUclAtu4J=B$b+K zay>nVj^DEf@;KiBDdm}{95WGzy!Y>G6Z6&PoP16zCM`^h&KvRhCZeoAdbc+POC{$! zo3bijQ%_UdVPko1^!?lqZA0}unc=^fKd)JvfoJ=a~2sL z8{X!LbxYa!jE{ddrTQ0V!s2pIrM(V$qw|`VC2hB*Z|c)cTm4&mM#JRWc@Jv4+$8nq zYZc|6OXXa6=;{%0$$7$c`S0cJ6NcuOPUjjUgG6$!)1(*yX^YLhRhV}$ScL0HpQmL6 zQrLXJ28wnGW9`_;1(caSz)<=#Y^|;f#DYRV7HuHl(}|*PE@9Z^E1_Ply?`6RNXI|y zQ=6$&FAaHpLgH#RsWGt8NXuN(mqs_Hq%$>m9ifTdN2(@JA>F4Sd}x}v0(ivamdiVq z+vU3Mq??&@4WL@=6AW$~~QKkHW*iqzDc9A2!3~id}9FT+nAZRdr%!ghA zD^Lj5u*%a+U^wBO{E-SjIaChdAsjcs7&wtDGqUc6i9o5IJ>fW(B5sllJbf1hRLu%d z%0+@@1FjMhdXG6B7zc1LB4B(n$JiYaibk6;OHX~8(x)g~1??&0CNDir7@Vd1F^rU1 z3^xxLJ)oUy50fG{KnA+92px0XoFY92Ap0ytD9APBVC3;8vO2$ot<7TC!8RwYNHo-) z<1Rdo$BH1`0j5b{3NFqkD0Y+>MQ-IUUj=EjG(J$IFZsZefO%0LpvwU8i#-X8EDIkE z7h-UP`#7mS<^@LPL&d6(VNiOh4JXW43CN!X+}3N6n>q4RdvlG&zLVy9v6Aw+mJ&aS^LgIPG^`O?(eO|ybi49=HiYUhqm zIQ8C$oM1}+R_WT4{jbp#GSQjwRN@ii-Q{8RT`i0_mX0E zyA#jTbfWB+lb6Xc>an^@p?L+h18=wg-1ZI2?4zDHcz5|qh`|*}ztb;-j3c+ptKW0` zPjz&3HYDd&s{SqgF+tF?$!au6>&}UK?by%Cej~_Uy{+kaq!DAyH9OG!LSwF7wYyHe zUS@eZk8)r>Z#++3rM$MJsau~S;pXHIA+!vOYK2g}=OI`2?MTxpVDsey_CDWDP!wH2 zC}U(-gQt&SkQVHN6Rm~O6qwsLB(03JU&M%3$KTIT^v&l{Q|5HL(a@O_udhiUju#Pg zlCnipGt&CyotxrM3o!hHrpVW_A3{uq)oB!9eFudeLYe~K^2ck`s*)&Ik$a5nH2(Hu zz(Kz+6Pme^+sJ>$dF;3$>Uat)#846Y%eRh(Y&&$+)YiJ%(G` z>5hd#*BBq`U0n{2{jv%~8vTrOueGLLb)DT4Q(v-uHK5D6l>Atd(^Om~vHPE&R~w}z zuF-v5@&`)6E98Ooc>UlDKwrOqBM~>!OYProSy@6>kJ3u#!6OJMRsYnRC4deIdcWhF zHMsNou5E{Oz!J~f$gcY2Izfibrg?%7|J&@A zY_$*V$-J|dHoQ3`+6K3>XeeDUUK+1U-U(ChVe8nx5#M(CPqX0!a-_8R@7#BEj)Bv@ z?$$_Q?W?!N-4aO!_ z;(@HJQXPRJyMNbrm%7m)yTEGaFW<#w)-`V?JSlLoZq7Rlac;`1fAGW9vP8C{6!_;rUP^$vMl-lTEolJRm$m5&#q5|J+L zRu0C<=hdX)2Cs{w;oD)GaF@FPKZ31DSM@T1D9qp@(pUg_NKkfQr34Uc zd}`o6Oz=uqcxBBIC(#suCJocffPqjgf|&S>>L1|Q%-%KE!#|w?L5Uz-!fA`uhv1?7 z6bM}`sbZReQRYAHa*P`Ov{q|#H+79yf1=`|f6qoRx7c9h%##$2w237LhBH0{JKARq z`?x0~9czGd<&j+;@;JO-qV?2h>xr@ms?ETYBkc@Uu){MKQ93LHBvhUC5gs3*exo&5 z9$ans@{x(l9F+*Y0LYN{0c=!2r+QQ0e!tPnQuUoL6LnB%dm105m=@%nK=QC0KGiw3j+paXh$!_$g=~2RTl{+ELI%S&f}QoA3xks zCLkIX^w|Q1wOxXb85H4S;o=O=7YWQ6kn`JE$xhdZTLt>(>b~Te%Ds3omG`M;ri0dz zXKIjKr+`Fb69wEGdm#ZCECxBFTaI9?O0YhJEzwt5e zXe8sgGa!BmuVqE#sq|`h0O7pUSClN$re-ht-)0}3Z_4(dZ%d|MMU_IF*mQZ<61hOO z-FzTgt$Dj}6Z5IaQoo2}#f6%EH~Kw`Nqi0I-0kbbH&SfVB&`_@6wBRIA8JBlseZ2!NH1GZd54VJ%{ z0=_87k6ACladt87FQ}DSlzuwo+xctEGb_Nw#a(L6s|C zImhh&`vrx?OMF{p!}(jcA1z}`sfTf;gt@LS>tHyfc)O)wqB@s~b4MraOgM)`+lpyF z8vV1l+p~#*Ip4|Ju4sSdt5RU^X?pAp2r?UgVPh$Ae5`XQVG{ zR%)^iC7oDsFY3?h$AKjhe2FiVwLZ?T*F@=x#Wx8`@2p!~CaddnC%jJ+SVM9lF^yhVhm8nS2n+wW!VhUWAgc3yP_Zh-?(f8wT=iUF+)6>0a)IVHB z%KVzH-hyB?nXG>0T>iz<9qRLWMR=kiy{E3`LQJ`~@vmE|C%#`kFX40!D|b4(z20W@ ze)~iXf>kt^U)SYWL6kt|V9AGPV;fBj6APaamg!B~Sna=f5W@-o5MBqUBOFLYkcQcm zE(06D;Ml@BX$WZJWDWEI0qu%7t>S}Nu>zpTuC@xcXM99G=GnYG3{rgXc zbMpf8MYp20n|Ykp%wB#fVlP}BCWxL*P*ZvEHM0A%)x?IiH1&k2d2ZUc9rn~I#hC8D z>i71h$F@)nY$efuH#q|y2d6Kneu&omg^_!5%|5>H#Sd>Mef$@1%ex`W!D4#TvX+V8 zdN%x|@-0qZ4^ba~WWwA27ohk0DPUg_!T}bt69Bg>krh zOS%g}mavE=lnLuD9x=RuV*V;36CvyWi2(Kx+FZc#5~Rt&fjL;H1M|YazBqv0?&$yp zF&K>O^*X@ulhYBh64rO;G};G&2bx(-UmtVl<@*oYMj8ZMO@=*}H;40uRVo-Gj>MlI zssJb%frl^o5IFe1^^i>fneqdm>mOjb!OnV{AQg-i$m~0sFA&fWmGkyWU3cnrE)p1J zhq-uf$yk}dW{&>p19~(~7oxGsgrOhkfgNf*g`jsQ0c8L-1tvwlgIs_O@$_LhNG`BZ5!SIp@O~Idjf?pJ zE7|T!_ixvao_?Tg3QpFpo6W^D7SNyI&+`B>e-q?a&q&8As8wRwx<=p-Q5?@J_Ig^6ZbA^khMMvE^ zZaPI9lw0C|x^uQ%`hyY-<53zHI!g6`Z~r9yc*K<%fbR?A{+e-wMHAMgQ%ID!T0o!7 zkKb-)`1{4ohe~AgGQ*y(!6SYo(f`m;8RyHt;X--yK|V^x|Cm6voaDfxnS6Kp;mqW# zxm8R?q`uR(JGGNZt8!iQLo?#>?eUg*zKv-}O-dr!Ao6C#l52x||9tTU;ftw_tgQOK z+n4P}$NQ0bvR9cqeNfdig76X!k2-T<>S{xM1+?qH>djb$1g0VY-CuA&%55p%=Ng`X2F&iq}?^fu@(G&`-frshi*l| z!~!ROe>-`P&%A$XTEBlq)V8Lk6o03zZMF2QR{Ku$gnd}bOnsSM+S7MlyoK-5W6t%s zGxE#f7h{7E4D9E{RRy-w6=ULQ-REin50ySqLnrFzI0^{#9accZ#E8|x;s%v1qw@mt9p6)w--SOMhswyijk)aMCasC{FA5k0v z>4A7gmWE75m;@232Q>xdFp`MLqnDcL$qnCojmergTlGjsXj& zx2X8&q~nq+Y{uJI9hs|fUbRI!Li7qu)5oocFl=(5FuT{cg7_YQFep#+jYh(o;oh^r zkfZC4COwC|BS!y0Fcv{8;GoX;b z0F;}-t!%zf$De>d1g79J5Dvs%s{{Mi1NvqF;eH?5K`|t+PBTT6`~(;Q@93k;e7itg z?lT-N5r{QPzv3uD?f^Zc=!c)r_?;TYdG<=hSe`(F{3DR|%`=7pdx7fuaKN0WK4mVIHmCon_xgAnNb9Tgd7B8J z6!deV3_yZg4v73&V~fD#SpgnY|0TRmx*!4<1x~C-n2cPOM_})t_o8`Nh;!sf3rb-A z61k(jiNk&8$L`*xApwV+v}mdh8c&wW_+*^O?0XmL!+n*T^D9RDqi=;0O~ss^lQ^4={=Zeg9t#HXRHKiJUC`aq~mrd96|w3$`9L?tz^fMm2$(wlKxm$FBv@7pjB#ow9Nw#w4(Z456& zUs6yoezksL32DFKWmt&=YnXTAue72ncH~cZvCah<){X;G!|D>!c9>$AtDH4{dnU-c zLy?+!2pOWNw9IwR1nwJimoJ4P)oV$n{xMxnSJHfR#@5p+TX-j%KULhhjV^hpvTnPe z{kLWAV!vR=XUW$OwI84!H;j%8ag1$i!jc&duz(JH#us49{^cm8d%R%-P-utx66&Z6aqn^(^683A{yQ-ITsXEzXNykA{BHyPNgmgbP*RdJ;0CfzmWpf|6 zkS?W_vi-nxJ*lbk*jY2K`mM=%SwT`z5*k zEbI!hMVa_KN9~s#zxQb=7RzfV4=y3<%_6C>K2D-J{d()4^tD=rN9k9-re1KE7`t-A zi1JGTY2(y16yxB|pzjj%{Nuen(bXyA6QsdGVXYtd?!I1aN?GAO!y(QOVNqt4Z9!KT z{#2c*r2q2Rr`1M^X)#t#a5Fb;IdAGHLd$L&R7-H}0y>bzTg+*FkQr*L(D8MGxdL!; z$@v+6ye%Az-5Eo{Am~Jgrys+Kvi%Gl!8|>!h-U;hhj-o~$io=H(<2m|3&Y3vy`YWq zan%D~L!ik7%utK){n1unEG4)m1_|4QEjKNIx((cB*$0c@pE1B+Z$+FXlE-nK$XvHr z$U3x6WD0d{@*yxkLSQ&%F!LOWc%D$t3djMGj$wWN6o~NhTqZCxH`p@4$Ckj6Kroi_ zY>T*225^Y77_+>1M?+p7dD#Q&@&B5)rw97m2V7S)(}({;p>=StYC=) z6z2*7Kl}=jO@qniJoK^YW7SNMJTtloKq0|uK!HS?LcN9~R0=+3c1}gq^dbbs{;?^e zC-o2{!66k7D5$yN$P6F&H~_Zynqiwx7{K%Z8{^wvZsk+PZ>NrISm=Z0#aO6`3@*^A zZD6`fPbG5CVVasDS2wA>0Lr*s0h|Vp!-L>Ku!$8+t^!^(sGi7GgB3+Rf7T^kIHdX* z`SB3)YL}){8$Ccn(s0H{P3F8GAPvEw2m|pvVg>i}f*wV^5++upE~kN!>CJQ6T$f_) zG&J@umILsxmi?<&o6_cR^vspwinP*#lgH887EHGj_{N?h^-SvSY}3*GT!wY1v8=?= zX;6NilUd*_|0C7!_#$kFc3rD!TA{o25c2pCLYceuZ+olxZ+n}LOt8K{&C3C#9Bkx< zFlc5##wdXM{e1{Z=J>F0VVZ`NFG~Z|cmL^b~+`}>JVMfPvX>;ZFn zw*>7Iz5xoL+?$gYvn%!SchGHOguHF323qr<{TsMxWB089-oUk(=fnOnX)+?B&PCPx z3-yCxU|HjS`)O}R>Af78$%SQy=amVKIvRw$!LN>Ycw6qg+LcopQ_;>748ys2o~5-s z*{*KAoujw!R(OS0<@$7C{6zQG-Fo^Q*=xDW6b&8o^!ika_+BSfW5t8_SE-|mhCy|# zMOb|8xuwkV?aqKad^25+d2U=@zoeJd zBFoY*E;IA&Rl<{Dm$?_~_qoH~F9w9RZ*5EW2b~*K9IF{l3o=P97QN(Vp>SQpupsoN zY@3S8`_`2ka&LH8-3%2njRf~;nY+`se@skM^BTc{CPH<{E=(?|)?8?NcDesWkDt)2 z-~FEs8sEIyQT+H5jk}*?>Fph9LpZ^ZwFe{ZpJ6Z2mr#H>i^xiX2UQVF7^cG8!ncm{ z6^}FN&)3j(&+n|XYR(I^RuU&;vJ#Z^ zNyT(u%z;xJsTj7?#n2yfiHF>pK;~4Rv(lq;xD^KIXLMT?ekV80_4%$_+w=a}BGIcp z^tCe5_0ZG?gr{_)xM9O`@lX-a8We0FpM8|9eCk5dy8_9I1M;9Hl*_U{=k2D&!zn={ zeset@dj3#THGO5qS3LKy@Sh^Q4-)A2i7W#sH>>Z^^vY&%tw8M}d1gjB0_9P@6E&)2 zt=DwylFudquM4@lhqW(@6k!{N!tfI*+gLsz6>pS2GTi9ySNC&hUXr>&q-5aXddhEq zKk_=yo)%H%u{f(CG*kxB1UxT^o3V8EGNy^nzkv#_Yns*hsa( zcGe47+mkS$KuT=`$3j{nTexcM6F3hSlT{7Y-iIZH4tgI`KfVcHB>)9D>*VUu8TbJ- z-C`^$(k{RYoJmKlCHYh6y@}oI6uL4p@fCwHaA#^B!i&*^WZ|&@;EU8)298eu@(`e) z=RyF3RI@g^9U^O6xJ2mc>@Dtr>OL&Lci|Dq+gI48$CeD3==LMLRf&o zpMAhZg7T^ZLv7LN){6w^F^qM}R}pqUIF1)(JJ}_WcpNnWog=uF6TIxvHIf1> zrFfNKi4AL|8O}QGpK}#FjZOimVsAmT!XlZ^?UcZSfd=dOH4V9>{?IF$1YftdiYI|TW1QpuO(Rv-E%>ttxaqA z84mPuyxLY-a}Jgm9kyZbiJx(r|7DV$AYjrJWN*0@HTyi5`)yu`Eq#D&?G0ti%VVEN zGPIjGsggvRiA)ClhXs)>xxz~ywF_$n=ku+HHh7Z8M&Aj4&N>m`zEdmy5Mur>K76zd?fqf4=eF65`@i@iz(|3X2$>3Bu>?4oycqjn zXKVf;(W2I9DX9Wf2qpY=#ZOE5|$av*X}nGyS)MTVl;{3O0% z@n%-xmhw*KOUm5hvrxg#-=!@ZC%a1xtqyYfsmgurC&9xx8>@xY=rZcjxY*3Ea+R@) zHMVg#Y&UfEU|^r;d4J#3c4=v`((o@?+3g<(a+yh&T~7JF$W~A%yiZ}_X>G9PKV__t z%Q$sBLEWDd>TW%@CoA(;>qVs`SFV?A+gW9w*z321e_eaKZKyT;S~0coFc?Cal=8X5t zECwETfeaWy7EFlHU4SRhA%^gD5;g_!@{6WlITU(=v6+Q#{e+tHseaPW?MJDCj zJ&I-;uDNF-$-LUm$gb9E(`-K#CMYK-@4NrougJm{ zj0I(h<=iBh$X2hU+{(HW0|EUqyPS;)TZBUSQA~aCjqu8nv!`>zhgB5HgA1Cp&+)Lw zqP&3x>BpmkhPfY8+@=RZbxfbCAsJk#UrLAt&E`nG4jqfFDX4WTjt8w$YLfTj3y3<` z=3fyU!19Mj9B?ys@TV8y?9U)7LM-7MoKB#+;~8P%3XKKybJDkqp&;_YR*n8_4YV^c zHU@z?hLUpAgl!Vg&s)LPj8`?&@DX4GI+sN-HuQ3)NRw3_8^7>BD<5H@-k)ol)9)JS zFldPS)%(yvvU%B0*E1*ed1yVyl~$qCH^7PtK&_q*tbdQhKZsQDfnDirv*kj7{M=Zq z;6_L6c0{jsR7)`yE~hiB z0`t3xc#)YEk7Q$h*-wNYmaO=ldKP&_qOGfCoUPQ4g zJWQnwJ{VpDxG!tmCiDl`(@$A%lRH=$p?N6J(P05!Bpj(UJ1^8n-X0bQ_I=@}6}ud_ZshC0YW!e3A<>aRqKQR$A~(6s6FuF&-&@)?D+%{bUo)l&EDQ zPu~hEz7Gt2%?!)9X|Rt=kb4WL*PyCV|A&H?{BaXGqtS9Oyzl`~pO5x(5=me!r_<0U zuB8@fSk%?{)p52BNE25b1nu+Q4!YS!)_vP*{VJy@A8j}F0q?BhKhypQu(%nJfx>-Gw(@+9+>zfDs}g`MbyD;Gr@ck3 zqf<&Lab!Rs`5*B1a}vb136N!2C;G!x&ku##Sk>WC%&pfim9Ge_e@^EKFqf@XP$U6R zfXc?MQ5$pOwpvqBka<+lfN(qGWCAj+W0h7;;&!r~?bKIt3buWow$Mo}@F^Wwt6l+v zJ-TE^+BqaLdVJ$gwF0@J`v4s~_B)-0=kG`#8L{_%vf<&1mU7+nTE5Xj&`@Pe!4N9@ zmA#>$1TC08;DTqNSv0$@eJ|+)?iYY`?JaLpET5J})#q=I40sLosE|JH;dJV>>q=X< z=HBc#b_T4_kZ$vSv`084Ml|OkMC|={HyXX7y+?4DNw5HRK=g(WZ}fTLm$PYTbzQR2 zR{it#aMa!df0Y7wXe&!Sk*!kq_c46fr93`;z840VYa zkcgbWH5#6~SOdZMWLp;dfq+%@lfgz0%$n`QtBh3mrxu)n=)LT1Rdhy9gmdT!(O^`l-t4| zyF)PMR=K-#oL+$7GwWpua;nn+wWa|?p@HKWG+lULo1E81&|ai6vN@a@Qpo)=Y?Y|c zCBIn6r<(o%g*F9TJB#P;CW)EF0Q|c)&)x?jx$iXCnBHw%gqQokrR(*eYbdE;ybNp( zaI-irk{dF65IY18(T4z;bq1dRY}E}54_L*3O$!lr0h1R4iLJ;zKVByKe6CG|_pR*u z3*wnq+Rt-bbiHcDqB6^|TYk7bjimDd{JQBoXKJ^lihp5QKNuLF8>FpxA^B!lG3LTKZbutl+>Fb#$B6&NJU_22M2=mwStHMYp@n` z!wP-{L&xdRQ7rsPD>sP8ev5f;E&JHvQQtKsriV>ml)7~PVg*Y<5_t0+aOaXk4;(SA zumcbcfS3Or{_|*9xyO14X@HW)g&4qq$|GkB_IzBBXJ(#OMD{-o7#qVt=KlaQ65f^S?bB-kz4VeCnI?HIW9D#jE21}yKySdxt}@=(>sr~1V1gjiLh zq%cj3+XeJA2L#C!qR<8M_H6wi*RXPcpaJN}WFk+Xlc0&dhyV=r`7YQ}!mKA}G=XIb z&$=ofGce-AWcD&f?x=6#W7duz}qD!Vds=>)g|qx(QQ$Kl(dEPLr7gOX?oUN ztn~Ku$Ky#kREJa4OZ@uk0pYJ30c|T~iB9g8n&a?`C)DDnw6CZ9r@*u`9JxEOX@hIE z%s~Tl&i~yF_A#67kv7X+liv&&CX7kN_fc7MFRwgsJ1JDEpCfuB`xbqSzfT3<1buTg z*_`1|%5LKpD3666UWbrR1*G*ZC5bjw0N7y|T=1G6nq1X?2swx;1i7#D zxQ5+4cB;h^j@o1j%-kdKzlKS9S8nSYW^eVsDC#2LVD|4dT|a$7`~FAPf39~7K9jAI zY{}h=HaUd+6b8n1!_I*A6~Qnc#Ll{Z|DG%L?!K^ZR!)UA>y3n-lZvP>r}VDs znLCQN+z&6WBfU*!_+1LF6KwqoUmRVh>wm9P1-b4~JT(Ry+yDMk3a#V{i8gt3<*EYO zm_zMCzr+=QN~mzOYSP)Q)OU zsi94@IFGFxL^1DOS){!ovCxwKRPxS{Ef*{zvz66*PBmLTF4Is_v~c?n^y~+o|4+jN z(JU)JRIqjVh0Wj}moF}x6GaC(1L$89O6qgo6vwNAg2MybzVRXC99mH3&3)-GGqSoV z*}Eq#wIt18w)@n9d398_&p$2|g;mgK?DOmcdGxOuotME?pmG3rvJ++l|w~;Ts)Y~)U zYV0dN0?lXp*Uha`?cuR^SDbJ3oMcPwzT#tK`YVeAf9z{&R`Ex7^N|NtY@=8gDoG8Z zcl15Rm;(3A8`$xhF9Y22&7k~REyF`| z_hgtgbLQ{;*f$MGL~bcw^V(BrTzgCZL#unBf2Lbe;$BONhwuY(bJK5v7m=)xP+-uQ zP$U{(Dkr^F%T}npI3C~KG%NaTjnhlrzpa0U6Eix#CErAL;Xuj&9P91{7J5V_?C(_6ciLeMw3WCY=OUPmc7=5dPQ&RU3~pyljRF zJ7>xoBpoVE@lX1n3|J`tjP*J6z^3C3~y@q0X# zYxgnpbjN_}%koHX1S!@ua<2wsY7eN*7^`{U{1Lc{u?ELQ_$;**Tndrfklig6ldV2; z5+Ciflm*ZSJ}?cj*B8MT|Du3=vjC!<1dRJu09pbCOlLrXI3O}>V$l7!Ad5%NQoysC zCID>};nKw@o8B!Z6X|$I31U#Q;L^4T&siX=OyPoT9L1Bd1FKhz6R;amXz9m<%-m@| z=mmD%ZYKFJ`bR)o%+Z-j$2x2Rp7#rIHp|Um>hO-ozcYzg2MJYQ0+ev;BzSNuSL_ms z4lljogOCp7iVr3E;T`ETUl(KY{_Sb06M$*n9 zP?^;p2}b^HYW4b$7E929*PKu0x42C_?ax?oIfT4CP()X*k1Aia7Mova5%I-$G+NJZm1rCPBei<{ z=g8PtpvU{V^ZRp~?-ugNw+2%32pKH2$xl1QMSZR;W8-Z?{f3jPmGS8RVX*;Z^ z0*q$t#)EC`0@A?J0kZYLt0K($tG({}?ZnWqeOlJdZ!U{@xx|=v$JqF$gfAt?c%y_v z%!fvTfu50C{x^R9+%(T-X7r3|msVU)W%)Pq#M_nbT7UYGk-P4%CMOfk;{|zaB-`dy z;xQ;n8RY}%e7!~VyA|8q(Gg{Vq6q$ASXw@U41xX^ZPj-PmX8s*I zN~0`-8C@UYwMDS>I9^>5gAAnWy?jMcOJ8JRhA1`P!jH9)WI!;`j7lE8sa;s0Y)v@b z(kQ;S7eajOEB8b!axuT?Z~VH)KdtXI*$4{;GU`$(J#=UK7}xIZ$jv&!bGw6pTdsB0 z%@vm5n@;Nf>-Kl}HGH<2gof~vx!`LAM@g2;fc=R;Rx^D7%DYvBe+*;!_lRe?|0SXr z2n^UWYT!I#@GI=(oc(n{Xz)cLI3ERQ*bI;C5o5DsZk8j(5 zh9xT}f-T;=bE$d>?jyjbk72czQSa@_k1ay~f>^6aPHn;6=sK5{dDZrQH_S_po-a0( z)UdA>9)?B4;$L56S~W&Qnb}yRmo=1ro4k_0gi<=Uhx#_nP9}1%4%|zMI*wt2XF!MA z2p4xikF0R#9UBY+$aR%lN;#Si{XTSfYB-9Gqgj8d*V1ekRa-6?1#_J=5dQ#^5=W>P;1A3mV5N)O zikySOJyj#VO(SZ+3Q;=-m{jowcAaI3=K@3#{?!BGl^By26&s@^OmJHy&kl-tj|+;D z1j2PaxDWg#)K$o7AH+Y>OZ&lQz^zKQGMCPRmN|%pU^vwawe~?Qql~wMUTU6c_hDQq z@5ej^>SDDq;l;2LO49Z@?FDQ1t{|C4q|~r+KX49Cyi`II{-l#S0wiJ0pOnNN8{V$R zH5qD?Xbp><)D1&gZNGPq-)ffVYkO1h#Wt?r#oqbK0q0kkqdbs7~kvR}0>QP-`x0kUzy1idzFOVME1{p@QsaR@p7 z-&bI8Av~HBygp6iLqvvZ7M@5f;4*4cyx^xUhtu3S6+C~ zO^BasL1A=* zv5j;g#q%}0p0*#i>_12sH;25B&24t+5f+xOE-Wojq}HJ?jf@o=D6{>Et}rO>w+k3X zleR;QNfqc+wqf?%Fjb`J_ps{%*Y2%cuvCa6x)l0)W<>K;+&%lc>oyuIzVq5fij#sJlzq>F5ktfyET zczH#NfiL!%{DQm+wX=6mk$rCDy~>NX^YM8=%Wq*It68L|@+faOUT>cKdM>Ku%?FWO z`xm30-u^YIo3Bpzp(gd$P(UdL>UhFchZGU*0}iuztt|J)ppUmxyn1$dY>9iz;-Be5 zh$D1p7U+=00D0+{ja4gbwgws?hWLcHuZR$O$tC~5-$?j6Y~x- zp6HrXmj?@a#LGGlg~eydk+E-I=C^3C$XUp1cD@tCldkM{j+gDIfICtgKuCg1X_~z(~h(6~Ls=p!E!55N}{A zD|?@d3GD|DD?36%U4VW>8>Hm6yCNi@uoaa}ghc3?DV>nv3><{OgUET&vqIc_FZHG* zhsg!1r1BrGZ*zLm#&Rxue4Y_By?O|dHzX~DvE=&Hs#}XM#thQk!_+HvE}@sNC&lVN zc=OmvL&HiZmIvGWNGh_R_bM*smZ6u>b;-Y3L26RQ;`;wsW?(af;jd+abu?hzqLBNdlr9a9^5GNJGEvXI>I67ds z&i>h~V~h7F*s*^PFY1KJ!|P%SP0!H<{}3T0M9Ie_Uy^eE3Ctq7IpFQU9asJt1mJpY zUub~-3|j-V7L*Ku1L=oRU>5t37rllVGJ%a2eBL7h#`xWn_5ykE|3%Y#$5Y+^|Kkph zy^}qTnPg;VpA)iDhmb9@GRw@$N*Uphk))1sN>;Y)s}K=ID7z%dCi58Y-{X9~x8HTU zZnyg5x?RS3y`Im<<39P~Kb6ZP>&zJ-dj*_{3@2~Q$ljJwLt9wDkpfDF*hgmNCU%oX zVNengw8-2BXn1%#pgSrkX-t^_ojG+Z#ms^^Z-@s@e49Dv4+%ijeh7>0VUwwN%QDIq z!2SPoz|(u9TMji?R8(Cz@D71on6yyx!X&-ynPHkWbVC@6jN@ILEXYHe?kyo@TVq>a z6bA{j)B6q0l=u_7uSUAWj6d-qzF*z1VOGhDrCBAZ|Hd%FjY2yz=$2a4yC6!~mrvzr! z*ZH`lFg28tS}q5{+I`Z+Yp~;1B{DI_9wtNmBPc%Z2vMv3CDDXtG0a*Sdu{Y@Uu8l4 zuQb7+Y8A||>C#EM3k`N%d5uh1p7v!gdY~ zreYdm3F7@EPVfT_B~zSwB6%=Q`xb=T!S4)S=3T5asZVJ-uNj;Yo-}>N(lEn%7@PvG zJ`v$hW2|)Je`G@)b4i91JLzIllm<=K@taXMg`Zu?{44)ds#)z>X-AJqhIUcz$h`Ob z_Jf*Rj0z!H7OZ;5454KAyv}~KdYv$td1=V%E3+hR+-u5M3H2162Lpl@+NqWtyEKs6 zv}|rY#=Ijk&04HOe&@9@Uu}Dy)S!t&%@@}FV-O#MT z?Om*yX~7P@1WAd`dpBjD#{QS`qCQJ>Y-=CO*%42sGeKm5cnOuejij<&5Qs9*jevE* zAGAvonEdbX(nc6Sr-+2y0BM(XB?o;3_z!3RW<>?k<|6VI@TmqirgdEg;R$yz=5-#7 zlV|A!Llh#JVtmSzJF!}oe-5z}#pF`20>L?S8{^@2^HVHFoY>0)njx4L=_}DFYD(%= zaIKP6!za|1$#C>OChC#JgV`WL7MaFuJvh`ZHjh#`S_o#E@ac@%9;b9ueVzWjfj1T0 z!}86ONGr6j(vA842`utP!w6`)V6coLfb4+Ot3XNLQG-|UvC@=81pAp=#5LdrW2+ji zV#>EAsLRID36#uU)Bcp07tPVDe(12N!Dv3vYL%A5EZaSfWwxebp^+EurT3Qc1+?iI z#Dt&4Vv=o-3Frk(CP)^(Xl>I5+rsAmSrQ3HDh)oe_tY5pzy()H38hU`EJ7UKy@fdt z+njjfna&NF9V>@@u{jm}bAT7X7DxD`^K%(vsV6KjXwI4~Af{tn{;azHr{HLKW}3?I z$f0CkG+*Jc7R6#u$Xv;_M;E7$KE)c}WN5&v+*}s!tN2s3g3^8j5IMp*rrmFVbUJWU zZAJ>B`LfDrc2MWa#5aQj83-t<_=tGJNE1w-=i+6+_m<%8b2Cg z5WTs~JOMohk6N{z>7f$@qj+=NQuEZcpS75;)1O@YkN7u^lhWPM+TFd`*qinJ{*X@M z*BYa8j)_DZXa)81-pQH6yN5AY0a?)s7#-OhIb@>Hh@6$)Nq(If&oz~-?5KZ>{fS<* ze@Y=#vLT4=>{M$|z7Z=0H+k&}+$M07^f7=mv9$!=-xu&Ok~6s0gK&m=GYf1WaYxqN6`Bk0-41ZjXHx_gc(xxDAY$E0ho#BJv91HW2}U6 z@Vb8)eT%Xy8N7Dx>*o-h-|@U4#R8pyyFY`Ub}Xd4Z|=0YK$?zc<5^SO&9PM!eJp;a z@fMf1P~$8}qyHv>AS%}JNKZ7zjvRC64S+;RZQX#u>WQY`xa()FPCxyDtL z&W=5yKZ%NM;LrjoV@{|0Ev#2W7(fPHmVr4l$#j(2CghtIObi{yx3w`heF<%UmUeI> zH-OJ4t^Vokwguy5%>qzf@Pd59A-v+ZWgbIGG`|7k*hKU^I_w+Cg`kEL_=^IOISZw> zZ3Tr2D=eXKQm)}uBS(;9TM)N#k^J*TS`h;7*fA8DuzfeUZ#{@J>BoCkCW9{QWxecq zde9{IG0-YC;I9l*vr~H*QemB149HO}GkP3`;HG|w3Cp=2nBpQL`}jaw{eNVd=C&+{ zQ&=k=O=b)+?Bh1j-$U5cPg+fWQE}&tLkqVZo|Ovj7wNt$xN+~aJX2KV-JCCd@|FXm zf|u?XpUJ!xDWrvak^9|nyuEgANuK{w%8(+Ds80bQ>BSgp*GcWVPSE<#k8GOrVBtES z<_cyo)h66ce~P-8{v?W=g$=-6e#D9F2jTrf;qz1KWx8C#jesf1lozWqP3kr1Kk`Kf zxE-?G45OBz0nNd5#UjTn9r+COgC8eAJb2q1Pvpd1a7Q~M8@3TQqS@eOn16UycdMkuhBsW#sebZqXZyy>b!2optyQ8{bFofiPOu zh5`Q$4hA;#>|d1QD4M2GR+4;#x@8k>KldAbw_^w$-eEz7y&2RAgR6`=%ptb_A|;qd zN%l-x3q;66sAj*p3&;v5C9*Mz0e>ZGBIe7PX*5AFuVJYEP}AV-$3o}k#mZN*?5+>T z-%*M&`p8PxGcLPCO%c$6MY@)QVzg0@rguw?MuHf0ZsRg&AHbGAhVJ|nQwafxdp3~p z4X=?K8j5atYuk`&g^~FcgRWi?P%)sKB*#i@e*l%a(`b|*^Y@q#TTiM5bfbSp)jdfN z>iEf9(zi+=$t;nG5c^!K_t8u5C;w$qS#qq*)G$ae2fI2Mgd3cXS&Jf|ZL#uIggq=r z39_#JOX75pNPkPpS&v`+jp31KcpKiUFkvR# z@;;WWt8J$4)V23JY&NR;6{Cy~1|@1%di+H@`65etmddC;XtaCZD~ZL%=oF z9QH~v(xiMl-Id&Z{zGSmx_ZF@b8qFmablvWo9{iVe)@)PUgWCO1Mktr1ElkIB6A97PI>wf(k zRzAUueploy)oy{k@Nwt!t~_IxCQrW0WTXn=Or@4P&E~Q5@uOU^5szudp{Kk@RH+w? zdp<>3@0G}V)4YIWnRPmbV4Mr7@kzBQ9x(w`d@H?-i}G4iBg#W5h(O~GX+wYLNhh?M*9-2JdAlP>u3&&eu#+>JkA7z9Awb% zbXb$``YfTlL7}YFC}6rQjJe_?&2p0bIlPtC_FR_Bj$L=HAk7*^NeYGRi`~5U8l|-) zMw7Gkx?FFyddds5|T*aXUXo*|1X?{bi2vNk=ti7 zwo>onrC~sg{f%}5!4pXTAQj0mlsub;y~vr3tzo8)eSS!B{yJHv{M`a6tw928J&Hliy%su@U>YW$UBL(rnia0Cq8vt{4-x!rgme1!@2DoYCZ4M!%`mj9 znj;LtCju5XgtU6MHqe9}oM+&VgLg8Ujf+?d!eg>Nf`LIfJ8RCvnvy$e{?Gfuq8CvA z<^9;#{%)Yk4H>2q*gMQny03$q8ON9U(FC!I2)zCmY%c`+bVgW~Tm^!(vqz*|9m zsf2c?V)}JKJ2k~Sem8r=+v9KEDRdfE>Nudj{;Pob;5T+PZTVwXJ40L$vwjfIC7Z9L?_~p9WBMMJ zT-86@w+>n;U=r_*dB{8!qelVs_yWB3{ZJ_63Kn|as4*Z-6+TX&Bj&--L&*q0!NPB_ zeglt+SN%ef=AKKjj*02aX(F=r z3y~Z+?v5~Obp9I)1Q`1x=aCh@4lZOrqF1J(S0lkTh3ftJ6VCnxk`GCShSwiC{RzCE zP*+t=o)eF7rmOWJh8oS?_uFLpL&WOO`%^EL(htk~9o{XBG10KwNDs*jKN*w|e^4SR zpUC{GjqQnXO$<)QLIFc-EN&-v4tFakxUBzN8G&uSN^rD?Q%?xb^#fj7NH9;WksEN^>AX-q|U03DK* zO`HTJIDV0Ralz)XE4_%hXsOd;nb-Kn>0E-8{Fmw7L!T$^!!2~d*Fy~VBtOTBXg?&{~Ow; zC3VhBV;l@saRFiIh(gckhROA06+%ZiUBUYi#%xlk93(X~)uQ~~+2VxX;<)emBM=~B zn2PA7q>d-k%Twv5U~sW3x`TS+;j$prktBOMrsxsKn(v_Uf|@Q(X-F`$?BUHay67Ba zoY5upPnU5JYi*;sh}eU0I#taPG9UfD{4z1CiPj=A0>giCrv-3H(V*;eO7vU36pc> z)-6wZqR<)b`mM%yxD7QQ&eG;{x)bKGs;B+?8rpe?oo;A?NJmjvpegQvVvrtW+IIk- zZ}<%O4<&cYQZtgB(HE?L6QZCS9}8olIFcuyYQj;ZI!F#Sc2n^D1C@@Yhg4Aoy6gIx27l1H3mbBTeuGb z!cr`rOG+8frK)JnIg{g1qa(MHn%@bXRdyO1ORVq1_7QL81uLB( zlR5tb{MW{PD$8o6g@f-Whfw~g$G3ih=)}V5%b7ESaPc^G62I^zFhfOTDa8|W zXewgfFyL9=!=68$rxy1$hb~AK6?qsuy^h%dnA4o6IvJ)28NkG@q6XgoUn8XYiC-95 zq+clMr9UWPJOT0MrrD}TSABMAe7F~ z;f8wh@L+FFXp3|Svk?NZ9>D_cNi_sHb3BDzwA3>w^QjFngM9KT6m=J#?)?;AWn&Q{ z4YcYYObPmbz;?8b@_NG#nW{6evB_JN!Qbke(9WC-0JL!nNH8>_=yS>JdYN0}XykSF zuz)*KkL}|%XFySo^#pV!i(bDC78xA)vY-I!07B9SB}mUskPdW;Qd$-o2OPUf>Q8Jy zi8XY}V^EKIii=a#YdIyU#y{}qB?IsuKUEmZQ-Z$P>c5M!k$U zvc(5QI0+t1qgR=ipIh#uW_5<9?`7g#zlK>A%lJHVt-G`B*EdUrg;)MHQBZfXs)#Lz zXq0v#%6Gk*aWeTuPR$fox)?NLdon~R0@fFPuZB!t3GQRaexW8B@J2}@|LkEE{Go#i zu!$`)eIgD-Yv4M-s!?jyky8ov`y)@zqnQs4c;KTfAz6L*x}jb=N+6RtAlDWBUKPuE zej>(q;3qrl#0LX~2~6sH$arH%gp*cFktf(|m0!)xIVo#t1!FbWcTq!QUM@AiU)^^S zD3bbf_*l$)G)p&2FR+IF;f$Vtmb25jHq%QlANdMloaH{njyRWCJ+fy3G36%esa#*h z*@vU(<17lk)?UKhkO6b3UZFpx)1B=s<%#q@!)RN{wn`sa+-KA}Ql$4p?@)qEKZ^q1 zB#6VH4t-rUUZ9&Sy_Flunf6_^5VX3(v3F)f12C~7sx6lH89_d`SB z7fA})FpT~V^IpgRnzIEkau&W^I3hsYwuYxaWRZmi6{yw@MTW&pWVLqLr<=V}urHA= z_Dm|g$RoeZ^!sr7g`bF}e&Y?9``lz^ySP*YQcT|s;B6P=kFXFS zO(NTviV;o|eE`_4g3YrIaq0y`O^@C{v$|pF^R1}U(OwY-r^$aeQGm>bi!^<>(EI!f z83fn&i2{l`i3%Q!wl}0E1+Io|h8Pz2X>=H&k5rBjL>eCkNMjWJssC$Uq*2lzBcQ>D zu5;|c8QH!>#fKGG#8Y-yBLa4tafW=N*2(82jl3=jL1AP|$2v-S;3t|u!*Y^>v?&SJ zRo>b;YbHw0FnydLDrkXBSn!=~etlM&0$P(7Soh1=J&P4^_xp3sshGvs5l3Eg-^SDo z{f?9%(v4Y|SC(hK7-fvlD`O>cib;IjG4-qoZZ%L+!v^Sw zI9w;PGC5vh-ipy0`heVYdk3A0I@hjp8wW6R%*FmUv|mgtkPCy~e2F)Ta_zat4$7tsK}Du=4aV*e#OiC^$vTGTXc)$y`K{E=1$MkReQNov%h+X_&+FR6?xtsVYiHA7mCR*suY z@u@Gsx{?{Lv!A=>7t6S#eTk@JWLOWUK|(8Q_RvXAU!VN7mqTHB1$8Eb(=;Dtx9hoQ zSEnAV{+@nbS-@_HMgDA}uz`t^J~YCB-VUqOgyZuE_rk)!SWLJCuk4pN8s0Dlm|Sg+ zAVx)9LSE$9fD+kSY@h%Vf4i7Q9tJ3BQ}84oLBaE8Tclr^_lax^MYvMDilQSaTlaW8T`C9jF)Att0Us5rLLne%F&)*DNyFPg! z{EI!5cja1o&7-^2lF~Qs;&Ey?t28xw*0c=?@kbUy{;YumJLEa1h0>aoFh*6HO7f0XQO8?WMB5M6Wk?QmJSd;uko-Tp-vW=BG zX`0<6^^=@#GpPw%kOL4~;iHr6#Q*o}Uo#E~70(LGk@M89hyYtpvP{T|N&Q0(eWOKZ zlMPMB!kasRRGxjL2NTyizQsD*GC*i-O1Q!F@7+u^wwmR-Ns?j#2+_{S*x9^In zTmTRfJsXPH2V5FVJk)2FQ8c~_=zvsnpok~Y_aqp<(UA~*GCkM@8t~fA4C|QWH+2xX zCWQ76h?D^T#Rw#VO+pqk+BTGq0Tt29eiyFr4su9o?uTqjaN?@C%h+Ni@T1fH{#ld^ z)-19RL+1nPhbBbF3?`H9z4AiCoOx!RvAP6%EuLDSn2ly1r}RADx$VX*b4#~gJX^zW zN!b`larCw750@dnes<>#i==Yx}OPA@*{`8H`QosmupMJNESK9#O@z(FI8!Kgm9cgtW#a zyvQQ)ky^lt&jyu{|3?dN!=2T8HI(3Zv&}-(RbfG}2cA1Rfj1s4k{|kBTwnI2y!?yD z>g}pzvfHfhHe0AxLgBHd`BO9z%G#OBZHJ_@lljlsST33{DHa`T4gTBDJ?Z*rtCHEq z{q3*t#NT{TUA^yoF4}}Wah(!SaTaXr5l#zCn4Sa|sUNpwinTVavhwQMMsGj>QRLb@ zu&-ko6!ke-2rmd)wV7vZ0(73{4Ls{|A*AN9G?h6Ly#uMMnw8PJcp7UGhy~rea7Hw$ zK+awhfEr#T5K;(}N#91X8|hGopog;dQ;@uklOB&WT|yV_VUeg>g2T|%6a}7O|KKgT*d*#vq!zi1DNyHZW@IQMY z^=7HN?IUc=YP2Hr7{$;pR%uHav_%}|Qu^cU7r$&^oE15WdKQwZ&u{3yOJdQ0` zMm@;PJJ9PGZl<1zGpTrSz;x9HePo_>N9*d({lfn~9N^CP%%MA(Z&9Xyol%}B2|Fzn zPIuRtub8#!m>~fgE#9$Z{8>dgI#V?s|GsfR(tAcdM1PAILI?b#qiXDg8-FTJeT0U& zf>KmA*jA5S`9%=r+1uzs19EWz7dlaQk4cXX>pN)gBUiYGjGEbF>A!ZLmRiVFM9^Lsr#i-D#^!=||` ztTy+^0f+Py^KkKQ`2sZ;En^Fijwr7eMj=npy_{O3T9FOB*S*pzni`sU-un+1N_eU_ zUSs?FqFb^kX#J;R=jEnUSPqe9*O=Ma+$_mCWLzjSe@X>E!HwMD>|?VY>fBNdic>F9ze?&5YG zC4~n6BK!&GS}t&Y0sL?2L2-lx?*upz3NLH0fEaQQ$K9fVg&!LU@YtK+8CNsZX1gNB3_WTDMrMfPW3|T{POU~xu8XOk= zlRK78RI9EV+WeceS*z<&U69c6?16^hoNJrBvTq4d_I0^*W!5lvazanyi{Zbxr8-~2 zV#=wflBT%HM&%H!?+i1n+ZvRnBJ!Y)_>M+-H=-ch80%6S1|$pwSI#3#7>`47Dg$WS zon{=zq$kx8i!jv+e&G3iWFrW@p+=jY3~l=p9nQkh)>@(fuX#I=Fg?Ih55q$WLRDw7 zD!wiQ=&mK-*h86e9+c2Wkm7va-H_$`}vgb zudbu2xi$OZ6Ao3eR*&ut4hwl0=OV%08#|(Lns9y&qV3*G`z1np1%3HJAG=KREFE2) z>jKCR2-@Aq$qf2vmC#&vWUa&BtJ7ey30XEM^*e{_o#aEhk$V;^RhdcjqIfBKou69)SiSa%= zV@QQR72Btnb|4WcAQNt)rGk9=>2ecRp6m_~K`M~+33ikPAPC`@g{5p2{tyg>*-I3Y zYK-I5ZjENAJ`WQl^9E$&F+e3Jtj)YQ2xTFkN6?W^jbjDioR}A-_V7g)o8+|OxIdFR z8>y6Aj%Df?TLi7)z^Bd|T|(RDDLZUa-;akS9Ijp3iN*?2Qhyc&xNcbouJScqkrP^z zUOfA;$mf`{Tk!U#Up-~G(NnX3RjbtP{LpQP&)^qg|Lu|OM|+3JVl#>If+>CjMg^1; zNwlPGO%dGTiENRlVuN%&vKSU^CsM%-nBn31xrPE=kt!{;%yf5vpUST_dVUp(0GOi) z>EW|k$Wc*Ai`8-($FoZXZ*1Su^A8NiY zG4U766$*;KJriT-~igjDorh=_aYK?;B&4e?`E(~IOI5i=}9lg5dZo%C9 zJzaB!-FBa1PnL2l%s4R)21g>fRA~m+4n9)k@aeS&+}kk-C^X<*KSvYOWhx>m!9)Yv z*h1rAJD3t{QSZ;@>1Uxco-vr`H!K>t^6q+>)MlQ?a~X)WX5{K zTb)`s?alaF=7L55`-t}H#SfB@}q!6O^Z_3dT> zYU{!sZC#HVwxmphBY*d(ddA6^KIOD?w^@HA@|AG40WJl~KKOSa7vXhpn<-9UiRut` zf2}QY61_gqD{o)S1>z3NjV>y; zpH@8RK0v5Nn~}N|J<``{-C|gnk*>E_@yi=!9mDluP$|< zJGV`upi*jZM(r1l0`DTm7w-s(<{z8zszfsJg)*CY_DVcgIi})G5`-^FI zWCLeCc^PBKEi`p5oC8o&I601PX#5gmr2HEzB5~q>)-L`Xg^%oUFR-dyE^TaixBdZ{ z=nRqoZA!+V1lYh-;mlCOAx~0BL@684%>Iz?-s6H(YP4PaKavHR4oJf9pQ6-Yww5kI zpnXZfk)R<2uN(b)Q1eQhx4Rz=nn`HjXi3Yd024apWp1d}?m4w{2PWkYi1CA7(HYH5 z`d}Ai_Z|+A2Wtqchr!4=4{|v3MjGcf+f)F3B<|s86w`c&C`2lTl zFgF)BN(~N65Qn|us{!X|@HcR#dNE^AXHpA6>n7*k*A<<=Uz{>K%zPU3Qh{iSB0?xcK!5u0@ua&W3kF!k|$ zntCjt_d{HagYQ{fUd{wz)bgq|w0J?YM)rTw+P?zk68v{eS0sy>DYI+v?V|MKO;*m0 zkjP)@LLZVWDQe%BM9~d1)fqxTNyWJvud)0UFnJAo>`lveTy6PlKV`Yq!iUipn4BbnIve+Tu_+mki{*zQ(Q-kL5XThUYk zVr44kP(tn>4obI_Dm*Eo1|Woh3%wWVLOljLNwxoxjiQ60<`~RVcGJbk=>q7WqzI$J zq*;aHI64LZYy%N$1&qgP$UmQ=_wLciwNapYrh!4k@O{<4q7`^Ql7^tF*tpHQur53G zO2pOwsUZ|Hh;?oY5AcOH`Qz(p7LHB}dEBXI+sgMAKUr6-N^~3l;24ynu4Zvnsh=Mz zH{+OS=-aFCGQPGJ51Kza(^9#d(myk1F0HTZT@t@&i0u8?HiYpPY%aHZIEHc7^0n*D zjC)7H=YLFAbp-^T0DW(kw*b`9( zG52Z&U>MyLv`{U!SY$TfV~PF4=9<7b{XPU)&-qW$;QZrrbjD&yTok9CTLbFwc_Plsp0lG3q@cY<%B zy_8{k8Pz>&jR3hNw0ux+=7PzDtW^To!@YKp4cOv1*~sSs(#Hzafc|C&FWtWkp+b-r z#8*NN*yYdFFylUX=;iA{M?;GyA0^l5c)6b!cqmC-1{@+;rXe zeI1XK_9f9VVr%dDIPJf8z&cZdmp;Vu9zPMidrY54QZB|M$5KqgEiLDtb_;1;N6@g=ZJ1eSCR{NZzhrV&gW!RCuf=-2 z1C%pIh}0CI+o~R<2JMiQEg8 zWiBmiDag1wn4Y8P8Qv`0dRd7*3z>IT#&Y=j-Mo)>|8y@p#M)K7Tu%4BEzH(u@7#1Y z?77#mDW>L?xJGfD6Z3{qcdsE^9lrrUsG_Xs>5M&dEB&RMQ9Y)K^egu}aGm47_VHDE z{Xb!eiitV{cVKbUJB~j$kIngmLiC@GmJtP{&k>Z|FMCXLO1G#jHPbpruX*cJ2suUA zhWpLLIjG*67aGVO)v>X|+KpEGf5j3DU3W#KR*HTH1{jEdi-7`!4{(P>K#U*2QMD)y zT?r@NhIGHEzVmWi0Hhm!j62TlUh1tgZf6b@Zf$ zViXkKHqo>w{8-r!v*sFFr@U3UYJ=y05mHmGQZbGuto=r_G`Nzp#aHZv;Vxpw`;w#w zIi_M7QU*q1O$w>Fxq7}Ql7;|U2k?94LW?LMgM!_lQXrvcJ57)RU&6CCj9d-x<@rO7 z<}BMp16XbkJb(LZlnS1vMS`i1e4Sa6q9%HVG<-Rcl-$6MI2dE~TiZrJK!*4YsyO$M zT+~-Z}m>ky*<$=E8p*1!X<&877wwv1b7R z=;hqS2XgI@1XU&UzUYQsoQ|mu>0s5HTP9i~trfjD-D2^{BYEMG8d&|`84wV4|DtKy zqmYN+3C7qled%I0TIK``F#vzq&@<~$bp0t>7~H&}h!7VnY@2Y+FQLat`IWR$l+i-} z59NXAbHQpd?dz1tURcKH{nLYS{1uDL*Wbq&lYNq4FA7+76>N<)_ywhX1!hJ5c)>)J z3b?{yrIubHt+bS!l$DQ+>t2iV`NAq}Ai?toRK3Jrp(hdJbc}w}W(6VfXpg>OHi1Fz ztduWXrG}N>Gd0y>C7jPHcfd&q)Z030?C-mOw_j9vCZEZzqPn)KKXJFlHww&w}7-@2}aBU+BWA0~zw zxxY!uHX=TC=Py#YcI|vOYF$e2<8=Oqt)AQXeevtG;wn`)$wPt>J&0{(8Cct-|0q4_ zR!rw~))y@JmOosoO*n@(NPaId(pj*?ocHNrMcc`J4(f~VI5mekEBfM6#w4}HaQ8!< zv$`wSl$&yF3QA_;_zO;CFkzb1mN!Ft<~M`*G2WA_Go(DMAk|RfN6$y$>_u^$gR)cQ zCRa_xW;cUVl3p-T>C`>`E6OVo|0BEDUBAO~r#GT2BHaJpZ`E@g?S_PsW2yKv zKexfZm3ddn48ws@bWSkgnq1q@O1vMTYHxOm2H#N_Xn!ep*gTUxy>&F`8YRnzDTCf8 zdhIeRiD4mqvUq!;t-x)@Sv4 zr?9!k?!%oA!u+=JS!TJ}jWL6x*ZCT4+D6L;yd*Pord}tk5oa$V+sNSB?S-TW!#a%f z^Jb$^nI<{6E3w(=;gQ{~K|b2hH~KHLue04v8t%K9H6ChjD`}l;HD#9L%J%)D3Z8WM zANB%?N)ha9>cp(loW%daJ<*^{=LEt0Hue@RE};2`gYTorn^Dyqe|~;gDbcn%vDe0_eU=Gf{d7#T_|(*8qUGNZ%N_ko1}vk06Z@XIrRRT;yAhxe z?6dY>`0Bxu39p^B?I$D+3eu9TN28<;P?z9jNG+U}yhMAxQUqiHskd&Hnt<I$ z(+BiDh=Tj5FfqN+I~C}>FIwxnIN9cy$~N+U@Z5t5ixuVDM@~X&PnH-^1ML+hr)uIf z^B3v$$cgYJd9x6oVnUm+0_;$g*|2@uZ76UnYf}Acw*VNhuS=>mM-5$8BA-rF(H`zC zJn0xaK?@+2y2KPZ?2|k6R3w z{K6{`OBrNUO^}2PUgjnWzr93qVlUIT3aC>RERSiTrB?sA9`qX97t>))rX>X4g+%h% zzvypn=->`^jDC)PZjt zzcd;W>1{oH(@S2uy?({n*>|>Is=C8+Go(|1>C>@ssi4;h_Ia{|n!)1ob)xfVxR*%m zb5z+=j$=*srh=RW)*r`r4Lh>9nV+6q(gakk)BW7yj$ISG`=tF$hSDnYw=Ps zUghC4D42&7VXeExGvcy+H%#8f5EC2Ky1Ukv+f6jd8~YRpJdq|x z2gjd%{<^*1nibu8rtFi_;J|n1SMYqoRPK1s(Hrmy?5$-hejsS&Gpf#S2R?p)%gFiI z@W3Rp!Qt+W?uW`d)x7?f1MYeU5;dgjJOk5rst%rP?*5Y&bn$ZR6@F!YVxTyE!OW{w zE^|Wup+Qu@#-cGpM4?AfZQpbJ3z=_x!Qrc&R6QKixgDA>RJPrR_#F-Hg*?aJj96x! z`BQPmq$sH>eqJJY_)*Asvc1pupUF2La?Itb87~RopgrmNi;>i)+tm7DwS79_IfZm`42HL-792f(+Ef`}V-fsyA}&0hnhf;x7h z05(a|edq)`N{QATZzyov?Tp*(_Trz_6?~j#wNq>PV~jEM>&B8a!+*m__9`FGCxUUk zT^Hrl=O*)~iTSx-Z-(3|cg)y*+Hx_=m$3biBjYtkmy4Gs>rdfB4m;W@2MIIHNJLdb40 zu;@FFF(Fg^c=quRVW}zm=`WFQpoQwOa!DXV*!5zQV8ZA_Id@4(s}J_6n)-52k~zca zPlcSS7*|gTIm*q7dLla9Ca_#DUdNJ*Gquo_^Ql^*jqbH;&P|MO`S{pvZU2q&V$w8% zAi3?ELCAh+U}l6hzjlS`414T8%VXHPTvNh7Uwk3jq~@|{Y!^h7c0U?dev^e|N}ct{v(d+ZxPS6&+Jxjca+sl43yhg)L%o7CL0~DTO@97p-n)vD!_l?jc*ThMV^!Gn+aQdvQS^aFEI^SL0 zG9rBRbRz3z*XwOTW8Sb$pB2Roa|P{Ua?7ZCWw-UL6Vn%G^3QDfk1c6Z7jF-yeWkX( z`up}ry}M7k1ClkOO|quDs^0a-tzUY3k{YHmCX=mH^Z2^bO?|`SI>M!0#1v~>fPu^5 zeO``kDCtYCl@fGY6#STIToh<-q4sB3gGa4+{7GRUfg^#QiBan1w@6FdS{09G!=v2h zaGga%#g~Q4dRh%MR6})P0cQtzLbhmIk24cs{bDu5691%?O$n@ zygR9H3IuUX_1k$xE?>iXiVH^C$i$u5Mmp=C2Xh7oa7}mLmvjFwAx}VRa1x&0a*LD8 zKFF7ffi<4r4AZVz2-=O@890>_(CY83HGR@!lH2l2E1M`frWLO=TxMDSH1kH~eH(+{ z36&2D&wLoaDaFegA^4i~{pF62^9(JemVNX3Q0I~2Fw`PA$aCeTno;m`%SQq_;;imx zrY5Jem3C9_ALXWd*O3+SVcFrk$r|*hBOYB-Yav$nS>~&mR3+c0BgEequGIG$`e{@BoI?=Zd39 zs;@VHTd=;XYgm>M=eylq-6=q$RrFVID}33ZY&))ur@G9>P6=N(a%#lTQHgh`QU5gF_rQ$wR>A?(aumi!(*6daBH53W1?~>Z&R%~(P`B6E~g|fs}AA)3IC|!X2e^0r_CwASZ=H~~J)t%P{ z2U?Wf-P^9;GhwvKOw(UH$*lV7Jp1F{u&(d#sm({_Cc7_tr~gI?&BX4!!ZSMmJ%e7B zKCcmQ;`cn+;H!F;rj<%&^@UTlH*|7XgWbLIUXRb-$XReSwz)^6W-|68CFvT!oOLqO z!m->=bIP=GxLe8r-^gE>B%ie@q_)&^F(UOs79_SUFRZ-0u)3AfX#eDw+sf^C`>)D^ z!*(O^8Z%o9Ylocpw2z(Tky4(%kH(IbDw<_2x0%vk@svhJYr3qTYPgUmM@C(<7yNG1 zE%=??^$^wespkdM^PM9pH@I)rN4-Rp52vS!B217v%ys0J;(kd}PPw0(wp9A)=l@hV zo?-M#*70J|F=e!3uj9FrKK-MVDuSNDIzQo#SNvXsba#IK+)dZ6uGTKYo2O{X1V*<4 z52U@K`m_y49>jSl2H!6f=NXW-P3@Bp?vA!@%>CIuHZ@rt++F=WWojWf(n#>}H8Vvg zC92H7cjAnE-4kE`h~NAlSmcyEjwV6;oNY>Qd>J(DY zc=F@FPfh^}c54G8xZFtkt=9(vrV;pNouP^DYj3`IRu3<}UF1o!7f@)b>OZ?G6WYlT z{MPBAd+PC|)bv6A*7SiIW-H`d3T@Hr`budZMltlLtcH2Yl`oIEk(C2dPk#Acn47vQ zdnHL`eED0iWs60-@kGJ!TH07>;HqU+KD$#H&Lf9gMDm%HuInws`S1!3x0LFZvNy$! z;oiT}q-TB(QO}1DHwReaha*M29(xW%8pt&~9Lg-h2JUa%5*K!AY1PYbbHAoGvuJ*8 zX8-eV!!K*8i}bJf-A1JO2@7BAn)&b?mCrd69u>!`8a}h0u4&Ca8l9-k^i528#$zz^|w8PUvgj2Ba}Ivbu9~yp#2g5%n#De{DnDsINU?r-SRy3LY2?S z6V)IkQ z@-3C7p2jP#+D1H_LZN?brB$A-$P1G+s$+_{>f|WkH=b8y$75C5o2oLmc z6A3G(K8B4}7GA7F8$HI;Jb!1B>L(4CPO64D(!TPjnWS8n*{_}Z^uu}e?fv-gxs%E2 z5>IBIsgEu>ioD49wl}hDng3;WT6<6SpftgA7r64HH(rTVw!UK;7k;J6uGmc~)Q%Ck zj`DeChXG|CLYfI;#qw>C4u$X9aV+%c1+(`ozm#50T_iByU6hZBxrM35nEoSUp z6hBpa2T>}N8cFOlR1|%mzWKY?Re5r*^PF?v_xJOWqs)TeNn^OM{VA{dJvxl;XnI2t z!!}l3Q51kS(8Fk>E^vCQ4~N@xGGM%+mdXWG>^xr1pMw)6fBQ)OxNr)N;8e#y?XZ6- z#Cpv)E}2gl_A@R)@b2XmVri1-94Zw)j!nfs*;g9x)i$Qcgs_N|){Vua>cV3`Fi8F; zAv}F8FSVK2)+sIb8OPFGjh(v4n&^+Hx4HKs`?9pNq=eVStJRz((;=*q*sUdZ-s z-w$Mv++&3@u)ZWhm@oBtmNSO7d`w}?Bbh0N$-iDzdm|~-8`~!LI>^;z-sWh#-Tq_4 z!m4?u1`1>4*`90*z4LJHc40=o;;qNieMscIZ(D~G)^y1|!l4r0$Kkoi*yxu6*AaL` z1d3;tV%~KWJRDrf|IT^`(-JVbwil{?l?~C!HOGiAYlQyNZ2Uv$AHgE7LYDF4+ow@J z210tWI}PVmLWyDP-?12ma{OJ7mx~LN+J+)!tJWcdU$hd(OQ<;_4i5elmBhBz>W2;p z>k7$$e#W=x!ah>QOZihSQjYIqr6^Lt#UIhS`kp+ga9Q(Sb#EM?XPw=SmL@&qk_rkt z;H9TyX55>?tTo7C!9_CRG2mcb7C}$C&PjL#Pi%qq)C0QIO!cHn(xjJJ&u^xfJe=fuuOatb>T`}Ro zfeC#t&~_^(k<)sSt8ts z?q8@^kUS16uldl@sWnOT)qxn}3VZ-_t44qPRlZ0nP`Ck9f~%>&5}ae~1F=7b{-8U4 z-9QSi5DzohY$Nr3@d}>tQF{}qzjOlia(7GIAIb?3c3VaT68e*s4zD-05CWRvg0KIE zBKf}c{VUbCu_u**jeLOEsP0}UmDaO2{aNI}{1G*oB%xjOXQi)1ihx}0M0EG{B0&bh zYvtj6KjpBRN4k=xWZYTd3O@hfs-C?{fdJ6!){p2p$F-F-V6rdpcIkh=-T+p*&s6l! z?rG&E5>6w1?~pS)a|f<`)?y)23kV&f@bRsWmecw-?g+5xZ>Jt9qn=s=x5jG43+#0vwN2SKgh`5x2Qh~2$oL+vl*DVNr?9tT zt;RM5q*k#SMs>>}Z+ri#|~&rHaqFu(6!AM4ouRI#mEqQGQYKJ z@w+sl(9~S?YJaC>w#;jxCoQ0hlf#C9TU6mhW$2r@v+~t3r|KLXK2XGh(RiW(~R#2CkQW;fb_`LwC6M<5IT!XMA8bT+uP!$hilXw+sH#Iktx-y+L?sr@jK?%d+!;qCt2 zCMRXQ=d!dNK?|;{N0RQpr)$CVXF%dw3x{Voq*hEvX8ZXyqhn77uNz|9WQV7GuJ2uy zUY3=IzQT)P26RIu^ULeY6Ed1XgN5q}4evXhuY<<9e2^}tm4R7kcoFST~k??WlgWpE;!{UY}&B=MpR76>OIOm{~ zRAdbJEWWSi1{bG%o?`WMzP0&ew8-D2gV`S*d&o6tCawnriATLjC>>KouK9~lsn6!{Z z+eY+J=0EYudj$uuTI7i&$B*r)qpd5el|I4Ev%MWn)Om^>F^uuI0adc$BHf4DJciFG zs)x;6Hw_t^#|=5EnOAuVba3~+*9f~eO>aS&&qrBUZs%M=krjsdqWd{t^GzLiMj+U$#JwkN1O*Kp=@8JktWWZeB#c zr+*gKGY<%=tZVqd6=JA~w^eVp!>moddeh$udeW0$)G~-90heU$8`j{6b*y{q7t_g} zxnI)U&!HP~7ret6c4^C%6zRm($~uh~Mg4%Y5PI4P>8U7)Uq-&EOwjnMcRvTXMfa?% zAae#q(iKfh_><)p?0eAnWo7X-9gpK2tLGsCd21Zf(TDDOHbjpFMZNqwN{IGH8BZ>) z@<6dZJA%{&a-*rP%ytF6w8@c`;T;mB*0O;pDGQGtv3y+PM;b;n*qf}L)lSa{-$gW> zckt8IUM?S*pRMx>A6DTeo>Pyu;`eli;mk8Dw z8~Cj%F<(UAc|57+uW%cEo&5FaLdqnN{hAJc4}(ZTrEX8x7x7z|h-U}3EG;wViLqrE zx3sB=EPWj1y!2z;H6zLWkA)jtP;V#X=>lrr7f#RV?l9dYq5mPvSJloZIY@mT2RIFG#J(ICiq8f=fotTUnktHJ zSK}m{+p7&MXbhM^2NG1>ZOj_TGLGTqDAmq$S4&0sRqf@iLY!hLx+=-Ko)-q?XXr|! zif&VC`P%%uq|daKtt3lA%6I;H7AejLHc+2Y@KQEGlX-u3E6_s59_f&sE^4 z7O#vffE)W2w>m*IabmswhcyI|=R(iAnqoxx2;<3iO?e2NV z=68zVEU7Xar}4xKA9gm+!5cjO&M(k_n++bBn7T3p{;p5M{SozV^dFdC`>J zMm)dh_ab?`b&ew zjiR@~xHg`PvQx(dsTpN zgJD>l8#A@heYW);QVsb>86E*de1(%AXRB(PQ`_ejaU1+d`IiIB?K#8t|zG})(Ll_c3w11y<&rP3q4KT zF;_BFe7<-6Ej;-w)4an(d$_#gldhIYwsLm$UA_PQkd%-ge6ya?zh>I}Y&NRNfVsLt zOO+@4qncjmsyA9w^s1XPK)Wa>whvtK*Zw$Js>mXHKcC+kK2!9I`)P+uFm9;LgknkYqzAK(IV{A%*&!GnS?L*vKFJ?3^9(f%F6|`xHy`)EVp-7u3MbjJ0;iS&kMLW0#mko!*j49)90Q z?CtFx=;=rpnfs+T1zcR9=pILOqDhC!PFj?ryG|&7mFw4^?~);^Ug7Lt0kUKJAyYcj z%Z;agEbje+dc=%yD4sTjP--=7+goMcn%DY)fw)aHi~q zhp&eDW*0RLXhnLUQet~tmaaKtDIp0aW=xAA`mE zPWyn#rPo}K#SSfAymBEFUoIdX)Z^AbX6Ip9KC$Y#B)iT>oHcE6l7n9O#P zRr4z%-Y}+MB3oBuPUvS7bbmUY!rfb8zGQ;eSW`pQMpw0>?zV=7+JD{;=O#06dp!lp zUsV#a3Y_BBEp@&uf~M33Nydwoyn?5I1-aGPjw$#JZ&tK=mKFQy}UbL4$6f~61!SOSAc=VxsBmr~kh zs3PvWf#jx(fz3?1w0aMuwHZ3kIe6BApQ6QJ!63^#JF_x%9Ie?PYpLNaxF{>8mDSl6 z#rIwPVcay(%;BY^yH{efnVLzg0Y(ae(Jmcc~UFSmWn^F-ts4ry=7qN^E<3FY)^j&H9QBSxJD? z`o*&Or3^aESbRyiU``g=$S9_3)Q>2J6{wkhj1~(kSh-1DAI+5-03mH zGq~9WFE9$?K&@^Q5p0zd#cl~Q?lTdEfmG5tryza?WXYxEk%jyw_0r}>=4~j%&IN5^ z+0ocao!=3Z^0cb2V1TO#{@4r4mK!*P?L||SKW30`Wp%iQaCw14 znpArLu#A01hmC2`w+(%FX+BmXulu4IDi7o%%!8w1idL^h@loJDDHRq5Os=MEw$b&h zV%EE@o}_cvyAN;Onva$|?HkWWcKx`6^mL(~#y8R$k4jHH$eZF0)0#QZv;3K&fHA+8 z!P9^5|4Ap}r)%9J0Ga_eO?4h5G#>oPH* zF865%SQrd!2F5+>f8=PSrF@J_$d=#)W|Y}C(1&jj3SQ9p#ZU)*G&#RIbo0K4fCnTt zLz2J`0qF;b@@J^4~nWz z6mr@ZnShqRWayEBza(4IkXVG%TfIHFXY*q_$_g>bu{V&(dt=Dx0Gt84SCef167=)u zsJiS$0fTqIRLS18gcQD>pG&dp3No8IzHh6v|Nr6y@E-P{2s5n(c&uNeyK+U@?Un<= z%;J8V-eq+FtWbb48O3-o@!xe8gL2Nsu(EL~ru1D|+tc#&v`=9*gz0x;d2G@o=Wmld z){_oD+6Dk`Kn(kH;y>Ku7~?)b2kplKv&=qTHFp4ar!1M>3P6ow18(q7l>nU+;jLW} zQ$vY{2|iMQ&jBb+YYA5;qTk;-|11TJkp%o3p}KQ-8pAGiwN2a$gtE+TE4keARmlKi zWzM~GtY-jn6~+goD!xQZv5x^5D>m3$hR>5=`zp3T&*j^E!Ysi!woB7AKoFkLH_d*ip2& z1%x^~I`I=3nQq9eyUU@_MF0g9O0?$uw!8a1fo&%+wYbv@a4>{`D3T;#!1gXNBar{V zw506Yxy=mEerC^V3Z!Hs)fz;=vXGR3>MY!n_#LBuiqkP~ z=GX&{$F4ZpPF+mYM45vTei=F;)Y8E-((0Y4XdzebS=6&ZzCnMi)=&8}w~rX*yWQ0I zuEW6r)#59V(wgDu(|eEW)gR^b)(hgwA|}O;XjN;Jhx$lWfsWY_Cp{fUUj7Zj$i-}e zT&~vSjIHv&2-~attcTfn0j{NM>PI8tJ~Hm(@vGAVyLH7M&iWm%3QoOlOdv`@Y^N^& zuMwEy)bVPZqdS__Z2bwTS07**vWgxZ{r)3LFD~uMay4)CdZc;iNti6!`K1Twddjl~ zJerInd}oiM<0%SzWC4-hF>4BtNl12bu)i^@chCWQeLHdk#~l~F=(M7Y5yDq4R%-mi znBZKo=ADfBO#^4|C6BLHVDBb>yh!77nTO!(vohO~aF;Kt7zjSKkX6i{w`Pks4+*Kw z4^qj;b39FQ{MIdZ1afAp8pw(mQV)lmd1{(cWt*TOS}QH(VF>6%ips)Pz2Kroodnd!7b!Uh@t|>krrBRX0ndVoGfL zOThm#Q4rZH0mU1JngjtQaz+4`u^s3DY?lQE@=-f?u_cI-tV9$&!h@Vr6<^>B~1KmYR$uK`P>^aq75l1<~gEEi@NffpXn(Tnuf1o7bAS z70H+$8t4Un)27xkh$WMF{>6`GfGF%uo9)qlu+z>)j^_AV#TTI~(Cv8%V+5u@pMl~d z=4r^wr+)pML2H(xi7h_EMc>KPk*Cd<3*}Ybj#rSgMI6I!qO!Z?#M7Uzb!BK?tsi{5 z+WmI}!Ke3c{A|!EQc}N^gzAEGVWy^2J4Qy8wU3kIlZT&*MKmTwEaOe;O3AGk??3ay zeiXp$((SiDmyBv3Hf?2e7&p10hr4z|qZqSd9N56?+t=crr@dRp^^B@fe+k0JDjQ8y zfx~_T+vMe&-{HF&18M^T=GV%LaeoPp3OBZa62g`e2U{jx9J=>~d&Db5vuvN;Ts5E4K^?JbaZ!e#)6sHgtGLVp0iX;0*CK06+_{^mB5p@eRa!Ym5K>2A(s z0)t^$5#E0Z8UTyrBx6qZ`tp0mHH^hy0{M1IPke+DUPa}1*Ny?Nx7i}mC{gI@z+$p# z6#Q*u64t1O~VeHn7 z6QUzEgX^kBfp>_hu!qvbiRh44$eeBOiImT@knfHgnuma+dg;)(HoIpvp+*%Qnw|fI zKH5V{S60^{(u}dP;WA*nW@f+!)t>Au?zs6v*epFCSbTc&Z+ib&@OMdRHSsQ&WCP~l zS#Bxyz$9VZd~xQx#2P(F_He)8-7_;xXnOU2q%Y;&;gw4pJV$L6ISD*MMGP;W&8YY^ zvYLZ2UZnYb(8Ad#j3P1G*5>A6$LvB?UDPBbKQJW~&H^+5P&GA2S3?drAZ!|S{5l>Z(V5iT~)YbW=&8|WdVHx)vXK@(0&ksAj3sJS@&08;Wjyq;UIw>YDvr~2_QBe z(23`G$kGoKID7CU2q)+RH{U;U^LVqwHV8|w@%znz zH@r#*T%2GlDP4sJ`VXz2Ny~SZ$7HRcU8_fLX9xz5sPv7o1>Mqr`{~E_XUc8mBjEdZ zKR?3$yF;e8;*KXm{t}cN68k?MAp&y*d!*Vm#KVLPS=Alf_2yTs6rh z#5a5G2KXJ>u~fRLjhy3&e9o!{Cf9e)zjJMEGQan$LgX~u9I{I^vg3Rob!M)RGHlKG ztNF$H?thBks#C5|&Z|=zdV0z=Ld_LY=BJRDtzW=@UVmWo`X6jEzXYTaD26!4g;j;1bN}8cmTyt0j zZo80?xuH&$5i;sF<`j`c>h!j5v7<=g1icY#eojFd<%9yK+RFAJB zj~wbKa{_kDb%8+niTIh4C$1rirYyW$7Xy2%IllGXjU-q%5ui%NniK{EE+ZIjf*(+} zLQ=of@eS<@7I`-V%M}%=0s<4=8i%c zXZCPPc}^=|OXT|3#Nhw5UF**jv+(v;?Xu7D3gBkOt}?J>lbKsSE?lBnzoNEUMrTh{ zXj58}OxaGCC&)|Vn5+a_g{yn`tia=@+VR#-e?n95Ujlcltgc7?5qvj>K-S?E>R87k z1v0nVq7Q9vH%h|J886=X^2LeMdPhdgmu_pemo`(b@d?#$-*FWy(s^92cA|vxICOic zVf237AC~^54*iW=R~0od@!%J-Xl>&evEi!rx2y_>#$k(%vhs88VMcUQi9XOs=KY_3RZ%D0*yTEh{7y1WUxBnpV?4m(dGUnXv+p>?I$@}f0g8tL|vNf@0EM_ z{<1WTUslSrxiPTb{7YbO8U-h5f|!&o>z;H)}tpM-gh{(eS7Up z23%i+?=c=*-CC=cs(*`I1?)3n0=Ke+Hm713IMg{-KC!tK`qM zEP7cH-Oz=2NXDIe{qVjtyD!3=@%X`8yL@0o-3Ls*AEZtgaP3TFWBBw&!Htt&DfIz? z=2PUEp(yBr9S9i7q)7lN%aK`{|mTXFoYQ15_GyKRRioe_%V)*V%ZOeZvaJP=#xO>c@eq`9=>bi88(k}*44(s zwxM=5W|@9~&l|6$uJGkk7#K+n|)}xttYgA50%= zC=6|fE#Mq@kFuTM*81B*Ht_TiicGha@t?#zuk+u3`b6{kr)PoWZx?|GIcz?jg3{pf zivl;;rn(&n0~K?+!)mMYuZk<0hrG#3zkbUhf88tQICHUeG#T_b=rxiuQm@Zd!L_0h zO|OMoC3mPwuY|x}`c4(@^L46*=IrG&O6d%|jj30|i>pvDv$T($L z7BG{N|0&9Q9W)d1a?W@Ku|Wuu?GaEq{C(xFtcX|4;%+G5#WmV2rpJati! zbF^pG797EWtwkK(Zrb1|0xej#aB7$GCS=Gyd)ZRR34c2JDYSqpoZ zdxZxB6(BcUFn-FD@$wh8u2a?m>iw;MR4cMWR+r;My}|drV{#v%XX!QLRSw(L)bhsV zmx8N&fp?R6=)~>!#1keuv+#H|*#M1MgR10RI3uT))+sZs!%XMnVfWr+cEP8?!Hz*Z zE^+(79RBh6PL+hFy?A5?F4+nim#H=(0lpMYvB>r0Q}|+B&_+toEBf-=&$uh5lmj2^ z@x)#1`+20W=X&bWv|Sw|(qRb+rM2Zw3Y5@{WlB7M_sG)nlU#SNOBXO-n!;@#m`F)_d32$bT= z6=VP#vP^l2g=nk_wYSAXMnntAaj`MNglU8bnVYQz=eDep5(wVet^gMa>iZ z=$j2u@DQ2ZcQU`hlR-%-FC~5lJ!?|iz*GwfIaRaa3a&X{`OD{TNRl}74yiwW?0x>_ zh2654pDRfFUKH=~gs!TGs5@&);1?L9K1pR&2uc8hggn~ic$vY^^7~%F(;vsNVr@UC z(sY(}qcTmbwh$h$nN)B}a?{dfKC2dA-5y_cm20?H&oT`iM$qbHh;Bb<3b_#uxltRO zlPvH_?=e__2t1hk&%}6PNDQwa`YLYKUH^U2O3?|OmuOJ9AIPPbsoxg=3U^I!Q1nFG z0eWxL9A|5<3bkAr-l5|S$RGaQmajy-;g%wIY9$mu7nRX;B~mdPpm8Jd7@*$lzjgQW)ZV;O|k2(*)>K^*2mcTYO`g=R_H{4;hL}ox4tK(FaZi{ zcURcANh)f&<}t1{8)i}Z@Ykb3(qf>av((J4=ZtMwm1PBDqo&Xy%?epnM82jPs*eeJ z`m~aSq)}d%INa`?ZxG1K+siMo@6pNZgoac&G=AWhkjTDPs|}^YRrUs6tRnUQL*}Hw z7YnZV5_O@8=nWZ=GduoEumM~vi}e}!#2 z<22)TC>oH_*{F=5kHR?uIF3b#)74R>MeQu&3L)~j(%@4RcPelz?Kr+^0y04z$ zZFXd;YHAb>?YPO>?0A2xJM2Q&qc({OdNehcqc~Et5Y^y;`9RI*jCetCb^!?=_zhy> zi|q5P(=Y6b*2je8{7brnT_8*rzbBos0)se|Lh#+=5h&56$MS)W~@v*X7m z^8hLYS*;HN0wd&lb2Ce3;)XAN>6&?N&C~q&GG!3^QdrG$b!z6|Q2KBwAOf$t8pS8s z?RJ!|sJU8Mf64QgV7kXaXAZHDR6pg&t1t63Q><51Qd&-||2)uqk0NkKWJ;8FeCg$D z^Z2C*%J6sMT`%lNQPTlS4WRNWU~4s16;6U1rG1@cP7(acXM30^=JWcZZl&M=Qh@cw z4GVdi6v|TED>?~Kvfcvn$?6LyGyB$(7=F4ZbBMYv{$YL$ZzM_`@f?G)2LOP3Nz#kJ;cObLl zo(n9J8GQWv9gdBV1ELzw9qOQCzc-D(Aj(sVBCGZq+;{9fcnR;(yZy6etH9QTE}bDG z0|Sbr`LxV0#~f{PpR3*J$WwNSHix~v>59tQCRi-CyU?Dh7zb_0I1FM96W~O6ga(yE z9ADAYyshXIbZA!<-CX|}PY()TO#TT**ilYsV*PQk^?gG7bgdq?mr^>Y2pK!!^fw-` zP8ySO{_ZiZuivCwXaHuy=5PTy-e%;xP8CyeY`?zs09FJcL<%R?y&Q+mT6zemYN8Z~ zp(H!4Rz*<$qVe|=|49W8HqZr!YZY4YtYBj}eHwMKo&7Al7^!Om5qz*s^;|3EI497- zLWTlUVw&`LKilJ_4itW1$3x^Ar@;G{V7Wu7vAc&8FCH~P3T69aR1VZOwp7lgcC7yr z?D1;a-Dulfo(jdOZa&4BR-+?(qHr%4q859UuCTNuX9Efy#P;Ix8a?}^XVn^V5|JP3 z?$>-RA(V4?N)OZjFi?in>tw6A=EM+{{|k+RUlcDTOVK4E>=;Gb_!&}kjCovTJ@UR2 zchRlsBVTXL92`|^P6iHS(pTblAZY?;EO zPBh20Q$lgTz`)^c8BtA1^1ef!4NSUUIK$&0A*La832^qj-&Wn{Ly>+dw!p}T5wGCj zcA?dqd1~5EHYEQbmTH&I%j(2+aN@w>t_c%P&Bn(V>yreW-qte~^&c~CE@(8P6bNgr zA3<6>iy3osbfSqzLF%6OJ}Q!TkCiYpv;+lGJA_uP?+rv67WvF0*~62-JgumhXY--< zy_)6=-b4#-+eu@V1@wa}CB#0}t`-V3_DvH;)t=r5{jL<136?9lp_J88ycXJwB2b5{ zKo0lNw6gMr9z}1;9h&UY2l=C1!Ez^`wy1oyTfaHu!j>oHwuze*_`w4efg6Ui8WyTm z8jtIsjWBFLbsi@WN<$WX(2g!i5j^_SJm~es(Ft)OSDBL7QL?=U55wH#*Hxuj;+#wn z;;XW*q94aJl!JKbroQ(y4}a>}n@4?IXRF9C#~AEL;pI)-nipOJ3IeTAmJxSHI>(H- zhPVZxV!=IqVR@_HF2hG;v}f_G;M_^WNS&ENO+7q=1*UC&BNqLj5qO`3k*Y_1SzPH> z#pt^rinOmFY&=$@Lfa##ef4fPC7MPzn+akqyv zj&^a?!IfK|)=p!@(&f=tmSJQAM-W}4;K9*h+#{hCrtbb^MICWAZan(Z1YPjLP?hL? zI!rt$cE0MDu8H~gpI&zFKjcAnsfSxYk9nvAV=Jy|%|y-JSd(BcC36^@8`H?%P<>kH zl?$gErxd%&0|v>X;eQFv{h?P|`OcE|A=n=v-)zZ#r3(yD95B|3@Wo3+ZU1UyYW_=* zDxfsY4`&dWwh77M2T-@Z;)Haz074s3$N*O9mtlNd$^eK8R~jB+3TUYTeS#&)t@8+r zePt>Die>^dXz;W9Hd#`1oaSW>*Y^nL2i^*BwSu87p9=E8&tnu`pG>Z5gYwt?!xofrQGsLu@V?%%)N3Mdoc(cwz< z0R5clZJOjypraVZM`@9N>uQnwcN)Jd;1>ndbY$$lR<~C9sBeGI6%n`{{AcXpr&43; zlU)`2@;H9{&j-Rcl(<^sZlg)+kc617L7wx=H>D1OIVD$*3!%rNGi;7bf~scBTU>Xz zYV_9*5F7kw2%ayUvfO0la_oixy3`Oeu_ zA^2qpouMqb2HMl^QYlAuDZ&H3NiVWLlKq?mH$?sH#=r0M?TJB-s1D}6( zpXOHOe8tU`T{Tw_OeNMlFr1x2?qt{+WIzW-a(v|qQ*db0{F!76O8t8eK|Au@da z=6h=O-Fhdx9@pjm^dBA(AOupRs@Cco1Ols{pbPr(N8WpMA!e}7C#|C&P=iX{$+`i1O*Sj0TMCCF4P3jgZHtHrqEZ*X=;fdtfk0s?F+`Xcq*I$!7LvKw=1w;aFhvpx^=8*CX$AzzDCvjw!5J<%c8 zrfg7$jG?~-`4FH4Y-tje$qkTCr0BI|r{~vu-Fx~h7cMoG^#U_mic@Q)eL>F#KfXWV z!6^z@cQqgtap_GEd6f8huX_Wx%Kslr+}zlDvsfGbaFN>&QmJ7lt3!5-gjl7WKkDdw zDcKFadXM}_y2g`&Z~D&|!(mh+CyQbZ-VoeYg$5dQ6#$}NznLTM(^hwH(cpL5s#&p` zVry7FPq7okon&k~t?)z9Z(zcV-f~&HPJw4Xt`dcAk8JYvDV#Gk9>Y%RLdCNdPqloe zgw@#fW{#$&6T669>H`$tCo}Z>Q|z0`1_5n>nwU)G{m#PqEWb`dU2<>%m9Lu55gZVBu1G*$gk`NU)SSR_FS$4>)j(18gZ=AFgrzXYE2fQ zYH8qieH4bu>sE&B&>NLLLta0&*k=d{>pghYC)|fu*9-d^ISa3t)~GGanOkCie~??9 zJ#dN5q1NaEGGIjQ7|zB122Y;cr9D^&j7{A_SGTi^$+sDDAS@`lnfSYO0byZ^W?W5} z==tb@!Eo_|Y6{o3vw#G`smc%cX+!HR7rJp7Jtk{7)t7W*m z@^w`+tPx1%g!_3hIBB$cf(n-HIPpW4;_GP(9p_I&%rjuJ9|gT$GbJNWyc~in?@pVc zX{^tvJT%Qa3iL21i=RFpme=i6y4(779_CAYv%PQ{qCZxF!eEfb5Dx)v84Qn9hPDeY z=dF;^xd(nUwcMIrzZ?S0JVONsb*ASXWWxwOm@AXe9yF z+b1*K-nr*)$04Dsb{q>l14W7pN$FtrJ*iUECR*2~9aNXosNS&ZpKGBb_7SJ-&L5Zl zA98HeaTs)G`^910@8Hn{(J}lRhLEyegz&vC16b%;{c56#kz}JMMfMW9n$Epq-VDCr ztzJUs_-4EX6j`mZ)3Z?Ffop6%He{9aHyXNSEuT>D>Z;Jb!SV z;a=?4pQ4AjLtDHhxEJFM+q7d=6M{4#PJ8_EFkFML(G+*s11i5AF5 zcNExx&kM>Uj`i&vI0pee#c9`pN#Ug9V`guD(dXQOi1YM@nTCDEyv1t~x~w@_^RDM; zz5z`$D29S0_S?&YLtKLsyuD;%ph`gsN~(zfXV+&K=dJp^4;fKIdTk4TJ-D9P_s?;n z5HURiH1ZM;`pdh_J2G`KXWq(QyS2cVg^%<7Os+7>lVu$rJAcyqfCdIHklwV|e-w{CMdE78Ub(={MG zS##@_E}uJ9&(kdHfYUOaV&4gylXeXE6|`UPKUhfN<6-;UK#^hr>CkrgK1d`6f@CBKba}aQaz-tTGb;SECFwaqYWAdXP_*>ss~wKLwvZ|FM=> zFxaok6B4S%A<`B?^-o;u;k26apCr#cKO#?jsxUUxT^dX_62P*QRj#kDMI<}JFUL(@ zFiC^pXYeIv$K%8gpWhu#r(7}UscEXHn)j$8ij?8mw6YEL5C?M@=))@rRCRe$%Rf%K zIdeqs2zZ#w1tv2%BU(@{oN>5PpuIS|u@)Zs9HyC5-rDMzz7^nv|>a!6SG`)^3y;*7WqD2&*T@dlm`6V2Y|zg=RQH_tRJ~eOV`ZqACnN!+%KdPqCujeuN<1`K! z1G+9qB;#UEB%C7E>=KNofy%oFTG)vrV$1y;u{t_Kk3{z)iY0%d2N~LR;y&a0nppU< zqL4nF?h!BV6<=&N)yX_g{_~aPkRI2@(f(YvFAC8o0>eQ%Y#JCn+AR1R-iWJfq~)O> zcQJXtpBNmXA0k2~LWA5j=sJ&#d>>SBKuT59d_*1yHNet#_MY^{f2jz*q};Jspn$pM z;XsLKUd!4VPA1Ox`zabpq3@Vm{6HAc&>dv2Y8)`rxnR9t#RI<_tgHj?X4edP+EfTo zgrpJ;wmkbsN&*4@RHI#%#sDqk0Dn~p)<}cRo1N!rI-t`4KnY;c{BZ8xeg=s5%=Mm>Q2hIuj#w@(d-u8^TN5pa74Apr6;a7w03auR%3*K@9tz z6lGgJyWQ&}ILVz_yM;>tc@EjsRMD=Mh}S_w^jRg12P>Yq6!OOtd2!P4zVy0dLo}4# zo6fc5?Z42ISwS&i0bWm^lNe?CVrKoUQO8|JDkzwkJt&yokA5g__eh1PaADQJ3fG{K zxxlE=r0Xsa?+R({@rSsx zU}}$1Nl)i_;QKqc)U$Z)a}DD*c|aI|i>(l$KRM7EiczOv_>RGQMKn56o zuRy^6N!*=AZ~t}(q1fUTFn67b>xiX*!*fWexlw`Vlbkp~BtWX9{o;|Jzpn zs$>N?7Z55F$bx*`nrl{;jqi)N$yM=VQ*2t8ta`>5VdMO`_bTuY4Aw6t(?1-UW`=;{3nobK z7`u5?lPKv)o{92kYwGTZA`1JnXA- z{>CFHkN45qYa6oM(bZuy+Mr^%nPK+Hw29zbOF2hjpMwjfGK7ROfNnlu7kWti{?=-A z+;Jt~F1TH)d(8(J)>w!Xe9LbA%7sPG-FwQpH5qgJnB8ajQi~Fx00+!$jR1qGnRE8sgHG^kJg0(r)qlE)h5 zhqt(_aiXmi!l6bY3W$W{oWgoSrbPEY3?U7^OdZxC6_JZMm$C@{7dj)%P?q7J+@BKs z-AUsXGWR2Q5FM%!W!tN$i;4B?;n9R0mriP|5Df*GhC+%xO|xx9h5d)e*OK7&7`MsY z(zMsT2o?4dHLeF|A)!l&x3i+)YQQh;!zL+L~zCvpUn29qdfSY`bLN85+D3W0iQI{AccE;(-c-cAn1mefb)`J=vIN z%oVol?|&WoGA&tmW_1g3+4yNlW^lKsrd#HzD|;Gh8fAzAv&N=1V37{C#lJ>RYc zW9I1(uBbHq?@JgVje=p{N+FDL8e0?531#KX`5(fxrp!QTvw4mGW9huZ+3?=?Zw9s1 ztQD&^wQI*-Rk1gE~VTa7AWZ;e%3?Ukancg+|zI#63FwY`6*pYQLw@=x*yB01+g z=Xvh?e%+8yTeKsq#i^0#k%_z1dm=_!-0sD#kF#rE>l9PPN2phKa&fLM<>MU)Y9vBK9w+0N7GM_B=olc})N*Jsn0wusYNJ=pab4#bvPt zA}3gkroRdskI$9@@g(kOM2zZrLVu(UFF+)6LlGK>$E+&75z+6~C}2c|?BoZuyZrkD z7oFU;zeKg95zpc=1045PooTfMYth44*B}IVVhKPSa0=%DH&wP8ZWly!f*jl+^@@j( z*#*qQKu2cc51g(J1|lDWD@eRi%|IIOg9BLcZfF=a(BB`Jg>O&-^}7$~M0qgl{No3X zgVaf^C@zYOFfSm~1pb-19o ztpXkKs6mNgk;^G^zx=JHz{i@Mc$9-u$cnLV)8==4HK5je_+o?-@R(0 z@Nuw+0LQzDx z<81pd^wM1;7FwpOlyLViT&yb{;*}r82+S5;A9N1>5hvY;DOKl)!cU~2@w4or_55Vw4{ zfk}Z~AAVgypOt}?EEtdDN2RNmI5RAiTzidh+d@M(BZUQirUfj%S^ALMSX@z?sTJGz zx%)LQ`C#N!vfGXUpQ;?C;+$o(?mh;Y#y zF5ym?H=FaG{-S%Ox0L++D6Gu;h{lqAO$(PV0Dsv^K){+x(s3`5>#H+et|ha#zrDC2 ziQe*&(QCkDmm>K2%ZQypZC>Hg2@(-{LV(B0!qHVqLE_$3X4~%^-7A5pq970gz!b3W z_(2INnZjns;#@|<2=pa>?9C%LD}LD>3u?XTcji+Cn@Z-~eN`inf;t+$%zIBy3g>`} zj@)Pen(_HuQ)_{qnvU%;s#Ze zw|-C1BQfF?2UteW>&GL75{EtaUnWH2@?vSlPBO%261R*plJA=rNb|z)EWA%%k{x>gl_JSgI(=Ox z>N(EiF+(PCnpetPa6P~AE1`4h>bOL7gvd@JZ7xhnx4q$19?zhl05aPjsnvL)L1A+} z{4ZL6T@usZ9L}&24v=y3Z-?mvT(FQH3xHbwNQMl@@IHz&k;l2|h6zn1X2eJi(3<-g@U%gp=9k1|WZR;B>_W ze7k>0I%-CBLJiC#2f$o{{v3Telcn1X>N1=F=snd`F`!W1uOm%6U(EU5TI*nF*)(5kT%urVksZiWHbeTwH^qkVR4+Lyos7aSNmI8Zh&ILGeKQ|DtOHJSTdLCyd)P6%ICJFpKc|KE?mJ33uB^d&)!MtYlkjX&N=7x$O zHWJc85jskQ*gQu7iMhIpV|K|HNP-J1-J3228;9DP)5q_VM(D7{UT^D@OXzUIe_?nV>IwD<8cD4cPq?<*~y2k z7gnNl49k)2x%sauu7(3t*`eQ)u!RKd@5VAa_jTzmERY(`#a{MsDejy@*CB#$A!Jigt8q)Y6jU8` z_IN-6Tkr==7xajrz8HUyl2eS)cmnoV5RfdNj)e&kUWteYI9t`v02UX(l{FK7-3#bn zgn5sU?(HDp-OCW`@Zc3tpZfeUiwN~A4L|$G1~~agu{A;RH((Q(9{dksi+C0`4ZA_# zR#4XeLx@5=z_R?PP8jNMKp61*AMq8(QvsTQ1!1^5A@WjS#SyUbGUma~hcoeZA|zJX z2|6HJkr+O~!;e$>x~sDEQXJ0Gak(GNk*6o$?c#ES4vLPhfiaGQSD>do4a?MfWoc76 z^1E||pa)VfJJ=?E@Ne@S8Aa0IQ0)rQH6ojZg@{+$pf(R%^tAnTuPrf@JbEK3vaz$f zy=VX;zLdbDEnllQa%wPA@mn~+$?B$-mfjeKhb8C|z#o1)fWCddA7dNVneb>3D%p_^ z**ZrseQ*J`RcoV_VUfEkB2ePsPAvThzh2wLp87}ST)H8X!r6xko+3Rb)?IPO{vhya zeKLV$8L&Uie_RdIU8G`XV8~PmN72Yu2z6lpje}G7bjmeiZNb`PSB7cO$56>pfXF*X z@Ib&NJRk!L`N6cbQWQwpxxgv$l=HXaT9lG$o%Wa#>D^ziGkp&CnK>7p+>_3r$h7%y z>q^|FcKf$+d}_%OGm*}KqbdV8Nrcz4y-YGtoO`v_2pFqI50hCr9&N%OTOpcXopoxy zjZ}CmPQrfsa&_h7!iV^svX8{Xa=^Ay$8r+Iw37FA`&+q#{UVW9K-K7!oB1!On@8pT^e&BlJ8C<~db zalm0~lY$xGHt-#eNpl{5anG#JK~3>yVEM<#%vLWI*CjQrv!DfzS~Z;j%jnm zajCwFhRfI4kYsMy|B2D{WamtsaYI$}6K}^`W{19a!QJ%l{JB?)I}@1@Wj6E<46Dl0 z=|6)6`IZ-V%<_HIoL_ddzgKJ6PVj06roRE*0rU$%n&7l_gzn;| zG8@h5QM`Vu#e;8OLg?8-Je?>oTu0ubIZKq2!2%r~2Djg?3c|eR_$QB-!zp};lL3qV zYDx_K2747YjDvfZj#q@a5Ay+pm|HGdaIk9gM@PD%K} zEPVgyUp2DykxMuVN9WWVHW1+t=gM>g#g8Q3ayUvDLt{)Bqo)BAtRNaF9u8;}VOgw# z0>=lt1uzYJdLul08Y2LZ_MY`(M6~-kLS5bu0v9I2M_PsDf*7;qe_bxnpn?nh26e-& z0aK`+?7)%0)3RmxL>$D_oPm$hpM)3CE|MtJ=^xA8q3c!LVc%DjHz~;<&DReU>~hR- zdqg{@81vxR1DKu$RC|!m_b=-r<++|Wt8v}Kl8P4)4F0X~%r(4-g|F=9xdOvHDV&up zy>?uk`teh}8@NSGK{2yVm&_Ew$v9IpX0)#O()Yl z&XRa|g5Un_v7Gezvx{20EGEJS{5G5W$X&nK;x4~=eo7FSu?vD%I>i;q9(1vka7NOw zx~pW5n>P46eQsE5NwN}p@kymn5wsoKQ8jL}zVajGWtOtaV(FI5JD1$?b#x@rKRZy% zTkfHRrl>^pfhw9`xz?56Zpute!7x)m$mM~4czj-sr{h2ue}|o!@ZkQiln3dwfBW9U z$Sm#cTK(Bv9VO+#6PE|F^rFq*J}njs zbZQo@*pw7Uzt1&x4DctT4hR`P>gYt6pcA!cuTrcTNgB3gIgq^e@$c_>aBFagzNSYt z(GxUDC$VZL6PaEkbgC?w_f)$wbk0SpgRD)gG8YP(4T)OJ=^I*av%A`tP3(s74i$`z zT6CW56=o)@Y%|_BfA9M?yM1O#KYd18f~MJY9kLfn6ji!V7kzeA!cVVLDpqdToD@}D zXcWowro9#`Wnd(h=?3Q=sZy<7T-)t@BJO8Aoysm+w*d7R@7=+g9ZQ+%u0}>&7BCvC zd9p}4utd9a+B1?|mWZcmNEO1ghposTPbtdDU%U2K;L{4G0!+xR;a~x%t$xpXWrL4AJ-x0h-GD2 z5W4;7UkiQmT;1=VNC-0b8EoFn zuVbf}nws0;X?NkO+^nt2&Ss0mcp<|1t(U)ReQLP8EOx}JY>DeZL#Gs)F`)(BMbMlb zoNf7+U-d|8CifvqVPQh4v|?8@#2weYd0v-NPxZE+eSH6JKG8Umpvp0c){ff|k&OYf zh>Kr`I6D3~eB*JJr|XxcTjjEImS)^s_hHU}Fki?;liTHug45>}6JXnBTx{f6+?G!> z*6i#niR_MoH=mxyNZ^z!dp9KOC)^iF3o>R;vv)?m zc76E21!AEBf^e>QV+gB>!b(<{O{dNIc9Uv+<7dv4=dOyXrR<*IGf^bP6sP(ptf%B0 zT%h>Y{XLpO%I?&=#GK7sc=n`((3XWXbOR-m0ggw(bgP*jylYIR`f75?RhhX}1l(0n zP6Cz+JZvmazWwW^Y2*ukgf^W6C>!K_2(gzGY=tNC_IN-G64~&8#Z{hWD$;oX#WRx) z*Esx}P7+|jHlb=&nY`SwE9KI$rZO>Q{s)f5zYOb@H?GAtcV2ZRz%l!NYmYG$XgO-R z%}&vjw})(C-s7b}riXY1;zTX|F20YSH4_O;wi?V5KjJ`dn*cA81NtWvAHadf#-kDz zw#|w=lkeid(3f(j`e4JNX8oLRo9GRtbxO#kJzK-MiXji3jht=*x z-mFyKRdUJpsS9D#_|aU^bakFKrUj+_qv#c zSJ|QC5A|P;m*pHq%`U^?G2g#2@CWRf^}hAuFAn`fvR@wSLmZk}_O_%E*`d)yI-O9{ z%XKs=*<}D3YSu*HTUYPV;E*HQ+%j;2Wd;sG?IFyLlAFO@ zT{7Zx?h>*tdf%OdtUUg~0P8CG?BSkg_|>^Ejg6ITM)aEEE|>B9u_s?O`;Yw!-xj%) zST`+EL(FwLJJ-?=M2SCOUv*sBKhK4uc(DJ$Zm}egvK65J0_FFjz~;g5?!YFkitq%0 zAgAUihTA+i0H?Kp99CiWZNl6mLrm1gDOBRRf*LKXK&SXdRTufT0ZR{m<98JWQR3Js z6rlz1m1%&<7!mWN@2WIjY^ezr4}+{M};_6KnKBdFH^7Bp-z`~dt~k_BPNS+F`_ zE&XeWoWrp{V|&5MV$Yzy_(m(?`*(AAkCAws5_`XCI1 z;FSd#_BiM&$?+mUW{N`ccZ3l1=l3a_3BG=-(%|m-FEmfGib~#OiNfQuX7(uZ0yFw+ z@G(JR$^oqJ0d8AA7wv0o^IfE6!EO3IgPO1j58tLI;daG5;l-=^qaG#~Dw3@BN=Rlw7 zwNj#`qZ*9meuVxi17g%WT=%s4WRB zu?v#239#WBIG1Ted4@hFYqE*AtJj+FYdXpHjV~3Qn{g(-4_wf1>_QS{l{s}qk_~?a zi}ZBzHTmzKTSaz;&A-bWtaAy0?T{Kf7tbm@JtJn6ljilCLJl@b zToef2X`qKxwf;Os?^o(C->E3Xj)uX3jj~1i&WmT!zDw(*uu1;ua#w=ge;5PpVgFqG zAigBE*`wzFhf^-vw_g33WvaM|7PZ+`E!_^Xv|Z?IJDK3MHq3mSzd8)jvikMOvNkc_ z^z~xFG5=w#@wlbTt6D$QCTVr2#J}lDY)Lt?DyV%-Wq{Aq{@c$8YnGo;(!cxO4DKH@ z8*iH|7*2~ni2@y0r-J1zbLtj-1O_#uhhKR{Vnw{A&Y-~^v@DC4o zMIR_dS|6$`3)vk+o?08uK1F?|OpVqzgv+X1h#E}W4m?UYMyzNq^fAzSZ28rXcnAHu z)NWZrX-{6&R$tMpI!8!2tEmrhs3;`s=f%gh$~<>mO``3g%4>6ace;79gib1y5{Wf9 zZH+-r+n=S(8_YZJ5Gi^?cThGxE|3Y+i#5M!!_+lIss0LFm5mPWgQ)Dfx7Km@*+`K-adDE zc~HE%RBOz}_|akg-P|flE^<4#G|}QR#8eS0A{xGSkU}Pm? zX<%t!_3H}}RKv5jYAJcKvspu4KN|B>be#*eW8Ji2>hzPJqnmW?sJ5ct16?F#I#Y%5 ze&$AU$~~MIJAx*s&vuCYW~K%e=$eR%Ul330VM@zQWSfqvISz4qH=7zOpS^swo?cyM zJ1b{Ix!l7@bBAapT0-rfu!usRu15dzT`Go!bW#52P(c?M2)zo^!KS z#Mepbi92?SI5{!Av=Rj0jJ2BWn~k{${{?>Roe$+e89R6{L*7iz(5w&Gag@!NRZm;$ zq_~?0)91HR6BMU2X|)Zd6OxGb51uzGKQTX`U(H#^)kuEvtxM$6ILM@O=7U_~v{Z|V z>OkDgmm$%#k&EKZB&#GDjXC6%1^XsF$C$L$O9b!UUruv!Y-{Il`$Qf_d88vp* z%NlX6W6uU*nt(nkUFqIejW-F~J%%<5hpA^;Mh^>iie}9~Q2yBCDbJ>~8!M`!-xTJvK6kPq_wLqv(H>WDy&6A8eIU}5 zu6k?D@7l8oq8gPK2zFcDY`)I5!1G3CTeW`7xQW*)@w-wQS1Mtup4#5dn z-(H9Trj09!mucnS7Rt*&JMU{mQz;p|bbS_ADI?5Hg=aPmu+;Sf7`p3Y1tAd0^I5)g4KIU|y8d7)QlbjvVYoKB z!UfD;CJS;00sJO)IY;R(`8O=gjz31(`qTMAsDqA)L5T|VC(!{n9f?qy$n&8O-x?P_ z^@+Yv;|R1ge7G2xOaJ_BsF(G?^VYJ%GoyBPma%rV08FY8M-~zKX!Yoqh+<+bRX?L; zqgYe#YZ|kitvuIfxgI3_Mv2q0Z?%}1UeBU@j%Z>sugqCl$OS%owQXCH*(7dq<23%J z?;L~th?Kon81sr4O5!5mV{P}OvyMCd7D-W_q<5fd)F4Dtgk#UIOZ$!EIaOakupI3T z-1W4DRtq|+oBo-E{W!?FhuQX*GG&CN$Piw{hJtSCW~V9g)9`$FUb&-rA+Sr`yRwr@FG5p-Ax%#e;vqPUvZ`;U8v* zh1l9MdQezwb}#YceJYufPd|Ar9W@3PoI_KqY*~oeNHeg#a~X$@JxMz4^DPJC(LBV$ z5_)q)ug8y{3th;aX?Q>!M{b~8S@}M_8!auX1Wbq`@n+> zd-)pkydKt51xV7$bRC!hXpml$t4{b)IikmqLe^>&>uXOCM$9RBy2tk|6&4;}vP`za zO32bYf%w~y8X!0#dzAJ!tP(SzIs==ipzcdNg-sd{gu>4zx`~T;n0=f0@0H=(L%5JX zAeB3A!u~yAL1g&<7^Vpb(4Udm1Ns)Ed3P0d2IkcysM`Lq%<~$NGIErdg#U9}0H`UL zUt@byVmhrv(NEcX|K5Um?E^j~Mu;=bOHyH6zHKZ{@bzE8;iA<%B@S@F4Cs!ih4obb zfc0`w_Qb%p$r^;gP!MzE5D7X_HBp+1pvu;KT^LQAIfvWzt_2$(94)}Y@?iZQq;(ub zU%EFiLw+h0jK)ZiST|skN?`<&iJ=|$kpf`g$Do0rc?rjjgrIUTUzi_&!3!vD z!#hx1(pE82S{2)AWwPez(Ev^lMk7vLTJKb>F|JqNSiRh8?e+yn&8N@gGNyyx&G^4* zEzW)BL9ee%{rB-ip_v_!%{H7xq?!_jrRnIpoImYo?3Bk#orh(1@I;8*zh zJz%L-{>Q32#YI!u8lpGnVrb;6I`1iY77yH# z?MA%tvT{11bOeybGm_b3H;BCd$sME=8w2ezb* z0(W2g9#Mf~ZvC&_Dw5p>52DAVZ>pR?tYe^2AIGkI`tk3bb>p7>73N=t8tl?xfKYoD z^3d+vzZ7r~d#!#6+i^`4naxr+6w{MQ%`B{Cu)M&Zv}N13adiC4=N8^!r!pD225#L! zgj&-(JOrbeok`Cs%JU^l5Cm}=U3~kKQKvKp-6odgH^pa9vkb4Crsl3h)DuJkEvD0E zD6?&v-#q*BRA(WHXhp!!yxd8CMsVZ%^m4Frcj0!HIdUf5Ct(Da_|<1Vy*6J%p~KKE zTV@x(n#I*)re@dfthp|E%Oc-RoMn)Ps(x&sH%9`&9r^)+4<^5Yy!Zwulky$XQKEOo zJ)EJjr9~r@o%D*I?CBe5UgE#|CGGXM^Iz=Wcy<1OX3R87B_O0iZtEsfC#l8lZeKn{ zFDyO9{h_tkt8(80)tpOZ-$dCb$?Os3Je5nU*W~KQQLk`tyYUxttanTn_MS$R%*j%n zu+P8r`>XhVE=LrSn5Lf2FV1)JQFXn@DecvJzKeiv=>~(W2wBqM7sO}tw85QDx5^tY z0vPZ6_MB*LD`}#4_;t{9z7Cf5#5$4%0vS1RwAnfJk5}`8z3n$%yz-h2t=~P;WaeHK zD)VJDH{K=|Dy#f!C`jHvgDGn39OSnM(g3`$Go>ae9e%ixgDm|Q?3EI$=9bJrG;MC z^o#e!2wboG{6f_UPKS+NmO4birKC$J{3AWM^@Wo45z2gmr|Q<4UyGB+i5Ko|ZQttN zq~vrmEja!VEYJD9`yU2gqF=e1^jYXr=Lr`5V&B(de(XcqrrKN+MAO~4bO}xIBIiv_ zQX7Z2kGIb^52n^fjdd%?njwH96|UUu%bL!0Gsk*z(2f;zn?&XS=>n~q3-P* zHQNwRk*$o!Wrcv+dC-*ETZ<907G~amCw|$ZUoAMR=@g{V2EslE zitLFDReTA7jX4QZNdZ)X5%1& zR@rn-g~Ta!p}!gNI3aE!_Qam{#6Vn#zn+1W9?sCwWeDL?&rj&v-qkA&ZRA5W*?~KF zGZhuN-cU=fLX5<>P1H7=d*pqt$fmCvS9mHDF+&vE}ntOOv|L zWg~BEV4YitblZ(lJ$jv^&5T_@X^7!NBt(!@$Y*n9o3_L!Io)2mEf{XdHQtE-)y6`y z9@fv#*T=DkdtHPFu$99DIP+$W|S;<7e8f?7}X=R{~pSHfELL$?l%W=m@DLI1awHSUq zjJXNx%fJpQj_1Ei2bN9h_1#X;+!}vloXTALZ_xJWEIr(QB2Tag?uJkohPt6FD(IaT z99lt#$of?GA?OG_*dS8=Rzt%@?Dq!f97ri~hq1OsBcc)bSnPC60Oz~_ojk>J!R&y9 zCf_4M4!PYL5IsJ5gUh-FGeciLh6=!5ZQyn@$3v|(K{C}Jq%RiE>Aw-NjO8#Eu#kGg z$|7+Oe30f%P%mn81Sm{w(gZ@SioshRH3o%tI|4h&eV877JuDoB3%shG8<-(;cs1cI zkonz#(vZV%kQ*zs!UFOKS{?Iss>hT%`B#<0kV$$8R;amsph+K zsZ6q)+B?OAYTx_)W1h|LN1OR=vTR~li|77k=I4aJ- zU>Ns4zTJ55L(jt%#@7JK!Tv5CR4;PNT_C{m+kY5RRT?Z`?=)*(eJGvW6ZK@)23(Tk zBkdB9M=I9?QlEUOK>mR+n}u=0zR8s0z-Z)M2}rP+PnynT$7p6}wqe`3KCrqcG7@`;SXL1y@ zDQ!3GeQcbYMC55;1t~M~wb)Y-6SkvNexOu^J}@bpZrIM=cM*Mz+&$kz&6jp|_Nq89>p5u?}`yB2`8bn>|_fnXyb)Plh;Mw2?RSk2MbO%DnLy0W3 z7FR5l+>Gi#QEHf(DbJa3sMqlI6PeNVDncjZEf6R>wqGkrgR;w!S$$2DeLB>Ujo zaP{tJN{7eS9g}d;x-7EM5Al+K$zT^3+aGTu8Xgx#V(Qp^S7}g zMxLTikRLdtV}ZEH@|$F1r3qb*9)+b>XQV<}iw|U3!bz|QCo80zQlkx&OoE_R@S0}= z0iO4Ws)5KEQ%QF9R@7=}sxFhOkPBX-bA zaV7GCfk=*dm|27ti9H@_JY3)l8Ws%a_CX2+_e?9$QM+mNM|h4$cpf{zdeud`uvfps zsDQ$`@QADvvK#{L0-h&X7BMSl{Q?@0Erh?oTDQQLY`Twk+MlYl`T1MJ2iUfCxwiYZplO(_ zYm0OLA3|J1Dp<#?A+{W!FoeG^6lb!3v72PETWV;55}aLa#-bCHdTxR$KaERm+-ZMS zB|RJZ=$`_FjOz!!t9dee?>~&P)UL8QOBLW&KM>~En)bsu)|L??6|;#YR8=K+Uiz9? zo9rFX=J_QJKhznBa)NL{F0R_hk?H%H<&WMv+D6!no{3dXFL@#gR=htiEymI`=LOr| zn63hxXRr0BX;qLX{?=>=Rfgd!rOe$5C-N`_h9~>$xTq$l%)RqX0`#r-0&ncyZ4dKe2-x)ls<=?Z`7WY-~DxI0qHUw$%kowre;Z)^JTK^8khgW zcq84geD$dB1LNnP%Lg@Kt4SR@xAGfz8kY;|2F8K1=liXV+UkEHV09^@R&7x%1csZX z<_ty2!9s(RauZ;jlP8m~DRHu1v2(7EZOGN4$B135`d%tE)2zJE_W2;%9Y@(b^zX!h z{VGb5G__~+#r3jicfC>A3+q+pU(U8MUj$DqGop2pq(xBlT?}M_S?W?C$roShpIvog zqfp`Um-?IwDaW#hxU?z$J_>>&tpAtELex+fCL!p6XEz<7wLCpl*E~>uW~`n;^{gee zSKC*N{46@+Q|y7$+T@omH)dmlP(u%Tt)fb73#mspKe-E{eGS8PCCx!hI;j_0&~^1| zLI!$$49mBZYe$T^gvXLzj@152uk#`TKXzpnE4yM(7sA%&t6#BxE z7-gZnaUtO^Q0DdQQv9Z_<+50pj*W%i#mY5-PWOEex%(!{(Uq}DvX^`IUAs6C& zPsYb={q6g;_AA183(I#pogL6}arTAXLVaYlF-W>wr@wQ{qO`X|&6JHC1&a-J^xikd5kiHR4eTpASMO4QN9p<`|mc(=A zbkgkHg;})AEhV{~8mlljy5v+-ff21$IZA6se~0299$LFlDlJSsOD;R`oiSUeHB;5* zeqWum<0x)J?&yw#Vg5X>N#s%MmZM&K;ybe&06XWJy(ze2;8*)FcQU)FB0B55ob6_Y z=}{!vt~rTwA(SFJF=t|fqFF3R6I-)p+k@24yE!(xct}`)m=3)TNxRy^r$^(Hb}ppQ2>?{F76$h9@TM~m3!-U zbw-936Fnvd(zGg=P0V{RbVRZ+h8pNPZNYkFh97)UgpeNtXU;)r71qiyJGt_M^#*KJ z0k*8&R6_VjsFmLDvuedDKORj3lE*&a2;7BfB$n(^5Qq4Cyjw0)S2iTTfs5J&afo^& zZ5TRG>g?q8p4V{hC!fdiW;9Y;6_tODm)cM(lSH;S_{rjy$wbl7aCr;=74gzf12vg8 zi>Ya5p*&l{m4?K~Z%?9j(Cn06(Ag=9iQy_`W98-)5FYt>mu0~RfY}b$WU4Bm_T)#x zV~34|N+tGxB9*0^%w)@E@#KzuGBbt9AA*MQHDeI3aUohv=8M40I67mc`>j3)8#k6I z3o9#&ZAa~4U#)X9o4vgp!^HdmnQmfP>q=`VT7iL0R!(ms_ehnrV~JWfr8xC7D&vse z+g-MTeOXTbvTk7gH>{6SY{0wKX{@~-R+9DT4-MYWE)0FhR9vuRV8BYG5W~_7>YFu& zAcWeZ`e9b3CMI{ao-S;!rS!nYj9M_I!@qk=^yVl13$Je%tpefP48n-jBx6(ujswRZ zOHZ$L6eU>(mljbJXFkOztC>TEqPl7REBq4Pzz-G&hUke9|Jckok5|}O+XHfJh88=P zt7_A==$i=c#p;s^3K+VGe;GJaA$wcmx$x;VZXnyUwllafU)ZY3JA2Kk$%zgXGIR4^ zJoj|F)*Emf7*|X0S)0$qE4kK}rLDnAWj}n3&=jRgP~{!;?={J`!%#0tGek z{TV;ezcDG%m19@V-jDB+{=b4LL-rLLzs&TU@(qdbKnBN4N6=UVMo-Hi$mIg`ivvXX z1SvTJA(L>x@^3_XqBm$2l7addB3QiwjHtw`g$5YOg2!E${$4;~gm8caL{Jdmo#{fK zA4Bobuu=)++mdl>TW%{?b23$30FY{E-oKRq?y=h6#S}z2aCMHe&X4Ns%OTb+7#!ch zoHk1q_`<|SKPe+|H2Z=^F#}fjV5HaTv>kOY%UvXBGJ%KV7CYq6Ch+t312g<4sGA_) z1xbT2Vugv2gV(iJWVoL(ugSnCID^YahW!o=laJkowL$R_YPlQt6eF}AA*HQbFmHq* zqY-s(aIqx>?=d?`6n3(Gx0fEIJy6}_6zM!BSQSpuh3z?nhLLa)`XC9>3YF`lWlxY~ zjtiH=^ew=DZ{BnYwH@4p|Lel#9U@1O!q!V#2a`%qtkNiYdp z2(icb6AH#;rFeVLE7Bt7l&2lOe=2p|R3m4u?j@*Y7^IgmrQ|+Kw|F$L6v^u3zPjJ$ z=y`Rdx_tn@DU^lmNOI0R-zo5&S$mGV+*em&%D1er&V|CV*c{g=c51) z)6@-~8pY-?8wcO=XlHSqDCOlIvR5=IeV97%dzIY6aGW)pAeBcII6~t>t;e^d`a?5j z>79Fw(C(4tUg^(V;oN*_bDf`4oePRd{_{$k)BbkjsB=%t?_tu8qpa1G8}d@j)j2}K z62CAuA0IMp$}Tr*GpdNTE=$WzS`lV6b5-q@lK;+F5TKq3sH?0ET@e1BP^WrFtNWf} zJkn<93Uu(B?iKkko04_WIi4ZR-gdw(UgH+^1Kaw!E_ZCB%p%g}TcpBpBqLN}`wE=d z)Yl8VJawMyhD!CVr^K!h@-ZORe>V>^2fp7HlscGdVy&OU#Xhzc6AAqRT7fD8oM3fY zAb1KiLD+ebHjw2?GTdA9(lINtl_y(PPmelB&`+4Ke?#h4eQ7!-;W2ot)+1a59m=4{ zeY^^0{M0KEnyUNBXchOj@e}G+3pEM2he!#3gkjAL<*BJd+GG}fY+%-egQR$i+eTeY z)hP3@(zg?v3*qk`#zFt~)q6f{+9l6Oca_c-%%M<`FF%*o$@g<7ZccUzN#Q7+ZT_(5-P_5DRS@Wy)sr zLFj_H6wvoQm5A*R;bO_omlj{|>)D1)Wi)KkdkWaB00+9sIkhP^RtMR=V+xP#EQhF{ zUDW3JH;W_LgpZCp+P&;?vXzwrcn?E+BC#F&#aC2f6TT+lQ=^+b_S5cX4PfZD2bF@h z2|nffkD8xZ=z}fb)ZK$}UohJfKFmbC5pRzExMDG`H1P)CUw|ADZy9R-(FBS{>oqq9 zKGsMnbwBYBUSEtXOfO3cWFhFUOCYzQ*!vmz%eA!?bXLUY)1&OglSK$Z2@3^scvhGA z+AGZH*k7SHncDVL*cLmIT`0t%45NMSN9QTHZ32e2!UsXp>MUt!!T&i|>C{4X4I&YL z6Mk?J7rblgFtIFHZ=iTvk3%*rV6mj)2(I0G%5#1hl=nSc95V}b_ukgu&38PU>{B|; z(4{IWtsJzu%YFCa#yqknEuno{YCxszXJ-=9UZDP)-2u&7B|l;!2PaQ!>QNRN7FvZJ zb_D!wL^NoHXgWa(uxfd*8`;BKzGPsq{Q$HFkjw#RJ!?D4L+uoPxo*EMo~RyM!ZLW+IR-j>qiWQ|qbp{x81!0>VR#kmGcp16RpEwK}0 z7tO0$4s%XfZTkVf*9WWt0jiZW-+-%-_611DL|FnCKRA%1sQ-DF2{GukxS{3<9BWCe zld#6{%`HlZJ&_4g;_C&-4Tak^MsioNmQV0S%6+h&dgHb=Ynjc4T1Y$R9$tE?8UO1S zB4PS-ceH5qJQiP33BS9boQ*8D4jCBs0IzUONW&LP#c zqD_B_m$O+aW)!IUFp>|fcBi*mOU%U-#`?32McFMkBGkLwE2w{6Ry;VW{togW8jBuI zALymeojv9F{=_`ZL(PE7lsWHW?c;e#t$VKeUzO~-(~GP(^Pl%?o3L-pid@(PhLH_S z3{{9O0{>ujL8aYW0~+qbbJUbsY$PaSYfPAb%xT)Rf$>%KSR_I0;ThEI?db_=oP{xm zWXcA7AABej_{c|Rh)08iapGUDro_KA{Xsm6yTyO7ZoC*#10xEpv!@{Phl=~(ojI#V zOxdgTS7^BXA<^4YexIa6t#?hPZb9`ryRo9a{LvP3i)OTU)qQg>ab4v|f#Jliozzw( zzw5*CGRJj5g%m+GMiw|C%8Pl4>awb6&)-eYAOG{^FNo3c^6dRTlFmDx>i_-!c4i#u zAnV}Jv5rxZMCX_X4P>u!LiRY`h!T!<>_fK3vEB(sHpemE895FrGO{D1GD1ki=lAUU z`=kEgmR<+vdOok~dOYqAWJ6mHvWfrgt;FC*f?Qt5r%I?sVplDH*=i;y2IBTR1s$KU zzNeSU-B+BqW69cGHJ6G0;aJf)q~63#bDi?3hUgT@*q(25R5~NP{%0j{MO+X$`!PK{ z&&7kB>@FoEyMPpFuFiWYZ7kBex_D3<8eD~iq-m3$yL|5cjO-9w-%Pd_7B_E5$gS); z8P&bqzbN$9yrp@A`ynz}l{a6uX)zKHv%h<%w56Gg5>nXCG^)Fr_h_d1q4i`ovubQa zrtC4S%8UQ}P9poj`Jc{x2GL^K6kn0%*?khR)YFAX2nurBc*ti|8&T?NhpCa;Kjb?r zP$!!EMs~0}CTCyvi+5G8CWqX+ugek|Q9qKCp;w{h-C{qT^>uY`V@=(!nWbRYI5&H0Wl`;u&Vyc+nFtis`O3jWHQC--^UqNUFqwglL@k9pHy(An0D zrB(-0XX$l@GL$Yg$tNB#8?C*?V^aY;)}~BG4nCT4&>og1-z^$=c2(T3e!>5?Kib&` zTP{T%$09!lla~MKRX7_ccGay;YABcIB<}54Fqt@NHfqszUNIylb$0*AM$yJWI-P&d z+?Y+hdCWSK*hrz6=>jp*EjJdNAbA}vA?fHidp)XYn@UY;5G+{3C9yWf{0go>hyLVM z(-3ggjBv$@y%+;SQFBVJJhOXOqMYG>HbDxEyhk)?{=kNA#nk`$(%+miE)GYHgkO$5 zFIgQGSvnKx0Jgfoi^%mF1o_%aYh(fe&)}$EWXx9ZO+SMBdL{?kt#!1_L`XY<>#+w3 zSvUL->mWPN1eg+{V}*d*uv!Ur<{KG(=f1h2g$>7#%FA$NXz{@}Q1xe-hvh=9`f%Z^2-&F!S8n)kzXSV3k#uF{ z#b}_UA{qxDm)(_GHsht>xJmsF%tX3Ig-~B!s4+ZpMk2VV2(FINQ(H6^p3b_c^_jm8 zg*_tDd4h!t$GieKPICOjW^Eejl?)QWv>3xK(F9BcI{qxD4rxrw1N6U`0pO~feC&^7 zNUn>bekUQp!$eqsH~X}=X8gPzv!SzSSBwKLTOsP&(6-aQ3sI$Ja?0 z9@6B-Juz~wla9A<9Sc01|1$IMc$tWk*6izoit2_S&mGyW#<>k8)q%oAD)&a_eI!rHN0}n z{_}#jd#%i6(+0_9)w=B;e!#Czw!Cj=XwH(6ji20H4%t_%y~EVg8{+gbg!k<#&^h79 z0GZ9hI#=CNSFG?^Q`%s%!b3Y~jb2`m>z3fUJ_iR`QmdM=^CN`?t^~yrV4$gbczmOjuhO{KQQk+AiYTUKF*c%@=GR@fmwQbq$%)y~;wVMc?Un zo=!=)YvI^^-aF(@(FdDzmwTE@)r^(iM>!=g0vql{tcXYy!A*3ifxh_eAi$28R-En) z%j<7QvS@re=R19pU2@xsghec{pK^CFWk1r}a6D>UDk-}t=Ejhi{`8arCcO8sgVWc* zddT?9er(Gy`JXEX}+IL_6Dh0%N^#I}(1e)h3Z&j> zIO}XCJ!<9ewRrCD_<^M!hTQrqED?kuH(-7iC=E}B*-}OrvK=7oaBLKCX;p)BxbKs^ zi4wplt#1x;3jx^Xq=MZwu4{=aC|xZ(&ve`}w(xpK9jN9|7ceUVfCP=!L^U?5vbrnl z9Kg_k`M&KxOx&|mW-2k#LtbpnJyH7+puRf2=4XD!%v%-hkY{#G*1w%xAIHT{XFv72_q#WeM)rMvU7};%8pUV8=$SP3>)N zNg998z+aJ=uJKu=qsXfSjX0sPF(Xf>Up7yiJEn)rTs5l!*(=OBj&M*RDEW4+ z(~j>GSa=g7u{^O?OBSq^c;onMg?5(FD#0+K9}71)dD*k)BuwHi!ZnlUg8Q*EZ$ z%7p-i%FOjarLeyEFls!Btr-dWjITll7It&dK%$??fD3X%b%W<)k9~-d&b*Ht>iC}R zlm4_*z_$KFG~YGw&3ig!A|Iy6KW(B-IMSK;Jn*bh&T!)9FYlF#@`?e)LcWtUv3cV_ zX9usjA6A|w0{T*PDJktP%9YeNLk07ktkgO?YA+x5r`}+dP3BFP<&#qT@zgX-1q%W9 z)bDy^W9Ufb`&aHCN|>64MaZ+EZpRAs@62Vdmg+@bn4a2~`fo!s$uw%`GXW!|t1qSb z_zjx3V9HrDx$4p7z2XsW-$~{B4~p3aufJy8d)iJo_j&nuTU)t6VAIGT_Et>J##}7h zd!z+bT$uVnX*ktTx1oogyXGOd~Wq7JPa+SUodf% zH4yK9-5JTk`ZAcR6;jf2aEy>lpzErhBfQ;z@-(zb?C9`=s#}4su$qH+x)^ZJaxAnW zot+mCA*`{sN-=p3iCYK71Lj;$@qxx!^|p2W6`FGMbgqI4sEB^e?w*o`H{O;;F>On@ zyohhNLfrC9*HBu#th1L>;gzYyWcqe3hLK3fDetgc_{SpA{`ZuNs9w_G6N2zlf~g#@ zf4Ts}fC?So$mS0K1`U9r znt2CJ;;}3bOw>4_E?tYFW;Q!!lZ1SyzEA*LX!2KdgWB=tx`nFjL3huE4@pQ6*YT>b zch0<*-{S|Y8tY$F50i~}{whilGyhj_i)ww%zFZ}=Bx+N zeA!yMS&dZ^9c1v0e$0J`wu0!cRvQGicThb&iw;d*=6u?XeQXjr(wE$KG-(kSV%eBs zrK{Ep8xq<7A{(M##hs6<;K8v;Eu#dHu79x=?wj=g)7y!U0Tn(_+_?%X`T__JXyfe| zTi0n^FIGr&Zr(5Bp!P7WmkaZ2*hg1ygA1(f?KLxjxD3ovf*NPp&Bf>-e0H9@f59uD zb40`X0hB^bjg6lw=Ppsi?_IFosmrv=1n0rk^pFs_@Ajp;*rK7{~Ac&;-*X`7X^AM@J?TT^M4nb(6e7BITxonUw_z!1PYXNCY$E!ppg=fIbC;bS!bJ zPenJ+uA@4;VSvh26PU?6GBHff8VP(B?+7KIKK0G#11d^)BqR(BSdXh-@zXftxx=Vsl!ik#^> ziFYLX%qoDos)@^SF0)dsRM}6E{~q5_q16+ct7Nij{cZZ~zve9~gLl5Z&ihqx&5D(_ zX{pY)s;|zsL!$7;*-}pX(Pg}@Rp8MQRp2|xp|LU;CGN)Qxgz48`QuErsS@bYRFc?G z-EWv3_FBhCK)>N4(a7v@2zFHufwsX#bnYyg3^#6u`G+n>$Im|nUxZbPal;Atv;PhH zW%=ryB20VJlIxuv(W=nY0K%s)W3H@JyCvZn;J5+6S*@Y1Pe&{*d0zl&gQ{M#2EbhI zO#Pw`+glJq8K%^yW>_8|Z;}$Jjx?Snomj5m7;x*8mU>i-X!!8;_d8Ql#NG>wH76~~ zef{2|Zo~$mb|5$O^zuY2?uP>tpFFN6!HYS_X)<`ShdYG{{-|30@Ua4pugivKQ7804 zO@Eq%$=gqJx0Y%NJ#dZeUXQu2WkcgXod{F!nYmbOx8PxoPE9^@z(>;Y90)u#{9SH7i4oI$dU^w5U z$?ElBn5}V{R6P+lr5C@;@+q}Pb-8KvM2wk756EkUNap9+f0O$ZY6AoySxVZPY#uwC zYmsHp_!|wyQtChbaWl3@!Ym&?3n$14+Ww%nv*7MQ&5tz$sE;?7&al@mE54lYUnCgH zh?X=GLh^EcOeM4WnD=|6Hi!MUyNz~CEUr3N8RCMNTAfJ0?J|+XK@Q~S7iSK-29+>m zm);58$nMhXN#J==#1ea}AtgDt;mah7JJloM8|ROO4~V|3sC%s^(#Pe{3HA-h;I$;S zG;hBqVQG=4w#nS4AMu=lZ{NtQI8_$RzPt4;n8}y)u|J}YLulVf;yx?3JS)%&V<1)* zoRi@VkMW8CY)`Zt;dDmk9t;1E|tQOr4aFf;A1`IQA^M1F=mGWp>2 z91x%&(|eCFg7@!NVWR6-sNXBN{P$o=&Gkna2pVpA#ai$_P)XHO{sUQJk z`8B_(A(-{1laEYGJNeD{(o?7Sgl}3|7qhRO9KP63KIyds<+Yq; ziO$I8koC9k7X)swiA!^E3>67xqVQ-O>HZ={dU7sFPA{7^OztN?dx)QSU3PT-Z)3Ae zO`SSPmF$vyX5XtAIAvpK0O+!Yrhxpr-IXDe1Bp7#`6hQ20npFyD}cyan5xFy=*7@N zN~r-LS{5llM>HX(oidYNn9pa8S+gWY^SQNfG6aH)<+1B2Z)L!K`U7UVzuf+V8N+Ez3KyW3oE92!Oc|O_r>aR8%Z~8Rd-frEvuGIU;Vs!t)FyO z>-4L0nf(5t?Pi~J2|jYaJIB!Bm#|CNui1p3q?)UID#;K3-f-Ed^1!1b#H#;%XQ=_J z^wW;*Ax0unzTw<_MRcs0O8O9h+WoE1cFb-dOUmMg7jX2=W-%nOfh%rEicTFn-AFmK ztIS~4AZ=(C!!u7|?3lOe_|B>3iTSUF@Q4J6h75lqajU*2tu`j#FP#xH`#q_Szc$#{ zqNDvkhO^6!KSKX){ijI(`812Z{sZ<`c4V%4sDByg4P$+~Uw??==L$1jMeqoVq1k!u zTMvepSdEaMiklXjR*~fO*VNXa;$>ty!F5IMJR`L*M4|DYuM57W)y5Kql8`~o4uz5e zAy=%>Mw8CwdU!7sE69{~`w1-YAOH;~*3LL9z7J(>p)6I(D1IE}@U7$aQ;Tcsn+&;~ zROcukk~_YkEegJ=-mmhQul?Cc=bUz)eRm!2lJa(B1+XvF-hQGP z$sM*d3-Giw@8l}=9`PBewAfoO^HZL0cCd3OW)awC^urGO#18I8mx!oiHOYO24Ra}c ziouM_tdJl=?a|W0C4NH-q10}VmLGmPS-NB^Efe)wj~9acGq=9E<_u9Zj3s`er>gnXVv?cC@AeMwb~iBM_PIwW zMc!L^*mC#S+tNZ=O(VPOMAYmev9k~&f-;Q&3y*j-hZmcc$$~;_&FuUf9@F#Av<$+B zogF_Q*}X#5bMW*ykE1!be5?3r(*5HOL|xVQzLUQEGirX1A_xjYrfvo!#J=p`HGQ2y zhkTx{!^(25Qh8}N=H4k&0w=@ZO1!r{`3S_L{@G_=?p(Zo(>jlsYejdmqMMqIZ>4XT zDfGX18f(-N>BTDPvJCl^$PzNYroi^@&Cr$rTVEp`fhRV0oOKEDUud4y7l?~yaYX_I zdDCpRSxQ1rv~Q=pjA-mkTMu4X^^%M4-UE_kriop=M`@0*QM0htwNK5GV;;{lF2u_38hM3o~N&;AL!U;{{lQ<~o-StvYoDg|uP@iK$5_YK$V#}8yo zW!L469im7|C_WNW+!a`b7D2Q;j(N`xECLxEOQTM-ml&S>89h~j5Cl-VYyp-RS&97G zqvm1#m{Uh)8lL>f0Waoo68nMKB}#-VD><7Prn6DbcvOCRY}P|$cKL7FcLll#VRSSN z!2>9oB)8nu%&*!>3W8D>#J-^yDOBHm9PcQJ7d=Ju_7H-mQb z-jP7e4=JEO4oChj=XsM?N7zQ+^o5O2-_*kX_$+bj&YPenvY0|?$;AZo!!Y&P;dIy^ z!JLWqxq|U5qlOC-?1$}iYfa4{!4EWn#P@j}9_5@CDm)Y;3e%KZUR`<>9{ZALsHq;x zkzM8Jn7!fZT5EJO&^M*01oj{KyX;zTXjwo&dv58I-=nu3YJ;tj z&i+~-PSGO!I)pIhAi1O22bNR%(=2he5P?A4;vHV2k$P!?LKJ^PSn`G1z|CH7MmxUj z6WQ)5JpWJUkYQ03YFqPO@whZmhCk~9@1?nSiUb5r+)SEoB)&M?M-e8Z-Ke_vV100V zV3SPiY1mzcK%9dAj4$A=%ToRROK1>t8^2uTCG^ERC|83|Y`^ni=oLlo1jOv1lfFZ9 zxE&B(75SM-r8rh^F3i*@=?576Q|x?8AsKsb%FcDvQ2CZe4wm?|mfBg#TEQw-?>_i2 zd1${D1<}k1(tV$O;D#2Bs~c1c3D`X?Qi~=R-ZJy3J2AInc;PhicAHx(`=hNh5ebY^5D)JhTja3faShmwI z6uq7h@uGf;gt2^W#qFwQuSb96w_nMMNL~(KN#F z)&V^=>j?>vU0WEhhcAwQd&OxVE%xl~L^Hx{a3AT$8TO zMo*DJLs<1-baTD~J=zyMk8OtRWQTWHo5_FXHN||eH$2Zr`DoWZ;nh;p$E=|<9Rj+- z?ar2b)5l5p_5U%X(cyf@OI+Uf0xG$@9Tw0WA-*fyuz8P&kdXpuN#kYW1KGL%F)%GQ z!xuL$8ez_9VW#+LmKQp)es`kPm#+syMlTkt=Qvk}l4{f<%43|saM$AzvK&l!C%_*^ zFz1G10fd;s7Mjrd*9iJKx-%IJy_MSjF3Fa_2?Er4g;dNFr+kJ8uWnuz&L~uw*mo8; zE~f7pJa<=J^pi~zkqfwa45|D8m}PqGKNp?wgJ0%+#T^0GuIPkq>od4h zt-TCOsE{^{KxZve1}r5}Ail1sI9_)vDf88#Oe#&qmc%8+ z4ePtYwhiVhM6n_iAdPo?X9%D$9r&TZD*@8LhqSXth@!SrYVcC0tlRR2zNl+%7Ix@_ zb&~&7RL>)XNbVfUY4Na}@kE$0pP4s))0KG}E{x9j90ge?ok{{=3Sbe@!*c&X7JJ}STpqNWHfTvGLf}y@wg6`~nPo~_huTb6kUu2pde8_*}_LD#_ zTJo`Ch3%A)%y6QhhgD)i2Egg@^Qv)3qp=sEfBzDcUT(C9maO~{wtz}69}{F#Sz_MU zTNf?w<)fAlb<>V{Z-%TSg&Ym8w|)y74rRLhI_MoSvXQ0R|58P76o@`pUIuw9`uwK> zIY04(pf-(3kp_Z&B%fSi1zy&U8_!4a+Ry3PRYvDH;-Ssk`tW!SLj2&Hg{`BrJhAXz zx*f=387{V#UjAct9XPWVqhnq%=)MKIvu@wq26@XwW&+7&8|EDZ^ESgs?E@r-w-sBn z8ru@8Oxhuv+k9qu(8SXDoh6gv*E3lUrL>ph+2#66)qWSXgr_v0`VstYDlL2Dc7aju zZs~17vz;hV{>O*Dkptw;?6-uq}pA z9QIacE&-)B2~BB93^;#Ky*Cm@E~jw2EdBlh>E^b%ua@P%tm|NkK5+QDOXAFZhcTdS zPoKA{40Ol51#&5cAQR@gmSzgG-yA*ATGzvVIE%}(?)>bVTKf`X$tWV<>Pp%i%a3D^ zbJ#$UPK^Ey0{fQ(DK0U+F-N_XolUCf`=jB!Qlh_T+smGVsZ_|NVw0a)x+DTcL+|;(mSx^@H#jTyrJL2s4Y`khB#3(Qz)#bt zV%33=b|pliY*2r3@mGYtQh^8%O_Gy&97s{ayvhw|2nk895JRQvz2?pg}=U+-* zmX(By(8WS32^cS>Leb_u(zlC`^GZLeWSLnyXu1a|y;c5dN0>Ge4b}^E)1FHZ^c~Qp zsok`BGZeC@G(FwrDaF9#Q<9r8$J1KEsmCRePXx`_84S8P{#>r9)Qc-(<0+Wx*gKSScyW zOafQ zx9E4rCYHmO`Z~PRMQ2L8#3jp;9rMs&3oRTm3LzfU1HW8)H)#3#>156wtR2zFJMn=j z^%I!igZ`M$LgKrn^du#FUYAv}CIhkb9`LM7T&$tfz!zpZ+sL|c=B2_ecdq%6N2k!h z1E|OWfLgaR>+L3@oz<-)CA0tBDLKC@_`|Z#iU-){7&#aN0+o7qVU41x{)Y(oUIxP> z`REXABQxxp7uy~c!T9-aR>wRDH#>#r_Co=`2}$j9)CS1Z38yilvrMHk7!2~vG-gpD zn@8nb$MXN#GLXFQWKl5!aj2A6pN36#ENTzSr6*foiz}QRE1r@ zk$fU7Ij{18QSd{$MHlHyFB{*r`+uV`P?KiNS?vTCo=Kn}1W*7R>)}<57~8dB6g${M z?2ytuw4Z_U3Hn$G`%dYya=&^gN zp$3nbCgj1&>@T~UCcW<`JiUfwP9SFb*M`$p4u!#ouA3sNEL^s7Tu(=HqE3(dTe<62 zja`@a9WSTZ$fdkp5HV`Y;jFtZvHK!8XYo?29>yUrY1qlzM$4|{LnE(MiHm}7HzX2Y zctu^W7vpk7@5vy6*`H5OJlV-&jm6|J%ghq6#XmL81w2mz-MHNbpo8NjC`?AcAP zEWh$+{%7rrO5eiSpU?NAQ~7FC56fl$-u`8UjxEn{tGkPqEuwM4S~6M5Uu8V))7Abj zGNYIIp&9ECE}1i!d6k8#{tEC_mw@b9!bYBh1xI?)@JhD%Qn^Tu&QQ6a$8p9%ag$N- zp9#lOXeR6OZ(9Asa;UCHYzjd?oJPF;#6;t#`HW+8&dTBCYUo% zd_uOw#zx#R+5Ke|MjcS{nUajfDikx}+>xuk8{eD)akNs!d*;wSxfLvO{Hpaui}m8z zV(zX$JD3zyHo(onm^dKdAH zgEUpCO{y|nlR2w$HJd14}I#&O3+;oI9Qj>TF{e%c2MF&byn zk}cda*U0?c{K$_Qp9xC(ZpiBsc}?d-L~8ATa2a!1^br;Po!W^X=fX>g&djiYi1vXz zQ;oQgAKg6j{iy@3|`Ond16S#8zIU{lKT*_qL> ze`k>X0pAv*0%6gWk>fg(@78>(8?R{m*a9M2LgZ?k`+6z-wy}EZ@Q$^xWn7~C#ia6Q7G zpDpbmY4nVd+3^cPiJEcKJ!MD)@YfqjM{}ejwgMLsS5mpENB+}08@W@?#Vsoy*xlKF z%2&_)>?7BIesT{BYk(S6Fs`Y#GSuFtJQtn(E(I^07jRx&l#f;1fxg}yG)Cp5-C6QPTcHFpGV;`%W-%=p#LL~$XJ^)UTiqMp zlEAGMH!{w7k=!u#n27Op-|9SDtet}EyK9fK-B9`?#;RI|M=TNU{X7%+Fnm<*j;Y54 zr#UAAm*FJqyX<|Ju4FY~UiQT3{aLx2kA0)a&176}m_p)%`f$1>m&Up!Q@Xs2v+h5T z=|Yu1XX6lmv>lz8*4IB@Yv;2_zf>-GKXiMvN)Ogfi*;4sw_>>G|A6SiPpGk$p3G!z zJd)l(l`2o6z5gzHd1OX|S)>QIbGDRY{`z`AGJ@OHrry$f^0!ZNw6{<8EnoT?l}c8{ zy5Z58QlA5J6bbgi&sgx77!K76?rXt}(aivKnishL=BaoHt?pD>RJUC%Uld6UFPe z_lfdgLo50f0EwR+7o%FhD!|~hJ|nD)O}|bmN)l`#9Q+ z$@Z%Q0o*Qs_?hN;JsJJ?Nfxrd+Svs?mIty0EZ+Artt?ZRL&Cs+02Uow*)Z`tjfF3;)aiN3b`?oV|Ju$Bp2-Q*> zf@jlGz-;PABZDR%kCo6)6-`ejDBoTpGzih(Qj~drqu-x&`-}{(>h3ZGm>8@UQwn}J z)H``NT`Zdv`(BH^cD|}&(DmZyW4*S~U)lduKl`Xx;_`CHx9^M6CdI+x7x)O`lSf!y z{9USw;HPhvlMU&!bTS8vk3x2$Cf^NVTl{~Y#VfcV$4gLY>$vjY`K+{)og%F2Kf2(Q zflF*yXMM=QnkjrEJgU^6KsmMWZuQFBec8$$PMs~fW4CnuYSVN+OBcv`M9k*13~!-f zJ4f_bU}P~4f_Z@b&enHBzPpAylm~n3yB3vZ-Qhc}RfbnfHO*{=e9;#J{|uv5`UWV9a8*} z5F6(6y&1<&*CWL4KlU(vm|p*i0E1F~6)DNI&y9aRY|H+5!)KAP zCf7q!ASBB{SI<5VjuxxRh1y|4*|!GT50ub^d*zdK&09Ge2WPG*$yDEVQ!vfgT$oRS zHPM)1M?6m-e!w^mM=kRU&WMJ^AVS?P()7Yhnw(KTzLO-^#(Xmyl${L5Cw$RQV zOTy9${&p+8`1f4f`MOudKq za!{~vNISbgt!8YoRN9-s8tO54b0?;j;GCbL?PX;-?>BL4ie7F)`qG!on3w5?&`g~*N ztF~?e=JvM&NDkBBy|(aPmghGE1ftZ=mi3sXzhMdDdQkxRl=?m~H)s#Rb6R&2igoeP z&Qstvk0MTsP5jjOfif}?*m26kB=%M#U!re$3N%_L`YI~;D$Tv9Mdig$vQ39>^B=b; zKxpV&!p`bx+iN}fqwMt5mnm)vvHJGI;!7;Vwqp2WpRhPEaZwnxXltlL!BsbE`=*Zl ziYS*ZO+n?u?bxN2%5mB63t6EhWx?mPsIaS-TbI6Dh@7xXH@!pfBp;P5fK(f;unZZO zM_{V~=}&0ItM$$5LnlyF(Jsf5@hX0HCP|*Q9(nxwpKG8!@f(p5=B;dJ38_7#_qgha zJC{O!tp72)QL-C%Gx>?Pskw~iVHsFmk2gzBc|3k1>dPa;+vFAa$LN>5UdwQ+SD~?9 zV@dhBsM+L1+)?-kA2#=GN1$3kS6hk%)4*ne?f4G=-&oK7fnAc%CzA8T=jeJYSmOS% z2U(PAF&YodVH7hK3|As!AWYkpVHGvozjI3iIBit9+QNQ&0R*!9Q@p@+`rPK z6vCsWc69eQ1MAls6`A43in4l5S@c!hkK@5I>u~ji1Q%1G2do+IhH8?EvP?A}$8y_- z5T&^PimlD=hjaV=A}V!Mu+7tBv_8oG2xHzv<$&=Jo46%V$~PWJMZ@kqjV9Of1Kz5) z8T3znCs~n;m5DpQ0l^Ff(}E+9)i9Lz*Qi1L3A?1fWqj-P}|6G zoW--aMbZS(hra9ocNES3;lu4seSHM-6MCpY{*gslOI3~=ZovkR3QZD|{MK4{-`u=O zfO0zm&nu_?e|TYqbL$kU>GK=Cr>BgAAU=IPP6Ov&H>7YOHn`ealzQ_e3o$I_GdQ2V zuGaDLew%^w6%tD|*=0cfBSSVhOWt%DzHeSofqgP6Hb`->8gIRG19ur)CMsm8zInEH zRy6xR86UldYwSOQZC}DOzP5g!HnBKow%7dPL#3B>W;50lYW7S^Z3-N2^p8 z@{k1|*^4F4kEy%bvI#n}c$3r1|>4 znNsVRg$EpHw3g7T(=! z`{baJCFpTo@>xA~^`vZR2pW6&CvG;Wv~+0&TqQAogv~LVN0#^npv2{&)!k4*Nm=yQ zOE~PyUMJiCZYarc5C}Qk35wwQD|p|XF#T4!kwX8Hxw!VYv1>eB9r4^2{7M=8%;?DvLB}d6FhP>Zk2> znZihJJHP9_vR|uP+8vE3_blJmT}e!K*VSiP{4z$#ahq4qkoVfE#DW3q7SFrUo ztfb_W$`6S*UR*L-bQ@nKrLyf#s9^W0`@2^L9WqTG+?0>VrmFf66MxuuJB}w#H=L*M zZ|#z>?_o0zS4{?5e??lbe|h5FA1GFR9R$@rc`N1Ebt7Q|RVKtu%o)T)J#~21Cjc2T z8@9H`IX#BQD}A573Wekli7Sy`1UNO>ru~xE9FWjfCSz{4&w~-VPNm$c8~3E78qyPP zryfrjPcJIvtgSU>uzYPhE5{uE*DlHg4g}T{zcN9h^AS`}(-v1>ichOmRyC~g} z(^V3{OvQbBO4cSoHV}C{ST|Juggq8}EG~>b%z5?xoBZIkq_XP;PXldK=tho_G%Tf#+ov&a_bCb(j8#Uq9~ z5=AUAPiD7BcBhoOqS8zU_F4!SmwQ~wv!3?%1U65R6f<5t$ruQk;ZlG9`|V~og=NI3@ueuGneRxVof+yC zhCe;%?;+?p9bW4!3@4|=E+uL8k`t;Ncn%Jo-1Kp`dvD!p%rZiXod3M|-5@;L6a1n# zgtu&ew-(UH_zV3!jrp%xee>VGcD7tovj!Ve0av&k;aW*wCGLw?>-doEAtk*$JPsFZ zTnmFx^E%k2B^#1P&(bJlWfz#!v&BTEq&NP_`Aj+58PpF1qx!*UjQtNgTZ^>+G3;Bx zd@>NOFYhhGEht8A6f>jx=2=voJy~Xwa#Rg`zTD;Tmj&S*Y_{;6Gk&Lp!G;EVy3$}b z)y_ofilKzOIK_n)DgM%dxY3|fZ|0eCVrmAzGo159BBnwwSahz*1-Ns@m-WxB)1wO$ zKve=I3H=IdRct{9NtDxQgu;vwqWR{ISvF7JYRok4$E)sq!%n`TR;E zam+zUEa+$BU`37q@~G1wjkey48MG%bOJT4sQHc=&0hjV}=?^tJ6CYDM0Wpby;2p6My0gJ;|tJ)BkDII&eWCm$)6v1^0mL9jFbA zVfq@v+%9W==+}ie^fj^kdDH{7Y;0z{r+jRZgRh^NIA^l*X-0p-11V?kGPysw#@6W1 z*?pe@|Iusdo0SFJ+~oRz8YCNK@YB*&q2F>fkp0z+P3A3ONI0vyA7-h_WmzP`A6s=j z%Y6jh(BMZrN(f&|Qd531Zso4LwD>;;K}Rb6HMMS8CoxH?CBesc`bqezuj%Ya>p#Uk zPYiBqCK@6sl4)KAe;R5sc++Ddkgo-nD7Q$?7OfSeB*lf5XeNq%2>&YHaw% zab+Dp_~8MO7F^^=J(G1#ILz!4O(+m_Ca^}~5Tbqh<}U@^C07s~y;%W0mCaY6)?jvB z6C%f)XO&2(8YG1wYjt;9drPCKY7~vyUngTfKJHv?^6qIfrJgyhopmO>9M12i>!MtM z5i(ByMIsu>HknNn)cZ@84 z0v3z*rIACgP-mNnFfd=ZgZ!KP4yhBYnI4ToWIViMpGh>d-9+k+K-Tp5G`gz8R z#9rGM=BBp6$)wh*^*&Fnh2(8Z*9`x!nKzMXdRh3oudD)jZMMAzT(57>!40J}eNzrP zcsj}MO0-_-UeS>3w^H4qKQ`@qGP2xdJklKP_JL;Sr_s|`f5j^2@m``$fdoPb^FM|s zi6IGz{%Zzgz6M<>C?V+bzVB)A^uY9dyBOnMqE5Hpb`Tw%DfA zYp-Ev%%i7%j8du+m!W$d>vp_%ASxNM>pi`#m;Tep2>wbmrJ4g>*ml__mmae2hOqoGXsM63r*s zqF=DuoL^(D&|mU7>6WUY>Y|OR1D&!slkqL-LPd#Ey4HQ6&QkZqf^6#-`TfNH`nHk= zWMe?@ywstYO0r-tgWdvK{OA!PbA9^K->u7o>diH4o)^llZHOpcGHY}10O(vrF7OwL z;+H1}Mroh{I?ik!9tFws^^VaPpXC+(thi1bLqfi-Md~Js+J%->z<^Zv##07Gdp}J) zrVTB2zFxf$wD47V?lpXI^CFV!v2nqJW%?Zc#Jz+~IcDphd!#floO@PHFNO1?x^7G! znlS_V0zqW;A)gyV43G~{$5HlCkbhX`1Qv^{x(-DD5ptOnEWRM2R2v5c!lJnS1Ig>0mP>NacPKrbz1RL|} zrSed)|F%)U;Bi#Wgz`gmF9-;DUtAUwzn$lLjpgC2as6%ex?4J5PhoYWfEt6M_D}Ei z(#&GhWhvqxgLd7VqSR_@4FPEv_KLu|)$ROKXR3#P>*P&M=Xm6GC{ZRvu2>Cb80?M~jUvPYW2vajSy@rb0)=lP``2|sJT@&IAoOjZ3_Up{m-?tFz-KJJH; zcWFDI64XxTsP5Tl{Dbp^@i(w7?mejJ)r12^1?T+8v~X z4L>Tg2BYvwH6RVIbE@$uYw^oMUrLlW?F>QvtIPoLFXb%4&iPsR>z zeyYa~Q9P;ESD|cYJ#PeehbE$aiW5tAoZN}zfs5uZ`nV;woKuyqL%bSPX?-A1sBI0> zKeb-T&l|^rzlk@c?vS2%jFViRD3!~mX_PB=nk0MOof>N@D{2UGclNfM1M%zeZyd*K zRLl9f!?HNoF7n&|JuB;&CeSj~OwnYZTp`!8eZ8c0U5DK9!iz&fuXcT|651{5yO4JI z9#vGO4>y}nwUCais3qOo;N+S99+I1GHEk=Nw!ytx@3~(TH{lT1GTZl|v9N(vdIxlB zwLWrSYX)rV!O%3XsF!p%&tQfhxC6Py8aMC4JLaV_xx4pjp=)c$gMSfc|97mm7c0~Y z@}D$zy+`{E<&n*JN|@MbZH~0M4e_-g{%BZt!53w)$Y0r-%x1~j{;i)A?Jz|NCI{gf zYkcGut^^WIb33Mu!z&#{m3&5ST*@yMiQAc-=zQg!|7ryXkxIwPUd@CaA7hZ;SE_Bi zPiLkZek};|mR~x5Hvx(bbnl(#4{`U=n)NX}7QWDI;prr7RjdFnDvy2j-6i`=&V?_+ zycZO`S{5y!4!*Lo3bp(7B)hm20>%`HO=W=Z@2oWKH-`$MdZpt^A2kPV!(61)=u+l< zGrix?W#U$=Ti|e zzUn1@E;=qhpnc)vSM0@%KVC7l{=U0$N&KV1h*sYv!_jkH?t&qWbE_-jJmatZ?KSo^ zzsc5N`tAon{E>{bPOKX;DG{@l>C7#We(e8` zrLzue`u*QF7NC@LcegOQySr;Bode0q5KvKSbcY~48tE9INJ+B+0|o=7M+%M*#Lu(u z?|A;%zdN>LyYKh?y07az*)mf>0A*=uDQ4gC-Bdg_E7sfNLkjc+bh2jle7>-y>cXTQ z7f@Jv?t4bb&sti- zXb;6$JaCoJ^`ZBQT0K#RE%wMZC0l-@m0P_(#HO=qTkF( zm^->v#J|K{6!6os@;WW1kGVVs795{?OkCm%q!|sF<2;mS4u?6;Q0Xu`hV;wlwg0#8 zR}#%Qt{mWZeh*4sBmIzI^qV!7FJTWJ+fPp8nJ$Dw%%*~PbTj_6uzEbDz0a%uzVI;n z!&L~^*KOfOwMveYGJOxgWe!Tbzk}VlR+lk3< zT*rsMc~%_3!nwD)d2BdZZ)|u4Pg@#Qw__n{EO^fbJzg)=$ZSBBuGN+N+8RCLo9qrr z`1z60aJbQ>CT(=Wz-Nof(((3PODiytw(81!0e2T|w%CDoI;H|_#6cPz79yUBHpYuMl zIlaW^v$%}RM~QZKlvcn2pncA|X=%mdCyW8zpdB8XN!`J)Q7*jkDiQNAtWb=LIgVXH z<94hgez}bfHRD;w&Y!OJ=Q+Uf&hSGW4)s-c4=g|uDEUahsVBOXhcqH025mzVpPeq+ z8lLhl{8r&I}7@rhvE1{ zp{QTFpzh1`JR!19C~8`;T$G{ii8u3~+ODp_>(;e+4}5jLw1M->80hTILoX~H z^{|}pq2xVJFV^Erj*j*(>-dhlj>=L;`U7tE-nY%TQWuf$_eSmo`u#7dr{v5-c!uwTk#X(e+PJgAAWe;ich19owyUtXwxI#p?UG#nIzKEnOp69Xthcs)t>vuecTu6 zIu`QR8ET)^o^GtD;pep;gn$=#S~IWjg9|fFAket{=Rj+@g4t>MXZQ*#wzz5O;AOXW znb5m`nf_`jsY1avqO3M0jmYP)8qqvl(01VeCa#9$+DZPL!yg`fce4@GP_?&U7IL28 zjDe7ARvLt#GbyA!OrySi+!EN4$7)b-jQpE)pKkP4l7r z@yGEq@Nb0R{6fd^G^D*zm|2O!Xqtt|qD}Vq*v(8|h;65Wf~dtl^tpm&sc)mxVqIM? z{hGAJQ%%Y%bnw%b*AhT(6R(Qw1Dk&9i%;dE9t(x}Lk?15CMgjTD`=4)QAd)2^f7LA zg+^go&iobN+J0*6u?K=lQ}5t1o@v5?5M1-hE3t~SD_CA)Kx8(K^!mrqGF&*JV1G|0 z;b2dQFEv*(*P@*$?Z^|?XaS1a-*A*x)!4_#!*F){2gbay=7|ehI-6VJWX#k>FJ_iE zMdL(fW8q@?ty$C)EZ$Q*O6AX`U6(>ZqBO-C*5lx0 z@<%ST&dS+}=}YB15wZ5VpXewJ;Q@AP+Q@Ke&7{RF?4cDVw_ z(jB0F1Xg?DY>S9}Y!#u^Au*KfzueQNcXYBWBi9yqU>VEjN8Neis4-^SpkTwwUeO+9 z4GJCee`%@P!F2%s3Mqnqv6ym1V6drgI&QVRHyi2~>zer}yF2+=Dn-{fA8v1Gta-@W zLn9r@ga)Bxa!`K6x=GppVXPPZCciF1P$J-9eu4ckBKsT{ep|NgXgpDZGM{w)}5h za^hg+c|t6GfMP06oep^@}(fbeExq3gr{y|=zlJw!PA-O1C_|QaHg@x2i zjgMsMJd;9&_F|jUpc%QW?5i(CfrbGV>kfXqj(I(0x_5{$1)FfcgcqcC%zdBU zbX8&Ud=KOuQrEk-_mJVx>WH01CK#dr%c>H_w1c-jQPAcHT_xv82}5IZ5$Zt^z_1CG zE>8f@!`axjwo@;!1M6Z^$3}}qV?eV)fHHNNKwp=h5swRL)}?u}oi6 zb~(@lfCq|z0iL5ZVDHV+YXL;dh zu~_NdrUbq;+d3v$|ChOXTdH+hBbQuV@#0mXywPu(6qI@OrOC`fwB_V-S#Phqs?=5v z{+0VQ`jjDQ3&o%lwe7E-TSS_X<^MQMeQ0#r{X9dge8VlJ1`?%&P8))wK07X4l@4 zvJyEp$7dmbOv$R)^6_KVX7DIg|v%`-JrLZcJ%)eZQyqXPoTM=zm9+B~v@_)av&Kb==jkgafaPWevHJ z?}@hsMM)#BhrIh>)W~YhD{Vz(X{B}f(E^%Ca;2#HD9NxQ6y*64`9QM*%a4?HUv8)Qx@&|v zU0ctymm5AN1W5Evf~z2G*e978d!o)Y?~04)eIvLFbpk{6C-*%j?zSU1QT?<1dxRsD z=?vX$at!bvM|YFMR}u;MT5SX8WKrXzJCgFc3#dMFAH&X`ZL`3vOCw9XX1bWD2zU*2 z*FuNCpBizC2&jPwp{9jl!tL68?`vur%ax1upeY&jENn*px7MS@yWt612Nv8B*^qfe zb*rya&?GEW3upfQvOUFT^c3?F-l>vogU)TX1BLkoWUhG!#7VE3%sm3KHBCv4Enl2AWp&3-e{MRJFV+ zd5Ja)jj68hZ~%Ei4BJU{zJ@&z2CzglBt07%<0fG|Gw1!I;k4@(bF*ax3 z#kA&*ZPT1u({I=tPTzEmptPoNPE)$J+Lbpp zm=!SFzcf~5>q5rWkN!tcqMhc+^JBTAIYjwnXoyWU>H9{s)^V3in`4@OYMYHpUdA>O z9zocc_+i5*^`G&E&UQ&3h8xr)=KHVokgXG7ScX%&K)iiMQ}IT34B%`somN4cWnYpA z)e3V$1*AylSz`^F4fYdjUA$Z%ah&PQtkX~^Tz13?mdKP1sF4SEdL!IzKNXYZ;w`05 zmg`16CI#X?*>|WK`Z_J(ZrpTCD=t&sYaJ)3u-GTIc*W=ld3q|;aq*WM+b;t7o6s5# zq7=qE*5(hU%t_xc{QqT3zYAhBY=m>4(zWV^Axhf)jEH2C5wx_=;3vh$N&Gko>NeFu z4=#_c{Pzm8wS_TOcAAF!J+;Jtp4fUlIGtK)6Hh9Qu_AJyrDW*S9Os|Io!eOr8*NRl8=@)TaA3}0Dov;iRGbyi!dZ=_IBmX$uCogZqd zsxhHcngS#ju4*UKXZj6eHpb-;VPEZv=HAv_hP*u?|HoZzZUPOdbtRcNm5)VZH`7B(8r-u(Iw0oE8LrbhHL#1%I<3jy6appva z!FUz=X0_il?Q*9Ki?`XHTpC7BkgG6}ksbx0_5PN(3J_))F#cYR!ut7#25Vg6^@GT7NmU?pd0n>8bke`3h-EOL@T%*i($o2`#@e`q- z;DBLvbkE6(BV!d4|FC^>w8nT9^ja2B2QxB{fQCiJ7~DPZG3JJ)T==Oy?3EH6EO)6* zl|cgny}ApQKp$PBPDxT*VcND<>eVKNnN2dU2n&hOhKyUWFSowbT42OJ?DIdz^*y95 z?7W~!=5sN(764?Z3NLGo9IutX2HN+@W4O!Po9eL=bG_lk?P1Ymt+18!7IGFxHc_mH zOx;1&1cS_nfbgTUp5Sr23Ru1n@h1^L!rwEt3u)_*CkQ;TzjKp+B*Op7qRG}!zqKK2 z{g!r7#^+qrdr$6XfKml2nS?^NNr{C#Hn0gi_F2z7}FUg~0X zFQcjB{S@)At~ZCiVvKSk*0+QG*waqv*Y(931OL&hV4o~wTok-N}fhU z`*}`h`fgWRIF9~(V46TmwSD|$srk1^k+o}x1mA+5xbeG8)m1(6YO=Bd`%v#aJm=YZ&SXj9Kw2z$hE5&u*iPX;v+ zo7BV=+(R?zu=A^8E7sZRHYf6r1wylFKPP`SX8C&8J;^?3)(vpRSGVgD^g|q9-Vu}5 zFkkl&nh{G}r7Ms=d4T#~tciVygJ@_|EkG;3f7_BcJ(hR+n(F`3s<-$$8|wp#^^0_I zFZ?n1(-T4}8&*P5+6T<(FDj;eA5pdy<=pcwWqr|3NUGYV>cIWZakV z%1r#%cQU+M)G?tnusHYuYs_ zvsebmcgffX)4mU0{tpr&dxtZv92lrFK-QF1u@o* zYXSLKVFMeF3WoOA+JnP^S%<1emg~as;5KVRYZ+8Tl21g5{$tF)JiF>|sr4xJ?)UkB z1!SH=qqdoe4f8tI8=T)e?w0ltFAJsjQ;;J$UxlP#vYCLP6$%(jr212gfDRHL?4gz9 z|HFYWQdaU7tjg%pwtVy8g=(p^)B@Cjt0`~35a~H*prI((esj)4#Jeghhb2w0i!4;Kf-qibToeBnKzCd;h2LzRnHmu z_!->sHo3T9eG?3tS`(6)Zx}X}mp?%Bxn)cJN5GkX@Tn3cFEV%JCQ4;A<+OZUeqbzs zwr^A%RywR8PZ0>4t!iW}s}HPuSJyt{DLYv5tb6+N!Lar!yFq^SIo#3rDx?vb%TB!gg&?LV~ew-@~KTALoscMLxCua1zjWk>~~$`7i${cN>+ z=j)X@&8^vHM5|L9nj|u96!ljDitz5I(9PRl`~l24T1KPD@%+TZ`aQP9UW2;*dPffA z8Ku6~zkpt%*Gzh>S6hd&bkUb5V5iOSJU?53m6I^w!-LTb>=W|LNj-}^T{8VYJEcDq z1N>QDQ%uLR*bhBgV%PvPv>&H6{#G^W7o45v*F)N(`dYkOdY>q$$IN|OlemCFzeN5V zEYO-cIiu8DnboiF6>|s{vZzhPS5ni^Ed};C-SG-FBAtF(KbSskXp0p#DO>@_wks>; z|4mMHM*h*K=6kr_-t!bh#Dr@zCz4edmku$;wL|u*D;v-){tl&EX)%^svu?5#q%@~O zzm7X+-LXxXCb`ijXp%~yx_eNE(9l?8C#x;!1hZ~(caUF$%t?1qqt(n=udv*z=g@YY zRVeVm;Yh&8(sK->shM@Wf&X+D!%u3@A>`(CY-8dMJd8h5XO?Ekx%fsMm3V+(gD#Af zX+3^L2bSe*!k+SlzijF5q=@5%eu1RypoHx%lq1U+x%Tt6cN+RR=QUZ-;hnnGl_lz4 z?RKLaLu~bHDXUG0fGYC|*^n*`Y7;;~otZG-X ziYTU(5!74W&-^dz>_37xjoL#4s^?l+hzyjou68vp=bOh$cm;wQRP#_zi9ZVHGK z2Y`VMP7|@>0}{43w{Aec0997kW~aSi2?_!qj1=FAiLQ5*Lnbr!0k#!OWYOm-TVsLXBh3PV$2#(sqrSvUV7U0_R2K|-WHAajjclNoT0#PbR zbT0MtKA9y_!n-k8D868NX52{f#io<}N4pQjJ;0lm5t6Xo-;g_g;8x_A4SY-{wEC4|gbR8RLa#d?Y#tG<#=idHC z*`52+1J5VujqL@KzhLF^R}g(&x>C;JYi?aGSTB96a=iKqIz zNdT%1*oU_tb+WL}9YY6l6}ILtaJ$+sM~uzPhsoBy&Bn2(ISbRaE2|nT{73L@Pd$vu zOYaTa$GPD2Kb9nb@6&#{a$$0Gm!~W?u*%Z?N1qp>(^W5Z{v+U(R2QdQY4VFq@l(BO zHj{mx^X1QA{RKCwXd6K$g=5;LeK)4}QUgG;)yG=hGmvai^--qaV9h!$Y<%dyMfE*W=frZsCe3Lo@`q=5m z=FSy=o`{y1w{gjG6|QHoXbt(o`QL!~L$Q zbSFvYke&+c&mMPty!h@XQ&-{!xH_~}qI2eIN4#{OhTt3 zbM4zW3%VhE!Y2F@(Dw5<4869=yVoq3uU+c4@;6Uvj*k7OKW6&oRqoQnWJC#vRuJV= zN(UtuF~#1M;IPOv6Z7L6sr|n%sYjC|zU;dJK}eQblq0Lj-=7V|kA^D3#M%X=-xY!t zmbr^Oq>{HC^RL_BaxWZ<#26|=nzc{4?O&`jh`D6MN`yW&vLz)+jd3Eawd(0s8x(Lfh>pC`!ik%`N$NdFG7q@ zlZc4jzTm#D56>B$h3K~9Wg6=Amd>WOBh#@p%a14TL6-kbp{i!1b7$>}-RH99r?ulS^SL;(F67Xq6vblkp$m7#heqez-y`T21t@_7f8T&{Tk zhD56JD*hR2$tSoVq4U@FfMHwAd0r()Fj~%g9M2LV8uFtb)cJTSw2)F(ie;_>;b($P zy>YR6i~If5x`OJ)bSWQ8Q=d@{wz!1%Y>-=! zukzq7IqtjpXwwqf(x?z=Jn5j|+WF=(PuCE?{=Sh>YM44&EoyFVG(vlr+r@vD>6&ib z;7?Jl42?}(9Ht=C)_So#=@;9gC=0Bd{soj>Z;AwY%~(mRTbsV}q!P}L58wOQ6I|a| zhdFo`<|IrBjP!%fHI#L#@ZB;14nlNiEE$F|Uy%FMS z{DqK`ZQzThSYAOQngz?!mHVYMIwQ0s7p1uvC2wh7RTG+QL7d{F)cF*el`=c9M8`LH z_gKI9GV_c%kX)fiL#8owQNMzVf7#L}-;LBUGHw~PaWts2>gaLW4~FnhJg6k&E$c{^ z;!CVkW+EcSzq5q@PWA?!zkb(`Z=y>}`yOEYJ5%bd%jTG7&Gh&bi#9CY5E(9+R!K!^ z3w}qSsK?#fpo*?`C*k~F?v+zBNM|nYR}lkE2YnE)Dxs)H-GWaB3_@IA&k&e~0B*|< zT*1XT672yeH-T7w1MhxsQKz|!;QbW(if?lH0^^%~9~nLYUR(ndWmsetR*g>EC0iyV z^yfSWuw?$o4yO7BfMIp0bH+RM7mfVs?+aQ66R+TMEnz3&{?80fk%l0apI^00+jAR3 z2g`8UgxQ6ePk^dVXBj3m0K@YDfFj@&8~{7DM21`aZaO}lAgMfM_?WVeB(@R= z&HVXdI$Ocw6##~$8eLi*jHJH(HY~mot4a$Gn92NgeNbNVNt|;x_y;~ueZGAKw$Yf>?mr&7$aqoP5aYO@P9=mEw&vVx>-h3>gYN*Q(1YDRLH4#!X%@7P;`XlBlf@wmgSL!e}UUT@t z@ooyT%iTS9DjnNZa4*!DLgI074O+Tz>!K5&f2H{Rl2(PR!qZ=N7(v$L;-z8<_TxjEx7_Fu-~DU1;3kKZ1`k zXGZ2w@@wcT>KbZmYHik138%jmoB{OFaz7e0x6dB~MLqz%( zj|t}*MXnyJ1mKwdv;$S9s)%>eX8{jid3emyZle~>`{||3yQ=?5sz=Ry)R1BJg*=%_fuyh@&0BTUyI;pB*gs(P4HQX+eRffo- z@Z@oxQ2`#jKrb9zO7xK7n8Tfc>Ijb=vmz*!f6CfqWhhXstMG_rKiAxdj=hH}FydYa zo_e~`L7>7z68_v*U}LCUd&=#aLyU)%=d$$SK;38HW$9Cimuj7N&O7(C;Cj#A;7v=9 z{cdX*uc-+7oxaoH0{|o(rSggQPX0c6@O1fYl+`^tzW}wKsBN7m+AZ-5AednN36WnHSJPhn?-FCpqh4K-e*S$ zxv73={z|Mi67x@?9y}*{3&fKmMzJZbNG7L*y1L5z0L;@9in{Tv3QL~Aupjo|$I%xv z6VgbQ%*VP}H76q>4wCeY#F0?Q!FC~|vO9AfQ@j}d)k3{J{$0!GG;$A(ZRKo@ZI3`n z&S0v^BefA`tH)ZJx#lhZMBf!X`NUH@-5WWFJ7#pD33K7@5`b%fZs}PC&~wN2iYTX3 z<6g=Gh}#k)f5A6NWQg2*5cFrrMX$4xg~jVlh-iLb7|AloQ$rr#$iuGQ!5 zVlM1sa#A3Ii({4*Z}-#eYdaLHLDZFpJPft>TlK2aKi#{RZld^UZfWb6r9B!9tbiQh z#Iv1lZfhYIjzC>l=n)g#X-iZjyJMb|5)PHn&HhZ^Q@jE%&T)K|ZOIs)hd3P5gE*8_ zVlQIt>wdhGl%G&Q#}W?~(Fcc%Fn&I@?CS;DdH2dMJUPjiMrGOJqB%9jqC89(KEHuG znI3e?0m9&IVGWJ?`Ku98Vo_qgW{1sx$vQ~+Yg6=Ygd8Tjtrf4~Eo*yY-q*kUZ9!WV zxq!~-uBj+qoO+c4_fk?LtEFl-lI{`d5xKaC*r|_fj9-t0C=o$p`9!~-v8zNzV0z>(uSU48$H*PnoP7g_dU2tucd#kGwN z%_W%af-)0g90?xhH$51Df|?2u*5U%l)Za4b_UTy2bUWQ?kS)t$TTY)s(d5^5I%s2a zc4#O~*0d9{kK2e6{(UE0W_65qVkS3A`W!lE={u|8@S(i!*?FO4Dx>`;IyY~&-N01g zsva8_K}EEO7;M(EMwO2UC2I4A*~DhT)ZT%zW&COTFvF?W8kcC#mGlgjrM{1P=GJib z<{3&X{bKJq&RR)f3?_svtdsY})O&cleMtPcwo-!fXIv%P8fr8$nrcGWrKT)Rbg^Gs zlU>J*{QB3@_{GKt7pg2AGk#ie6p8PAa2dcV`38JmT{gz-V3;>{B>uH=?NuyCTN(dH zFu_WV$ID2np0_r3*$RdF_u}K@QzqrNc6a&PZNF+lH>$4Ng$j^R>c zo8}4)fb2j+QE7K=7fp^I*EfnQH^tqxmaF>$Rr{yge=4_-uDHb;U)SY%y=7*J&rm>@ zjXBqK>p*%*D|Gva?Rja~s*cX_jsS0H1xqF^;MWc*GsOuWtAaVHwi{wM^Y(h1xCwd}1NG4#)e z{a~t%(4Eed7w@+IqoYQ&Wyfmf~S?s4DV%!*gA%u@!9TE^?vR2bP$W zRQD;+V!Hps=GPC<{u4g>D{D~SaL;MGk&+xp4-?oqcNdHG>n!@UHX1uctjJlDXN_GvAN@$3L> z2dIYpI8KAncIMAlV;fAWE`9%*GWi-S*7dH|KSf0cB7YBCBF1S_3B`VTOc{Tn#S*7=kJ(1k%T2^Cm2p4zrF4Q$49%CUDZ%Igz88VJ_!dR=znsXCyUzBWHpctKvL zFwA?Miz&rp9+ti7P$_&3!1pcZi2wy`!aRkw!Y)SGxuTMe32PBwZMR3njX0_YzMoVB(I0p?q(f zQ9udu6vRU2qRo{5&{Gn4+t$c!K`-W7oCTjMi0=f^rtBQY2u>VCF;;{rT5)E3)gVHX ze|KNLBp|qkKUQH~1~=PMN>DmPmZ&iCc`jY`L2u*cUFwHm9*7RIGQ$s!X+^J5XIEX~ zvS3AzF8+$Xl(UT@2UV*WSMu4i40x5O<5%FX2Kt_V!UNf_%7$!SOQQdl`E0A?OTUTZ z3hMnNuR`{Zg8k9Fjci{J*4Q-z{$-yu9Fm44A%R29+W^!ur_!L;b69{z}K3aB*g}40<7^4RY0|G4eyvIJu zrN(YCMHdRzVoMI}cWSX~2HzEZR#^tMDZFR3y&zwL;%mO^FCSz--*AJ6LOLXEAs(?MI%zt(8}I&f+V zFPWy{V;XzSR@)GWmCZy4a7n#aT<1_+4KxaY_xgHZe(Iq-H7QtbFg4*RRVQYfOHxbBj0S%v&8 zVH0Eb8SvNEu4y4ZVi(+bT2jdYRhjwmT0dDoKJr2=&@iYLAmxC^RL6#9QeuUi2x73h z5vpY4d2+gS&W-1}i@m)d?^t8fhoQ7IKN*dtPB>goq4XgxemCGNG1QJ?_tHoIit~`g z!n(U)G8r=(DJBJZ5`W`2@=xU)W>MGFUn(dJ1uH`^wk3}8OY@u!%JM^wj6Iq%#qWQl zGlz`MlTaY1HVlfd+NxJ=J?D2A1;&tJ>dZg54e7+!W`qM5Y4&HwKT!Kf;W<$RD@8lp4eMgqMF@{dYwv*^1DDDLrxp9d`#wxPbv&JSDl3hQce(rWd% z1qTI%d;RSBSbX~#SC9Vyg;|qc{9DU1!S%AP~q)bO+ zdDN}&>$Z;2*-G`sTz&>vd186SYS1cF5pdN7u7ac1msi0sos1~ayni~qr>Qyfg;`a* zU)xjoq%6j}lScXE?!voG393@e`r^pzD!khAE1 zVS{OH<3x?i>h{yNHyUp=P1JCU4pux>)m5BdD}$+$^^2gJ+uA3o!j`D#;`_?pnMogC zG$)t6P5NF({G7t=mc9fX2s5@dQ!t|t_|A)^8VP}9;{kuV9Q5v=h;RzOSHx@`YW?wz z);yprnJzm|T3FTJ7jUH^u=repz%|I`9v^&>hRT2W?gU4w(uJ~OI=xC4r2V(>G&}dV zCoM-0T!2PDt>6K0nM*DF%l$JB+27$sX)O;dvp}Lp7hI?cmX!!A@~sL<<&KxPlrrGl zf`r}96O~bI=1-uuEcr{r*0=8T#AA7aF|PN22yAtYT$tfYUD-+BsKx+5v>Ahr<$H}F z=1B>f*ZK97<7V#W$&7u*;Vi5njc6|~0$j9<#L1G>9w$XGZ{y~)kQ zY!3&oH{US0-z!A!372dKXviHT8K&x8KDv3v5_G-Um`FkrkLgGkDNkBYKX6O#bXi)f5EN|3?s6`!voq z(qIa+4b_lX$!~Kj=(kcgkW~fO;-?)S?jNBSy+sG`9#0zoT7hkzr>po#y(-?D$()n$ zJ%j`F34a`BR94D+|ADd7Q$mCU>&_|@kEPZ#d-}obPpBr!vGOJc()aNU>_G1%6<*N( zqGo0Gj&z0M=HHXT4bo|}$oKa}>grsCJ@-oktcd#XjADruHGDf9jqm+U{x^Ivie)@yMTqqE+IMF0TLGF@4i_FW@bVj~$%A^r+a~pt2||)X z3WrB~7wNJMdVm$RqV)T3w(&s7Fao{%JddW{{8=9+z}u)XmF9*ycyTCHRtPV-X1+*g zm%ev`FSv`J`4W7I!&8%2)C&^0()>hXS&aW@K@yOUl0fPtAj&mOv@3Z7_rXNN#rRYG z2-YN1Y9PD&z6;_Py=z`7TUHb{vn8a0dreDA%iVDeN-qwrv2fwPGSks4!b~SU=A`SA z6+TmEdsVs1m7x3bBy47~wod5?obU%Rb$MA}Y-sH)4-otARF(g}wRFEdN_$^+q3Y)i zZA!Mvd8L?ce4l`rZZM}W)vh|&XzcDB1E&SZ;B>;%50D*VLSHEMVlQiHNT#?q8=|APUrM`;mSX+0-Ji{AbwgI;2ZvV!YA#}&_x<+~) zD5dQDR!~67bz>yXTm2(vgDsQ&E5-gZ`w1)GrYjtEh8TwNMtOcHo7{_* zCa5(Im9-NjGmIz}^8xBFL`l^4 za%Cp&OHDG&^85%C;rQ|OQjr-D5YQP0KV}va>^u3b(JHJKoHSO3@D&?4B+|J7ws*d1 z%zXD+CRn+_{JRoJ0-vz_;`gFaroj(eDXpuy=cuxw-Y= zvu8cu+&H={;VO!#+QmcE7a#JB_9+KbeNE$sXJ4g`q{=m9S||ZOv`kZZ?xH3=!66AN zAtpFzWe3y>XVYvoXh7p2gGtV~C-vb?_b!;$&KMC`nR}52z4Tm|A$ls7sOJ8F^EH=o zza?XbX(VCl-;GL->bSS#DOl_a7y9rYCnqP4{q=lce=YS3`f8y20vXedqHeJWjyxdR z)Ryeq%wI6RByd^1J!}|M6>SdLs1k6ms)mqJu%x_YONG5ujm@B=!1}WW9F4NMKnvuV zd#DG*0&X!2HJdUVm(5vhX?0Nh(CR`#=OQfxB7Nbz)BBU7quC>uVB8DLK^;_S3)qox z@x=jGlBX1tW3ng2c1g1#kq!9XAzLZRUDMucQeHxp+1HM71~xAt5#mq#|I|ESn zDN|EQwD;Sj?HD(O&ONjoDz7(k4E;S%&8Gav$nnTIe^czYDTV&aVvf)<7{suqS{Wb} z{78D0xGeDvH=N}2;cHNU*k5|#14qj#oTW)`v^AOG5=OPg`rO8w2?+yu`f!K4rrHFQ z)34n{UUw=M8wdKDT!65SqbP{-^NCm>f2F`zDQlWt#l5PkC|H*Swc9V?UIKiQi6%Y= z`{bZl0;miMMOrP)m;@UO%2R%cgf{^IfIj%Jmd@N2TLBJwu%}a4RBP6jW12Z;Z$~y9 zJV5$yo;#*+awXcTkxe0_zvSUe@utfG3+Ox9 zqipwIJ&4!4KUUekXd>xuwZE@ZrMJ$=no9!u|WIO0<@%YLW7$97*E~BM054WyG-!>Gp z+AP}cuY8l^WjV`zsU&YVa@!Jh9D5pdz!gZ|Mw1s*{m-lyQ-$+SACx9clxNI8@ct2= zMYQ#Qe|gYhRioDv6iYw}RtWAWMfYLOL8IhZ6++E?Q223QwaB-rT@#a8DBz{1B~wm` z1(s&DsCqG=@S+GGnNvxEL733QE6XnR?{*2n;P7E!@fG}R#NWX!ldnYyc}QfcFx|i; z=|GtKNppTYfnopJS&|bxh~5K-U%%)CNosSkRKxs|Z=ek{H_rJkxz+R>gf;XpBR>qD zd4@+1Tu3OI9OSRd*v#KJfZXP#Z%k_39v|!o@(?pF+a;d8mH@w25d`2@;DXwn8sZgZ-cK!P)^?sRqVKT8+V*oVRa*nLm^53 zn+qf3n$!FIf=@)C;(>|@)`>Xt8(>I9Q1+e;NurS4v40)l?`)p7%f#F zGFj~so&_IZxCpdc3ajgvJ5;Il9<507_3b4t{Ej_*JN>q(_7k0mGQ*FF@_FLI;j$%_ z!iy{?DHnu|)sSvQC7lmPd73BR>|iklgXw4Z(TOVXx8WRwYx9s!i%ATq^BsMu(yU*Q z@|vJ`42_1S#_3cbwI2|t07J=j;UTU^Ml;TN{?^(JTlnqe^3{4FLff)>)}X_2&PV=$ zttRw6m7Ee)kJIRKpyx<%!6+EQ_eW<|XaDz(N8>rAx3ZK2K+lIkR?|_6v1+LCD9AsW zWXaL}+@ZUJRR9+Y3v1{8WJuy8@b&Wwf%}{14eGrc{Z}_;t6oJu)6C_yxG0e-9Zhpf z)>Y~kFpIQhgljU3%eCksQ9F|`DC(kWp3za+V;2O zO}zgj5UrY!W$<({$c<>qta`!4IT>gk4sP~%uCQpi$8MkV43WFU8Ip8=37&`NH~v2W zgF$@0v*GGM*4SCP)deAAY!2<<{!MIMp*W~lmQd=zL7xNPp#B|jz;Yl zvCvHkURMa_9w@cw#?ia!P&;mp;eCx{p_)g_hX+|<-w5Av5b~AH+_ehz8(p5r1c;Be zIAQTwX4NFZ;T^(RfNj8c?{u+MQK)%HU>L}IicUE3cfm@HOSP1wGqy3h$i#QOo&Nw8 zZL&Dzo+_dV%FqFFc|2I~bqq;0n=;L_lz5bQV;TTqIHQgsD~{Wk%XPlo5HSy#j4ika z;lI6D3c?~W8>MWlUfw7eiGtC$j}rDEStMW~w=wg7S_pi)Fv>zQTaFGsjq9FG#WZp> zq*n3)Z@F}0zR=~Yutw;LJ^rt!6#`-zBDXeMcmDNaIkJe5+&GQbb)bY~yhO8F`EMcR z_NWEYh{+whJM%M+^sw~4Zf|0h z0>&=Yxb-R#$WJKS$|xh)wYPl;4UOKnb1O9%T5^USC!xbrN>MDkgGN>;$ zZ-DH%n4KLfR;EZ?AtOK2o?`vT_G5!vCpF5D^e%}yXQ=45Eh$7=4@T+z8Kj;vsHM^X z<%@;Z+WXnLpNP81ot*7Vo|&OOQ<}3yqynQvbWNbNR+DCT3b@QM2W%g63?l9Dc2zdp z)aN>L>z5C&TK@p0`bpEJrF6{VQ(I(FMApX$V~wKQ_iuhK?)~eO%+FTDL~@3XIQf5B zVwMIp5)5c081r~ZS{9=#%fen2LgYVptq`#v-a#<%R+9+*R1-&y-rs@+lQvTAC>k4F z3)V##NB!gtZz>4{f3XJhQ?%_au4%}t>-0<-W|#zosOlY<3l_nj7iZqwcr7K`Yj;gm z8h2NVL1=9cNvm2SPtw6i?ByeMwk#sd&)2&b@52?lx$N_i6)H$0VhJtf@gN7@K*By0 z4cX0=1bat5QMDDZe)5oi7N9N5`%oFKK-T5_T?JCE4p;|lUM>Oj^{#f*tG#s9WFnXJ zrFWx%eG8SXo26@j+BLq#D;(&AWKGM=NVRz>?94wxVEa_t#EiPY|zLu?IE%_G@I60wOW`!>B{jP!*g1y$*LG}3PKr6oScQoaB;)EO?;}b zke(?dA{&T-u^vB1v1*b=AVqN(46Obv5d|uS87&_p=}ZB_3fR&B$DLEvTDjU_>`<1i62;V2p-Kgl!vc&71A`AZX@}e7&J3 z%i-#D5>w~p63Le~^b2!DL*a6@{Z~P=&>B#*9+}blLE#y^j;0!ojn=VPOju)s;f@?| zb+O5l&9mtrUfW+amQ5^lW1~(;7fjz)uoH+X3Yfz3FaENXFG#73H-);*rW0@}U z5}2wY-dOdPFV}~1RI(j0g!a?hbY+{~^e$SC`W13|OH*2Ui0ddT3XZlSxN_vhy@{uL z(brQ?H+iFUg!Png`B02C;5nE}Az{`oy_L3a4fL-@uUs@tx<;NFs&OeLgj`4mi39K5 z>~&RhaymAQDysy!qYTe#om*i?O)B`^1Y==bzGLbnx3q(S)~YrMq#+*HXR^IIZ!V*e zWxm380snu$?2aruDjPuG2CeV8$m${0Kzf>3x1GU-FNP) zwW?U?Agm&%jA=>BF+=;8ElmXE=r)nX85xzpBX&{dUMqM!>H|~~(vgQL6|6S?36gOW zNw65lXPc-vzp*S;3^G)01jvMhF&AOp`}_TiR3oUqY}u|WVs5g2{{Uj=lW|QjpD>Nb z-63xFu8c-9FcC@@5py`kU$F!+jFlH<@_7p@UBBY$1cgp}5)G!%`GoD|R-A=LnuJ5v zwZwP69e6CUP%<^5U!)hz#$0`hRIfE=);};LULv>C=~b2kRT`kfn+NJZj=hTElVF>ga75=oBIJFW42Rfx**F3|~g)BvW6?D;@AyqmYH z0FxYLn(s*VkOEc}mu2xFhG9EMV=T|h+$bv4LzqaifN-?8lloK%h?{0s@{S@zJ?+O7 z3p8PLW3#%_x&DkB;;d_Ql_*qm4c2C45SEXJXBc@uX6HZJx#HZK`t1tz<8T&l0dIe$ zbGDnMbsB$L^_M50*7&)8l}HzOvY;(<%0EgZY}h%zs<5RSMVPsZgCZ4VE64D)0+8mn z!iz@3m(a+BcB>0(``&~=w#&Z-LNXtkfjdZ&7ll|0meKzJc>poy{iqDTxdbu}T*Z|J z+eGVDkmf2ILEv2^4Qzm)1m$_gl@}iWhTT z%!wZI44}sJ2dnpx8?Gym7kyM2K$fD7cZmiOBrGmP5d^=(AU$si0^|_YRY5@x)~aaf z;%?l8!ry8RKTLG3qp0o*2xZbo%E$UR{+HhCH&!k;OKZlQ({};Xc`ZBfhL$ zRR=|*WVYVd^{uGsDf2FZ^d;g%Ek}>gh**rQL1S@d?3QF2eQJkmqeS_NDHy&FxpT2s zAHMGr$7WCn6W;o$3%+U&W?|V$Ab2Ek`*BBF`4E(yq4o-bEP+Uv2I9)y zWLywalSwgtf<32vrIbH=u6ERSu96ussQoDvovU~N{1*#bH+t6s?zhlAY69<86o`G| zKyN;7UgZF}hnJPO{{T`5N@pvr`bkbo#TjGuxR+XmmfQJ|NgO9oR*3s;S6ZUhZK-KO zo*4jh8{u;HR=7NNwrI*Y?YLpc#dEh_A#3V#Vn&I7RKMR(y(a7@F5eW^A zmD{a7v)DC6hEd7qHe|%&-xgbDRUCx$6n7Mn#vvWVa(X)5VdoSzL0cHx9iT&SiEex! zbG{2JY}IPunmT*tBidx#BHc={PC%xR>GFt?T==l}b>Ok0o)_5p(dOsw!>MgqVvNpY zKqHi7?DkvOrzb;AHIhemTgKKdABxl$XC2mv=9jAMH=t=G&0upBoC~|OfvLroWQ4O9iDOmw1j1JgWIRZFkT%RVkt6%(JMa5e)JP?5q9bjkyhw0wrC?GV!yuN-gr5-|*E$8L6CItRL|m_LbFHw1 zYP|GuPaULVY;DETE{VjgJt+}-~G1&)b^X4#OPxlsm_48zNK?r)9{f(S%xk}z!1Ia=gf-w{Qc(5(J$ z;kMIm4~Mm9ozKWog{fiLK^Tk=!rlXl)}x#B*9?}=ZK6IVWLbz@?sw##RwDTS0g=HMp4q_`=zQyZVMvSTmuOcDbHjm(f$L88`kDJL$ zt7cz{font7Y^yws$Yc}E8IJp~{1=~AxsAb7yi#5nkEpKY_Ad?~lA(k|ZZDhKS{P(` zY3~U$c6zv=SmT18poC+$5xVaV9b48^Rk`Y|xQIsQCbx6$;ewHKXwgS-jldj4c&ib{ zQV~hn7Ruh@0Je!Ka51hL1_Pwj45yuz=c94~%PG1K> z9MtejRe5G64cWI29n7FeBIY(-aeWM|F2|c{TRiCR}kejh^2n~Fh@Z4Mm=zr@GomR+>?v8 z(7h%>QD|uxe3ZYYk9d6?SyoJTly%Tn#xlVm%@Jn4GR2i4XlA?JK_JN22_S9PWJ$|!Ps$dSMOlu>?i44}ooePl~0q7dfh z%7IIY2yU|E7P;;r>f`F5(CLkM(3%?HI63l{Vf-Fw#U%XgaB@nZ7AC5=f5 zW)dFBF*m{SLFkmQ-s} zx=PZJd41Fj9Y`8N%ArkNRCd%Ay`>^C`p6_4es@x#CA_{b5(zeA+=)qQ1`*7F+!;^> zBbepNJz|O{X-Ln#m%Rg9V4%VTl0b?wBO#1B$hlE!a%nH<2mb(jAmHBy;_HRAT`Q&Z z)#MYF)0RS*hsDF-%bl&8y?g^{{_=ox??7DFa@^ExBV$ zAjK?Y0mpEkV~Z0%AA$&J==_QjiYW-9VYQ;``c`9ua?NOm&Bhk&`y=Y^!IrQHu?%2Y za4p0;x1b>@0JD|ZTz%&6L0&jxo^7ZRM_iC1l*FzO#9T|Vf)dejL?khPCn6qUddyjnAz~b*X+%yeTpxcGt#-QG(V1$;NBSFBW6~Z{T29<4 zh6`LV7cOTf$A@z&n(Z5=ExhbCN27<EU67j0lKKTwGC>Lk%0#$7~jm5bu7n zd~sQdvRK+blvybA_Q$j6e)X(F9YftV)NL*Jxo{S47<*P$&9zbK38spaOh`u@t!ZM# zk6!f}mR_BFZdS8ZVA3~vMMX&yk2cZ&00qLfy&mg$-3Eap(3&)921zTTjBsa@kJ!Cc z)w|1W3M^>~k1CE5{8+w$>m~L?Q6FuMMJMzLLm@2hHv^# zDi`2yA=he3(h#htC~?X}JHWlTtg(xIOQnLagakyOa@{DF;=}M#V%co~_kNQe&!Jly zx{7*;Dei*d7_*5M{oa+xNk&pjH=ny|IFpZu7F$->)aA7+jEF_D*~5D}RI+O5-k^rr z2yyBj{`9d_k`e61vfp!M@h*&0s2SMbHH znB^6$HQOSNF)O<+W!Y8~gv^Mpv_~rsg|Xx9PzdSR20|ei@5h(5?N$_|VT7{!uEW22 z3bBl`meiplAQv2N!*lgupiDAtW4wffpDO~f9FVce*~{S`S5PCUj!m3`1Tnq4oVTkQ z(b0W!?8_~=y(^wA$zH2L+(IHmECX%U?=M1|RaLWFHjQ|ryhuoSpT7k*tF3INSRb%d zD5N>R1QG21aUd=K0C@tGZEjvwX-95i?Fs_is?d&3UstIFWI4P>fVR(A->p&#L-mkD zy##wdw~8cM-?&gMzgNPn8#m_c@}LU@3PR#P>Y%YlT~ngwDQRjYr#}>B`1Ly6lZ&p< z{U%Elp`>Z{gZ}_Hr`-Pl5&g=tPA=O<>FPZ$B2;xlH+T-`A8RU0WHKOar>)9@OuXHc z8SJ3Imof&qxlm;TB3S+%6bBow`KSUUNxxMTUweWKpvGJfWfBla+Cd@=d&mvKiW$Cg zBo+t(MFGS)kt`s`-bD|4>YzFQ0BQquyx+MJ1hVp=E^f*O?A(Cff4u_opvoy3c90=S z^H4)4WNzl_Qaoo)YetsScMVlx5M8<$eB5|@8BR`>t5zi(QRU|9VO-r2-6t_~b*oBD zftb0JDGt#2tyU%*_Ib+GN)o_4R-lsC+4F4uRSGc3{Kb@dzj`F4Pyxz0m59WoKFy=w zZt_6ePG407e7wBgssa*lyR+Pa#3bLj1?XvJlx`8Ud&y=^#kSG3Ek4lgv_P$YYUOJ? z)~3^zQq#sfre&0E?qsQZG;!neeP!9_Y$^LbvJJ%-Dh`^2yx6O%Y}rSX-BiWM`#vNV z2LwXIWt5Oz(E2W~PU%W|3MdMurgE}4gNwiHZ%WbB$?{&J(Jm2dA4obEKvzkaX=HIH z!QXcCkRARErw@F$J^Dk;dQ8*?=;v4>(Zi-F^w3KH)CBZ+;KJ_g%=}v&*zR}S?4o03 z)^~?nss8{cO(&=IZY@2h^wkEa=vkSH8T5m-<}bjlcNS)TtVx~wuvHcH%4Yjc(7C2Q zOqDa}I*lc&8qcG3(kf=gNNAmgR`d%o6Fd4H+25-a!`#gM@w3Twa9nklMYb3_Rm9HE z)t!_&Pe-SGy8_OYv@D)I3K75m0FIg2cDGkO9;^K>vp2}kqmJg%5r2}ZN%F$0{$#ul zqn?el?@GGM9){2~%{4{4NoJMpiU4Q9%*%cay}RA<+|HsScWYWJ8_U>3R9D1zB(5oM<%e^k96Ng8qGd~)6~sRRU0vhgWVj! z{0s}MUkCK=c6MiHWiuN(*3oF*9fw38C;emTZl0q^Q_D}HG!-#8&7~`y+B{jYb{1}D zX5Rc6y4`F>>9yj#o%MIge?W$duBg#HE9&-@o{kfqT5++h5Emle5}WR3@T=L8t2^_n zt@#>i9*2`nN361G`YOFH6tcW}8Wwk&nVhz7B#!(yV$96k4WAyRwNACCY<6*7B6L%! z`V&OyohL)mT?UrYF%y_*xak;9LUX~zi)#Eacj45cVmTL#?7sw%bgtbS2sv{D_H8Os|p&8 z6HYS6OfYR8q?}FI8SZOe5W|DV2~SHLL9CkTqBVC&NGx7MA%Vyk@M6Tr z2lis#mAL!Um%17rl6oQ1ogFnTMAO5hG-XTS4Q)O)yWx%w-A?Vjx4S!ateDwRZP9dj z(SDQZ2eR++EqRZOT-DPmHBQpC}ulhNal0!_v+}ztGP3b>ORHa zZshngGc%K8*S*_wI;6z8%~912DX#ihbbgD4q?ZehLwiCo@e}no+Oe}cJpj54(UHsK zQ)||Vk4j^2l0CTH;ofZc{4rUvm(=r)kTnNOY7UhOJtr9X(RYTTC&oEhxVXQgb}akb zA7Y7(l@q&{5pGqDdIqa>T-w#BnqN=R={##RZO@fUAOy_qw# z?Bd2XjCa~cqV~|;8_{b$UXs~QT4FFzY&VlTz7Kug7INk8Zne8|-8=Kyok!@CNo$1! znn^0+~U+yzkb$?3!aq`d3(KNd) zg_|sbSYvbD&4&iywqs~yPV(in7L0v0ru2S|+U!QIqB?!0w^?y87grkXl+IoNYxED(l(ST z9S2Mz5wjGvb#H`li|}`BI{KT7{2gE-DYL`kKY?RsNi za$@dpIg5Q&meY&!$cJIzpDPhNneFCKO=?(du2q zp4NMt2g`>C;sdJ~W&kTKxJiH;BK#l0@8 zx{qphM|r=NH*%dQbW^4JHJX^}=Zd#R)nl-&r^eEJF}2zFJ{$Vk+k@_WIo`9U)z+7d zPL3FPtrh2b7PNg4={+S)OBn!7Q7FVNWoWaLvopK(HvTH&H=U6)v~Km!_yEzmGFGM2 zT_9*}7o;%2sY3}IU(<1mx5byHG-5i-&EHIOh;scRbW5c=GnR&`S*f&^h^s4Mtft1& zd@*Kr>UVAJgS$I*shv5cxAiJDBK6zWrKwtjU#_}nXtY%|^WfxC8DShl<1Xg=S6b=T zTxU|z)#*jh4vVImI$GU+(G>bfGQA_P<90kZ$j|pzTt2rv=iKtWKdX{xU23b*k<<>7 zni`KMBBaH{jkj)WF~=R=)e{`{c8T6MdTbvj=^@c^Ppw+Xqcv-6*(02V%h*_uwmyb; zS2g#`j9c9fXQUpD>9s&Kbd>sjhfPz}IkZPhy@Z1dab|L6ZSB^k)!)|XTW{)1sGSnm z>zx$ZPFd-+E`*7k3rJPHqC~~M*4>UB?(Ep^#}tb0nYP@W9Nh&qeGHT8-m_@!WRjR& z<)(p{B=$B0Tm86Vw;yz;FMK@9Md)hXGo-1sWK{B&kdk4DX~nS3-1zXruO1jE+0&!c zCFm@ z^IF5igt4_k-DgIcr9rKlcA6a}rYW>sLnLDH%FlgMkzun2?|d-F9oV+#Rao9rY1!+2 zFzN=cYYw-SO@6sjXd0g<0D4Jj*xtrx!THB?`xi?@O!afD%tuE(@@J-om!v&698-Bq z$3XGzu)&N*P+=zaw)HgX+w^MU=v)b&r&%?hM(WAcVM!#)pec?g7#9 zkeM;~alM`2(Q3WDTeCl@rXQ33n{8&QgGhNMj-jFkd9#x4eedZfizy$&W{OS3YpJ<^>0@bdjDqN_Akl9G<9C#I;S zk;ZtWY#ujm3!g_$uS0{NohM(RwSP(I>aeJ7CkxFXO&-QN5oTw^j~B(azf*AFuNn0t zCd!|nS`9L9Pop*OL{@1mF?vXZNuAq{_BVVRzSX$>Y|rX>p0aA?ZmQ{OogJhiD5`0S z!Uud=+1nO&eztaYcJ`>4+mhmUYYI4wL?jWlxIbFPx*b8(8jW_+)6!DbQc?s_Jo8Ie zCAP-cGrs10ce{S|u^YB$7kN$4W{1*sG1BPWebE(~NLlQq02jIYnc7Ep_%gg>-sP10 zo^7o90=ran?M{l)Ftl}WJ|x)U1kTv833aowiH*4~Cw^~P={%jf4AfWMi#%@q-=QVa z-dII^($7Xa`VQB(VrLf#EqCtNw-m3IN%KR(e3bl*V;L?m&vy&At~mG|a&}!6YD_&O zX^FICx=^%S`!bRK=Vn@QjokfijH%EXQmaMPg_SgO94;-x zF6YD1xkY1X*|R&w?!QoaE&l8@9-7ki8d>ySjM0E@^7%g2{H{d9m~g?FzOyTe@68i! zxilJ&s5)m`w5(b`Ma0uhh0|0>_QeplSwB~?v3FTo%udkTS|&G_q11E_qGy??Ute@M z>2}D}m<~61e@Tu%3{~Uxqc5rFdiAI}UsCGFMQK=tr6yvEXx|v+7VQiE$KK1G<7({b zOT=4vSkRpnzMkm2O6#YWlqEwe#reO@=YlQ zjmcFY!sC_3P0ML#TUR%v>xV^>=uK1AZDfN=1!Q_=oC)b#3pRMh(lfE#_i@96cdqlL zYeUc9Rwi`zL#v$>)ayq_dPiAlYKls#O2DI!M+H5_Gn2&3?00VcFAN`trErR6S+qM_ zQY(0@x*a3X6dJv&^>uo0Tl8*^($G?!Pv(%eNeRSUm@#t~#qh&(Kcf{>rL=D{=Ni*# z+O_2H{V}8bwi36TS312mtIzb7i>ulY?8v)WS4!FCwwq5?3BXpIWe=)Ly=>uaJJDY^ zXNoZ(`@Y3MxBE~qlY#~r5J)mNXizQ9Y6`O!Ul5`d?(m?Dvs>Ztp!BU-(nDRMVZgJ1 z*iGSfUq-ghimPEuCf8;o*pqsvM#@PxLPy%Sat|xhno#tXl#raVF<2|Zt8DJ)WH95( zU2DqdnmqXrnX@q8o^80;HmE^EIBMq=7+ zB{{9-63v+ynn4bJQ{}}4awz2+h)A*EY5*~`R~X$PH{h%TB%4i;j?Uq7yt^!*5Xj;r zC(Jkv<-_2}B#^DlIfzGf%EfUb0={u8OO=Ovi>ML9Pvu)n%3DaT#!RkQbu7iXEo{s? zL_y86-I>3sbYQeCAS*;Ugt+@10__^$O{QLnPUVM6-6S;-Q9&Y?4cg>_>51l~|4$JUs8kyiCdk zTB)LzK_ZxG%!<(tvV3?Vmn4oe%wBKABfEbNq)HlmV!AUCu!`o)-FuKp$Tr3!cw>w9 z2hf5!Bsc_f4f60ltWZbHBX!Z3kJiJz0|MD&HEXe|nhbc93w zCh0z&zlyw^@pl>@U9@JFv}2oNKlC$Xe}nLKO>c&7U%?QVWbBd#jF2~LnFD*s3s4)m zkThkN-puF$L6jJ|&;)}h1Og0pQ7odE?4Zg7-P!mcVetKk4_lYrM2=!WZ_AYwUeDe^ zlo);_i5&j`JBlfk7$W6Be;JS{txjfT#pzm)7efQMp8Ns|-?RxVgM41UpCC4Y`%15jQQ@cZi^bNsPN+>Y#2x=CqIl z;=AC063z4=k`apbvi70TROj&WiP`@E6?W>)K8qbOVg2Sk z9QS^3i~N;RPnH#5^Ci6bFKX-*{{SaFbkY&&s!dw0(v>n&9-6B*0H%yU1YOD9u)*X! z9~RzBw!IN~@k7rWGs0oYW#MMzVv-kd)HePe?bYCnzJFB{TRCO5Wb)Q6Q zE}WnerK_mX)p5*6jA4nB2|Ken1G{75b+Vl}n3?3c@`bFEQ9ez*8S2K3C#R&+G~qp7 z&vwrRZOKlMCS5IA-*m|?~A*rb$g9mg7*!{VcbI401gl6 zb0_$#O!at~v$H$C_gvQYU12iTuajLZb#uJ6dNQC!Ig5EaG`luzebZ+7t9sR)Eby4) z`UPU%tMY%=QPur+8VTK+i%N%+8y72|5Xa+){Pj`Q&U!UEYoqCDdQd%9fJ@HS2t-A{ z2ubc@^xzMR`yFQ7_E)QSNAil(@z1O@8ofsB6j~mfLcx8^WX-$aEDiB>mY-2r^|u{9 z%6bD;bw^jJ3F4s`9OMz)#^4~r@886q+W4)vD2Qcx%)EbAG|fh@Y03>FN@X0>^9i$y z@oaaq`W>-n_NZIazEe6b8a;KQtB6=mu92QxJ47Voi~KEbg1dD^dM>Yr%XKDr;n!_iV>}4-l`{)tgOlw?tF27io2J=B%c}WIRLmVF%N%yb-boAX zAA9hA4Z*%Ep01?UcB`h2oLaltt$ALC$5(ZGNoz)xheznDIV$U9 z(Uh2V0`ugG_5yt>}uEY+eew`%S&9?7H_;9cCQ+ z*q)It*QJda`J3eNtJIQd8f_|6wV(l6M<&uUZ#>MxU3fNMg6VkMP9e&ZzNE^p$(Ko< zjnyrDuZ{7Nnh={oL4<&hP%fcgs(b{X~iTv5}bJ5g)oM^P$(^a!aSw|+)7xR)cFq3#$+XG*;j-Jkh6F+`!e0k=e}bylnr&`PS4%pXey z)1y*vd{t7@Km_}&jGP&;>TTHjUDVp#<+ZOT6Qg5cnxF=4p+zI&+wm8D`_$ETeN)ml zqtMpsj;!b+)@>cDv{Z1hY^!7u+mi^h9`bB(#GU;lyUcQk-RFttGqal14NK6Phpm*F zSUN<|GDRDZ$xbyfi^wF;h~u>OKf#tnL{9svW@a|o%4-I;&}w&1^?G|pY;=x}3ZRwV zn1qH_mKJFo37-dcb1uFtre|wz=@BzsrO|6gM%pK(T`gCp^*dOo=d7rAmZL^h6|xCC zZ+7iBvD*($3wc|eWf3^?v^jASu+yGxXJ+}|Gc6{_uK{{W-7 z=ZjtSe`@gxhb?B&dS^&z*<*N)3XmhV_hx1mCw;(Jdl_x~tf!eDL)u8R7eJcZS4k_3 zu+KY$f>^k_#T#PJ-q_-l@|W{GC8c+g83PNia$;w}+4`Rq$<^;)DUCT%`JYv(q>;u6 zqdJ+I>=@0M7;*Z=^scwIJ2_L<<$g}{yd5UfG-Tnorqzhif2) zTgU_-7xt8nUfdU3a)^XeoXoseL2CteuIXA@+IKkWDTrkWLGTeQd3W_c2V8S>!Ry~C z`Y5S&pG9dHViuCRlL>ckcLLn+@Fs7AF1PCANZqsPA5B$g?~}%=K}{pa<*fvBVZP|t z2%LVFZ=r1YV61qh<2tJ>+B;8Zs)|WkGYZIv3mxq2Ou5HbN$B*il=*oUzfwpMUh>dK zjt_<}e2w@sE|#686pi8KTdfii^UTn3DiNg&hm|k$BTKQ-nQOYMSRkmqV3%YYtvxkYe?98 zB4x4COL?K;mY9t}2RV-5TwaBpSJxSJKU(xPd@;C7PcX?KgW}lmFn?&`-xU#kr*dh$ zZ1r!HHm}o$vFPn&qrj+i!~$&~w&y$HQdc8P?A#?8xVB(rSG{YM;s9ShUSHAzN27#_|JTOeA3wGe1@gMD6WK zW%D~f>^EMMG z`1Rt8Lh zy9MI6o%A%kkD+>8jr4Cpy%~fP6+6XA2m|qL)Z>FbJa{i$-f38vc_~P~rJ`Fdg7u)g;D3J%xxy%Mw2! z)810+dEHbpMOiQxiPz4sk{oVQwTTAuxOuw2YJjp1)I^8itXid;YaRT=Ib2i?)~)HI z(RxBKy6C0K;$6?d2c<)#7zRD9(cPBv7r=f#mCq*PZ!U@~vXIAiSN8X&MkygE$hz9AS$6^5h+NnY^yAql&XLRG3|3Rb>Q7;lJPCF1y!UXQ63hR zxNi2TV$l%XL)j7DCB0aOW18zkhTYz-2%L;Cgb|4pf+Nj$wG@P^nv|@!X%TZ6@D_E? zCgRumV0l!)@$CQyFpqaq#XyQW{rA#L3M+T;NZ<&^^L{<5SE zpRodvx%PQ@AW{`+1UY@x0T3rT1XeL`_8?Lmz9buM6Rnz4Ls~FY6p#<|GiMKnTP?{r zyG;wyJq2M|SU;QP@fP_0vvByXnK9TyR1%1o5Xc3AY@2Ejo<8`Hy^5j zHzJ2+63wWfTo41n06rv1b0UUh0Qis=w`(#2+^83Shk6Cx19hk)5#|2?Nl5TH3Cz7- zwGPPcVE1~E5)+W-D}4fhry#q;Ut$RAB=xg;t18Sw{`BDXlcM98wV+7XY?*sv%V&poc1MsvR&9LjqKgU8dAv(g=m2GBiw?lBO%re zk&I<;F%I!;RUxC((*bD$j0WM00K3BdYpp8s-pzR9{cExpsl^7`guP@PCXXz>swk)F6pHpjS^}O3zbvI7*H>~;`w2;9T zlZ~R%F-H`auv;VA#O=ErLHJ|TrebR@u`y_SFH3rWeLvCY&34p-hQ4>E8hXthQiw|# zGrO}r&dqaN?CkE?vkSI3tF&d#9IH5TmcOCigY=f5YY=OeySy3)MQD*Jf;r~`Ba+u) ze6H-w*y7EOF6_+AvbEcsw$|P@hm>n(xBmcl{V++Vgh(N)(lKmAxU^#80gtB9Y<((b zcb(S}wRU#DE!aG(q*^$7NQw%L=caR6a{u z;h?pLQgx%Ejbg109~PXtN(z}Bn0BNLE-df5=5UOKy4{_);f}|+yi86|$n+G#c%y!V&o$N!s#&hR@r9iv!(; z3`2wA#aCEz@>_pX%IUsH{U=8qOqH4zpGMPD#!?*sNI|#0MMZQZI14+z4H*$X4&|Fm zuX$HZ@*>tsJrUBx^p$fA1*CLzl+^BTgA}ZBn-8_vOAkw6mFlf%-l`oZe4lmKRcbWu zlAA@ex*C+^ne>2EM`1+exUF)#9qqdee-)Dsk*ixoN3Gdtr*H2T)>p@O=K$aT0N-@$ zeNR2V%xeBeI?qX=!&o#9o|I{HHnGOg!!(6!G>pVAi|}S4JQ?4tTfHF{k6bs}Q{>yO zx<5+EO-Vr>lBBx`>f)X;5+0{^B4=&fTMuR`ahB%}&s#>5q7H|PQ#`IJong|awW}CQ z7Kxq4=YK_@BG~cX>t~c~nDJY5e7}hQBLf`(2PyYb6 zfBkh{q)#JkDbCj8Wqvw`g&=>#J&XV z{{TxW+Ectc`p9&argR^rG=8|%43)J-Wep^Npz?^zz^&%LOhpj~qc_oWRT9Fg6FRSiIF z-Mm}g@3S95Z6@&F^s8A#seK%1-9x0Sj;gtdrLHi1SYGEhXY{!{VBByW{8=ZLCdWD5 z;={86%lDM6BvZ=-@y#5s9PyJF81WKk#hpm{qeaQ1H0S2NlV)%hrqL3N;@n0-efWDk z==@oA`rN-o^6r_^v+2z(S)?jo8S17fjJ+iI;LDS%+w`3P^y|^)hm%H65BEu;17|%X zro!gV%*6iy8%5dpacoujp&nUtx|`5OpM5(GPOwu)qO?shwA0Bn;P(i=E-h=m7~#e6 zW@V9C^|oyur#;iJNK{(Yu7@o=>{L{-H8c()kfmg z>6f9cSE$vABa=wzz!+wwG69jDfq;h>d<3x(cE=1^)=j4L-%YVtrS{Zv-5hi)r1e)? zs5OUMMhy$2sOkbnDw%>wCYKi3h}!Sk!;f<1O*x6)&ezn7MAp32K2uEZ(uBYJBtL_! z*7GYv$nuTCULy5Z2Y0)4JESNz@1tEY(d~6mQCCV&EeXi`i+dY0ce@zk?Zw!)aCPa^ zn6+k-@@hoZ(Rgx&@^aV4ttcBs#8I>1bc@9=- zc9?oDcf-+wy-0}Ch=(mb=T>G~?~}Vbba~P~Er;?p-Twf(nNE+E%GUGM;QYO-MR^{F zzSTn0{FF36zAWBYPk`=s{!uFW6|QqC{U&Aq#pRknLK$*)V$ z(Cghy6)q9aRY>tuN_(#>goqo`?AZJlYV~rzM!QY)6R$P8$yc>)x`l%Vyen?&c-=H*1vzX+ce+ zqMj@N08SM#uoHE@@?!fjQ{BqD$U~`eA4EMV#(GHJUnQ04>RKmq5CR+>+jjghXZR#W zGEC(Tzog!TG_JC1B>Kgw+YKv2q>FEibAvd$z9qb!nc3eL-2HfAxoxX6JHsOTM$+?b zcj(VeY7HbBOH9+nO(j{lM-+0go4Ye(jkvd4b*Y-nb#$b}^m`qCkB_HLkMv9E`kHpu zZ4n;IdTCDAELoVHyRo!MpNAH8et2^7%g-YDJnOAwzz?EAlV*5~lT}3G&xQrD+W>uLY|iQA_2~Pc=9@o3vzcu{mJ)V}scEZtG;MbJ>=jTe>*<4%d1L z=6G~Gkxs{OPft@DGe3!n?aOhqGOMcT?x)E$8&$MUm#YfxXr}X%$PaM~SnOE4ce{_a z+*aN2ww7MGZ3@0I}@|xzpE9KS)Prpq8^v1 zIy+5tchTmt9=l33nkq;hDryRehC*_2CUzEQc5AU_w;uPwmB%RNiP~qA=D6w_35o;E zB`f^a!>w?wo$+*9xuqk~I?JM~CfyA+bQ2MJtZe1>GN|gA==JWMx+K;Ob=JylJ*&`; zlBKAph;fQw8(p!%^E+bB&d$!tuSvA;3Ddk*HkEIaMFmEU=?70!&cX*BA;%x8c^!F0c=&Yre|bVsu9+01}q0lDcbUdtS;^E zFpJ~E7IuF1*Ub)IS#x@;&=#>&>3B;{Qpck7R3yhyB+|xMgKu_gN%*&0?qxAa^^<68 zdUw|vJ$Ba&Xr^f>C?VJcqFH1tUEG_|i{Rb%;0B@9A5mKSGewwx=!tFo ztf!gedbb%xrYLTcY$a754R0=HT;r>x^m>=de6iQMNZ3T2v}|vKlQu22mvX!HMLIls zIfkITB3WI%Eya{%yk9|TEeyKd&>dES&@zB&Xr?W^8%6?=o=dQI?jgakea~(k>!fq8 z(C0j@ytw^d=z~k>O6YX9v;xnUGkFA)U|yW z>UB1UnW{8=2GK(>_JAU_pX^(!6O3%>!|FwEHlJHV(FTic5%Or)+IG2v%jG?paSUUF z5&CgcALYq!^J?*5;??AR1ae?r@&ysiZ;1tZiznMcL(9QS)28Ig7K%a=?4@kmReF{% ztf#cOODPKLlg(DM=BSBBK?Ll&soJTHIHdR&#o}z1ruJ@6qjBJ=xEoet72;(be zATCo@7)9ykAs$lvR0#_mq$WK@y=9d4Y8(8H6A{`GM#Y=8iqxbkT6)W6l(vNtZtAuA z*F0O2LZ=Hzpz~x|THG+jUMR^KQ^m9qIK;0jNUr5fOp-@K9VvE*NUm#(AA(|Jj;a`f zVVnm!U?pxGJ}N9#Fw>Zjj?(M}_ixSZT@;R%IX2Qc4aEF^tI)Ekv9`r_T*f(aiezGr zLGvUf9Ayz@woGs)e?rv_jB?4cE?CCvM}Z)YJs(FAZDNknw(I+4@m%q4Ry2|o(Ue($ zviB`wxe1iSHrggxghvazpU}!wu^_yo=i}j-t?c?+;He;nJ)rim8-$5i21dHl%tBkA zf58QEjf2e`cN3Fin|3M$g(PFz*??uYf6#(5lBOtbJ8c5y--!pM1TfbRETqL-d^y+8RoqVqeokygn_(m1O6O zvZ2yc_4NB%d84R_`%#lRq^=B|uMY$aC76EH3?=<&B)R-Z0nfbwZRi`bb;uWXKC%F^ ze;w!#bpv|H7VC=C1*jU-3(AROvVuejc4ScfXF-nA4EncxS7@gGMt}&Qlu$JG%=x zJH8mZz8;rN_hdvzM-#eGhRqnMtaf@-5UBIARMZuYaY88$54Z{E5@ zwy_xQ=BB_oh*pk*kEK0v(e#5yORf5Ll9XE3h8-m^12=W7SS?2J?sJuTLZeC4%T-xX zEmYDzCp6~fWd4_Z?yIJ9k<{?6le;tE7~pF)=3+7sZL62WMF9?WWhgWz#w>sH?SyO4iZ1 z;pFudvdJC|>bYR2cHST-6rN$DLA9Z1k=D%udJW*Nqsa*d>B#|A7NvEuxD-DsvX?dunN ztV>`zUcd8K=FiR*Uz>5e$oA#2#~g9995Kg#1*|TOt*p^9xzN{CQA+$yo>GjymUV*W zkk(x@rJ&i@X^Q&Td^Hs(ApH*OMz>%MnY;N^_k&JpZ z=$l1qXv`(0D__bhSPL6Q>z%!qS}oqd>gSYfi03=JOL?eSe?2~ioMnclNNR_8`7ygn z-pn`sDs5~XE2n$0rS;cXbnF`{-7Q>n@4sa|Ny>j~yEnmbwzIu-sMALq2Poz)CDvZo zTpd@mR+_HRvpm{9x~E6V?SsipDMn7-(RNo8G0~F|JyKWe9+lG*M=gGltgenU^c12@Y z@{cDbEL=^W9GqFydPCM(X?&mipwf*^h8r&}lH5I)V3yRky;ak%xuh8kBxwYk zWX9$ueeC`C_pVEBYPHK)G=&pV)@j`*Q%X&1!!=}v7;J10(X6+m9x1uzTnV_eur=ikSIywrLws@hOq8Zx< zYzdj!iLiHV{qDNfw~mfCww-#ywJkdt5K1H^ZtvQm69^ehB^}wgkmB3A-D+5jno$dkM3}aM&(utVcT=s} zYN{rssMDH2;TFTm(`9B{|e zf^F(%{3X&(JGo#N>yn|9(^HM zRb3$OzM#%R`d!^)RkTKysfu!%l1Un4?>aXmStYJu9) zrJk_J3%#(pZMS81YT~BEqM5Lap?pEX?I3q;>v3jH)9aS9#c+nQX+e(5HVs=Pj@?g% z+*5g0(e7%bt!k1PCNhxZYsjR0UER3vOp}W3Cbj8p2In0Pmae1*c3}!SlaA(o4TC!= z%~&GSntHCfK$A&URMttsq@H4x+v4u(teUCQjC(R2p3F;#@%W`n8XLq&ExQZ_htQR4 zX+^C1Z$neZOG~9|>FDmY;)0~(0rs;#3B0ptSEJLqQ&p;tqKimY(@9Z|GSkRW$n5Wn zv%5Yoy|GUr=Tg#8oj|b&2}{8Ox)R2L` z=64}y!T2{G=2f|}u;i0BJMp`jV_RJrtom<4z|l}?YWiAd97Z~NqXx&=&w}0M8!A<4 zI;|s6GFMhjS1H|uv&iOR-PpUVSt8Q13nJ>n~QZa z-OY&^S#bL;e`>@oX>Bj0G~>cGxKD5tcG>HugI#Yh$Ffr%vfgX+p0`)@c~p+aai{G8gu< zy4~fQLsUC6Ap*3Esf%^EENbl9UrE-{wIx+;RaG1qc|9!k1tc-$IKDnuGFnzCY)m~nSzXLonQ7k%EBRWZL) zZIyhMGmb#ZzcUDzE3Czt4GmvkL4{oU3NJ2L&wCk;4`kwg4{p55XcQEsf(H#Wt4Gl(f@Dqx79^H58?cv|%|6 zbH6SGEcidgX4BET$5mMBqZ@;=*`2-{)nuGkbVUVzntKx%r8t10kh^bpoX#8xUMUC*DK9JCTV{;25;`Lyu#iVp8`?%Cn%)X+ zS87?v=}dg1E?b2v>1C}Cj6?U8I9Y0Gn(V`s^5Ct`%^sT3;9262Gx%3}+2yrdtkJv+ zwO(r!N0#JBA4{Lw)fUD;40BFbHq6=aj_K^$Y+e}W5;j>vAh>y)ai0y%k6(84XY z_6iFZdBp-5iphkBnOKmD@*fMR7BoC>Rap#0%0$a7y1jaqO@tyAcF8$Bey1e3+NoivcC`#AMn67feuW}0m7z8$kQGD5V`*^Dh2*+o)yS@u74E)4dd;`073q*4lYLrB!xw*I?h8k0+s+h+y z$X%`jyQxERSRvUCY{uLPTM^Vo5{X5$A;*J?1=+l#`aVI*CCY+JqslzJtiFU0=7^>u z%q5gxkHJ8r9C7Ub0Fu;f;)^M@yYb`K)}>2DAO$Yc;n`cdUuvYI+D2kVBv!s#xDMn} zG99fzm`N3b#7J>$J)P(zniq?Zh=50y?c4b8M57%a6cFsG$Z7Vad-eV+F>XmPYEk_q z*5SU~U276-V>vdYHkXh47GfdtrrQW?O6SBx`mtumie%hOQ#od+v`NSGcP(NX;+7~! zVU){*T=*AzEVF7@>KdLhArjrhJt>n`E!xZ^IZU&Y_?c=|>M9xu3uq)kZu7gZxtWnd zLmJjh; zTPGJ`p!!gfAsDo@B_Q=w!??b1{^fh87j2^Ti%02WA)~5-psmKiEZBP%rL-9`plgsY zmHALf{91tKKw5#jT*xqk7WTU+8srOd45C@Ngi%Z&&i>LRgi{uh1JytlL=A6?vV#aQ zcl97&<1zp`kT=ahc7GHKfDWV)$;g5dC%H)Z?m{z@#c3#ZHqG+pKy5ZzEwp~bZbcYg zSvyh}Qx6nlc}JjX<&M*~oJ*^(;<(!G-P&qxR|#hQHqZwx?o z7jIm$b-{8vIH~3mC~lV9n$g@X?M3Xdv^$2_#?j2d#qsJuw``{VQ6xlV+K`?1_XxM` zL1Jl}XU%B%x(hoY>_QA-qwIwW$4sj^jbi__mTeO$i+@hjqAj`)kQR)NTx}}R!vRQkQLra zGh3U@lRDg?elm>>eHni$(X}y)b&PK9_9pACo9z=Hmc~HYpzd1&^k0U zCXd*2N_pl#5kKs1r7ty`L6K5YZ7lbYFvx+1XY8U(Gd5HP(=rCydr&pqlm*#&P&LnX zVa$NqSOPAAH&nA(rmZq|< zbndR_-qB))j^QIX%YO#DzpZuC({j|*Y=l^0j1Mt&`&XsrFpPH*5c6Sz1}OuSiz#LF zVu40Wt|E@!&Tm42S4eFJIL0ePwwGZ9#sd?)9<= zZ3~39d51H1Z$Tu)(%LrW-HV9#AZdsUM&Y%?3=st^B97tndAX2PA2dZS%!d9p@b;q8 zNqOl3F2$}zZwz0CES}lyCMgW$w1=0ktABC@5qN|`;?2VC{7@{Ew-FX$FI2ZJ#hD@6 zPd>)j?HhL-h2PbJ$3s!b+i8Hj+^$V8fHM1+g7U8iogTQRNnfTdr|?eGHj16L~?(L>A_@;rOOTDC;C~jG_V&CmXNu_qv-ENHF=F zrF6FMKT51xj-F{{7{*xbm%rGtYXjzn;mdhk{?|koW)&HXMoC2h9FHz*c=7mkIt7kx zt-xI2_gQXC#T?PWwAz$+A9(h?9~C&&(Y@83bkf?BRV7A}Jh?>h+HB#6# z^#dg-5E%0Iy0BhbRqm~`SDHqYaJ!o-Is%!ZghJ$9T3V_%o=fev?h03H3t9oRl{u)^ zRsofxcf73@EOHt4a<*k|O10D>Ja=ry<+Zbws^;n_WQekkRo=F6wN=Xy=2XOGBXbHM zyREpnZQgq*^N>j$FKCpj6q~NMvW;9UGKwt^XpI9AK2j3wpoT(wg#?|o z0%|!9FFFNjF*XYjTdxlGP5*phoXRjQky!3svfLRJ9KjgW)bITO(6XHOR_a zv)h{zZ))^BrP-82XceUSwpV>PC`~Fx6*)+oMW`T*V*wD3$$rukOYe69%1yLQiRB@aoE|GJ4FuAB$i{g>+NjV zKL=$ZxWZ>pR$C+yOO!Y;zwP3rO$=w43Oh#SKq3LC5IDy_DRmcm0-_hHhQcC@3n>hE za9LoxJ3V2x)^hCkCL*7c)s1wXOCaoz3`S4p{fiWmva86pa0y&wEr+eWQ);mu$SyIu z;mG`O+=wYt#&Q+Iv?eYE!32e}+X&mVAj~8CRfuFOhCm_`BH`4<=yd`}@$Fk^jkeqP zAg)w7gtmnl_xPD+Ey*;P!6o+=T()%*)+3KSyIV?9<+ru$K)XX4timEBIeW|d5J+1w zv`AtbI0=3##d@i{s%tJCqn7Kq63l>9;j*z>sxURXn-xgf#y4lbE zX{b2F^5z?u2YdWiJY925r6^*e@-ZLNoD6dTaK-zQ)hlH?f2ouxvJHdpD@k^C=DRWl zA?;htf)cnhAdj{0A_cE<1tD`lwzaClkk}}McIEysR1}4~C?mJE_8>NIZeqC-Q5QhH zo>U8K+N?%HdH`_=1i*+%i*fLAe}WFHL-dKHXf2Af{xE^KIc|`CcVER`PI$Y`3$2i1xdHrKgB_F%gBfl>*JVImXSyho{;x6y zZqfwpBALtYATB^!8bPD|NxNblyfN4Wy+wo(X?%V}_mF=5@_s7y6Sn_&pTUNYY5aTUm1 zWFsP$PScSS`Nvg}vSF%_vH*;IRY$fU2+M2NES{dN$%s%H z`9?`(A}gG{NV1KQNJaWXyN`?Fh%}VrvDkF+Hr{*IYZt-<9GOE?a-d8hif-BbYq#O`1$Kezk3KHd3H`FA9 zbxx@bggMY!9O#7K!=RW+0s9bhwbc76$%Jy+TfL9Ha#dAr`l#qOe$)&x_E0v@G617< z&Geu)KCWK04YTI`RcJ8B>Y#0lJ;)>&b0Dz{cA%Ouu(J4fppZq?AlCheB((!tfrMK! z1`%s*`>2s_R1IngE&C7`Fm}D7f-;f)-&9ddDH$IM3j$x%gDQkXIdZ8Qx{WPQ0Te(* zRXFw`;6Bpe%bm3;M{4Qb>M~SRRu7$%Vg>xwKJTQsy5VhG-RP|;LdP2b+Ys!>)m)uT zZH1W-F7W&n2DQ&E!|6neZTG!o#77}n+RUdVVuneK$C}YolJ-Mu4cylCu4^$yA~N%2APEH)ZczW>qB87zl`3L|I?j?3OB!b9>&Z#(^!DFy%acln};KW$giGE*V?7 z1e;)rLKC-eu{GVu0wDb$Wygq*Y0xfvvk3_ETqX3f1>G+xY{;`?asooUN-WWn3lo*N zv3)2kLQO0pL-8W-Rw&6c(v+TTq#JG`9qs+AhD%Kh!B8>mB(#e)ylv}UYJqThVG&2? z_HH+N76`~>A`t^W((Qz$D`{=^+WwU`vZ|UnB-x1`$V~XK@Gna( zVPqK!F|yJiE`AJ5i%A~SFqbKCw|&1tAsJyy9Aj}1nR5>I-^bX2rjRM~%a#qoU3=e# z7$8v-8H9vx5zUO7pASPK#lTxah=hoW%m=k6AHfi@PEWJ8>xg*U=|F85N-*Y>#@6_C z??DMowJXNbz^uC0$I`PVVv=a~rD<}I?^R})NyKEkHeJKkuqejSY{X+BAG6|tYa{Vn zYvsgv?^|Y6!%r0)F@Slo@OYp1rY$TqpgDxDEp)h!k$ab0k~1VL`)?Fi*S2)(2s&AV}M_#lp|@`QtDb=hsk&vKKC%f2yB6A_R1cYDepx9B; z?P+f95n3Xl*0prn$qQ2Gy&qH~v8|^T834OX{2gVg_G(wa>a={`RYwe^n-RHrZ06ii z$aNI9U1TS`Levy|uAZD?sE5i8q_v1iu_kU0 z?Le^ksf2qcCC)N&SytI=b;WdfdA$px3L@h%7+brKvCv8705V7!L_~Ku`ag2alZf$K zZv4*UxoU>Y#ALX$KMQxZ4uY(aoI@Cur4#W!7P^5Yt&|JHYcQ)3mGre1TeFL1_z>^( z?@$}cnMwbdnDqmq_LU=b;S@q6xU1xl7F zi><3Hr=+Rr{GvLbx}s1f7HhW)_xn52%Bo2#f?9b52H@p)9s=EN z>5+&jqY8Y*ZN00p-N9=S$x#s$et2Ud&C9r(y#$cM83{-uv_5Q0w24i$u%;cJM#9^; z5(OgK#~EzPE^g&u5^G9Oy5H8rxdTTVQ;niG8Rl-k;gB}O%1e2Oyjze{s1}rMKR1UG z>%nudhi4eoMnl8 z8NndWXzu1NzhcoIl+o{AQV_#&?Cpq%zLn0^U2N6OLlhb|LMU#iVPd>{FN$JT%}ziS z&D0S$XPE?KE!sg0gPP&WC?goz18m&Bast~#kqF3aAH`UYXZ27iM*OHFDE|Q7L>AY$ zZ9t1`^DHw|m&2Yrla&57j_>!hpB> zkQX3tdx8ug!*LWC?I6vhfl(&)zUnAjnE+f6WdaX3Dgx}kwE%!Xh#;7dNBYWE^O(pB z%?Fvohkv&RUq2VnHqq&JVmzKJdff$&H_U!>(3ptoJnf=Iu>tJIjsuTY?zc*dQOC07 z%043OqR__}Ny^OCEWRPPyd4|#J0pN{M(vmlm%r^*^D-WZ+b*qiM ztuMO04=O>81&HHx7NL&PyOjp&hr+CGsY@>v#na88~*@u$3P;2K@9mDyJta78Dk>xxqYn`i;LY^9#x`2TtCgCsrs_0RdjQqbI}D8( zTrBR)`=8kCtm@YY<@^>21YHAL;mm=Df+WO0H34tlLFy-|njCrw4PhET_~Gg{Z&S5C zU8{~3<8Kc_uTppB^8%5F)>5QoPIVy0l1ad;w+#R11n<}aP$BbsJlt+wE2noX=-h1rEaf3=?X}mrsp9IAjuTMKq5occH$nlL12e!S%k9iw7Gq(f*OgoMRATtCK7S|thUx=L}MTg z^On<&;g1&_csIdgQb&l?31uO-k69p&YL6$Z8+l$cD@WOa%QmKyXOzspwQCX0B)d5P zZo2EEao|ndixlKrK@8Vg#NTzpj)=1 zY*K8jH6-+lSu$i*jZrm|UcfH+f^|>sZuq*(@c1 zjhpRzd7b*!)K{8ADF!HtEvV;k9owI;1&dlJ+FF4FxJvEM)J%v;8Ge(sZxZo31(G+E zO4%*DDBZyYS%$A{Bt#<=Sw+Nea(=gUo;KG7i3rDLL^i?&$RnkZrJ6z6+h!P#iPqJYO&I2oZu7n` z3#@9qa$j&5kqC1Tk6JAZlSma*@El}O9%$tr{^vnprkBejux%3KcI&rrWtn)>>=$Cu zMkmd7YkGy-iq#r9FD_Cd=5mvB;pjvfIU}g$E?F&aYb~f z+5Z3xw<8pDQM|HVGZn4MBiVLSiCYRI2HE9ZowxJY{aR`@MqI;wCAaS*!L$B7m%xn-*9r*9ixSbNKx(yuVMe#OSsT~*|d z`qa9s>{w($%`mGd;s_=IU-FtSp4`$U;MC+iy2AfYL{lY#f_~*hdz@y@=YX`8*QVUvALi z8yeEV@a}eg?)8|lYB8L0l%1?t3$oqVu7aIKML1$qbR1)@^9VF^$q?-H);R)-^QL{!lQDwuqOUj7M>P<+!CZ(D}T@vj)Q(d%Kpl zri5)6#N^DwZTvd>m9Pw#+#)1I#k_rpD%2F^StUQ{a@`r*yN97bv2z_Ll(Gp~8xcvu z=T;+_o>CAWGjQ`498fQlutq^~Nwpot#mCs_A^hLvLmUP~Ffl$i7I_QWx#HZD4J;I+ zY+hy|E1Y~=yVpi7S_C^$62GXu9Y`w3F&)rtE=40cz_~6J2S~$Q& zh_=K(7|aM{2jJpZx7dhHwDus9;XvOy(Lmm)pbI(! z_8>R&57j_^)C+awfxnNX22dgfEIE)Cpvnwg+CZiCkQT5YKNJBA+JSe6tLq@ACUq+> z>_O*t%Pm1maETUNZRKA*^a~_+73Wk!BgF1+v$--ChA_7!(g|>K+>1vfhY?$F?Rz6` z=-CjOo<^2Cu9jWdaJdCNW02$uIP%wEMt!eKauLn6pNwikLgDOiT8dV#Ry zjz95K``_tH0y=$>6_Jmmq|D@@M!G{1@`*Nw{TyS9t8zv#$+i$7%thwmjB#;p@^@4( z5ZiDCyI)uNziN@Atc)$HFdIdR#&YdH3|CDzEBPAu;q3D-OU|(zcjZB9I9n~J$=lQ*)LSE0{gVy>5tJTQ0t42drLs>STl2h1EwPu1QvHLB9 zyWx)^hQmWp{bbs8Z@w z(bZLJeNA+6)7td()I*ET?~W|*hU_@{kaq5hCGv^olxLg{S@SyPBp z)k#qAabdZ)nX^0fV%RK7p%H)@TPwXx}JmXD2g@7LZxuJVcq> zm@#Z{-s?8n+e>%eyTe!04x~q@di|s{Wh`$M30plNySw2THs;0mz7KHX{uP#urL~>m z({vBf?uXWP)7oQMDc*evqUo+7+8k`>yq)nEXUZb`vF$S2#7{Y8rel;e-5PXi{V8ij zXhVjI(A4hp&TQ^m2;JV;#mV=+4D8PDz+K-SyokzMX~rFNwY>`Hx`NT|qO`t~5PKg< z1f^@giJNFRx6Sq|@TbJnbf3{h4z6f=9cIoCST&{`ICa0XgE>c5Z)xb)^ew3x6I=9dx6h?$e5Oho zaFUw|WDT3R%J0fek0|lSf>t+Wr)`VSB)Yyj;X@XYps1?S(og)3R*{+*a2I==c)Q}y z-rN;OQrqn7dQH>)A5v?smxD^`wOw|W5*C)KI-?OXuyA%3k(sw))zr3jWJK)qzKps& zpQJ4^aFs`rXzD=P)zx?hshb_xz7NNPGrv{}VmDOI&bjM4AEl{!56zlZrXhPDNwlSd z`pnn1@0;*j$sFA8N_`rJqg7E=P*pv4gVF)CrJeA1ZOrz&w&&dJ?EA6q+_Gb0CwB}Y zu}a9iqR zPWE|EMqM7u(hi!E4Zo4->Ok7n)jM(zQ#L!Xd>@Yt9s00b;x}B*&amscAEl~#56zld zrZIaTNwkH7`pnn1E%Sa0d@S)aeI#^s2S@r#Mpjcv`P)~ku$lrg!OU9+a3UNyv$h1- zV$bMVF|iZ6_f1-hqBV9c1*SE6o#4>=N}m=Tp&K#tGvZF~yh*oX*>$#$a;q~urOxzI zsspaN?L(udjLwK%=BdLG#xZPNo!fr*z;}3-L~kv$?G5ga(b}h{eozr=){oJzCW8rO zrj{|9OB~~f+@ALowVHEx@j(pbe^qL$*bBsN@(pcE-egI22UAgYn+|P+XifU+4v~5 z>CAXzo26q`C&fIFbXU=xF165U9bnV-rK7cHM&q}bIprp1cM;t9V9wo6?~5~Uea$*W zyjJL)OU-8*^>ms#r=h)I(h=yP(Ry1%oaE6(q~@9Mx%V@^CQR7Bc;VlI=^fP0$e#8i zecpf4R-x8(bFGJ=v$MCMalB0}v#l)`uJ1_GnwQb}& zYh^Z()*Uxf3r{3;rt!raV(q&E9oVzC7k9%Q%e2;-e67x0V%OB?UQpz<%Cn;y{alu> zR_S!6i_;=v(bH6ulw{cEcXxB#&5voH7jH`EZti2l)zZD>Pm80?w#Iy;cX1c)TwRN_ zek4~HdIlnSM($L^$qv!N+rIAg3r$N-by7+E*nr&s0J(LgGjg`34WNqz(Xhv8j~Dna zRci9&Yg!>A_GJ~ULmeEuLN6#G0V_%_Exm3m$uxP2NXFkN9K~sOENWpRmNK`Ws^k>( zeBMzcmPcrZFx`c(*0Q#3s<9-G5XL2#47mChun@V8gXYTSc7GEfYn;e$%bP9T=!JOb zzzZQLET*cmVZ1K5h=7Nfma!RO zEk(Ix7aX?le@-YAZvv9(E*+;R_cL%oB$f$Zmv(Eo??6Xb(!;e8v`o8Ooo-CT6)PUk z#02g5$q@O^H+8>a2+C%QW@0;txOyLQ%$Asj zF&{WK*f$Yz+_ebGqh*)`WE0I`@xz8J%Q6iZw4y{~na1Br(AyaX>k8uDEq7%F87Tas zK3wKDy`_iXvliso4hN8jhFrbNqYDgyD3Ji=h^@=$P$SuZ&2Z&2#IGJDgYfnsB-+x( zCNb@e9G!Joli%ORX+d(6l-y{^p%N038{IKRNR4K6qaq-T8X*lL-5}ior1afI=H6@h3 z`u)0cF5Z*iZ|X{pm!cPSNAgA5xVu*J@Yp6y@-O2iB(dlKZjmkzP=&-7_QD%H<%>lX zctW~Ly;#g!e68L&4!X5Q?vHE!hu1V~)Xc94{3jnB_;c{mgU9V=!6{iC{X0e33dHO! zi#=HWP8*r~ING^JWYQH2WV`PR#TUCzbRIT2?==<~)($G0zl`5ORDau1 zFDa{NMaQxcb)^P~AoUm)uF~?b6356xTACCQcdFBt z(Xfxo7!`kss<^s*k*DsCiRCrNoY4I_^H}2eFI<$2+u$SRnP;-ehwCLH6`Rj>7Pup| z-m}VF>steW!t1**^*M<$M_Fc8k_1NbjE0v@e$|#gz-LJZA-%<(Cj-2(6T2dsi;>Lh z**3@q;R5!Juv3#iGA*B*o2Up`yT#MtF?%LCwAli&_Qq)}l}a>C$~IgQ``J}G*2|Hg>ejEt-mPF#pD>eL*cYiY&D+#3_jODvFhO6om7jS3jgrD0q;@mJjX|j2T z-`u*Fq*I6=N44X2P763F5~Yz;G)!_CL}iTXWN#C+(@!p#qUHvQ3lsAQYt3F&TQwEL z`4NBkX1Yw9m4|>|METe(pa;Bvt@I*we@-jtsq+wTH>W|M=HqdyD!eJG%&ZyMAM;!Q z%y62RbVPjnrbrL%BN(TJRpOwgrN@f_`o2{3&aNjGH9=Ze>j_nHa7G4d+_M|Xcy_K zX0C8;sv47_R*yLP8ZLKO#85cq6!P0RQQ`#aL@$X5lfjkf(INxw-A$(ckZ#7Igsqoj zgIEc$JiTG0I60g@=tZJnin|kSo97)TX0NLff|8HCI`|Lo0S%AvanJQ^ow0LItQv(f zSk%nZ_wX$?2FGuIL<>~}()A5bs!Gj4IkS}ytQnibLE_@?s2w_{!i^EU{{)lpFw??8kwmRANl&TVp4n5nwiu~hY4BHk1t#jTb6xYvAg`|qsnbTpjQ@)Vy1ZCi zknD)3p7NEsh)jwa(z$lL?6;gW1+1BNwqvZ0`!)BY5sQ{#8ecv~6TaG! zXP9jwd^1ggGJH_Is1W~$iR5LZeA^cBRgCi(`@BNZLUxoT|a4g_^|ehDvsxI$gB4E z`9hJV>T0UY;bd}1Uqyv7G4^Mii~+Gh#9-0Z=H$g&&DQjZFh{!tKDWp{logvKM{)tQ zIIfzd?;9-VtJlL~xK9D74*Yb?=Y2T!dMpg2#&^KGxr>Hn{|a+vR7KUN+xj{2BxXx^ zKNSOU8w%Q(s%v(PT#MiB==VqH*n=VQl82|Z;q7^@I-=1G_eZ`faRKFnno6~CVIor} zTl*b(le3TT_KBL)(k|Huck7Qz*2*xrikdKs9OJ?$G4iCJ3&UZ(9$N}tl88-)@}YmK zHNwS?u6Z~qz};mX4QHY8mn9SZ53f5i)bBp!KfIyj`P~s8+mZy_W9UD;YvVfwwOx}! zr^>rWj%`f>H>I=7{5-J}C--4btlFLYzcAYT2>(JIZgrE*I$Cd=b~2P3tmvlnq2T+R z+XJ?kCW)*WMKT&0sQLZ;16BOJP8P2c zb@mjZ`;DHohX6Z)NJl-xMf<{*MJAg7>O=lOKoHH`zw%3?g{O}a=t;u8?@F3qsJTCr z;ecK3>F!=u>pFbe?5TQZ`h{;-!`9!J7$D9ryKEk4UON6`DA~4PGU!OgJtE0K(dKTv z=V`sk>_|}V<3oMsOzA;oT$hj1zp<>s47-{UM#`CS8Lsz!V{>3%7%> z59FGSSXq8oX5XGpGW>_9i(3R7k^1FTrIbXrEce-m$}AkzLqz@$LKdVw{pcOxEUDFG zE#q1&lk}J4YoHx^`{ZL&XQ6*^xlgdaa=)&R$Y+CY?Q?PUaSK-=>ht9J9lqS!zcb{) z?+xoUPAp0mr8_9K3XYbyi0_>5Qi3%;63Y@xs4TAOS=qElf3HiYH~p0ML5a;Hhc&m2 zg!$(G@V4)#4Q@ZruijQ5Q?8*!WEK~o!or0XV=6D3|L}BvwY&WL(DRS&Daz=#-)o`D zN4tj!|DNe;l4h2KPB}~L9}C=b#!0$^$6D7R-^aWjDP0uxkq7X5WRoL zP3|mYpz(zI)%`!ORgGog4(FRSrBcfeXF96qi)^^IuGy(n7JV4VIFw9ISXdIFf*a@6 zKbrMziyNo%WFM~n^!Z-#5%gzKi*<@VI<=C&$AK-gaNFH!Q8o#+vh4wW^b-0jAuf?vl;V4!9Pn%^V%fF;eraA-|J@?OX zW7Zh%^}4PMZ)=Vtl0va{bf_nHJ;%YdS@O&vGC%fla)0BJfXk!}08NT((P{dM5~$X* zC6gg`qOvF?PtU)eg)kY4kE&KLrfsw9(3^emgbPxrLa_(G>S8YbNkNSdxZB>3^p35> znqX3HbJcE-QYAa*sT0^OWPb8U z%hd}2RoX3Y%8JAkyhdjZczm%R#W_fg;#*S9K~C10U6pW5ZY@R)EHWj!v@Qd=@B80x zgWieqlV=d2I1X%gzoo7ls(lY!7NnCar?7pwG4YM;Y=UY2@T{x_0#DF`- zTl2PU6EIxti-e}BMW7Z)m`Kea=QsKl^)9(fg^pf{$B6DUW-(zK;Huxj=)0O^&qwIy z*INVrK_shS|q71$<=M}Y{1Yv|quN3G~KXp49FVCKM% zuAhO~1|5lQF%MH@t^o;FXHUJeW`2nE`r_K#TvZn%4%ikL5Z1q?fBwpetFa{>+bVfc zt5T(CvVB?r%d9aok!E&;a)C0Uo<8g^EKS@cN)T#33~sYsyeDD3kpz$v4dU1^<^ccRIFHitE@bee`Y+&uEE}mxX14#ea%>VDxnb-aK@Y$#u)$E>5u8dmt`&GJu z{=d#nzd(;5r!8b=oe#Q<%&R_gS=oVoiCKHTX*@W4k%}LOY~{|{vHi6%@Zdb0~I2@$ZqF2}ekawLecAB$q+x@8XLurBuI7io-W#ltXIudd)WwHDdK zU?nDcGnJYx#CP5-=2D@&G<~Xk1txtQ!Mv6=^AjW?ANSAWxhZ^sib%&er0?wcwQME4 z&fDVk0xXt#-eF898N z!8{3@E&6*`mY>%UkEb4Cou zkTst*0S!Kx!a8=2{+Cv>CmOX zUjNahZwAUf%uCd$e;1KRm_+FJ+K$rCkZ~!TOUsJ_rI4K{bf1D7?Q94$zD~(=NMzx) zb#jGC)wZlCXvT`A7J^-Bwsl)Fd$_DjhLv%jg>Vrb5d$YS`Yk|9_scGg`c7=f?4Y#4 zu@`x;1Q@7hibt8PRhPgVV7qVEtHk9sY%;B?2)lma*q77Sn$r|RTu4uZl z$5c|jQ=CmQQsrKz4WW%GEaDsub_B&%_xh*TU1u8e?4@j;Eb1ybesODD{#+Wgg{&OX zCiEoJ;UNzBU~wU!sP5_Zv4;t&bH{NWOh?@QgkKmke%D6MzBU189B=%b;#SJC&|%rH z&l88pg)9zoy&>&;|0U8e;;E`v`c7w#hJfgYr$>9f0)ojf9Sv9W0_l;fJ)g(PwHpBZ zVVPcw(z9TOQmr068^)Eb$-W>)U2_aGOyUVSVBr3QtS~{WPPBjay6pY#8yAg?Hz)aC z&lJDKQ2i))y!)DYN-hEi)r(2XlA;`U8Vh|e_QBnM2|GJrtOI>vUR5$>0orNLQb$*m z7iF09M9hE7`o1!b{m5I+%Jwe**-Euf>ZE1(|h!$8&$>T?ysu?<&Q-v+$-;wTJ>51!Y0e@3Fu1GuJgQ8af(m2P&&e z#6LgRzS!Jq51H~oI27IS8WryTswtLSv(L)XOJpbQ`$XX2w_d+&W{Jtp8?%~Ngc+U3 z8Z>=SHJEVREqR<#T#;c*FK8N_IkZsM_imw!s=0yLO|Vh>rbp@LN^4K`^(EiL50>kv zu-<2lzsVp_xI37^ZG66?S!i0Y`DbTyT_aUwyK0oKPcc$1IikXcCpo^LG7j;ZO|UP@ z%u0ED+4cT?k~Dq%GRqxsmo2gU$r$?-Dyw4!Nd747i%lS`Qqm?mwIP^cWas*yPmk7z%(Q?(Z`;@;6Wb#rVle# z*cv_~O3T~tO15U7xCQ1<78-&L3`R#`vE<@{!irjL+1@R5292j)(HWjyfU{Vt0;h)= zK5-&)kyCh+)BR(y7{*_k%WnSzhBjQ&EAKDFW3N|Yo0v65je-PT{qcFtlHl@tet%56Ge)t@Fx zc##MR)LxL}w9pG3i@a;tAZDxD9DcgGV;KTl4# z7-DOFr&b*bA7Hpp2Rn2@&FCuq`rn0SS|t}4lv3VDZnc6Jh7(4NrNp zZaY;1QVv7}RnAI05^{6@xcE*Hfo1P2NP!S!v`Hpjiko?9y^}L$+ z;ivAxObd3r&1;r(|6>~n)P%lFV!E5KY^|ENcI~%^?#Y;_8;E!uGrxA*F65|*CKLr@sBDI zobX@8GY7olsgr9oZhKrTteb6zO&_!U7_A2u_fiY$q>U|H#4}bVj!OT8>osNuLeV=< z!m>VIHX_tQx#-W<<#AM=bj!mJQ{xs}8`Wk)Ql-8wh1xNVHI;vaMDC`XDET=LcJnDf z3H0>-Zih<`NbLPXUNP(@PDeB-EoIhzZB$+^1!ZM(&`|vD+tcW_GL!n#t%?5OV0EjPxC!0l zD4nD>F4y+KeqahG8QIXBc#bvD^f=A6UC%z7*dLdUgtT&b^vwU^pJn*4^F#~{gTO7; z$46wFOorQZVYjQYbH6O+kBsb$D5md?bT~3;B3je*zYkDe;YRds{TVH;aH>(pY97!M zJc#|+e7EV3{YeabUqGdPdn4wLkP_#x*sHPOoO;z*vMqp!}j(GmNbO)oE|DSERs0*@DN)fU#W2>#oo@ch>Q~*Q=)hai zMOkGuu`U2XoD%nmfQ{VC9{js~in-O+9RQ#9B9B-qgkT(NdRT92`v?}#^_El|Pem;{ z*oqJeiwrw%&CC1TqxZe?82VxXMF``70BPEq0!MexBDf{JjmX;|daP-YW?fK__?xF$ ztbmn11f$;=74ES*_ZR*X_Pl}0wR8U1jwS^|ml=pWz;?_xVBKr8tgRx~nX7m2Dyp(F zV)>#;4`89kS5?lE*67V-y*PK7`r8+oD2`-FTp~XPYs1>Je*~uuIpE9K>LA4N_!x1v z+#C&bZC!#F0n?}97=lsrQ46?Gb*6JnG!@_e!a>-6pBKCgh#hiFEuIy4oM`J>Q1bRHRAq@0F2oUoWLYj4(iz9DN@x|9v9> z7at||NUg&=0^_p9d;@#~LdA?njT(`xhxJwU>aiqZqh`@))du$?Bb&0d1i_HL)j9vB zCw5K`C2PPRK!4e)UgNf!dDZ!e1@?oZ)yKsGLAHBbd&&G`?bm+4W4q&4AE2u-4T&%93-9=&sRs?yvG-dzT14BIT-D#wg`Dh@%dw9d??3#K@~#-$p9) z^*r;bL-#SchQ7jQSpvA|s{tsG8$DFF7Bo+aAe$_Gi)Qx5C5)Q=>&Z*dDRTeUm5<>U z;Z6*8ZXr;K>NZ7r zy{Z1Qlr$7qsOM=R82GV0ifU_or1F&!M<45)r+~3+JX>ys$K(m4_x}BWuFSUPl!IXP z_aHVi{-ICl^%!FU5&!Ea(`}@+Feh){xl$OBpKno{~ zg0=t(K___%3&5QoO4*H?xOUJV_D!~C+aHsen~;52OIr24cmGa=eFOmlM|b)!> zQi`7XQ>mOfpexrAlEC_u0O$E9^XLc`AlK8iW}bj9Xs^_5Rv+Y}U}Nk-;G z>JK>UVer{R1|EF>tC_LvI_l&GYK#a-pu8K&OW^o9sB9u{H&3&H;bXLmv!@{tC?2QY zk;l?3q$v0V`uoQ`tnC4%_M53@1an`*&dMkt5lzYL9|bmC$;(Xfe{csG_JaOh+I zMI1x`PJb$N`LZXhRt@f;ZV;8pBO*EF@x8SJw-6a6r76&LAbP+PBMIMwBPs%#yN$Qm zq}me=gxH;E`bGoN7*IU&Utq&ZDM1H%eHhAX}^7RNto#sb9W4;?jF>F1yW;k>9^b|5f-AAwB5~^K z**_rgnB&QLo<6(T6N0&xnIn0cwo?v^OLHmJ0LkP3C#~*nCruWBqyl}E(iYn8iEm~$ zf5)~?1T8C+ob;-&{F2K5fW8fQQI)ky1_qkHt8wWrw?GXh?7mXSU@FUO zBCbPap{I>*g_Bvre?22MSG!w0)Ae}69e7nf1W$7nm#N1G3myKWE!wb2CVxswXADpSYyc!>W*)%h)#g$Afw^CNqk_K9u&$opNdi3MT zboT9>31^{#;@=AiYz?B1Rr)qBI)Ty!-dTgrk^*%Tm*{Rw%>mcIm2pT6*V zkojt~3PQbG1~}oEouL{oP&~H3HsLO0BV~?6ZP{qhs7kUUX{;F(MElFs9P$ZC3$z;C z|A$j$Sy~>XE&984tEYPRRXvg8!Ij;EXnL_cOhNra$d^D8$Zkh;FjGrAVzk=Z#cpcm z(SLa1u+8KD@U(O#zkYiebZTbuM|w_Ur)(d-xtK|({B=qd{Z@l>=u9*-60j*%}4N!TtXtkD7xCaQR7!PT72z4Jcr;4)utQM*VA}w3%IcHE6P;CNXAViMvw2r_?fP44?8d{q4M8+KjlG5#(oT2QZOZ)b%O`F;rH{1TGWcT2w&&6%JUPs4IVv5!wrd z2@`(n_(x?bBVgwPK5J0r5s&Nb#a~aF+P++WuQ7+nq|lL#I$*m3kV}3%_2f`s@WvZJ$4a=Fy_AB>I+1LrSh-l)uqqM^)TAo5y{HBydF9<6vBpa^ClXkJ_0M@qJHCKjG_H&&wy zSKZ&psvVThs~K?y3iWdGSgc!o4l{i&8r|oZT9@Q;cp>CiDpWJhdB@kkdGU865?B0@ zs0o!#JpDjMo!^l(38L4Bj2gFr0X^0|?tgw{;OcDeBjCyTF;e14*TQbg0>53;WKS5S z!|x}iq|l`wovq|8M|x>41H|aRrG>Sss&2tj@@4veb+HloAS(Pje2 z^|JO{^CIHyIDdEhGa-FUa^&Zs4UXi!e-ZUdcW|pVtoR(!w70s?WhVVJ!Edq$nLajs zEIoQ4e59N`aHYOkt0MVV>u1)Fxx(9fi0@q14ZsxTQ11{L7{`7-h@#JT;WcRky=R27 zU+BMx*0)q>RZgox4wYym8{MnW%SbgSCxd4xC>IhoOjJE#zgN&}{cJ<9Y^X#+6^T}z0xB}yp zOvK^H<^RU=!eSnoIoe)}FV)NH&Xqi66^<1mxCS14)V`5jjy|nxNRgsWW|s+kMhX`^ z-xLFI3RbZR7r7a#%M_7F_(u!tAYHe8nro)*A4@gc*j|HIRyFb+2u*dkh3ryJ{xz_C z_S!KaH_|K&uE(woH<2)|thJ`L(Dw0+q|}@z#ne+Ir`gE&P@flg0;z=!bs0~Q!(p2q z|KV{T^H=N{CdGfu4xaP(Y>tN&Kd~Cc0P+orkjS?;4;g5pVol^EKWmM8Vj;EFZ z+Og*GH{eRjUku1b~{tzXF2D$d#o~3%)H;Q^RgXX8l<&uchB&&ihWQI7P%&8e7fK zSEjU)3bJ{LTDZN~v5ou`j7d{vM0kJeCXp~sSebY-bMm{pE zM0Wl)npmtb?TP6_Ca&Z+#*6MD!E>zH$*OiIlK@ z4CprzVo$-XAv3eJ%Q1#^MTu03Lb($?;S8m1E|fe|aP_s;S7q-PX2N~+Hsgxe>RM8X zg5_oMI6>4d6L+q=1Xww&6ls*MFO7dgUYz4*SRN|D%~S5t^6>Jw>>dOK%~F$(1dU3_ zCMO7A>>+xTBI*WQ!#Uj9N>^|lBcN$j{FD~k#!a5{*H4I&Rgcw3HCVBlo-durIE%@v z#+s~0aQ1v-{vqu=8?s3J2z2aIb(IhP^TlfDoZ*Q?*Ee#r3eN%-x&3ZxK)ZA{YMf4} zj^{<#M5yS#7#YL!F@NNz*kBrdD1gkuH!A8lN}qI?VG-cR@``Yeg;n0I^rSMvjeubh zcg{>9CP_K91QBOM?)k~L;52fNEl6Wdu*l3=9wKXlD!78U3<=|<) zaaWGEm_=tSNxyg0E5+nWlT6~XvA|zVj6i6Ho*AU`ThM%AKyBR2Mso@!_H%GSO}+jm z(2}z<8l)ETSYMMbhIRQ3l0c-}vVFowcI10`Y18(hj@A3e^m_`H1&mK>$kBO{2V&qA z!Iw=BBuo`oj93io692XEdaeDr5Eiejb}iBC>IuN6ZJSpcg^3_m`)Gwn+=Z5lR9i$U zs-W&>4T1lbT^`)M4gcnJ0kwj?UZP|h#9dsWx@6s$IMyJ;iiBT?< zffklMaO1-G4s5z2+~~H?9Pm(h;qCBD@)KZmR>c zdd{g0)-1^s{#eHre7dn2=iIjHk+D5LLw?3og(O;UdK8nVLM?7%{YzSnx<;)<>gAyU za^~6eFTb1?EddYwyBH#$#%%&qs0?-sy!WQWSWs(oTK51s=HS?IlS#SQ>cUk~R$IOm zha6)J_>!<#O&+eq0!UIgz=gy(f7Jj2%K5$TpCGQ0#NJQ21B#{IG7CJ^>G zpCe&hfxG$$4E;5-s6t!fy*2#Ko8J^y#`Cs4^fxUIF7VtaQSVKfhH5L`k=O;fyM`Ib zY+F-MJ-x`;=jYYgvo6_v=f=d~ zH+sW-Rv+r8oY zV3D1*F5lw!*5oqJac46{eW^g|Q@MppmXIq0|3X?i+xd6-g1suNT_tbnWjy4`Lx3 ze3PV2Sp8b=kfW-2F=(*GUNTb#0W3<`i(NrD%-=PRG=P~+2fFYbH5el&aD6hpvHSAa za;FWN5hlt^e{2k8$n-W{%1Phze#vm;l7#rB`LWN?bIE@)J=)3!w2=E`g>kI|Rd>g_#{EKUz6fsCe$q z1){B?tZ2)nG&gf&TxW>;78qxj8p)oV-H&w@@)E?=rM^gQ&F8}o4X=;Q@Vkc?3X%5z zCX?5voL#){MU?&d=cK+?ajK9Mw&X9p5h;)>G*pkVPs{xy)O6faF^3W;%(RX#1~SR4 zsbKEEDn2}Qb9)ry5+Tjm>#0(NVY*0X$hi!#x?kBOnb<0B7sN$Kzr_C`h(LlyO*OH!G z6Hq0NQDrfzZyoGJh_Am%urNGxXrMW{Kb0gdwOpn8YM6-gx17n@!_}Nm3hFY5!@p)?oLEtL7ZLW-)QnI?8ac>J&k;ke&u z18FrkhqvB%DnChLQPJh3viOw!Ccnq;A^kHHKzHEnl|p~-!A?)qccYN<+Nv!5xF`od zf_a9B)nHEzc(r~Ybe6H#ZS0*?x=85*%{aX=-ke4vcQ2RFD9<2M=MPF0K7W%`Sc^<+ z6S`K*X^3)4lKGWU+cw7!O6UJPnRc_uKoamj6b$)xk%171R2sJ}+svd*T?`Yt?n{5_ZJ*N~K5PiQPn-08@xp~Su8{Yd zzO!Yji_W%prcD^eOmnU0Tiz^`Q4MZ6)~zzK%M4qiL#c`TQ+DU6LYn3{7W8{U#20Hm z8-G+zIr49BZ(r9db%~l$-cNLL7YJ@of>*%`@60PkO*ki87GwHqqg1-uq9la*_F~Qu zT!a}YCA!@p8njmoq?U1BjcD>@5e;V&)E(7oymV7uCx5iR1ueozGy&|qRnH2zozxfv zu*-KEV{ZvZoGXXyrAY!mhCH! zMB7+x-Y%ZqqW8LKA#N>}_a0?)t*Qgao!{Yf=8bu~kGRQBf8;BWOxWe>)_KR;b z>}_=USOKJ*AFj1lx5X1uO4H88y>}Og(kDI%h{T30zwcD`Xv62|n!SL%^L1BXjH?6S z(pvXYyqLUc?I6{2%VPEW2 zV|}j;0HCaB0+D(-P;ExeHTqmpEI}L^9CVe(6JH&tGj5%Ec&kgO!)QpmmUVoUP-hQz z9D$fE?jkq=afkRL4m*sxO0FrjOF)VUl@6zG9*6Q+fB>@HGzMGKaV$@36&MlY8X&PR zUk?*D^Hb(c3DchN&C{y~$EokP65<{0UcX79fHNj8J9$M@Q?LgS18nbjY@266>~%yl zOq|SK*mYb6!mtFp4FYlS49w~lrA7>}L|A$gbT#)U){3sAmQ+5GDEZ@Id)4zJ(N&CO04%0IS% zq?Fx6ZB{!;cE!oL5KdY&+g-((>&@&NCL#4C;j%yOh*i@)#d3GKgCDY=`5 zJg6q5Cmb8wEub5L0EHM6-s6E+pBZt`2BHKD*W^3@1$Mm0Q*!8x=1+)*$Gtxgc=Ln+ zJ+Dd&d%o1XZS(6YZ`twAE|~yO!Oll=aDHpl!eCTzRyZu7Kjg>|8!0;@_$gZ=`E_|zGu%ptes=Omm+bY&NG!4KroPZ!R0VY;T?uSuVucwLWt zXwWHrR+^|}^(NPn?Q=1*s(oe{ppwFVzeDOKN^+j|AlP^p3iD0qCuKS zdJqh9!;0_u8zfI0$P_?QYO)R=@a`iO``G53Ksl38`o%F98;iFj3eW9+(n|By#3cxe zum3S+dA62OldR#jWR~skMO=fC!gY&ZbSuwqcjKZFVMg>?9FaeMEXqq&v0dNgc#V7QB)+qZ3ou%y<<1YL;7lb7Pq0hWVuHM_s8ZVl>kXQARnS%% z$~i2|78$WUq0dlBjpj_4xd1?4eww_QUYss;DGhEqb$VEVd9`VE&wBD2Mfum##pUinMZ2L< zBn@-3C)OX5b}173S$e{)(A%4#DvzJ;w)Y(@jHE^4x?%z~yGb&(#T?ANCf^NW5O!Cu z?UgAomrf#K36@P&RG=pip5iL96n<4lurzxWp^GR^IP*TG>{yK@zcvY)>Cqp_L?y!b zzL*^1o`iq4-Rce^IU{O7OJK>CsW90b6AD6)B-;o}_5^)`+)u~`Qd}4F29r=(_E<*h zdnb#mDTlXV-&qx4G)o4w-2L~TW3Xby82S_V+ssDISJkm^1nVZ;n4Pr!J%lzbbNRR! zyWcnwdH%h~MDg(@63h1^osM{@I)hf{Qy)?92(xtG8b9>tw=$oDn}}YSeg3ugq^X-@ zVFhgBD>jYazeg?M_L0adaH`P@i%U)9@z9h3(TBCQg2nIWc4f|pZENj6~1%v^d2(z38~Xcw&5V1XO5ITJUTFlsi*nyvxj4v-mT=6 z^-@BAMp!MPcKZ%M%{JHMmKYh4?Z8E3CQm_Dd~wcS>6!r@owGpM-;Ka4o%)_7pOXIt z9$gj8@?bP^a__-W$JG*=CBir{@hUck)S2J1Lh@S?pRHHZw_vRuoF+HK6+bLZ3jHqV zfopjZ{7G#;5+Z&s_)rX@<+eI@3|!J4q*se0vTFfZM+*&Qq`inNTS%nr4OqVwvR~Sx zi*d@gE#|-s zOPPR)FIAAOx68Dd{lwhr!b{7N^+292PcfvwZT<~DAyr0E*^hl?xG2n9G$nmUnz|Zz ztjt-;&KYU5=#UJ9#4Jgi|Em8&g6(%kM9JnYf)xezAGinMX6TGUcNu)gVI>rs&7WjjwUT?I+@y7#Df21uS<@v}l6U|JMOoJV;Ta zNo}Y-FqdWg)xfhZAn-UP##Do2z$5e$=i@AN*rHhw4Ch|&CH#IfTMmKYA$S?lCmjJ_ zQWPRTmXGiwh*L8Ha0Srh%?4_o7K=R-b!E30vA77*{0AHE;&-^?5v8GS&k>J#aS7x5 zrt%?*lp~tx)Hdi`3r6xBTo2PzpV_d}N0^uo%y697|90MP#}WmJ(~!mdxxGPtc)rng zGu0%79O7S3sRn~P-5O)l-$zUh8&^~t;+!5MjXE$v?9EG z*oY`iI!OGgif8KeYtPHOUaiQrpVPO^>mqr~B>7|aa*~x;B9rN^9s>vbxUm}*D&~!Wo{8rQ%Fd7@MI&M z@s8Z}w;@uO_BdLbOHq>e;shtrM8~KWegQF|NwyQJK02p{6yyn$X*dYhLmC(W57u$l zI7-zCz0OS3fE}o^P^qex<-w>|-bk2r&uj)UmXcaA|0#Ot(N$DH`(=P|XO>ixIL54y??C*QZTl9yWYNc@ zc;;~cPh*rwRR-P90=1?$k|m8W&I^M_^rdRfoiI1i`4ilmujkR$Lk2vlMp<&;LyTYpfX zxF=(pi~tj4=B9^T866hzr^0WbbN$IL;>*1bM7Cd2vF;>A+gIQN7t=<~;Y6qvodkN# zI1O#F6r`ZCO4fHK>GsQNn@OlwG=BW|X*q72PLB~<+|vN>mmrb!eJX)djB1Rch$QFH*AdnLBVCoN7+ptCiDs4rEv3BEvBf@q;|0V;w+=Z{l zw1031LVXMHxErL*Hdh(tzOo9-v11^+&=9ac#3{5;Ju-*pSur+q4|$paS{q1U?P_|} zr>U@b`-Gqqpcp`WgXZE5IRvF8ge2A90)lvj=KN9+HL3N{&|`$Mc=#5(sW-f%{-r6w zqIns4Fz4K&d?EWX&dQ9_>;mC6O8)!^Ic{>OQYIm3ixYyl#eP2zGbh%vul#tH80URI zS_)&TW3xmxQYe0tDdSw|TB*Q`lBfs;ouX3`2Yre|R2o2cF#{@v=kF?_?1G<|2E~?r zB-zb%vI3okGo?eQkGn|LSp_{Qe_|$HjLROK2@L(9A5Lq3k>AP%q*H@`oeIwPm_0ao~FM~ z$GO8q!_C3NBsozK5wr1#LYLRp=KI3>LrvgT==QEKa{PyiK2%?U$LVRVJwUgjnwE#q z?*}BH>xpreGm;;8UxR0W6QE0*fo5Bl?=OmHInDKZrKnji~NC z@S|?6ipQeVTUxrcrJnaq1Gh`1dlX$=fZ|ccY8jolOr0hFba#zT^ zoVQ$p$)4~lJx@z%K4G8^>o6K_R%2{bHbK&`xkH&3TZXk3HwX_&2k8B5u6o?ADi-}8S8p8_ zRk!{R(~`=Jr1TJiG%6`b&rr%BIRhx2LrSZ3*MKmTK?(wc)G(wdFvI{NNOwykN=fLu zpL5>xz0Udl#dXcvYjf|l*Ise2Pw-E@Vp`_=PE%W*<)A*ivx-@|*Axht3Um>_aX`!3 zs71%EZG~9kEho>}$1QM(mxoz|!LhlBaV9S?q#o@u4_Vp-^oi4JH4G2^!$Udx-#bDy4b^}F`pkOx!^w6~>u#?8ONyZv*ZpFHp<`AO~R zquTr!hSQlGr!<$iB1j|5zY0eM3h~JBI5C9sHhfL;;1{DLkgk7`hwbr!n^G%+sl;xk z<~eeWFK*oG;PvBxH}N$|eg^5e6({dh$r8|Sl+pG^`O2d{~s zXH_5Ezot$oxTOFoODTkaG3)G{c*}ku$JoKEspUMY42byM>H!i5+DML)q@c5tBgi;K z1VHjRwB3jf5}9!kh!SL*`8fYg42MjYE=~P%orbAOxw6V&B4SL;eOZM6dcz`*tO|=? zV?O?_rmc{G09S#;S{OK~7h50SRQoeOMmoYmw$z=#*cj6I@gB%UWVPL;j>w7iI`I=L zcNd6}DQAblqNBU##d#280%8&=hHK!}0|-65CbI*n=Hrbc>*31sb=;Qdmzj=12WisI zQ>JqDlZ{>9*%6Id2tmn9k{!Jux- zh~f##`)+r~ar05?9|?;b%WNNBF!=N6iV=*5X+XXFA~tRy-}^O=I$gEeOe-&j?n^ro z@JF>{cl~Z4ki`k2dUdHsACz(22`+cnIB}HTX*&BXqS2Ly<0U^$uMQU0yt@H66!__n z2gbOYo(yHPNz!=9kt73MEj_`xh;<(Dp^NL2**u!}lTk3*5pKH8<}qvOmb*>O1am|g zQo<5QWofC58v2|eP1MVZGw$n+%@&UNjE)RqhtIAS#>IV483E%d`&kuTo@~B<>f+vo zTDNlDnR>MGHSW2CoB2Yw|9HR+z|^FjA$*=t$aXjkJpn1!r)4^##ttSuMdw3 z(Hh7X8`Ecp=CC6Qk{%RE`xI6-(R=Vvc-J`QY-)NmtBF;%j{msVP+%W(D^XACCG)__ zhQ4L3Nwz(vR*%}BvMV-}`IfZvSxAv++yg%E!|O`^d00nrA|ZusIn`dUz8VE;VfccJ zPz<8=uwkUfy4bERa07F+cGKoBu0n~&7R{KNo0%kiHV!HcoTm1(nh}0R)X6Onu0^X; ztW5!j_{V#l(_C9!-W{LRy0@4Vnk(w4PoEX(1-=M;3mhNqqom9b}gyN`aY-C%Ud~f8e zyTnf;o5pR*MyRczzfCpLAvQ#`#%uw{v#QOo5+dc90+e&|zzHxmvb{%+^NRrJ(mbP; z8uin?>JTju!-oKeQ{GYmKad7zi&9BklL~=s)aOo}wt}{f_VHjU&fKMlMpJi>-+IaL#G2_&Jy;*ilALT3qxW~*WgV%M__9+Rry($xrnMXel?kH{@JaqyTg`ZB zjaT)}D#uc>?VKKHGR5qheT`tRPMlYxP9E`DQ-w)pgggktHHGk>pvCdv{0=e7Ej$Gs zYHfLt7>?b!n9!_(Z@MPHYnO#%t1Y3ETeTh%39+y{CrnyieyQf?7H%9i(OC8%ol~Y~ zhUO*Tpe&CDF9NW@if;O?j+UY9TwY_AHkLFHPD7<%Mpx&k3IcF!#w3;wg87`!6Wliu zjmm<>JUXUKYrRvp*XShg?i`tx+4W`ZT4vxLaz(|v5bqK8frXq=>OOA_Y*+N-zKbs) zCMjk#%06q$A7GyT-L-kFy7cDTx|1C3TYX*)>IyN-KhBJ?54K&Y!(tTrQ>;ymC7}GT z?CLmT38NA0F$N_?d@#?YIX6ML12LF=?YnsP^9ro<8cMq(OPioaROt}ku1g;unvT$W z24jOt7=sZT0&IUt-ji$J>WbtMfq?0qZ_F6#c#avfX|?V&ei9mkU zsQ)BQDBCkxtmOIeY>7k4>r)I|Q)pVsfxARq=H@*@UK0#{0e9p!roSi-XS9dP&;sKq zbrs_u6G?N87_vX<|F+W5-L&3)uBD}AYT-E5^?0ze>7yWF0yB+oX#?b&IUpPmP|`F0 z&q4DMvtdoY(X19zswJT^Mky@d6to+y=;ryT`s+;_CN+jQGyS+#{H+&#N>Ce*vT4f_&*1K&x%viu0MrC*$*2lx6Qk^#XJ;ob7{!f~^*94EhZPW-$b~D5wS(^y zSTgLzYiK}s3Ekr+2|lvZdc~xi0}7AJFn5K{>liv_8KHa%X;Ntnjh;-jM(nfv*^hBM zTdFl_qs%3}L67CW9YaPyB-;8KUM$EfDcn)&?HDNIq^4=SR2_!Ft(`JQj=4;CSU5o@ zi7kM+|2DuU+x-)lS|!UZ zf2-CthKq%%dREXy+A7Ffvg85q-FZP8>mGNERSNex$EPv9&O=MXlxsPz$c==RzqF}u z^=QPB9C#qzWXfErbnKHN^!$x1?Up?n%s1qsjRSPNU=JX&dz^C3G`IMD)AznCyM@S$ z;{aG^%t5c|OHc5R7Qd2&qS986=6fk-(t+N~MAr%qN4~qqtD!~Am3O|z$CJ*y6`pHK z9BxA87(YE+g{T`jG_PM0-AoX~nlTFaPKo%dW#lY=mMH2lT|s#_W6i?|v>Ra8W~~pC zfx^A~V=M6?EcxpEOi>`@nf6W6W%&cGqHj; zpIbnDbDgijNYpCY(V(l&h#+35klcftIxZ|PwGiM_`q-_;?vxEM z+BE}s3eM0_dT)Xugx@Pg-tknt!X5oyHDRW<#&X$eGr`9sy{OMsXf5egt|aucZ4IIk zl4N^teC5ppqO@@}4L@2u{dJwfwfIZw8ZJ>?0c}CPc99?WtGMh^$Vi{U7*e_Li7dWy z@<6w$kJiOj*nFwaFP+_sskiGJy-{)}TQA(phijS3#ZhF!M7ooc5ro|KHxr$j&`qfM zR=apy{L|A!n%?j<=n;#(tn7=fu3mR{eFUwNgc>{4IX#RKU_}(Y6w&&XcOv;BrnGt! z$yUTxe57|^ok`XOP>t*Pg+qp&b>EJy4@9t+9oHdNoMk-|Xks`h8Bwp-0vt%|TG2Xg z)cH1_N%Q7aJH*1V195j-8}n^ATc^-+C{>9k9C2u~-13XUl+3ae?&0Ug;tplqpP{#z zk`zKPQYOk2rC+$`L-)0z*&z`|R3UYW%+Mb1Kz$Kv#=pdR%moZ{}ti z?-Oj5>x1tl2{krxh?07~I3YNg*}x5-9+BIt7)r)K_+P!?a?i_7kajDUh5$;`+@(zK z?I%2a65@t^qg0jl>%S1MkofzHE60s_d;i6V1k$;4zc z>>--Sp04d8#$M?$#P#H2%I1;Ih_Gw9>7S!&z47t40hguLoh)Q$S+seI0!gp0rRhhW zHnaha6vz=0AU?sHqU)6hbo(xtjPAT z?X(7-nJJkxiFV?`T9bOq#S(V$9IxN{i<-LzZn>ANzgX>5 z!la3yUnpq_mLtFX4}x^mqe1+785UL^$tS4LnpWxGwMAMLVJ++}JB zHt%tSuMI?6D>9c~8DOZIsyzt+h&O`4$t+8E!>m4hS9*)h*s08IUc!)pq=}Yv(M0!c z6FAH7awarX_HhDL!$r}-Qy5mU?8>=}|tl&-(fn6RrH*^1f;Z^Z`5@ME_b_ zDXkHod;fuSPiaWPAk75-9%d_sAYk*%!?SWt=LU`ttKqDQ)$~oFV@7>imwqf?u zjK?}2I)sMOZ%n^_u?(EY1BxMm_D5C58FydG_hi(u8fBVvZ_A>6U-o{gy$Tpl=6!8+ zwb=Ytp)I)egV?Bu)fVG^@0VZ0O{H;GhN&!a%ff!AZM<$1Vgxm%&DXr_At&n*lt z`1RBNPlEC%>v_Dj5@5Pv@N`qtR*i9*-}#7oZ?>_8sn{2PWGG&C)tIuEWp*BqprMkb z?>0?EY$nLv{p_K3n*Pc6xJpQM{4a?Sua)!KIq{R=(KF5P*l}XS;ZtvSPYLTn=FPpW zC6r$AE%RLvUJlzfcH*+n@IZ#Tmpq%~&4`42dAS(kc^iT0IK$~o$*ANdl+y|BZ&SxF zW~p)Jw7CyyY_IpgBVKM9HQ==$qJX#dJQ;bv|%^)b;p{-9t}{gNBLup6T`5!4~6OU zvZ0wXU3ekeDu|u5uGXhY_nB(*4NqZklztNopB4R&ms-&@{rK9!<4yBX8JaFFVW?NT zRJ;T0A!I;v9lq9ka3RkNOqh92oB^tkN##jT3-rXq_5Na7(v&4JhTI2~vA$*a*EmFJ zse)@la0En#LmMnsb5fOL&d$~g>$R)SW8tY`6o@7&!2sDsReJAPnWWcmV=jAXq^6yA z9atnd714L|nT{QJw*Vt;A8l}u{Hcf2!86kr5&Z(GeKi?{(s!Z7-mNSJf8T7@NlZkXgC; z6*x@GEoUi9YA|v?5PcPUyQJJiP?>`w0Hmvhno7(uam};f^npEMbniuR%rs)|jJFn= zvbgv41Dt82199#fNk0`ImHY{H+g7Et=+>Xui~N>|^u+x!E}gTGk>gpXg% zd&dS4+!%kWvTL)XF;_j@aR9`ubUeCJ=HB{@^X2NuM&?OhcjD#;aDu3UE_hPO5YftR zA+>KpeUh!IBS%2kkNF6gJx#YvTvcM`-dtPSmkx!usJh)O=N8yE z8mPoK39tSD1odjvRV6xU1!QvB4f$C+jujBTb3=_r`v^3vQ75--M__@My6Aa=ti)5V zw|i1qB=}gOqo}^Ed4ETA%&ZfaINrXed@MLcLvI~e)#7TY^)C$@tuZo|G|&@$>nL23 zsldx278`ud?lLaHdsNGW{w8Y1h0`4RwN7j%g|bpS1HDrO0f`^)+0Kn)tW58{b$iGS z`1B~eE#GU~s?mn67SXu2mQ_t(Wr_DUUbfGbnW7K#Pi}hEc(9G==%Z8P-I2*jy*8bw z@jz0KouZ`vt&82g*YA1~h>6UMQLPgWiz@_^S6eCI^kqh_0;Dg9W!Y1=M^o-ju~AeP zFTV%*#|gC$JW71**W@Ud>!uLzl8|R(iem1+P4e9dq;;MFyZWjcIjTlXpbXS6AF@#} zB97~gJwr<-sV}b$K~*3v4BlAYce_6$ZGtJS(^F0wg0k=21}kJ2OTf<p^dL~iSi_xCxy7En~}E}SbVG3qhr+qu+q zT3+kwLRI+6j+Y~A&9iVV z5P8{k8i4`XIzJZr2>sT}crPYeQ%w!b{$aogFVfOK>fT^DO%~UMp}3~Ei4P|5mo$w} z%O6oOz8f40LVT}?+x;Qu@@0f3mO@mfrW{JB-+B6eallIAk&rfEkfxw5y~f>=NEe*9 zX_l6tm=G8t&4@1GZeaUeeb_vH1J+wyFMtQN$hmwKdDL1&o%xMT9LjE1lSh`6KUFvgph zV#Jj%|B*za<;oU-QywI~0Pr3}p2I9SU`@Ee+_b7zh(7OJlrFr7W& zo#>F()DmX-q9ImgzSeX0^@e&<#|T@u+WKHi;t}B1S6rs*Y)_VY7#UK-qIBxguH|Bfu(RMbRWogs>Un-%zGeBl)Lg9W&J+1Wm zQSeumd99@_O*&r(&bbYi@yoqR4mrumFkECNqY;O%!@_67s3IRUv>sN698f7o4|mU1 zO;9jQ_aC7>?)<}T0>0O0Y0PCo>yqUsndDLG;eF0@_7fdHY7M+1}q+9+YK`6k}N}VPubo|87fGz*S>hFZ%^=)f>#=LH?&<)Enfg2!VgiS$ey&Nqa ze7IX7M*6Hmn#D90u!;q#cE|ybzmspnJ=lJi966=No8n-rb^u{;Dxipv2*)31@^I=<;-AkK76CJ}l(CWKq%J?xjGs(zK9KO_F5rT&??YN9 z9%P8lfyf;E`kaym4p(l-M85d zVT3-6>D~%NwO08{2n#g*CV!yAyZ^q??L=sy@gDa(P^X|<}AJN zG#~Zu6|zWl6pz0hqBuv+plRpL&Sd9@NADeD`?8DY8ioW*77v0g>)2n6 zf}vb#=s6EITWcXT&WJ@LMu+w|*5yRmfzrPuV2!k-z{TE(-`~I>Zg-R$es5b9Dod2% z1B)rde&EJ6-DaAwmPP~L&eW#)NQQTQDQEIS`Y1tkBaNq4?wcYa-*j@9+BBYFfjQ?U z)7OD3?AL_bMNV5X?O&O6IZXBhNDNQ50SLFe!X-xzXm+C)5ld~8qQ(anf9Et1Hlv{9 z@dXLJ+t~>mJ2p7EmvRpza?;0c*dz2Fi170^OdPLiQbX_9!VkKjjfNsjVeq8tZZno& zkXf-r5fI@{1evDf)IkV4McR~SE*MPT+A>VZG33Pb(Y+~m{?NQZt*p8j(oP!EBJWpA zy}4DY_`XosgX1kbMN8xDLX>fr7{B00z$w)Ft-6#!eTE&WsPEk#52dsxMN0N$FYn)0 zIE; z(L^YNhAu=K5f_15-f=tWS8TovJ`gK|{u&(3E8 ztsLpz+By_}`;6tT>E=xc^%Y*`rWRQJ)1UVa(sTv6ep`zMq;N|6Wg1}klcPR>SGu0b zi$5tVb%A++_&ryGXG}6{WlCMmfgLpmaFDO9yv;>N{i-^tI_Tp8*T92t-9jBlUSUnu zKsL;QKM;}u?~Fhf=en4=-*uJmhywVl;yt!TIU6y0qgC8%f9$_d?h+Di}` z*`&~{Mak-GY`A+r?bD%EM*l7tu(S-(GpsVngHIu|V*^itb1ak9kuVB?`9LF&@5E~B z5nK&kH6;$FJ<)$|exkV1<)GbdZG2lV&|069vo|8E7CLchN)`!yW?4wxJxa} z^u%nQO+*vCs@rC-jNqbgb#v(SI8*Wiqm|QaoxpM`Ory5Jw`?+u`HR-ZQUapHNW+3l z4e&YC%1N#8vA5+%Zwa7nIk71!HFlp}bI;-<__8(qokTo2LMgk){YsuWq-N-KG%CBn zQ(gSZuT#e-)YAbrkW>4rB?;7jNi5Wf7NgX?aN7kijfn2X?w;hf^`K}Vm#Zy@z2vpq z5=(7HrV(dt#iX<(v1e%UsoGzD`Qj~kIi#*(Gia_4LFV^kRjDsl85(H-H?k*d+T-QL z4>VKW^C!2!qB_LLuvCyAYlcigO&)53LsM#kZN)ydZ!)T$-+*WRa>|nWz_lAaA7Ts@ zRG#>)qG!GjT1PJWFr90poC-9*aJ*W0C|36J%cwC-04cqN5K4Np#I7fIt9s%-AQ8IF z!y3TE)a@1(78P|ZEDLmOo6pojPGqJqs@})9OxI#-%2rV&MgBWgtH>XRCGLp#wKQehVz(~Efb0pl`Rj4iK5=@C*aKqYEy>jWEiuLqg5+5-4vkfm7 z`TizfUtsE6>g{XF7cZh{<@*_`wWSt16D=dScm&QL3YM1&!@T)0>;94n0HiGPNw+4% z$gXFxS(@wVjId^dlA6pDqWnxMCC0$uAqRZ`5>?_C*>(Pkv`J;#_?M;a? z=S$&lbQgU-ab#*-^L~X!vxF!VxV|MOC#WYd8SXTdGD#kG0p*`9(IcmaYx4@Cn#_ArOUx1S)?%f+1FDwC`)8&mvgFT-ywIJj z5-M-i#{}3OX4`}J8UwC%Z-wAal3kdiU3{-1%>@@mw>i26VR(yyLSf+}mi`!QJ)a^y-GS z#>B}u4WXw9X>L1+Dvf_^Rwi2K<3bQcgu-(VOGX`E0`JVwV8YehHz|shE9?5FjmLP2 z>_+?aH<)0hsN(5s_KlY!35kYkOoE;wcI~lWF(}K6;XV-%c*!X^JY@(uW>_4_rRZkMnTWNtlA}fV@REBo_IyG7RU$` z>)&sL!-#e#S~}HpIV_LIRIO~u7Mdf4rHm*v>SfpnEn1(cKBB|{+WXCv{exN$&q!~- zj_LYiu8NYw(e-Yhk3qCf+^jy=s?Bnzvs%6(7LD@8e-pVt7`afkGP?GU| zm|jwZG2Z>hU|vG`m~1UU%#O*MXyGY}oNOMcGOcrHj8PNr)udbcVV%Wn9;$znsk81S zC&zfFKTnhTaI$wl4NM9>>OLzgI6u@hZvV=xAi2j0hc1SEdOVGbbEVaT6*g$#evs`3 zS4ChsZ63n!6yd6WblLZ?9c+2p0%L|oodQLKn-_<9tMyo=dFs{PX^qbpFqVAlVMbA} zfgu7a2VR%zsIIOqnDguYGGH#BoK)Nx^}3OI9pA!q9WkR9qnDWWNr%Gc`fmm17B`xo zEPGrq4*y3W;xiy0&+oE?cS4=o<+a2J-%#&&VRZ`0qGzYz*B;h}@Oxji5s{lo^%+2- zXM$AGVM$SJc3v%VBROmd76O0#Ws(pELtQ$r+qn9S`dQZ5J^BZh^~|YTr;r(ubz^OS z%!!|Bf9^WRbNC#AJzc4oCJxJ$5$SgJVKiA^y3xurVMkfsQ&n4Ch9RdA?`<_V8lgjT zY;RS-fj!`z7}tNw*eARmSFQ9+RD2Qj%#9T)yvC6-cl-lUK%aEyVAdkIKZnuWF~K4( zLNAVXg1a(!e5^rMM|T7=ZRIOhmU_mu)!fKE9Ol_f0hpYzcwi_vYA3J(*wDJ65b4ZUCtBEj zle_gEj1QgqTb14+Y^{6G?8V-pf!P(Q3^OKs@}b>5Z5I6%w$~HC?zZY(J!I@#ufhm- zRY@vpbmg$*+P)M~RZ^YvI%AoloYoRXlOhcAK(jRt=?d2z?S#I8YZF z2yi9h6N8^iGyrRDVSCy#T?yM4{2Pyq`q{-f$5Tb`*SOvInW8$Pl_laBz|BQe#+}m? z6_MuJkWS8<-S@sl05-_BXjNaXmY%OOg<93_$K4HF z@9J%ch(vovY{y18>djN1*xRv*SC+%y3+nwQP2$?{B=30Y?>v>b2xs#pUOs$XRtu*E zrTo&%!6D_TK+2ie3Qo8iE6Pr+sYN)V<7OQoBloga0ER=9?cTD`2B#N-8h-R z_@js})L1^5wL>|hVa}0za6l^#>O5;*MJJYvc?-pf&6o=a@3VIAeLHz4q$5;BV|TNX z3)e-k@wDlTuyr`Rl3xFasi;@OV^G?VQ)C6gZ7ce^KLeA{tm}xe0rh)0dFp*o!M;hp zRne1ScC)|-3?P$D40G3;hfTwMZO%=?;>ps4uY74@G2(186rm00YD#k~tlS5!X}3cAm06H+do&A{=QsmwwEf)GAzu=nb_#N%EfGdT%Z&s|mIvTEl**fB$|5Zjkkt(Qz8@P?Ua zgYqR;94>QEjniM-h%~d3yoX0aQXCr@Bf_8inIA8C7tk-l+Ez{H5oMQTdumn9>w;Bo znXH)SLK}X@I$z8D<;k*doDs>5YSqHbtAF0xQf*d$T^^-bEZqNL++z)ca?f^IVcTWv zmbR%!5_ZiJWFD0kc&AT?6FJ2t9GJ^@9X78>W)rPY8&+&lF1Dq7ygZ6iuUF>$l^^uK zfxrmI1mVmAR0FHS)KlhXDcdO`vfe7}6rN2BGoO74O=23{#N}5B-}`~uF}14sDL=rq z9^js~8sHpb5oHAZOTrHCcGMK23~@i*d#JEV$&nNQ%$8N3Li8^lU59iVFi#kGldO9$ z;vzDTC>*<>u=s*MC$h-_X`hzilg0@~dLv8^2$yt4U<3O?IY(~C`hY}y4TYTmR9jv8 zcle(qkCnLyIx>A*0e-JPqiVX^Y`c)b(G8rHfOMv6T4tpMo7~4gRb1O*xw&r&l?xul zrP&-lV=3!0vXq|tZrM8j&2Mn7iCiPRgIBAb^(J9=+uk7Q&W;Sz+amr?ubc3dUA-UO z73vVOEoUt6IWx}T5E|gL5buAye_RQC>kSuQscUsV^pD^gC8Ept}TeeK~|i@02I^eF{25q*%9-#u^Kc zE+uFhO|)#Y@#nFnk@b$Z)TpbIE1*cq>p~*(JBQscEP-j+Zi;J5#R~ z)2sKGEG6bO^^r3~x-jnS-dx|omr%l!i0;>1+#6GrH6s-G80x)gUL=y$#eNMhkN%|l z=TZEgr=FL;_L%h>M-1D*UR}myi}|0m9JcIY*TP%~7!srRoN}T`#`d)X$B?!1*d%P zvucK?)<32oy=EU2JQgo||L$3vvAU9~FRP?sepLLBG~_^p;j;3hppD*j0eb15XGC)P zfS*7Abg6q-60%yx9G-v%lnccs3mivM8khM%{jne`%RJq9&fTe>te%~_NE>Wm%=vR1OKC}3moUF$Y zDfWe}>g<~jmAV~g9pP9{=DA*h6xLU@(+VCTcu}mc53U+fT4IxzD^o`%bYRyRQgu|6 zS=DC2kv%J$c68sGuC06tDVm&72v-1IfwKl2i9Kcft^Y`!SL+Tvav?c?H9-b4z^#cnHVIS2oa@~JV=DP6bUVt3GOBW z7(Iry>?ZS830yR;HAAo7(*Kn=z%r&IEvGGf{|s+ zH{TKilmD_OOmjP`7OG#T)?%mEe(3!SWD7Iro1zb(acB%oB``Ygl!8gu+;tKwm?%Y{ zVgh7x9WMu(n98J{z1D z<}c?E>1|c`!82JqP%eLQ*`eazL&p9bJB}L`2%Pg2&xwP!F(!FV>pYDR^u3<_L#vqW z+~IqC%!C9MfK@l?P#F27jQ*m|3ONV4rM*1Ha<=r0#F>@mgayRKr>XGXQ_Nel68m=}-dngBZs1EnJP!lbB zgP^fBj7a}gS(xmu+_dsQqHtzr^oxPoJ(VjFRJX!t(&q3qz$36V0URPGeK(ywzR! zX>{iwann)UWu{qm^IP%DB1wFWk3TGa5U~BAVLbdOuAevax8>>nQ*5G%k79rVm63!R z4lCjK;>f&|*XW)`fVXG=K>rPN{2o}W2sL@M4D6@jL^}fAMAKQ2*cgX%F zxtesHhRUsq!((u6SB@ z3o|$T{!)Z}D>O4mdw@a{dy^eHJdaC$u7(1}sloofP^GETHI*ZYcx~t!#8?QtZW`|Q zwvE)A*RB0Msc%TzYIrPNo4r~Pan-_J!huY_e@OfBUB8iE%_g=U*5hk?PbFKi^!cBb z6UpLak!Vi9OqSHsg$zSYCIkjf16ngF99)%bE$0t-sgzpoQ^@FWx?WH3vg|=ongq{Ah3n>G>aic!>s2`8-=yv2e~PVW)1F z#sHMYHwIlTZ1+w?w1j^KKSPf0d^326D+P0CTf_OpySA{VrXBLu%hbi-23b~*g3squ z(lQ40a=l83#1hUg%9^;i&GjHxTJofZMf2WOd08%VMPe19>=SXS-|+!5X3rAb_r9oH zI$er$@&`^vT3?jJSj|DUqyf`~#=VIV{Pw6%A;H%$G(QvLCj#?nb z-wIH>a8_AP6_rdt*dv`y{Z`;I8_+K-{T+H{62_T|rVPJBT79a617&DrL&!KBh5MSK zVp#;ZUw-wE$^V8}L5z(WnsyytiSm<*PuV1YarMjOerU-HxsfmY$e2Z!=X8Tk^2y7N z%BCmx4L1IyyumZOZjFnx4Vf=YaGzAT;5TMWT)VUMK9+9;7g1$A!Txlnk7RWe0)L*X zadLltZMHpk!|izDy5*r{h4W^s!MfaK>Wu5AzhiXGSk-H%?S!5K!#`V!5Fek5{r7Sz zZ0#At%K(-75Vd(_yPYHDGIf9CLX4{JP=iMTGn%%LvXv{lut1PKj67OMS^(rsOitNR z&KuD+oqDc%c7I8xo&S;q|En&0yWNY5A6Ldx;$Gu7pX>f5`I&ovJ}+49Y`@!c^3SDY zN9Xo^O@V=-5}e><;O)`jz4J$&u=`f0gXcU8C8yAnhr@K&S-+!nnsR5Ky-Vd(YJ4}3 ze$jG}cYMEH??=SAM;y&mzwVY^i;CF(BWTn4>3s}|(B_o5nx0=Di&y@V)DQnp z85mQ0sH(4jW@f~dnDeGEH5C7UZ3hHH)870d&a3lRL-A6iEcYYmSSR*B?cQ#3%7${> zh)!4^nNA;CSi2M2_Mf85v&Ye?doK$v|B@V36??8+0Joj~ce~HF{L{1sm!nTL0dv9b zvzKkve@STm^PKJrH9*~{lFGJg7`9C-*fV)MIJ9NgppEx3U`1{xbnFF{o<%S(Z+(4L zvHXd$7B^4AzdMP~PUwrQC8zV!jhLBGCD#XB^N*nC-~RP7r`qlQ)vC@L@iW)HoV|?n z3o_u@|G!%T)g({!hN;+I_>CqhwHBtH{LfoF8ycod;dza_d39gpKT-bsZSbF$Y=lqE z{HiJj4i+!}pL*dy=g{DI+ECnZ&+GmFTkqXQB>jEGtp{u?u^Gb$XaC(T%>QgE@;tl0 zVgQ@#{H?{kkNdACjbf>Ns$#p00N&Kw_gljM)ye;PK5>VQutuQCLQz`(`*b!(i3Q(9 z-|B2BWrd8wSN^w?p7nh_KN!hH15a@9p9cGP??>w39zDAArqaZ01A8sM{Jq0F^m2L8 zyQoh;oaTkZBlkVTF7<{=dX6z~nGM8IZe9BvUDNY_Ni6kS7NQnC3s45iiux!eea%o- zVjW$)w(MNi-HP+`-{4mCPC3=cklVDz?5xEciBx@|X)ttg09N2$IEa+J+2ts zd3$eQu#*{6;pSGcDUM8mB)MG7r8OyehP?K{F(aEUbHe^4#nON9I;wiGGS)J^krAO> z;d87-c1Gww0}jxo7QCOw@$rRV#Xe@xT7!rQwqce&hml=|7&)p-}+Ju0k;?9%ilXm1{_$r zADQqbA_FFysCbaL&uKbW;{Bfsb2w#J4bFzgnL{s`=scY>u+>v@18pBbQ9vHpl?tSG zw=z7+@NQE)MWiz?8Yp7upAnX|a%Wr4Vd0Hb`#5ts_UGGZ zp1@X^xCV3$^arhNCaOstl!e&*4i$BM5|g3Y`=Jq)Ryf$SAKFP#qG!?g(~ESiQ8j=E zacq0AYL$5P%ToPs55eR+F98V_jp>FN?`Ni~EU;(g7}Xt&ql?@-z9JC{`}AQ5H{@P` zoX;l|Sui}KsDDys7f_8~#Oq>=2YAwM43R+#>-5k>KG zRPv~g^WBIWvX!Hu!5lA7@_U>$pMtG;Zc0$n;Rumoo^0}5tZ|XKIx@UI=y^rrP+j4@>hbIBBoCiO zJ#ROXU5BwS@`T~o%3S9h z(C|G;p{;!&ywv~Dg=J(w>oUQ$f^WDc%ECWSjkD$)T!O*Mh)6VAZ$r!19V)dA+f}|S z+u-HMw2DCK^}f`dqO8K0-Fd>Br@z54NwFw1YQp@z7j)*Rk`nJZkD-*Es$Txdn%~1o zur5nYJ>Mti2U^)t5Dwd40)ebW^a0I$oB>ha9y~6TaieHlo~h9)&h-=&p_=XNzv&b) z5Rs|r-(i|YvaJ6{jNR2+cJeq1%9YRG8k?fr+wraMDdBldnnPXJ+-YTnd&=ak@()A} zzevd|1pML~-`+giPCi}l9qz{U9tf&yu-VxnfRCMSR^FdnU3Y)jF&-3>V z3kM%S{j`>46&$!lZ?OhsYEurZ;G87n+nEaz?C>5Mb;7@{oPJiV)1Q%Hi@n#BeWiXc z{9U&2(pr6UH%Lt&n$i6`Wb)WNnvvFy=zoklT#k_8!oo>=UY-Hg=oIetnsLzbdA0!F zl)~ilS`@WcTAXEIB9L+AD~*nE5f^PJ$+^7cS|JA2bN8`Cs>w9XOpR7Bt@7o4Va)?^ zSKuvcN*aja7&?EgTy22jNF$Ky=EY7!3V3;QM^U6T{mvJKX;rJyj}|c5Nx+3`=axLx zXVp6%?FxYFfmHoj2uA!#qNIdbKVW@Q2>Ldv>maz|OvpM>`e(CHF>c_X`ib1VN=|E( zFhLMA@%b*z-jh26qss~&r^^krkrw;Vy`a5Hd*=^$ttaar;!jG86NVJbFH;{E%KFH` zxERXR$xL`YA*Hj|=hoD2x|qAY=u+KTSL14W?m!2nTV%6kOz!{;>45Qi)u8hl6fw+ID&nXmz-I2tDkC&*o|GNxqhP_{po!Mu zdKH@`8T{+6JRMpz;R+5SIHUXb$SXBt<;sy$n&0hhzWw z4?=(3RVsL8L800_|0yj%b3bG~{3o8(gMa;O*SGv94!G(|hvY`*RxP>Be@g9A2Bc5^ z6}A)*c5vX^-_`$w|F0la-64OHfJ!|t373pOOvgNG_ka3+MZWz@A~bk5BDvUB_uC&> z+O_vx2Gsr~5t!H;`t@uEekTKGWc4&sQhcE;)T8dVs|!s@id6sL^xn1==^xUEZgB~Abe>4Es%gBqX($m&lkjsoFi^FvWNXCVbYrg}tM61}pz`MJo~1 z$0u5m%PnL5@cNQTq9A@%+DE8`%8D_aJ=Ts5a8n^~UMBRnuv(Ngze`b~fHl4Ls(TOc z=ZX3H{6WFJ#h3;-s8Ng5*HZSvP^`8IDee;xbOe==eAG0UvXW} z%jD;}`9c(;C<$$<^+lIe!=W<2LS;ztSdgtmskUo}wZu4olawj1lCkMsjI~nMuF(}( zZxz~M>yO__u)9NU_hw3ZBK z$L9eLFCk7epzTtjl%$*Y-|y-EVYvUVI16P{;Mrwtv|C8I-)gwE8kPeVvj=UjJvrjY zgL$OQBj7t}G{)QPWN%~Xk8#XDf1Ys4#HgMVB3J>5h!b}$Xeh6mpvXA=~S1m8Ql2GJs4P4jNI5p80XcK%KH}-IL z0lw@xRNPW0PojReDRS1oSb0Gcl^}zTAK1v?g`0H;c(t_C8dNhL-lL{Xnc{ZF>wTz%|bIO%iJY7B@sMl zADI=i-WxNi+IlEsX}=OFY+%y{Kvw}id50$fK3rtq&5OccwJ9}p#@3m2e27(NO~+Jl zjkYwYKWsVml(pZWY%6$jAVWnG7y8QSbGMt@7<$)H{4Qa+flAf)7Ld(3rnRL_YoeCX z$2+HintGUUH{c{A5zxU&u*~E!pDstkLrVBOl9Yfm=+uoXqZwv$bID7TWvI9nf5&q^ z5)bcWFbnMb} za8Y;#1*i4WwJ^3(DPh!cOY=Rq&j}g{A6?2F1>s?0n{Ylu@8;AE*w_b&qat|?2M}Ld z<>=&Da+z$}htYgMWhVC&7$;~Iv#BP4r0ql1Pm&L4k(@$KVpiNocIB7}96#4zhiFx^ zGT&K(g`l$)Gdj58Z4Y$a$Ha%G#o6S8&LHuisJzqYz(X~tdE|{*JtA4r+wRHli|P?$ z7Fd^L!f%m?jVG-QtAF_opxlmGZCBAK@N>tRR#ggf`B&rXi(*U$C03A1j3(y$;y}9 z|6FzqF#1UwA z^VEvSAJa2*QnZ|adsLi`g706SHi9lb#xW**9Q;AU(tT!rkMa-5P`I>boa!Qdu!3Ftg)h|hz%2tc!ijn7((U|SS&G$+D?V3LidS3Np-xKsamGQ;# z%OR-U9Y;23;CsNNKf2vUuTXiO(P+Ny%GD>Yb`Gl0AK7SC-7MC2olqtH^bbRW&Sc@e zZc5!3?0Cvi?qa+z+bcd%U4<+LJvGW!$Pvoro`Pcpt*d@2AD26ATQ=EOU;jU#Z+d(R zjM+aj>$)a7^KH4m5Ahi!zj&cLGCndefmQcR;PX1CJMulbH7gYjcZp%}{EXm~rM$UQ zcztd0WWfY$PoW|GJhhp1!cMZl$@AG%f>619^;zvaYfizA) zA=+i5Ca=E?YF5rq3xlPW?G7ZU^Z#}SEj_;7c+~H|`BnN4qpIj1hDep!!^``^kbbG7 z+Q@Q-1CDE}ze}5r*C%7)PoH3Xl4c~r!TkUI5cGM*@ILQ?oZ-Pl_&}*Y^lEx*`C2FZaTzAwk$2#K)}1&-zk+*lTNGiU0BYQ;KP191F~~{B~?zt3h%=f zlxSpeB7qQ{Ge=_|AnDkxhK9fXWKq?m84|`}VR5`)5PfoHmf8 zdpWm1^hJ0moag&hk5Wc~gIOnl=-k#U$sTOIlxFBxvd-G#xxQ$B>slTm^2r_LQLp=f z#dpON4cP!=x@?cf@Zp-AxOw8fjyRkid3xnRpsfRiCC2U-eH=Z}$DW4vHj*$)8DoZi zj{KiZ@(WCDY=AW}p2INWp^Ao*^u#3nDe`k<=(GGMj@c$YKhcbtX7(63XW}<;lzP32P?t|v-u$d;nyTfiCA9nX z+(iFBE}NgY5b7f3yepKA(6IMuwE6og@`a-yYkcIr7Epertz`V|che;WsuUTbFyWuW z$&6(oSJBcY0cMTFTrS(U&eDVG4vePTqQNQBI9J`0%my^B9%Lo|FjR20XMSk0Fq+V< z@`M!ob5{BkAfv1HKs>k>Y{=|7eRa~Z*F-Cp1|1XtZ$rB`WyCL( z;;b&sCVa-=t)G<8_}K_quC}CO8S{j~?@T$2#0i`Yj_qx)<`zrf%G#7Swa)$T@H?6( zQ=^Czbch~yBGMR%w>G(Iz0P_}#G4#yZzB!WgC&(;O4Q9|}lOHTjur#|Bw$(ph`8a z=eHY!%3f-EO`P%;=c{uoCeSyN>pIW3N3Y7eGgk5BdcLAUnOIr471*a2^su zDfiK%PbHOE9!qroRJJhbOq#V0iF<+_g9_s1U{L%(R(Mt)uG4t*%lrIH?oEmGc+xY7 zE&50!ny@c2j!pz?ymH$4rkL0cM;}<7+7s+UfTXBT+W_vr8zX4KhM+!h!d_M!jF-jo zM3mRZ=liFiw%DXCy7T)x?62pNl|u_O!U6yD|vs^!yAe)%D0{Yl479&RGC zHRkILi~}h8v7bZnHU2pHR}s=ztpJt-<|7|YS+V%m(&mI;mLCTBht?0ckfp={F>^=od;<5e&ryePlV?_QniRy<>I8Rst3mSus)`XX2w;m zxh*h(CHF`_7TQ_iHroW0HbDBO2KZL6DRiutG6IM*J32^i4a7L-A$#EAl0;h*;IQxU zSO@`beh+@laJt25(WhvTSwpd{VP-t#U+kpUl-~yrOsZ4~I4o=KAW7+ZUng9x9b>Z# z8?kE4yQH_b-n%jX4r2zyODCInTXM>eg-+&1E1_?a@SYozXNfxV)O?Tnj7Qj0-t-HJ8%;iI~#D7BPvNHs(IJUdx7H3RhX80r%dHQqMZG zDCAqOwz2g*ZPE?5D4C>X;2`V!>4gEX-a9aMtQ~hdz%@=W_;UKydXu8oyon`%d&tiF zD!ANBA$eXqywzOKFNUiG)1b9DCJpgR?NIu&8Y+h0Fl;KxMjh;K;pk@&p1+(}Yx+;4Zhl`Hs`K*KfIH=bY!3a63?f83 zwcf^uezs1+2!R3D8+7PoIaob!JeX1(ogSh-cejj3(Ig7L!M+V-rwrP}&qQgFmf1H) zv$*M|RD({@(!w`lme>>$`*<0pUm{V8?^FE0Z|iUpy*<1APU!cHz#UBjkeGoslFeW*Wt&^lU66Ti29tKkeICRr5`( z;rdGC=(SCTq1(g$8IV1&cuEn<>_L8E#W85iQn24uGE%CmWT4irju zYvmgGOnD{rnB=FV>qe`{dw!@&|{ciq| z=&^e#B*pRC?xxT0%pk@gtZRb{VY*1ddo0qQQN|VK)%J(0x6xsylx`+XF=J&=4!IgC zvKes?W2y0JSi3!E90rISXKj`Ac!@ZUm&#wnf&A(F$&uCqXL5D|OF{Z$!L7)5M zv;-&r3le4FXx3j=0A-zw(>#H1IE+wO?(%?-$Q_o4w3ETCf)MooL|pU^INcQr^a7$aq< zlp?-=&uh-G7$Hx2&-~M6id7~?lki)TqRZ5X?9cs&xtFqZdBai9qR(xwwS;KnX59iUQf6NpRrB)Pqrf)>RJs;XU^i~J>nGxu{^d`yBAb(J52NgSkH~MA)CT{ zgy3G>mK6JquMnDgrw(#Lp8=w9>y)6Z3Ho6R0DElW2Mbt>xQ z56L|dpEBF%Z)i9g`PmbML(X@;Y^-W)@HP5{*Hsd?g5glSH^n9WHQVS_e z7G_gEhE+vgFyrAgIT4CQ31a5-uow=CdQk?c+P|I(tEeRJDtpUozgM2}Whp^1a%fbM8l z8rq&QJw*zmc;23gm98EhU{c4wGm+-j4R2MB5H63C69{vWG8Z|Or?Db!H)j>L@r?}# zFjyyT#JK{BMy5}E7CtdzV)Bprj?UOYZx-wnN*l7KM25k~*BvkVj{cKVi(JuAyVDg# zb^PG9>vc#`GVvW}A|}~ku)8d3!vDnL^Y*`*vOGq$Bu>e+P|Bh>N&S}n{4CluRP-&< zhCxhWY$lYysv|0l?|E!58h)m)xUI4>?B`w{(|WEa(4re{%0I$l+UeY5@-ikO#u80G z_f3o>Lm+@0m|;nsvHS@9A}XQ+$B4rq9`uRI99J%`YAt@W5z4KoWZ*~YmP9sa)1!Ji z;?epQ;*e@bg>*kGrtvlF4#6CWO*?x_8b%ov>+9ao>d`F2#@u~JE>NQO)BwMT`R_fE zBHjSE$oTsf_r&O~WLut((9YN^#v1MK9*SC6l4a3 zL9J+d12A{U%09o&y#AePD5Sua!t&ypv)SRzn^1P^w8*6T^TL?AI8`c0U|v{?seI&- zQL#2u%pLGRHz|d^-u$E1L|co7>S>&O9oyJ4Vq9{gaZS-9FFZtaA!pUDqE8M~yhz|l z?2itnpkT}j-Y+90V1LTh_E3e}T;$kS!)11!j2-R)aF5zDuYc36r(~!k$!4BupkH(s zIgf@^IV60)EIH7#!oP{-r{W@@(#D<$#Rzyc{)tqYOH1TR%g)u-lWd<;oGT%{rW!Dw z5V7=d3=iK-0zW!XaVgT3JD`yb59v=-H0xs7ceb~scSHSqs-U^HH0b;)NbZ~>*!`NL z)x%@1hJnRC*4`$m8EVcD^BW?Jt7m9Hhsmr3)FmNnc#uoN0ojw6Hz#Jo~p&^=*BB7Owi9*q{-*v ziNmX#EeDz3eA<5B;qRXb6uh|L*Zmeu-h0-Z|FjXw$B@c=`09b z6Ok|a1u;*cna9fsFL{?{DrF}i#{tx3lX~^aOSzQw9|B^bM!%S0A`NiD)oYLDNJS#UP>%TZH zUfta-j0gS(yN;%}L7H%hh}rWr{_V28`+qH;1{oFtc+b>>5C35ZeEg^;F4L@emzbCh3$)U*e{$=hdsyTE7BF~_*5C7C=;PE!`$rU3A^u6XKKk)>I zB!%0+wYby>jZJK6#&2S%91qSQeD)i^=`*)NnvUPQ#!*HaL1m%tW+Xw+c0qV4gKStW zJayeaFr`X3hg(EVk4Bm<7<1NgOnxlSB0}?liIs3Z6pt>ziS@wr$aFaa2YhMEM++y- zKbcFP<*usLFSZ|Dy!!HDIc?&zn2$q!!;S;{RyS8hs*UCT-v)C7KCw zP84OEth%10eRyQU>JEr4A$#4#HEQ{GPaRTQsag#>GCgCgvd|b>CXtiU>T#q0Irb*Qihp(rbpE(Jm^_X+&uBT zM|$xC<+00wxrzC;e{H1-3*b(KN0qkl$VIwc)cwI4*M%P)2{Nf9wi+$QKbtRb@ufsi z%J3sGoEoU=ow5!apb>h_(d`N#_X%$Qwb?FKLYgbq z7qUH&6$`j+y{Wel@g77SS!+qnIEs&Jf@-_x5;6iq>IB6k`!&ID;sHRAxWa@k6I^G4 z<-3;b<}t?R-H%0ACyNB!X$e1ZMGZ(n?S)Uh{{??W{eE9Ig75R60xmeSa4>$QZ`GmaXP0tl--;K%zqiSb6z-@^6dv;Etp;VT`kok z)b(e@YRg_GYS{Z9QE5BF_B`Xc($0?8;wvT($IVD~xwU6O=qr$}5k8Y6r>r|Oc&UF$ zs#htZJvw=OrXoA_O$4{^RhV<|rV66*0#c7$Dz$@Czt;CW&V^k}DQN4aUpcyeYRPx4=+@pV{(j0oe{HDgxzu{8kSTf0R3;HJkwI^c~ zQnHKjzo+cLz6GrpZuR*LPId^0-Ylp~P<{h1M_2Ku3W@l~SlsX2v2EN5bO%Dt`?r-f z)Gnqq^o0gco|M_yFwrzIp%j%ca-a2eyyFR64)BAua124*b~{AT-6AY6cFrUtzm--ihWQ9@o!b zx_vrKA}dK3R~a+|D=O`70G>}zV)?|aTsQ82Sgs*zmm=hSD;TK0qw#~7LMw|L&8gb( ziLyA$P?i)hez;YfX)LYJyLWD0VWn^h!h_>@So5C4gB$_`VW3>qPp4)s`apitJA@}8 zQjb(GE`r_icdLS{FI&-0A4PmF1=eN?U7T3)?pvx4w}utd$)kmH>PoxAmv*|X ziK=_OETsvxM$Z&ye(G<|6SlC$FFv_)=CT%%qM*=i!040 zE9j~l0_3=W5-G&CZr;aUZ*)qEbNc$k{6XNFeN=sfh|H8M^P1y37q1CJLrvM#>RS7H ztGdY}z|~|IJYx=OklZuf8Juc(v6|eNlR-yj!X3ya!_7XMtxVHK*@P>^eQNG_de4@T z?sX~XNZPKPD=+_$+6S-sbGy*9he#DlXo8;nafB8m*3L)Ayu1~w5i9v99OE0s%4Qd| zDE_ViNvn}ahL)96BnGOf1#dfm9Sq#&>V_ZOT9$)V+#!M+YTfSSaUBwgjOcKnOLCvX zBZmHe7zcKH57hA;xeseQghWfwtLe2Rrq%vhDOMzGf3yIenGwY{AIn~ z!QKIJZr(&f(!LBm^O=Xw!=u{D*_i!ZNNDQq^8pr>&{Vn7>NlJYSqzgppOt)tiN6`I zVa-OZdy1&|J@aPn9X1J8y*wMx*qg{+qT75knFEE(zorgdj=yL->W=3seVj)H{^ zLjFGT{uGM#5LL9gV|Grj^^bOBinf9=&JUVNBX8yWrjAmlAlCjTd%P6GZgiysS5nWb z9YE*l6)k)s4^5W}l`b_5C5OHE+>$gVafmt)vrzno@7mSl^y+C5EM0#-44+%jAXzll z9-uwC!}4*z#noa)@DkeLZ};DGweSuaXmfKUW}@R(<|3sVRPLo}B*2aZOo5Tj5xuiK zQ&(|ALn>5Tc&O>hznvNk$(d&sdV<(OJiGQ?k+<4?6?wx!Zf_67s1ZL|YIDZQ*kHFE z{xdsDTC_xiK)04|OQWa^bG)O7dlUcropRdegh*4Ne367V0?gbbJ(KckNAEi)Jub)o z1l(~(&HZkLKqPq1Y{k%?UgGnPEga`i_7&y))x)<$#{;*h;3*dSs6fB`9q%25{etY; zO0g~p{IXh(7fo-fs?|z{R&57-d6A|B36);8jVjA1p{T;}spF=>gVoMi4O@v*l4cwM zL8n`>Mx`Oe_j7Z@LxNg^nzR}xVSMD2xZT}uW=A9Tx&~cBb5Xrrz|)?GWJHK1i>i*J zaLg18;l0J+&=v+0vrvJ}&5e*LXz8>etA157Q-%dwdOOv3UiZ6CoQhGCmkYKsw}6q% zwk&?vzz4hih|!FSGBtP$ADwqXp~Gt2JU(v)wSNpgR@ni^T7il^fpkbL|3)M7Jq50l z;AO4ye=maTiH1V_##$;c+*YzGTPr1MFK#^}uDbmBw}Fw<=YP7zuHct*b>^u(nho^E z(RD|B(8@vs&drL7S@qKWf>0Lr(H2V+Y+=-wzaJCCI~s+@eVzYdY@)UTraDfjAXhHk z?LM`r>y9bOht5E~y}bm>1R*fnYwvT}#T5;c?A%`ediy%{dU1JXW?SzsM^eR{7qmmz zDW%n=RVxA1zt~NU|4Lrj4Y`j+rn&z3oM(?U>(vrs~IBv}kEf-Mgh5No}`PtWI<~jPi?dsd4OW zViehuA^`zfjsoJh?eI&+N~E$SW`GF;q+2PI;**b_rLUk{J~>Sm8CL~QE2!If{>jK2 zBYn9Ymb8Yr#m!@5sRQrzCo84I~Vxh;wBbySy*;wK)?%*3lBF%v>ndw((tK5n;2l5cd^9%}0^ejTIF3vYR$ zyX?4yVsTq3a9_oQt6h|SAXtoRr})xaa|UE1KKp#GkR97PL{_6%7E{EORRZXUjJU@t zjG17oxwy=hhb#?0#o%EXpG2vZzFJ?xb2g5Gj8P0N4|sam#+O&Y-@*o7sJ|Z_BK<&_ zOwwC7h&n#tcjko!r$4IaWU8Ne%=&*Wf(pe2r(KF0?p{VTD$T-2=kwoUo6~2SKUPkIcA7h@q$GFHy%*lA?gX)Mg&evGv zVS8O#m;l^9^)}3y_A*OoypU@YTPn@zmf1IG0_VJT0#z#RR`0|w_x*ZqlWd}?-e&iUx=(MXVv_gZ6zV^UsPhj*6h^Jj0tP*clxuk7>>rvpxolzDugY6!OmA{6)GI`uf z-PGGDVy~tkoH^!iA-}Nym|P9Z(TS-9?osRdR+QC7m1M9uGk;K<;z3PKL@N5`-wJ`M ztNbS#J?3O;LEYu85e^@~Y>5h56MEXu`tamovB<^CE_t;J>q$j}gaxAoWPd7Mersmg zeaM4Z$bxx1PxHCsMdY|xD=eb(Af5@~@L08n5?7_^rUS;oTJ(TCE5_fkmNF@$3z9C? zOT;GB4NLZ+5~gWh&{^&IK_hi6d1vA$K16+2Ar9Aj3opeNa;X{Q4G-{r;b?zRJd?5T z?%tjyhc)kqSn;m?S~W#Oxw?F^gSJZhtNK}FZXGrGmp?8Xa4{Z#-}XO~A10foc#XG+ z=N(o{4uC!Jo;kg>=rrarS^QVV_Ty9zpgacJmx@mUXgFK~MWo#4f0p#xR8Yb+V(1hQ zpq~cS2z$W*m5JK4%9cVkMFkG+Vc%Gg?%PG)=-3Y@!@0f56YOh{o9bPBGdOag>}i;s z{r*p0Q%KaTmTulzx6jvD@lsn$(eY!b1AU9b`((K~|L$@qX39njK8GClyTYb86H;ps zHylJTbNjuN;*MRc9<*C)CfF4_4kfPwABn2=PuurWNk|8Mps-2Mbr>_Yhpxsp&gV06 zlcyI|!&+gI#JUEu+DiY^J=aD>?_l8@AznU!Y7k;UxMeo;`{10MAZ|L=FUq8ij!+v; z!BFE!&OTA}7Y}S-4u*^-?z&ibHbg*pRjWZGh9!9}4u1vocAg~$!$MaiM5^rkjPlz( z#A%dAmX_8$S}qxb3LN`eiMmTJ1cP%L5)y$hJ+uj27)ydnf$Pg5z|Ke3mZdhRE}s;A zIkbXZXS?#z0Dkh5EipxfX-)b^syO3hK8I;#cX`vnHz<<_{oM`FRj8W8tgWY$nkLXIK+p5I zb3UEEaaV$+(vihU1)oOwl}w9IN0@kVnqgffA~?~jP=|mB!EFjhK2>JGp!@G%&ul(* z(oVK-SJs*7>Miq%RT?Y3(8n@JtxrwKNg&RUy~1hfE~$XgnbbS(o||~R#Mwb`8_fC> za4=vV*Xz{h%I_Ufm=y_p!stoM0VeHjCu|QZeOk)TUJh{9I;AmaeGa;8 znRqqR)n5jkBPEJUPq9ZDzX9c$(87&)t!#o${_Dw?y-tXxYWDkb5Dy&KvGYf`CY1uY zv4zR@x4Kn1qpQc?@Qx2r0qIPVpLfqqy;dvQB+Ta_oRu&0?lq$Fu(DB4$wQ| zcOjbHlK_-M*|IWH)pom3ScV#t@R>a^%TT94gVcA;Jbry~H*fDVSobRB4n_-S{Rvej zN-hjSt0ag$PqPFeK@F!sf}cCCXmG-qAFkKQUc#|K+w@zQ1UZ-|&Z}JpJeAhU0;*~i ztPQ2Ea;SP;!m+Ws3CRB1l3#Z`I6QULceM^{L+NKc&>u^2C4>n8lj#7(kLtI?{qj~; zb9+?9DfL6WE5*sjL-$s9{)p@3V@)5)tJtl47cL*(vtSwdp94a~o#0XiI#v;Eq; zEIk~*eq;^Xo7s-mEPKe~*WqLv3_4)$!N;2g9({+DXW9NDSDva&BhSJP)KOt^d~W=q zJ_fqgT*Vx-Yl&9q7RU_F2Jbw?=F88A{;`W$JmKsN2qCy=aY%)D`r!Hahjn^d%}Hv? zk2DC@iJF}ISyFy<$%_xho#j|-`CmKiMp)HyTsx|8gMelWy~EDG)x3=%JdgRZJk$8& z`tJM@*>S7=*j(r>6<+}C55D*PzlC|vcl&`L7Hvsj2urW=UP`}iRqL{aSB>vRNvcvT zsa_(Bid$57%i*w9R9+rv{dGIJ6E^{{@T}3%JR|i-YkR4LIs*TtNlb)DdGty^Q&KrY zN7xpfD+0YgKd5j(eVoUCp;?n?Q4S0uDS>)m$^frhWLd&+T3Wt#_u(zB|K%sx*$R_V zJM&B}RjdRoIVx^f#iTHa=>W=*N`r@UQ@<9!^KT@$MBuzXDV2=8oUKsj_vh5PbniBD zv?3P;ro2yzJ+@0)dx9NY`P!P!MR|?2AhU~hX1e^cTf6qcIfhm!y@^&|Ya|hOibM$i zuH|FDJAqZXMugx*u>?n{r*oIR-Arp2FiPNy0Ix3Ilq-NJdIOM3aLP9DCuoHTRJ)67 zv3p5kAo#u2p#)-%aHuSSkqI=9y-)XO$#ohfdYv3gIgRb+1VP0R$}lAHYVH*0Dz^iX zazE<&#;Pm8fBs<#d-(tBd{bY;8y0>Me;$?F9vHOvV{@rBQc{~M76 zSITHVUkgdu*}`gozzt${iw?kBbAuK2buV=)uroL)%@y5}v!j=Op#HoL7XK=<(a-Y_ zBaNW*qIwqnjxQ*vuS}J8s3>SGgL!_{#SGx1G8d0pYG8Il559&vv!7>xHB;M_kPNc> zw&}V04%?**Oztz1@^160W}l)z@X55m&z(Ba`xSWD5D|3~*p z_*Lu$3hhxba`}f5Yl}KBvls}lJ3D&33`xB`v3XQ(L=|rT!Eq33f8z1N=pP387}mqs z>$4tJHqp8yd8Pa>V*!vF6u)Ayy$R`js-&&5?>71i+YhR(=g z%3l-w>fuS}PT?+H2uFizI(aV|K6X}Wzu}w{;rO43=o-q8Rm-~5f(vcTru?_T?B(MD zYGr_lH6J^=-CW#H-l3v(!wm{7-?dk)wsAZN%Q4`xyKzu?Q&*JzF~>c=}>A1 zIIkC(uV^O`q4QRoG>QUis2F*4=+-b@l7V#eERZ2LpGzKbG3yiv&68+!Ud8&pt^?XK zph;^i4SX+xd_$h1hI_@BXp1U;W7u}qdH(TRAUkRFO^}|kyc10~Iui|nW-dBgPl2U-c9zj${*MDe}I-23!WkpcCKbW$YEumfyq6H^e5{7%a9f&2cafMe7x=MZ5^@DW2&j|F{!P~vAaeD8F{ zt-{(w#P1AC1i1P7j^8yJ<+u4hez}p@u`*_ob1C9j4_y<_jypJBo@&v$KTj*kEU*wJnNS;`H%Xi=K+@2|SZ z(GmbgmcNvK+`eF$1AJ}6+hGAZZ$;A5HLV{dTy{@aPupMiPMhs}O_W)ES8tX*ZB#PT2Fj}s9f^VDA~OF z52$(jhnFRGV6|Zv!UVzGa*bp$zf`$h^$!RTN>t~vR9#81L-N}e)AJ$hgYh*in#rys zqPu`fV=>hmv0XFc-HD=J&Do!&;40Zl6-V;u86Ew6h>UpCyNMPi%Lz9r+I4P60z!`- z_egf6--K9LslW7%swY)rSLLi^4HyJ@SG?ELZ+P*THM66@IX>t-IQ0wfmGs8{R$^YDVythT3r@lU}u-}gH@EOu#JV}?e+VtQ(I$; z0LZc1JVV;^ilK$4v(M`EU@&FwpT&VO#AO&`7n)J4M-c}N-S8F;bE2!l%(fg@7wpV( zH&WeRf&n|K1TKhgjE`qIL?=F>vF+9(wEZnA*ZXL^9wvCe`}unUcX3j}kC=PanC<yxaIbMo zN=gOPqFpD(U;=Gu0KeS*2nQe>et&tZ``wAn2ag$s9Nvl*7c#qRGBGX$aRcb+wa?l! zYKx@OGnx(eU&%OJeh~2TELRK&qgjv(lqG(MI@{t zY}Y%;7~$|hd21rq(**>1d_?9aNzODmizElVsplUb*0}2tPZyGdCH;?l2_2?xHvHXJjeZ3J(5|4P|12_`Y++ER1P)FQ7S6glSWa|KMFnGwFENMV*Pbdc%c0qpxFZbJ2e|U zmmObA@(utRo|KoDA2X{6={~+{1UvlcQHT0k;CW>ug|iDB#d_<|HO`LjN}++?%4@mK7YWtmnO@NIH50lMLE@{Z2(b>ni63*0hD zQ<1PSeVfa|`r~$h>eO!KT9*<5k z?MFSjZgdgN)dcx3Tj>%pAWcZcIlp12-rqd3coa}zEFN2z{jbu zM!81e?d19krFz<%y(Af@_`-Oj_2N>>#qeN|gD#MZ$eP8;;b#WH7 zN=86vJe7n50QZhgFz>BANQ53iI2L|E|Nd05s)qYPP9F36svU26;n0US`+|mwIj%@< zCX5~=b&WaK`qWj+t?>PV_hIt|TAPMnz55Ttexd!Z*omqJvNf@B;VuLPz1^ZKtTl)I zu57ui9HBjsnt1f@8yR=-xRJc@cAv(xY83M-U?UQGUG}Bx^up~TwVlSW0CGOt>Igzx zGG}%q>+1huhz4o*tK~CG4Tvab|HBa1y;i(OLwBrpZY%ve@m{jz$T^v!P)miOkNp4u zjofML&XidQ5agr0-`BDmbpZjx#>5o_wDibzQoqbDaomR1g(!uP7@j(lvrFnB~i{z zFW4gL13YqpJL8{PR9|#MrG~m$4CV{T?$NgH?#AO)3(ls$E@`J}(R=0|cT#;ng;kMA z|KD(fEI6Nj95m}jf|a`;XJf)6U^+T*YyZNrrGM~_QxOPjZ5v;6IxmdWTuhi^uf_-_smN7eM`K;OW#E0weW_+V|yup6A+iA!yoNN0#Xp zQ4yDCy{zqoAxfUr%i{OB41}gWmnZED3(i5po0nJC4u&m_@5xce_qQ(XN4H(UYbKxJ z5(1u|OCpu*d%2CZcv! zuk9cHqAmM{a<(_ZIwEOD+?XW}F2t@MsE%GHpf5|eS7SdrJ{ncA-(_YB4=aZ1 zV~*e`k_p(k#{QbR#@$Gu{5{aY8^1&!fqw4w`e`ax9afnk@7^K&j%d`-&wA#}hPY$& z$q_aAXp^`+guc?sr0!=!KO4$smR?a+q2hH_g4lT_?Nj3j`|Prz-hq*a+H+c|XVpsu z8LmC_9u5X<;C_i(!G7K)@xF|PUXh0H^9UsKEMLZIXLLdceokV_r66l*1Cb#CGD3xk zI$3D&SHOwgP;Zlk#bc3)K_PQn+>vk3(bZq?hZEjXn2FD6a4wouU?%$aE*epMvoDlZJR)UJhHo^izSq64BHJ3d~Sc*n@XNN zJDY#dUt6%&C$x4D2|LR3O`wsBU3LVCmP9m&O{e&3VEp=77E8{lY{K zYJj+By{0d$lkrn;`#N_J=1kBQ+~(vL(~20XSh(eWQhYonW6n6c*y9@ zg}n?`Agn2k2&&za(Q-V38alE_I^_A$=;Yl=M^^ zLVpYJmILw-%&$>2z`Nj`cQ9Txq$5bMO~MF~lBjMU{{{>9Xai3=&uppvo#k`{rBr~p z>l)fjdSMZM_(%|-*uw1DD$rJ-`+g&&!490z)9<)*W#@3u zL{~vu6U+W)aX5D5w}tn7;BD>U230AQl6Q$P4l2`qOnxY0(uK2O!v#}ThUO*TRS^f8 zHlawg)$PGu%N1e2f_+er+rGROGom-rlF=;71DOte+oCk!DgO%03>#8qGz8kbJ>>4j zUqn0CCUsMOTX1=!e0qn_ad=Etm9%Z$WJ~QuF6_^ka63mH({TBKRP{f+KVC6{S)rv* zxK`>{KC8%a;6OIX*_hC2X@H;ll;k>ewXO_{Eo_MLgo1%Ya296X(W&^Unp%qK4wC}= z3i%2qI_GuM&)Rvi(=675glj~UTI3hymAo-JNwwaqhD?sTOpE;QZEWkQj6p%uxX8B+ zN@vdgcC2Z1MxcX-Xm~6arg}657L2S}^G#5m6`Kz85)NU=71#HXR|?X)hwEIu8JR;z zsz&vo6!>#ZBS!70VTESDvbCO&_;G%(k*^7M91%uQ-ZY~!?ZMo0T})PXnwwWxu;F{| zmBCO-`MpgVRnCkDbevno_$ASbJVZ-xU4A*TbyufioZnIY8IQRI!ONLSZT)7t^tSBu zQs=uqPHtO76?nWN&$%!;;{Rgnz2BPZx^Hj1Zxxg#BE5-7@6x;U4odF`NS7udfk;v5 zy>~)~NCyeMsWb&C354FHCUin*f#AvWeV_B5^TXMHz`m}%_qz6)YtAt~W2&t=o)BX^ zQF*IuOQ+eetcb#M+WdPJZT3u1!c@HLQ=F7bBxKb;Xqb8x$-rOh?+-hmXe(LGING7i zR@Z1Z(^D-z``U;V26C(^C-W{s%s0DG_!92e35!a)&{iMbde`sfUvrLa z`>rSlYf^%fJ1xJ=T4^GzTFPK4=!ex@!K}sZ8&STo_>BZjif(Y0`8!vjb;yQm6c&P+ zLaSB?l2-r(4N}VBRu$z=^kE|KS1Ka?BQZl1vD zv^tT+$;zJl+c+s5O$l~mJ&PgdPoKo7CEzk7edJ|-2F)5|2cgw~AUkC2W_I!Ju2Ndj z&-#YShb(ORrVUm|3oAJdQ&Ww>%@bHOeLPqs%AF-YcaGuWMfD|bcD-fTb!R)cWCu@i z(+O5X^gKoNkRvEE!);pR^i7A=%dx=Jl24IkDRXu&eeVE$hqk>bqwg;r&>&l{txN05 zY}*=mfqfaoc6(saE7x6@R=1rnemEmvRIMsAqXuK_(kJ{~>3G}&q{p~atU-b^RAeKJ zSLn;+cLZ%6Hort9+q`8@UEP8@-kbO19ms`m=d(|E;rC;1I~m~F{?pi69K>8XGjWpm zC#7uwe$@fmvRj2Uh)>1j56u1;S9rH^Q?GFZGn@Sm6+6->cdenhP~>MNji0>!fU#1( zi#tU;F)dn4a}#A~mU|oID|pb;=JXvb4*pLoh}F6FFOe`s2Bn3Tgp_W7)k2k;wE|5s zHiTSG)zCor;{zLt&GSD=!co#|zZWx&W_ntal3L)kR~glp~h2u>b*SQ}1Xofa!Xz*?vb@$DGYIzKEapT20zXE!7SqlKp4x>vi*t63Am=W*MF_R^dJw1^)n)ME?%&bpH~d+Gp?JHhSP^Xj1wg0>A) zG`Pk!=Xfy*Wpc4zdAs8TztA$yUZ}psk$CA!Zv*9(7WNJP5q7ICua-(406^Vez-m_J^C}^h8`- z-?!vK9K~IDYb0thc2_L!i4Ura*hACBS0L~w3*cyV_bdJl_?cINv56)*!&DQl%Pg5q zL%R7`+W@AwJHx&X=Eg)~r&Q~vadr)s&uWX^b2cZBREdn4EskOvNh2GV1_nVDGy4bf ziiL~s&`P{!6>bn4belT5j!Nf=13`Qxi_6)drIlGweVl%OkNwSX&-`k9xyiJg;=AsH**fq&!u>2hGO4eT;5Ws@dG!Qq>kd>+7bDCcc9}pTCOS~o|W-tHT0-G)B z7unvVfi$BzIM^N@2i<_ z*7@2NEx*d^aiI*eTEu+&g8Bg&XL%$Gw=DbhtvT^Iwbo8}pQkg`8$9Yve_Om6S9nDD zCXSxwYCY^otQTDQ^{z{eNAo>W36>`>m=TT5Md-UZYT5@&1f_RZ*G4#NhyqWybEv;? zfvh&V!M@j6*54Ex3Pbb2Dneu=?or*n^RLX<)8MH@-9^{fg4 ziZB&u?#d9uGGx#DsgjB>ydDdUMx;P05&JME18D&8BC@UqptT(U7 zf^!4z=Nr4byLYP2R)+~UO!#bydz!7~&&Fk# z1?<>c)xwFr>U>oLowYTdsmfO$H7w^Tag5Wpn_Dip>+LE<3l#8m9VF~S03^K5GgC%S zp0LWX=EN#RLbm@_i+j74eK~8^(ALnnOji~-9%Yg{YmaU0I&1IDaxN?+gk)cA(fs3+ zY1f!f|7X)g)gAoi-uSYe&Xw)X=I(%m6O>MpaJFB+?E5j2MC!Sx-($dm@v@W}iB|i` z*$r@ZdUF)tmv3xP*QYTB70xo~@UYhcf3NDHGgJPuP*E(NffdK%B$KGYu^g#GmgO=; z1qEZVxHdVb_;s{o4x~74U}J%Z>!(bn3?aoBEi_h@G=u;6FX;2aD?+dcV(X z)HF3+F|JqAVLz_iy&Pr~cv)*a?tgSB(nojL<`gwJ)5_~FHiXi*?trL5VwTh81a4|@ zAK-YgX%s;nf4~f8dKF*8@P1Xe1R=6#6}Wc$wZTD2L@|3JAW?F&ug9 z^&o1oU5e({!dTXE6x!u6)zD!Dl0*YiU8SWn_w$5{XOu1JjDWdz+m{VVCI7MEQ!q@X zz+Xl+mGW-$V?A|3{-e%4>#BMGns;aR>F|H|GM$qql9Hu@nJ9NS?4z-xn2`SssJs2T z3Jgn-4$Jhp1)-I8d6dTa=$$4rbI6uv3qk>Wb3i1brtZtVSm_ zwemR1d#IW0aN;{jd~>)tA-blCNiVu4;t|=3Qhpe*P9C)enos+ScqCWu=ZA4tIV&>k zDK4~6|1*yxTqwonoBCBuI&$KgTmLr5A{>s>n0>gKYX4KUEQIFE_5z3X*(OJQ1LB0# ztKXeuj6XJTusn)Aw8Rzo{TRUZf?zKAfo3wnX~C)X2qIrEZ=^n_$rCGARnL14vs2TE z5xvJPUpvHT$`8lq91p_R$M^s2vt=ISfWb&w7Z(>~&U|j)d36M9PYKwj8l{S{+m(c& za(G8Aon+hr3btw-!l@>@rY85KMa7z#R8GZ|>i*{*$LG-CrcOtsAh2{s3QcK&El-&y zYkuuc&MkmN5)H;`_%TRZ9mIRP^s~$X$y zC?_^M$YM?L+gmoWV%!wQE^K5`H4NFZx(Ojpx~W#$5=FG(s}S}(FP>gsm)GaPl9iRx zyGr$CYRc{@w#-f%xk1><$Ejr8{?Q`YPLtvaelSGKRxmLgzF`oqXdWW4JE14rT+SD8 zZ2>?E;B-i8+{7!>@~R)k7${TIJ$Nu!I2+88TL5zSOmU5=@_^j0y{TfYjw1Sqor$PG zm$a@|8EaPV>G))8+q38AJ_zN|eg8(RHiNy;j zH*etqj>=MgglB0u4I$;rzf(cP-_dioMLq2i*-|MFM_$1e)x4HupWWFw((7H#Rj+Q0 zu3%5SfNmjOz!BB22ZLPRv;XXVSFib8^Hxkd^tG|Gsof%ei}bFbSJ_#L&{#sf8U1^T zw`9+@Eu)3sKTxonwFk3*Z9^Uidk*BgtV-Pds94=3?$;6bAW9MLd}tE!ndkZZU!v|$ zIu5K1eRm}_jATwY`R@w;{^UJ&`BdQx9MD=fEDY*|eyprKLXJ52t`&OuVW#Y=K; zWoS-kF590gyO7-Hc@MSK*@h<8?@G5u{5B(l7aJnkOk!g2A&+M>wv+>ONGrvSebE7F z0cA@kz<|+ym_KN1Xi_BD4PoR~_il<&={2@;yiCoID153}-YHnmtV{GklQU?Tm~L(N z%nQ7jficK*2cIVS6u?$T>?;p|(_<3%(`Lq$D$d;gU_zc7lF~>Ib2M7BH@*=t&|6$? z0=ewja9!l=9x(!9x0qLsFvOp|9IxbVD#ay}VyeX5yD z=(6#wXco7Hv)o`Fl{JIs6Y+`^;c$y=Z&7FJ(^#TBeuW-p*-=}7^S(pF=xcKTkBdAe;s)mvA)ji3m`xWjRJP|Q- zk-5iC@9#T&uy*ZdHnno$cI6w;^FDydd2ShQ9;2ys_HI)VNSvzn2vS_V(lyO;DBWG} z>D4OLWA>EX&iVPpxRtMMa=nVh5L70zsq>;ns>}yoaP#$gjSYe^HFYU_VIkgz5^&Ehan%om%vdl&> zaZnAKmwkK-P4YT|9DK0&_Gx}K$;F$Z)5=9wX66~V*9N}IX8?iS$QsZGOc}aM7gx%7 zoQsluB9rV&rH*l?bqTh;5EH9fF?Eai!2R=4zrE~JbYGclP${`gIoA4@DiyUPe1+i| z==?#q^!1)NPLB}+3jQS2fVPnMYv7aU`q!}}Y ze0ZRC#ewB47B4rXNH3lrHl~&CHoB7JqQ{jV5^ObIrOX#A&c}h%_ktx}QF!`3-rG1h z7qSD{a~u|>6BVhia!{nn>P_QW$j$nurZbPP4LJ;FK7d^vn!R;;lG zGZmoQ6eam80e zoAenb+k)}FAZFXHg|ww4d`dxNi>Y(K)%SqM=y+E(dxnVqsBa`w!k<3|suB_9ta8PWBBaENaHyfe3) zOc?5U`dS5RWJS8Ta0KoUEFRoNeYl#$jSrgPv#pRbE*T7NV|oX0*zF1Yit-~E@c0&b zsKpb*M_At_wly|649DT6?#;8Le)E&@%?qfn)vOLWP%^`_@!KbCNGA%m)QQh$3B*LiauVntDDD(IrNRM{8>QoYMFh*!Jd-& zB4yJ&vxIn!_vE^a5k#@$FHuq7zIV$xJ=k+v>uf^f+a&tniJTyZ%02)6+@+lSJ~Eqp zxW6CG=?B&etRZZt=`!D^tY$o`sA9_f8f-WV!)8Mhl>G}OsV&quU<%=w?}%cvUksKK%*qr82p?duLel6-=*L|nd~&2K#LMe1 zk&o0e_H#3{%PDgud&8Cd-bXisl#{7bZi!@>y>Cx0#>_BP`Z*9ykh7x-i`l&-P8 zb*B+L{}pvvscTI}C%F}T!x0o3*3|xgO)^Iy zJbTuj^?hiM9j>&T^1!OWzeJ^Er3VK;j^Z0iP^+$Ck>@VSl%g%IEB_s2o}L#`W9s>E zssEj1`sY1^>h9L5b7jIYGn3T0uz-{fk}S$@p*8(@AFn->AF~qi@L;=bVBPti<${aC zRGS5^qTkTmI(pIEz@^W6wNrei1LsqMSm>+6J~>OBGRlCXKPE=31zYCRdHuFtUL+HB z2)3LLV?VeZhn8A(+JwE`)pwa$09>qa$>N(?t5!q(ne>#L=5O@7>BDQ$8}2J<+YsdZ znXZj^Qhd#Wr###8BFvJ-n}^Sr3EIbonR6wUiUoO!Y^pN3fdQX0gQfM*_UvC9;==uV zs|F`~_=&eANF1IVV=;AW%J5p(+KA?LLSna5&>Pxd1p$hK1LvDr`^2dY1&Ke``96^@ z&7wy`r%L4K*Y*`tlfB6fyRJ;mguf$r7~^rPU)KWf#B2@>UVRJ-Y*%~Hd)K-cd-A_T3fcfp<~-L;sKt}UCx|I`>O426alJ8q>b~!>MRV;Q z9>$SaMC%Ns6uZDh_#d9+EFRdH1$=nynA$xPbQ9J!)+sSb(>c-5$(0tvnYa68yC6bJ zl|EgDy3hE{#HH{m@Q9^s9uKLjtMTdoAg#Fs(j<)c7EI8-?>h;__Bv&;Hdhp3;78ScWQl z5GOgfK^-Mej;D{J$5{rmsRbSgQY>y<+Uk1AX5}X0{jIID7bh+h@XaM52E@_GS|6IE zuvQM7wB5%5JE$QxyL2b&0b{x*Tc)lggK}=+4Cv_n_r~)J;aQyXFzPrYwFVk=;-MkR z+OgX3Lup59c;Ai{x8y8HHPXFprI-sCWGzJVTkwC&L9dj#JQj20bP{o#n3?dv*(Dse ztzEN4!>1FW1R6Ldx9!yTK;LT5FE6`6|1VLr@aERT%a{nACGhCQ3%uMW@9?Ys*Uo06 zK2HzZn0<#qhz?|Xojx-ZCzz#IKOij%IwnM>>O_^cVqh8uVL>jsqK*NqZV@jp6Z@iD z+}wa^!#f+Tm?h?!X5Ya_DNR|WDv#NTnEb)7R4o6b3zl+v7R9Ez-_3)wGrb!Hojto7 zvGFw9vo=`kPU`rdGf*6%?-k^|asE^iKEWKy!30SW&hn>98s{EOX4!l1!m|lY9xz)@ zoPAFKLJMdbGHfq+k$&BZ;@A)PPb?k1hT7{T6&t1ZL)HB(XH>bv%>(wNgd`ajXR{_z zk>L?FwxP5702O0(Q~KqMXt97J%N_GnaY>i`B5SZ*Rui-6u$l##{E~grS&M5y#g2ws zv_SIrQ88+;nJnMbPJ$0ryUtMnp<^>gC4Q1(^Zc!JP{j?k~!yZ)e=`G@$~^6DnC}c15eTtbDZ_!8Bfe`a&?S~ zbb(|-R*_o-sB|Dpm;Ge`(~H*aJ8XtV_w!t!XI-4$7f)1=SfeB=!%}yC&KRUTtt?mY znbqf|cSCu8i(xEa&Jm_!=cc_=Kq#(*OHRafPdmh%0or36Qz6L|AA}IlOdOPMP|VT>IML zrR0zvLx=uq719h;`)&v3Jcenw_=7#Lls0>sgZN&t?jqyK{#BI03Ha{YTu=RCq2yqj5aa92 z8$$!wALt(saKM!bcC`ZMIHN#H+w8t<$7jncLCzIExeb_jl#nDEE*?mg-paH}7Yy?L zo@H%x>Yli$FRShd{9r%oso^OZef0#Zs#|Yr8jv@+pdp5MJgb8lM`X%xZ?MaCb&yh% z;?x1i74Z#_AVchQs{&&#Oy69;C|y_?zPrg?4ydm{hZnZSK^n5)GABUVl}mLK?)}Gy z*4v1!UGGcJ@!Pgv_@?@j7c6Nv9O4HylNB&cLkqzr{%ZZp&DGqv+PAW zx;V0U%Mh!Zalq_w*QN%bnw11(T3?YyyFy=RnOG!(VJphlx(8nd~i71lzBv3J(w8 zv}kSP#ac4*?I9hFpjMxi37#>!rszM(WY(Q^sLRoH=oSIn9D$SlJp|DKvH;%U3 zg+;o+CMutOsTSnr)ix4jHz{!7$a3LI_|zD3&|l?R*Kf!$TL6|Gk8EW7RWrp6+L^iG zp~cOHo$e6|grj)co(5PSFQN82IW3#GmR8!*ek*SytWAI_INs7UcpkM);fy!;Fn6by zol!IND8S5D)8w5xhp0PQfpdjk;|AmXpNIy=ucJfhsT@nz79=Dpg?BweUxH5&1PU}> zW(rL%T9@~$GC))PyL_H9fg~@hA{O(RXBl$vzI`qya1*qvaY9qU3)7UkQ^mNY{KY=Q zU)w#AgU1-2)ahB9PPU;o)5P?Sx_&u( zZJbK%oU5DjKU~DXZ;i`I%%X3BMNjk;>uxG!V{Oe5wBcwrjUlk633fXcN`i&R$^3Xh zKK^@iF*k;U#P)K#KfG+Xe?c;D!h8rRVme$F*Y3^@rpheltIK_tr|AkLmKW)m(>~q^ zS9-62j6q#HZG9@;1-oB~0>lt@4KKku;cBS$Vnn~*xQ{kRgo=UQ(%rY8l|f;TKxKm! zYtt>9>uemX39vq`zeGIx27+vw;xH>FZDX|6ZVB=HcV;ex#NhXW0(#5NrJgV7I=4D* z5NIk|n~~o#)P8yam{%<}iIcLx+KQSqiG{bw{CJ!t&yw@;;`nTc*|688?w=|UG@bv@quonajHvr9#-bZ zS?-LlT{0m9i)1W~>*FQJ!|6<0UgO|oSj9coFW~?u$viJ^(^}@=e{xS zi8#I!U20w2&pSxpx#CK>FQcaAemLQ?-ce;&n6bVvwq9GW$Kj3)jp3ge$YZL_49$x254X>m?v8 zKPKe%<}XoeJ!?i-Ep$0~!!@;GwU70`Tz=&#_wj_YE;E=jMH-^BsRA3CSPxCAPirlW zd-*x=Ev<-1>H>o9vFl(_9dUDTctBV=<55ObrTMO@WGbVUc!Y2zANt!uj+?L#4?}!5 z@qI3rP)={AW95aL_C0{0&*--1;9HEnEiw6({N1o#A%< z_;9)6OK7n{9QH`hmfz#B9>w=y?|ES>T~*do&_fIQ`OPeqwPzgh>-afIq5YqV)i(`A zS2swuYcaMfqzXAyw+K%iLK`-#e{0o2yo00c3*%qC^~1>#)acLu5($K_J!i8D)t$Jq zcJsltcHN{GpR8tT-c-sG-fWAk?#;Fun|W|OVQtCv8rq!+Uln{&e2O|Egds3C|0S|A z`b(7ggv~D0TD&rj{7KiIM?qkMS^=4NkS4k`g>kyWuoG4f5M}m z961p-^LJ8!i$b1+yhq262?p$sMVawUtKa|CcX)7TvB3V08aurWI~Dyo@Wh9%iGX-# z`R0_<{+OLPb(m+)IXhd**<0{eRV{qy?hnxij~4stf?C8^s+To(I!C>Py0RhDw9n+* zoU$|j)sVa%TzEMkV0|q(Z^m@it@X+KEz>7DyV=;Ml-0EsNm6QDR3l%sy~_NYUsi|# zL(^0pQ)QO@Lbv#Z4_?vDE?FOrzcr@N!`AFcyuyt9MW*GtVG#k|!2 zJdlY9=9?6HwDs~ycHK|Gi3MTDZ#K86w8*lqA5y{7#O#k!ZS1ICc1;NLTs&;T7O4~5 zn$(p-@!|rE0)RoTCbtn^x3y?P;~r%V!H&rC#|$jF`S)G9zqbn^X9!#;YmKb!T^PZ> zg3i`5&X84%H^tK2a2CTWwi-xJ)}4YKg^mUN3fdoA}K4*m(# zS1+F$F`X?4{8(c07klwXOiXUHR!z-|(hJpw`G{?T+tq)sX+*k>xlU%R!Hp4~_jpaZ zpDx`=&?6u0%!!@P_kS~57f@$0Pdix$4PeddwNc;%>{VfQTXRFmO9Oz8{}ySwd64I5 zt-W)IWnd5!B~>)?W}3D(n@y|$!0WgJgDzA;WIaK@uC3WD0+h7w3BFC0Cs^gEU@0cU z@d|0gcIU2y%NzR6R^3M&@&{CIC)r#>s5Q5I>Ii!kgj~6-C0yO(Jiel$8Z+bdK+X5b z*M$wgR4wo8*xO9=>3mGaluoCAx4d}slERfaxA}A)p~mhsM)sJ)7w$J}cvQmRs7sZ? z9N2c8zX%a6m5pfHrZi$6KljY-wauq(Ae~Glhc&IAjR%7L8cX0us z;ro$rlLJHT50YdSj++K!Kh}d~2?jPV1LJ{d!<9T($*3E+K<1N! z8Z1=rfPFExLnc*jlbMa>msqExB>1jUhJOVgxqap5-gq@szw2O7J?xH%bQtN!jS;^k!4Gx7cB?DWU3p0;h? z-%mg}y}Nm861ES6O9*+sf-H3zI8sg2RahsZ;nrYt|p7G8+rV24oi`Kc(A<31F~; z__ga*=J@^G%7ZooCEgy-EA>~C{ZMS^CpaKa7E~1jAZPftB}#GEMa|`?>%>&7gC@oc z%yi`d$e&F5oUDS<=hZA1=gD;_1#D8vi#GS36FXAVf>u3g+Piw`yXxZgs4cS95$2;) z<%cO}!dkmW>253!O2s48^(}QvupyD+8gukc?1l8rYlm}66&)r1=}Q^Sq#bHHS0_5JaiQ^vnGrC54T|q*L;*1t8pmU&U|E9bqDz1w zx#ETSR_4TFpG1)TB@&}lsjbLS{n&>Id~J3?M~{jpyIHzJIR_+8-;?Kf_?E(MpkEV5ddPjI~Yu< zY3n)dwtLwMJC#1>X11JPq+1c1n7*uw&3QYZTZQJ{8bla$yHx?qW>t4vN; zGWy>|;XW&0U4aAdu=R1bHVV%H_EjPt#hN96+o*Cf-m<9-XF1~}>BjKb@b>0o$6*Tc zaIqJ2uzs#4VanMt$2v5d4XhRB?zTqGUBSsaqVqa%Jt5vdCfQg_%sYVE_Nrd6jccle zJqN6V3@nJ=Nh$P|N&t*;bYuRRch{r2Ayy#_9y zx33`A0~N*04f6FtXnFjr)4~++n;HGk@+4VwDI?G5qvCS%0`ma5BT!g;FX_2$CTiC8 zTo7s;RXet`06S6|;W$@aKe2@loWN<2kg{dw5@O9|c6YnPJr91Yg2a=l34>!fvpbLe z_|xub*)ywm&epVcQAZyvGot(?Vd}17WCT~A9(XYH7Fcqx~QJ)g%{Ct}py3bN5#!gXNQI9Z({_Njl!-B?qg{^_*d zLhGu@Ef)2)=-ok8wLyR`>wz1%)uWt7y*7MGm)X7DhB-ER5hY7 za4D7hZ8~hb&7(DG^6Uv9k6+y_%P%S~hWxXc%QwCHXP{8IlLNW4n*EjUe?G{?AU8Zc z?ahsA7YNL}FAE%Q=;MeJ+mcXjg7k=rra>!tXWTS^xV%T|ipB}dUhG&quj-BZnZF-KNZ?!?Zx)P)u#ru4E6B?lp8Ht``8RCt)D*hn7^s< ziSRQS6q?imNz+O?^AkskOv!t@>|S7uyPo~$Lw ze(7V+vBmqK_IPF{W|98*hEbq!88fAWhrM}JzJ483U?sQP-l$trZ*LF#S^MGi?8csz z$AFq+&xNecypzYE!Btvd$kEDSAIm~voG(jV0|sJKQ*~5(Fma%AO32TV*Gu2d(-vWT*v$Wlva|2R+f_*?a@nWj?!8*bsz93Tjbzdd3Y^fgk4}{(cnnuLr<}4Qd zB@)@>ZYWIpnxmrn;BIT;bD@3ZsB=lKwSy?>hPIj~JuZ2v-G;oeXgORVqmN~5g9Ug@ zc*M}Uv^=UX5C%+1d+O=Q&nuKox3<5oH;41J|JYUx$qdo%;ljr5SuJKC#TKpL$$*66 zqZNUIDaP87N#BE)daw*UyeN0%ra zJ0c1BOLP@2Ae8_beaG&<;ejXJkxi6CaAnMdn8EX!jSY2axZ+%RIAb0p=~*s{b;v2P zRytqZQW9PfR$fXbz$CXm_x7t!n=%7s9Zm;0Tt& zeb^$d1CQzpB_|McgW};k-Jj`V%CRzD}5t6lrwuF_k4c3^|=R^qQgz%T=6=u17bnq*C{78Uhxs6J0qX##;vR^nnxo^O< z*)9HiHmHbpO8)#p?L(1L{6>H@-tNNe8MjwQ*sl+U+MTDBoeD_rL{FH6*|!O`cKrv5 zCnJK)^rECE{dB9tACBxt@ND}@l&yiiQ}7MmZjH(l1ukxWY|$0v%y}|H9l_SwnMYv5 z?i?1H`dWEzQP$yH)qlObqgm>{Mdwbb`SOIp2^mY}ko@7z-nk8TiEZYOy`i43(>dsZ zBQ}zl)$_y4yycF;UG#W?mqii4>t<_PPAcPTw#cIEtA>?6#p+iPYR{g((Bbr_qaFS% z_#ED%?tEcm)-v-a)3sID<~+&H`HKoiVB)R+$`cxohh=W6Pn?2&4K$7XY?c@gUzDu~*(fSYjnWhevxIQG>f-^=pSQ-iCh+Ey4mytXRks#*Wu4Q zp0+JkJi%EqWE|}_-fysdG@)wFdGzPSCaoFPqoUbVuFlmK%;h33&m8>5(0j_vfm<1G zc_l5GWl!EdO7I)Bb&DlQ>7{$`G<)*;Al}Hh_qUqvub=Im=$M+#<^(Z~_wO^|^e5ln z4|Y6f3@lE1(fY@4RX85eK>N^7_I-{w%%Xm5VURDMotLBfOWLywNc&QYZt5^g*`wsV z-~`11n!`C0vO77W%p@u1n3x|9rP4nunA^^dR^xVXs49ay)a3Ei)>Q45#c9;?GH=O~ z6lxMPyAZe#;gYw~+rh2g%oj$}VHuJzYzSPk0}!NLhJCxxQui2^Nkb#5W%}|wUQR=w zgVf2%k8XYU*`mf+-oW^g97Fe48Di|)e+Isz06wWG2o>O>9{;aLfK9T* z#B8A>-DP}LZ}}i7YD%ZstK!t`6I#_uoLH-Gc_kTfYUF93^{bpsYv9@QQ!O=&T)ag6 zpr2S0Z5MSby|1?nli!ht~BM7iMq;= zFxNBClcSle$(&-%(K;$Q|P?(@9Zq-1!fQHT(uhD%C~bDmL3vO7n9ENRBj zP3>hL&4`bfjq{B7dg}-cnEFb^v+dWl!9@9)oK6sjN&G!q8Z|FL30+Ca70Q{p-n-)i zbG?+|y?iU~@U{vcCQEb(XK-JqF`CY75AZZA3h5zx;#;R+TgDeut$rD+rSbMR9@ym+ z-$o3ybv2t}l9^S>gy6b|p@)UAzeFQ!HpMeu&Xw@#PK}53*bfv5F&haVNq)u7{a)D# zB4uXDkJ^6islO8hsNgV=jGin?TPNo%?o^wt3#h6IVW|RBztp~3Db+ZAdqMVb1x{Zs zAJ{C(Qn9L8JDN-lo8jNf4R%MYYMF+J00z z5ad@qHBIE}#SD=dL=wV`)}8$}wGX^kV{_x<^BMcW@Ym@UO|8PehEVaS`bpGC>6Eyg zsU-of>4=XLQdsXZGn}dngTOCNj7h_p((M8sLduvU5GKk`5>1>V>LMaA(p^F8Yl7c<#kUy!tjF;0R{NQ9U~Ajp?<-{Uw@g(6G{d4Y&*Dvt=;zF90tTuZI2p)u_2e%>VVE9!t(Rb)cn^v)Z< zoL+&0>mvVSfPYSGVg(jyxW$RKtBiZ9z*ap`;h6Mo%CHo&J3RC5t*`6(eb&f)`Bkp6 z5s9KL{`v(pJjA;Uy&EIm!s3z_A}5(v&G4{g$FFrpZr|;)i#)$+X@Bm8>=4BBT?uW? zP03lhNhjrucRUXYW|P+k-M#r*T^U#oZd4L$e^CC$<@C+~TddEYj}YnnLA>wjKWFbR z>H@&g27NsGPFJev5c2Y~qVdtA$JH1gz&Wg&jr%>KMN#y{s&HC8nRR4Q+aEP=W*|GM~;b{x>Y~a z|JQUYqmxt<@#G0HXT1=H2(mp#B}wt2DOdz#^mDRYZMbJWZ>RPw4_^-sv#i;OVmuJF zRZJUvPVClruY$cv_(Mg6z^^+MrM_%dzvLz-cO=D zj7ou~iF%U<(o;FC7#N~8vle855FA0d3pLEJYr83dwI8lF86{byBA0 zEc&kW4Yw2SKV9S~w7x7F>y6{O^2KHndM_;hmh8E~X2O$c<2BHoph6zY%SP#xe1cnm zWvmC@+;4W;-GZ0BX$-jDqAYe3r)?T6L5T};zM4^2F6CKyx=2F*K!$VS*t(0hwv_-vRS>LENJhR?Kgikpn5xZGNMrD}i)wOUmr@1uUO$36v>|^W zbsl?IdHX6UQ^Lv29meT~Qt*IQ+#zwDn&uS$@neqS`Qv-zV+&lMBam^|pcms&mywcC zZ|3uv5QPfyOuJ-6cm>Q76_8MS?VsrR^v%I#SNnMy#*8%=Vv)S9fX z8j+BX2CDvCv>=enKoOZOzJ~sgM>b?ekYQ3X4VA)!)!IddxXu1DJJCA(pe#LcN3bGc zZa`jnl{f@HHQ|+HeK-Tqosw+E(h*7^)*AOaWp!>Vg<8KEwRWGqcMaSmUY~1LGHz~` zlapNvfb__7Fa<>uTOd zaq(Na^?7o|;KJBv1Ra6XGr{JUw^PlgUyirjyYli!K zDD@N@_Q`+9KuVUVX|KV>!-o%vh06aoX*ztjFrJVqs~1AETN#HOu>`Q@!>xp}Wcj4A^~oTfk^~D5(h}+AIrZEo z0ej#DfUac^Qvz76&*SrWXf;M&T_)1bjC&aI`5jv#R3J^duiO{73slA+?-$jU%34Ow#j5Iha_vF4r%+d{*PvuP4EDBVt<&wMD$kpwbzLdkNfxQ6*jTegX+r z&1jf<;IS@;94w7#IbpDmS;S>|g${i0$^?*#@hE(cBkB>@83UF77Ge& z-Zwd3I)?jPS;LlvQVFsX9iHb5oN!#nT~jjQZZc@Woc)x;zt;~^0%@CWzDU$q-WtmO zTQX9|Rjvi^G9~xyK|;4pBw_upJMK^sRM{Ht1}Jhg|(`s5>Cbvtfjs(B(R}W z`1`Ds%!DS`cG8>ov}xNLYY_9lXBtqq72PY z68UBoG~vVNlptP_Fk}6PU(^2_U*Ej@zc_pEK(@d3ZycqiC{eR!BGiaotM*~dk%8MT>BLO+&E zvpT}xF!dodZW_$f(OONK`(PC;8?dk-)XfX%bGDTJ0Zc^4xN48;AKVjNjSFv( z2?LszzUzgBYEDi|kWEH6<`7o86Fz!G2C$OSTBDp>Xpmn^l7s}Q>u##b`SR#-3n-L> z;lCe(H*~zZ9xY7nKh6mlZQ@hbVn|P#UZBvE0;MTML_L|GNBjz`f za&o%Et1C8cHUk5$Ru;w-lwn+LQna&^rqYI;$19Ii7R@8+Rq^Gr(GRR~Zf}G1HM{$= zq{ShOOyqfr-}98{uYOa0K0;||!9Y7J|C)W~T5NiCeF-+pa&>H=kT?BMZFylS!&?dU zT9|SC*Nvm$UoQE=J~kS)>0P`hHm*?VXI@g@SSy-7An(*Yx4*6^{5cp>xN+fuB@TGI z%Z1n(pVPP{?%jC)ZfUb?0?jY|Y-a~c&R$7=1j2vrmG5R8+k1BR3#-;LTl1n)v$^%B zepOH?oi8NU4T`-ezBRFaz~Z>k6q08lK-Ecj+cq>sOl{Y3*J{jtZIT{2oBas`E3_342&hdq+!jn8Yt9caJ8SL#B}O{>)G_kQNXQIK+ZbW`hMXlDE8 z3<3k`8SNErU67ftmmi?(j<<=nH0{r(0+KF{)t9;e|SP~N&mBDePLl64xFFMtzIQavI?gZuUJyx zqR1K2vH^$t*CcQxhDi0pBbs629`% zWeixJlwTUTRR|RI**!(MRHL*SrBQ+4Tgb!5Nt%cQw3; zE`>{bN(z!ynLl0=L&7#VRqaP*?1+*N05_Ah07s?}JU4;fq!*;h{h{l{@s2&K!j*D= zLIH@A-(c+f7?)C2=XZ#boR7_BpC*6I&wXHfc}@Szg1?NlP6m3(eW`LQSmwE_*Dvg7 zrTIy-cBB7j=Eqx&74df@t<@_AeXqbN(hCAS6Y%5TP(zACU*qnCJTwyASyO72xuj{m z6lsUzUoh4v)%=njO!{R(Kty2|V!tm>e^)%`N71`Nx3JU4gBLpk4fPVzR~K7VCSD-C znxm2Lvj>iZ#>O^}wHl?@6dR8ER=qEZ%DT3p>Kb+hYOmtLEMm^=>d_r~O${%q_dmAb zsiSx&Ix6Tk+8Z4CdpJ|?pq^c+BJMdCLc@3fOkq8 zTS{mju7-PrlsA6Q4xH^gQJM04J#4qx89wR)9Kx$lU4Qcpk9p)$lS`Q zdR_!OW;)dZ;Jw**o*!YR-EnKq)8)IXzZw-kvv!@=80Z~D;U4a^7h zNU)3Ku*S?D|Co8@nBu^qFI&Z0CA@RU2uvz0Vo|-Hr|2!rTBSlIAr^FySeF8iXtvgK zb+kl1;Y_7i;aYLkV~AHXF@9i8ujY+>HaTAl4c^ zW6I~Ice(d{af^xJoH9}7`9AmAY$5i%R^9m6O5hQpfVf(PyzQ}J;wodmaF`fKwt$HZ z&))vyF#lsagRvcbfjR*u-_zlX5SCT7-h)U8AF%IHOLxDDRT)Kh<(tCOUjULkn@tiu zucdLk`y101)f*wPKqy%10CsLBtv;*+9AHxmXj_%*dSi~jNKY}CK*lEFx>CDL7iBpu zS+0kS1q1rL8UwGaM`M~mCAdTe73vOkCFO6}7;cH&#N>7IJmv}O#_AV^xlf|GOV;>Yc+Ca3MA$&VAtH^BXmcr(d=749&&0EZ7_X z4x)A5(oi8y-4+9m*vM&h7ziWAxr#sKGs07K(WYI5c_ob9C^WgB=K9_)*@-CJ;TiQr zeTsiEX2aDof0z!(6(8LZvbWfWqGTJ&QQnFYv#+l&HqzF}C$P>HcL!O-HpP@;2A&&- z@a;2v(KbuK`-}t@CBrhq%>kjJ}9%^1&eMNFYE^2WV;r;2+H*o^2o3o)sRAvuM>BARp_{SSwBB3hQQ z#lN`oXYZ9t-Q5tPbqA+~Om1^Oj?b{3tmyN8+`keDxy(L^&zI7;BZf20S=qb|s?LYR*N=^wNk_C9C{6Pk03g>85IJV03+i9m~^U z3-VZ1U(V1->c`vzcndx!pBk+!E)UWjq7Ovtv5E9sR4hj78OFmCA59U6x-UEEhyy&- z!ExoQtD2U@8wHe_dxDS3Lxk&HWL%64*{?B4ZGw|DNZ82jJsWEqK*OT3@@PF>J z1a8-BUvsWK!(GXri!VN+v}hC^^+=L*iE(~Xl%S_R{Wyraf3mw%xt-~m=+&1lG%5w> z1(uYCd8KbrilJB~L%*5551s`muGBYg%gDcl=QRFkqEV$uz%E(W5)f9V3njD655qGb z-d~r^4K6M5>gYLgJ&0#%OJl3scq?~cXe_iI|eK76V-ad^{4ej(`^(-Xa}_J z`7_X38jk2O3foP2Zd=6q(4+j>?1&k@LFe>$W5#%snM#3x{Nc3Bs}|Y zIuq!bjt74ac$lS!JlfI#-ii*xGoyg@QT$K8urgABfw)N}ZN=O}Rax-eAWVFRmAp*d z5oj17+5>z;ernYkOrq%89}uqag3C`ui!Kf=2*1A7++FKEUt85X#5QsIhBS+%qX1MJ zxtTReV2i)z{zmgf)#B2&^8MOg4PO1C4GUY?>eh6ip!JkxxP)EpO~B`XA7Jz3lEt_H z+%!Kl9a9HhM64dz4rGOt8=}4Xkjix-mxl~pnjbB;>mSwltj&%#uf*Jyj7r4>_sr%j za`O0Y{Tx-8u6$bQVS5EVG&V)niL>>!1sMtcU}-1!Y3$fzsobJ`fp^hIDVUyl-C5h7(KwBf$G z=l5cnL}KFpz@SJ0zs3#8$lNQaI2va(ht6#YDHe-u2oV zEo`P@`nfv#`L?TY(T}lTM=)rNZBjlR_awy|M;b~m%lr{@GUmje6{cca$$h-47K$wePkMD&<7bmp3FB8<9r46#j1Pi(%HLt`7{lahXu1M0y*T8$iFWqcH?mA zQKj=PQ%8=S5_5r#vO!<=y#& z6vAY>I&$qy61NjD?%-LfEpoU9WJ_5D<70r&hu zpXAH5Z5i&Xx@=LylH&H8C|Kx@9j0-(w!)VGX~SKhDJ#EAS>*R63ef{Ap%=`pSjJ4J zC7CW)p1KKP?z!nP3rS5QZSN@_q!BhF>RLkcR~|6prckyzNKA?lqVJo)%7P)Uoe)rT zz+oVYj^@xpU1)YL49yo#r%g-nfZQ#wQ%IRxt+|`#BHeCN!UPt+R2Vaak&8<6fb_5> zyIubj*MPCC{-UKzmpBMhG@O%ryI4oR3}#2?Kd<-{SZ);0ksQn~5SA~7xSEq6`(z4V zSK(jdZZ)k#`tx;r2@zlj*kPrs&z;s?C6rQy3Ep}t#2f)#uR0ajns$Q#s{KTDG| zIG8$lPTjkzG$_SBAyAf+Oe|jqums89oeu7V#;SHo#=(a|1^K2Y($ypblzj%gu8+zi9FU0YT=QK)ZCS4$H9QYt zJ^HLHq_IJ3c87sNh9yff#ofn2*&f0deFA*#h2?p~S}W~aO7u;6M%Bk@}*)RRDlNvPapJf#lI~L zRi?c#R&GEm*E#gQQuq1QeQT4JZ>cv{syk7-nsg{8oEd&i%t4)h#LP-6Oo1W4xrpBp zY@>6PQQba6tGz#3a`O3zik2*BIHWsN5ob)@V#Lw?t2p8v6K+ITd~$}{zktX0?ppD| zEIPBgME6N9Yedzx8)KI@`ugJ@(gRHllJ8ZvZ4U~=A$IoZeSSVsv9+@s5p8WCR_)lK zZFN*>#7bNwjkHKPW}w7Lr$haQGx>BZ0gufXbN5xQz^h(yWsC4AINC)oOMB)TO{Uuf z)5~{Ha&lFwuUqiuglqGBbnsrnesm^t`ZcAvB#cd%qMI_dI=!@@VaU@G{$2 z_%h;!LF@e6P3_jO zGJ>dRDW_J`Xs+>JZ=b;sx)nXG{h@MCo;q~l_>MltgS zDssoQBA%H2IEiS=4cdOf<>Yk`CWUzN%aBBS2{*jzhPWItpSIw7#Y8;+Lw(V?JQZFs znM7UwTsyz*A=C}!K55~gni>zF(3SP5o3*5YxM!rhMf46ILV5@h&Rn*9+4?{sBOOSp zI+ahW>jc~^QVWi=DB!ppmg=0Wnsr0Qu0GiVh4v8q$l2O;c1rm^HwAV3)VvE&vyru+ z6+coxS20rKWi^L6tbf(>iMX%#HMzvEV$m?HV`>pf@P=ODs*~NEi@O`EwcKoFmX4X} z{%<1g*fzOk-s7WZOqo-yDjOAP3fQMha+m^Y+x< z@*@HU*yJ3_XILs?j`_6hIM6b72&-eX2PSPJwhCM37Im?rKZm)tsoW2nAf#an94bw- zyDIwG4s2Os5bimRSSuVFv-;IViXmTZQwnr3A@DdOmrr-7&y#pjz)i4CtXG;UkocRv zB68C|zS=JS!$~SrRzq}+q7^_d3GUX>B<;;UokZSCd-oMLVyP~$W;m2?0zi&X;rL8X z>ATg@nzh>TG=&R_Sir4==$<&i17rPnHQ-(}Yw#$AK`TAZ8BAX3e%yOH>iAa<+aX4i z@9U{~qP2ijcD&s6l&uXAV>Mu$!|Fk3^<(+K6M>${$SNM(-ek%Or-is9Po}HOyASFr zecsktjE4|EsbLYw!L#;gE^yq&bqPv4uBCv>7V^k)r;YQ{JRDx%#%OqDZbHfQ@|@}J z>UtW}`?#w*JlX1MrE@!Sv*ViNnmR65^Jg=VQuxlT;8_PXw<(L5bzykt7;x4VO&4VR z!o<;5oV6jinbOC%1EamC4RY|GSU5x8p@&@YzR@3rpE}MTpyCZNkdZnd-#cvta&>X_ zWQ0dY1wjYqUTMdXy8~C|Hwg@BxG^hx~v#HfN2P+)9)uX-T2JtrXW-Cbhbf6M{mWLn{jF)A-ZeIap$zoCF; zHKz;)QR`u^%XH?!3prdv%mqs9sL3@RsFQt;witOtCi8~7lvXh2X{U=cF&B>qPrpK+knvbA>O3{pHEYnfXJ&@J#3dh-;%K}Aw6bePu~}JM z#GqYxv4p5^#2{TvsY>FGH-Mv0dfU)s(kGW$X#Z8Xout1;QkvhHFq(N1r&X zxdH}ObVGk=Hub18y3=B^Qgfdl@k9u}=x9}bxL&}au@-DZ;XqGi#1$7!>cD+Ah<5SS zSuiH-ev)qaeoQS}n2rv>Hn=gTd0=YiRQA4KcBx5(N+I@r*88lggmmPt>dtqIYXVY* z*vr6jbl$HayIBUJI-%Y%p{nL(O0PWGhD7#C6XM(vqRzE}G$OHl;+rH8XfTEJRb%Bj zjlMM1VJbJcnxvOTs+PELqf6nl69B3xiL32nbPrFttRXM<6)g-5K>As#e4=#?ZsG&; z?er3c(2TBVFf7N!|Bad$ccGJuT)#FvUC^ZOk$#?Lc0r@z;M2!s8$UjIKc&+$pzU$$ z@|KyN6BN_^@Z~G1I6%{ILZmOj%m>z3JhYDD(^gfwD_?H)VpI}?HtoHYFVj&JX};pg zv}=-*%P%!FN&(O`J+0@}HVXW ze^@9hkC10I=e8Zs%AmiAkhi1>OpsKZYYdc??;fS>o~&J9z5ZWrKePLOUmhK~&7=Pn z3VJ&pBC&t}1>vS8{pvnAS6{=KLeW%MYO%F``O?fdg3IBC9dJg^Tq?-ph2fItODxIE z2?d1}layiy0l5s59qXjZ{ibbx0+X-3`U1x4#rozec(K%kE=UDH-NwdPtZD$&za7wF zAQ<1&GfUQOH$fh)4dx5mn&X%HFoE1-9|(hJ89qy<9)E0=^O6*hrmhA?&H}6Ewii8) z)fdAZG4j#@z|uIsK^(VE3923Zy^1XRze<;n!IQCyAn-H)UHeCaOzGA)L_I z_AeJsuRY}p2T3QB95ZEBAd^)~vopAEe#5SX+AKk)cVZs8O9moN6->gPspuE&t9Vi? z`h^x5%7ya4(oowQYxEZGF;L~+EiuNIx-%-(#BotVsEmhz8$rIWeD-MQK31pmTYED) z!q~f|Setaev{5C9U#)9DdYU&r=3MFmnzS-`Sa%@0`|Htber$=xxc-T&V<{RfB6mBf z>8+Kbv-% zYpA#B(zFOb=edn`o;i5!)gkzRMX2DQQXaNxL)dBEORR&-46?58 zHvH~InK>|J(2*?*k2&Fziu0jyf&yTiQ?Kkl65@~dygoj?OCl!1Cp^eU-g7+8fV(K> z@3*n!p`|iRVkp;`|9%V_<6EBE=63)kn|F>UMr94-Dgw;0ZDKe3A5rz)8f!1SWw}^5 z*)1EGQyKcp)N}yvqwQRQ$V1nX;lt}g0tN7q2vMZWy$&KHN(^(I!jVo^L*d)quxJ-o>}&AvR$^+qOBg#nRIID*!wP47ZQX zMgm!kuMXZrQB^y3wI}#MhPqj`HMiesOXq?4Z>Rt-Ju8c=-M@#$KXj**thx$qhScyb zRsywywc(^6ve)Z+)&sZD3gILES}Uwq5JOZ#iurDgrub6ltFj)TEQyr>4nbo|t!jAq zevpb1YgCD&a1d{tDhNSb|8!x?0S)o)z9RJ{QpK%(WMy5&RQF>{acFnNj8p>krnrY- z1kbRlO~p#Ns_IxG;vuMkG2EUNMba_eDbxNf=_+in!}B(f)GU0*?SUn>M$2i+`mI4Bt>K{RmC63^^tMg~!edXQ zIByUTd6oF;iDHI&FQ$i_G?`Gz-(}U^pEe1~NB2ml%2?4Mw3cNEUt{*LL}ys66PLy3 zX#Y~YEWKA~Bybg2ABVhyWr+9BS4ijenVG=!Szt?B)8(Pe;m`8T`W-&SPA2%+!|KhG z%(2KSA0q7^^W8qhZ47=4 zcZcoC`GaD?Qk^`sTOGQKbua1fKfM27for)9~x*E(acx{Uk9WuXwR>5?hg^0yO56Je$ z(c^A#TrTjSK&lU^ltMqZ-bV>NCaiH8Z2EgQGlMwUyHQG6@(eqC3zD1Dj488Le1#^9N`eJ-NY z2X{$Du9L_daAjyTS#^iEK@|7N_%mcNF%pcp{D%H=(qLD0udfXUpl!!qwkv$+hAWt6 zV}CIKbI`YqU54IKceyeYOOg0gnylq4EMo}yW!OAQN5e34p{YU4tBxXAU{viMsd%c- zqe+>)04pIYwzDQe-n_IASL@L<%pV)062Gn;s_ovm(A3oIguqmn*oJrD!W>+woA4uq zB)2K5SfY?c+v6w-aUG-2XJ6{eDVYwtoW?^86EQb0zUtYdn>?o+1KXD(nA#^=QShlJFT7h7@)ZbhqenA= z_Fl8^N^Uhy?*i)h&z}5jNZ3^$N%*-+AQ1S#d0}$Y5)_c$*h+C(`S#$+tCQ)ai;T-d z1)bkSxz4+1?H8#(SEg(>&Ts#EEA^D~d5hBITf*$O|I9Z2*JwTGFd<85d+|Lp={J%5 z*ZGszzlloU$~WoFJ_;wuvHJPSZe7=z*v0qYl!Q}{KQ>pIG|06s+^KAPS@QSJZ!Qn- z|Go34-$bMT8g?ac$s`=p?5mHY|0eo+=iue3%6}QBCXD|#(f$;CLaFDb(aW{Wkjo!0 zj~=e2JBO70c)Rgz>f1}be;s-Ke;oP$J5+GW|8gh^!lD1$xaqUWZ_kejT5(irruomk z=d-M6)}Ots`j@)@|A#J9bo-%r_OIbTMN4}tAM%$%P0#<5JnH1#hQaxP!OJc8f` zTx%pK^EZ)$=V#&J6SD=Sk)PO)m+4(+G`ng9JM8>-8~-7&zS6=Ub|6eu{M-481}d%{ zwkQ#dL}T>mH_`pC1HXwDXpaAAOH4oF+Km=bN=`|{WsV8 z#}0???4`z*X+!JZshP011n$bhqFl^4ZgiZ@SB5m6&(=5V%OxPV%?4Zv>~vkzl{ES{ z!*kdblWv~R^S0}1sTx{Y;jq)=zxdDXxYhI>)wQxXDLfc0jK)lo8+8SGt_~-sdNBg# z1LUFK-iX}P5*smPs7l{|_L}Qga0>U$pvMgMp*-HTLE%qf7d=Ta&Z04Lg^<@Bgq$Qc zBK&djieOa91s?@CHQ+I~{|slD4_R@_=iqPBZsCm=We{OaeY>nIH1ZvD=cnv&k3BAD zl=DIrx#rHb1^m?(y6f+l5veHh{ph1u-1Y{elYL2%P$&iYE6+qi`RYk9!}~tK1lUZQ zXYR_n2ECR8R~(Daj^}l9$8wBpoKG5#9fdfyNb%M|*&c*gwP{Kr!E@njWgs9ZJq?Ot;g?l`$*HqZm9ld+(UuQ{(1(xGwx%W*c)8;%mKnm&h z9o_Wq)wKNNF*_cuF{9vHfkl}MkZjy35_U_>j`gJ`%ph#YE_cQ0%2CJ{SC>0S@*0?^ zpT_9PsHl#5eq146oCy5O=xU2;2eRMj;{MGnfr zE!*~V?75fnxHMm$JXj$pQRGKAK2j6@5~iAcrp>nvQHa6M|; zILae$_RQcTuK!ImsoW;~toYWn<^mx|OOaF9s|eQAiKK;BtcpP2c<|3kdHO%NE(*lW z6n3P&)3lw`ac>BY?Wk`Y!vmTbU7>TzGs|GBX4TN6*qV`7zDbs{%^cvHY6hOtW)Xm7 zS3RC7U47U%YK$;<6I+#}U>;CMapyoQc zm4X$3g716?Kw+r>v!X~Z)A?-ZtChkw%%bxP=w?-Ki+__I++a}^>9n#eRM>(ky7M}E z1%g`Kd;m-)RD9jeJklezC|RAJwGRWj5_o@the&cAK{Xj@pT-#$cMID)VkSm$MyuBZ zt2Sq6GFFG%Ig?Xg`?sz5La2H80FMR&ShN}l8CILpo24M;*q&|zeg&uIb+^*@2&ux! zKCdLkMLCloW?uI42!85n#G|0c7C<>SLG8C=pDxL3)Og3TV;1Yuzc$cjI3`{@3=GiL z+Jhz{s){Dyc;;@^dyqLUzZwDl1^247d})RXjmDjocrCZr0c~PHQ0;L;3B+-WaDY@XYv2nb+Dc{TYL*BEuV%S6wp32RL;Sxz-f)MyU(gX}z09-I5$ zyxXNdO2%xdE*n?w*3?t=4L9hoMI}l)6slE2`;l{Uq`!KIEyWnhr7q3zxwSY1X%C^Y zrT055FioqIefk#da#IZ+|6wd8R@(CV5i^CRs%%B$JR=pRzj#_dk*PWN(1UP3-r0^gjrFhTBfpCExLPU%5hg0*I8O+N5_1=(*M4v6fOV6@PURQ z`HY?Gj8#jdZfPH@C~;k?`yAOByDP&o>Vq4Ju%oc&P?LX6Ilh6nDAU63f~R95HbKC+ z8jXN9*w+Zv`J;_w79%j7nwiIBxgb8c=G)Q7; zXzviGQoxT*#uvYdRKL<~3uUecg}Q_40!}tGZmG(^wM3UDFW}*#$T2y}JMX$m9H92o zv`Dr#!$hBHyeq@;w0XC-2Va40AbX#<<-(0Il|6)`h?dU?kU!TlKQ>ip^`g7lSHl^< zMz;4c7(d-WlA0W3FMb&XI7mvTJLXD6Q8jpSBUHlB`^B#~t4dop|3{2ECEk!a@qyR#uK$^9Zo2^T*d`a!QFG zZ`*nwds=5>2oQ%)1mO3&!-ZfeQ?q?JrHvCl$Qhg7^IP(w?jU>9ObN*> z=`!E%VI_9IYMw>osz{N%XNAZH5x&L0U6`1oz~VaONyLn{$$c%9^keJSEgTY+?KpYK zcX;=N1FWsKF^2a<_1N<@{Io`+eAZl=?+^-YE(490x7>?jOGuI&R#j|tFr^HRNoQ8Q zoptVDEQuKP7~|1!rD9+m2V zNKl@wch+00T4HSvm~0!L#4mLAfMZvjxIsgeN`5|uDCToWNg|2#9}h}HS0S%`u45VE zxSb9Np7v-uoQ7ZQq7e6pN}cNj}m3SBEeQ%n!jpL{E7 z3PKydP-D;MW=49J7By*(LB3?8+|(buap;>tmeM;Grf77rJWSGllDw{zbzEVi`Sa`j z2Y!cgL8|~UUOL-_<{x+{!$v9pN+}?WQ$V=5E2{2Ge!E?M*@kmL_EK>&kyn+?8XY4c zjhA!RMROdU@oN@zT(GM%i9P>mqsEF%ES_XM0cKz>N)`3mFFjhxJ$ofvvd`_~-`9q> zX)vag#wo4G9ydNqk2;@yLHi5^UH{yv8~mw&|3I&xl=s?_8~*I;@&~2W%^$BMcCo2w@TXvxal3y`=i0oQoSv@pIX%`r z_5}U+)Yd7Q-I5qk|Wu*Kg*^nc0B^;5I%>)W{e z^M!(AA80|D1jDDb=xvW3K}9XXc@=3tr@20tJ?#@I4_4>bd{|P-`=p({+Ix5L?d?Cb z`6&FQTFW2mN^K|L;i|;FF4)k>sT1x0O{BI9-M8U9@IO_1@#p@0TKdki`rm6KG}()L z)y~BHm3aO#$6w;{zZ<(dc`yIgFLd6j*EADNp;^z89%_C zivQG9^^dXs(s&xnQHq{1ZLG6PWO(OZ0I0)jzKdaSM*2^CVi*5(rC$;jeyKxlpLL97 z5s*O%rfg3~ejBE!^O&5?4;-~39tP*>|k7rOP=n&U$CKWWv&zB^MuKR-T5yCsQhI**>yC?-tcN- zc^rZ7A$Hw;{oh7)gfoVdy5jDtzKipE(gN$BJ%9Lb{#^91JlG~vg>G1)s@LKkp%381 z+whMCy#H}{EXUhnpU~EH6AG`}(@aY-t$#ZXP3j-^>s9)ksazl+F>Lahr_Nmy)<3WN zZ?2=_{2UCJxND$oHNBS%ds+AI&QY%Q{t(_p04OY#KE~nO*Z=Y8zt-+%moC7yT|P48 z`XM&WsPvCdzWr-sio=#90pE5V6N-+fb-BWvx_t!18p7u^avc7L-=t`jOOA5wDJGUV zi+-9|mJU<^E_)MRK?>%ae@o_ggeH zus-3kTeqpqamzkRTRQLHC)j-R|N3oFNDsUj(sk?lruZ>f?^h;ZG?8^J*ojaa`M$orBSM%`)>m5-t=cL~4_LD4~{s zjh<@lR~gXaEFic)azEu4-^sPEW-lCi=Wtv<^^O;z7okC`-b|pJ5UVRLHlLE5)LpSH z_}HT?TuqW1@80T9>hSg$6dLQxDIy*omUJfj9HzqYRmuuKr=6c9d*G=g<)!0)gLuolzYyuwPuHw7sns;YlE ztinQb#D&l{j}nb+5L^g_(4R7jU@;okG5@(rp%iN; z_^e;6qi}UZX`G;KZ7eraHjP1{!w2`u&;k_{3bP4c!p1dCzvlUHEk{yFa||KQVZ?q} z!LD28N$hg^<)@#c)GI2V4<3dIbpenfZh)%cs8QRKHF7)Kz{6Jh5<49~!>w>MpmX>~ z&5vJ*m>BQDAmaA#z3_AC(OI{AKWozD^4=*xgxfF951F^zR7A=xWL`2pPCVE15vb!(}r zh7pRKP_q)z7n@F1&hT7n4h>X(zBAHKGu+@|Qs&rq2q9efqwB?woCO9X<52Cx}!{p!N1 zb{|7d0`r`fe3I{%!_<6la@s7@xlQz{lB@_eGv`$TrBl`T(%M}US7ywQKtt^&4kiu? zV~O3QLf-={pttEp%qZN$Wnt|%k572YO-p#=7EuUd_IJU}?>%)#d5f6HZE4xUq-D|p z>cpH9sX7}^YHw$E}LvWyk&oRd|H>Y|^%C16DRxORtk z+9Fm=@81)xH6jOC3&vMywBL|tES`QGBMwSgqoE1A&0q{AQ5Phz zd#t87XaODQR_mV&JdaYH<(f_Xu#7l8Rmt+PXD%-;j|&g*>4b>PD4$y>)Si*tEf&B< zD!Oqe_nm<+Bi{2lYg(3E*U=mzX_VMJg_PLOJ=nYNOaTR2&U(CIMiukMX6kq}3Ens+ zF{2zXZW+^OY8nKlRLc%`W-qOF{Xt38}+s6!@|AjJGb*E!>Vq&iRR;^#vsg5ch<3 zz}pcr5OC2gi88poCc?+6PUIfIL9&b2!hr=!ZeUaZg8I@;qXFLt`NRz0dzvs1uT^lg zpY8kA%8`=q@3pSNCgJzi^$OS*9{QDGda+e4ISa0McwC%%`&0w7QSxG~VSPb7+g9@0))6RxoO`m)fg!Q3 zmQYjNN=odlPMrbGl76Sjk7qIJ5^7T$NE?}g<2jRSHCR-ryuX<-nI0)jdAoMFUe$>S z4hfH0m_$kkTl;iwbPOBcd9X#KJE?Kv*@^ zMDB_dB`W2RxK_+>`F|d41&O1Q;Vx9~`H4_IA+1@T>fiI~f=q~O_()6T^Pcr}ZO!e@ zhILlbq~g`|Zw~-gHy6vg!iPnJ#XN7~ zR*0Q8Ni4wdcc70o4ztY;Zqp{gVk8&r`8KRx*35A@zrz!TeB!jZIRerKw-6Yl=oI4` zB2FWr(+K*@--Jo*d`uKBw4m{h?Ovq_wk0 z+v2A$YLYVQ8uA!RRjKW}u~U6w`r5|{HB)i+nyj(HH|}9|_&35z>F#>-OM#a#Li1Nu zL=S98Rn>*!!1Bdmzlqk(tUyw$oSsln$DK>P+w0^X?mdbXCy~)#6v~@ZsOXV4y3MWQ zG~hjr;oI@zI1f%zb^~xF8TC7M3TKLjES=s>yt$u2#*KS zqxEiyAvO^TZ&)ll1dXd}uS}6oS*NS>|0arf*v*p~3qNais-YGnKrkYvsU{F>^!l2J zTd$Ib4_=L#Jzk#uUJ$Ixco)7RD+DLoBk7%sK;GA*a(of!CPlR4>V4Wc%3b9e|{bQ1zA&$>&#MAyq} zT1`W5p6Eb<2Jz<$Q-2~Imqi+Fdp2R47x_dyyY`v=cWh#IyD4OV2!1kPW+{B+4~0>VmQp3t7p zMKQBhjfW?V<<(`CJKk@8p%ym?r8~B9a$xmnozHt4rmxAd#jIo7g4Ab*JbjZZ8jM?W zU_g@6*aP}-18L`aItYsOtj_V1Dn`eZMr2GK@p2}V?(s!2YZf6OFBR|UZ2l-Dy)BQd zFH2;xT%`2MfrfHQ4}ttbCw-LR>rKC*P9iDzg^9KurUc?^z2GsNMggw%z%5>U2R585 zPABr)|0Xgv79tcqw-o1()w+BCROixgf_f-b2iG2PJijls>73Ev@$&lC{`C+L;?thh zrpq*;&aQU}z(VD9o8+R$B~6>hzk>`po%6xG9M)_?Ev7C0nLI7~#wZfa3I!KV2Fcr9 z`z|N7J5ySMk=eMF2iKM5X5Q~sFmGKf;(?j35+$pM@tt87=k<7uGv0gGYP(Ab+sHK{ z^VE3f7Q|SHbXQ3junuX<@x}bT)^F%Z^o_`xdU8%1-*V@@8wQN%fR({uz#P!i_EeD{ z$~&rUT-`^G95!O&aBa*H6E|nOVGG#yKVz(>YWqJNor^!y|Ns6Y$~kkK95P1Er^+Gp zb{HE|%-I~u9CDh&+-{z(eN1U%H{gmC{H_UCk2JTlRU>S4EU}V}EXx5yw+iS=uFi+0 zOd97IMBZBbsSs2Os;tWkFo9eWj1+RFQv$v+{Uj|I5wR`ER}QBH-=Elv1CHE&$ZI>* ziMORaxl9_@i`0mAvWI!WFUx7=@Fn;Cq-?V4a~-X&Xc5PmdKXJuvd;|oo4rV1aI|}5 z;~+wn`z}1z^C?un#=$S6ny9qr-S*>L*~jd5Vm(SKhaggDE%CT36ly4@ovFOhhGG8r zeY5F&TH0;7wq1#Lu4VV6{spzc2VBb|GNLU#X8Y7a*0oTb-3YC zua_mS&WRac063v<_lEWIu|8oIHPdKQCk4x?*7eQ?z6k5tc4BqP@CTtb^v0oKlXr81 zKfX;m0912v5vJz{TwKJla()0jQ+`~&aHgehE&DL~K>r2mZ=K4htejk2az;$(SBvVJ z#;hvCtZ9uZ4Vg@_xyd=sKV*ICr!G?7uNNE)X<2A`x`De9cYVj$Ly}K zRPy{gbwp5Qc?UqM<=FR{`ZqVhD$Jh22-w1{fL#Io`=9&d*zI zL{?oe-TvM?FWvVnNG0@p8E1bQ^<8L?`D}^`;RrLtv#%O6LOwe{fr14K*vJIN`LwI& z&9lnovX->9F9d&$Dw^wdU9`l(2H)GcIa|v64}e7Od7R&+N8GTe&4ObyQ+j)5YBHTB z+LX8=wU)nL+FNRn7n+c|Wgf72`|NMAt5;T?d}_EfBxECKL(dkoK8_F)kdUkhLXynUzn9LOU*!_QRS@us7^HJrvJmZUna^^+##e}rw z`3&zbv`DHIUx*Gjc4yQV{ZBF41p%@NM~r$lkqEojX!XZ4T%AO|AD-<}6(0KGZoB0J zY3OEzR87e`IVgy0wNVy}SuTRMbuU<{s655#NIxF@#Q5Tpr|pt%t?w`r;%i1Lf@b}D zX^neF3$m);1L*JP7rK9=-SNIlH0-E7F4VK9V7vC|OP{8DqpP9$BA+|(_eBXYW)?Td-{ZR*4RuYC^y zzw4euru|L5tdk3s_N!VXB`*m{05ftFeh~ClOco!qf9+Vb)BQ6Fyh=D-)bGUZ{p#$b z5XhMXJLM-3dKlFtGU{8_tV7QllTS@wfgl-#>6hB>d;6qXP%k)Jcp4&C{f zF%Z|OubsyY6ji^thGc&e9f5J{_u27yx7cclDxCLobUp?UTin&;?K9)P(M;owhf&wJ50pmAt2O0IksHFDm`y5JQ$#^|*q*OTjEZ6I_HIV8TgM`+o`jxm z%^#Z_rEh2k=_w%Z$vTXhMdwhR3wPXdf*Q@u#oqa0QJqcIpI$aS)>ikOp891pBM5UY z`gZu+X*H8D0!OUdiw@f9FQ=r^S=T?Sw5(H^DVEF4_D4jNZ`$<>7YGFaM_Y<^hn$+k zr=is5qGI;x{a^Z2cLP3Bhk5$~BSxC8t>aR89(Oe&$(|`GnzH16&e|zDL|5-oWj=b0 zm3Xt?q$)_=mdy}tdGfe*X36ceRh%QzE#jimIK23|i4{W4{(g2~VFD{GR*2TN1c&GA zi}oLX8u+1T4Yj*?lfN=xQi`khzu9fb6n@^GU@QG}!6PwC2@GJ4wCX7HU1i`vQu&nt zJ`yk^(nDbaH}0&Ft(+mQ2iQ3g%SazOG1cH?ikOs$5#ey2j*B_J4r{EP?rs>)4ai&1lYBP;BO(vkXIS z0t7|0N?;1!^7oeku3XmcvwI&M!=j>0TPi<0j~(qg_aTE?We;4IN(LS$z-lnc>;Vja zi2E`1T9!bPwUol7&~2$|u2MBCJAf!vA^6ejrA$dnXUwiJUC!-S8oAj5do*0Kc-l$$n91qVUBU z?~C`SRN}`Uy)f~|Cc(X4&1*cKPYwxUPbM^!&VOL*ZF>l7^{@yioPn_oe{5&ZENEpBsNxrSF#*%gw;#xLB1dOA-T(!r)}?>kE7EA6yMG0>%2Ae&2#%UuTv1r%uN#@{Zjp(2rYw@qU`e=u3XTyoOM){oim4+_qvi|C;kNl zTCyPxFV(dpGCvVFsrXEvmz&Pi{8dRaVL2vtLua6@^aEDNemG*JC~c-^S|h}`A;RCR z3`sOQtwt;PqW?#zCTHF(a!6tc!Qj5sI4(k5T6`HczhDp(w7m9p z;00IP5GV&GcdfPS__3h37|v)Vq`Q=*MMu!Mfy=?4Lk~qP^~q_!Lc1~;J@bjoO26~b z$uLW8OEUo%?XMAHL!4fVm~Uc~+qhtk4&Ps{yDRFOh+xs{wurUgT0p;^MY`D%ecKn+ zZg<0v#jjEvElYu>r2Q`aL2j{wcwbJ7vq~?0)VwY7j4wo_Mli!;$v-di@m@v??zvpa zRUb{m*8#`R(F~R|6TyG@)58pdc_RGIkx8ZW+`MIL6sm7^aEh z@)oaSTFMt^;B-Nq81Cvkzo_T=NsxD$_X?wm4OXAkDB_TwIaXkum;6seSoZTqsIAn$ zyVf6-7GsboUqW?o^ZEycx0|$J5xN-eIk~$Rw>N@RPe4mUeB~9E%U3i#^AC|)7 ziaM`yb40>8OJ&4mYa=*j9Jz=d%{1ow+0FKbzKy+5bS;8q92xalAUxRR*8jy)k(@lmy+X84I6RLT&v;2tR0?L#}wmkw~Xh$2nGB>!AStC4zRztcFi zX8@+H+|b)>RxRG&|Euu}S#t87*8X(|#fjEJ*_=M6WV+;jhf*@LG#@cY!hGZAMXjO3 zE0WW%13SZMkHm7I_ouM#$+8V49DXbbTAx`2@^=eXY!@WB z41+lf!^QWIabl{ZEH@4q)^hK4{Gubd&oH*FAXQ=Zt8~k6_kN4J^kcwVhjMBP`1P!( zbqKRL&(~yit*4oC?d59$@PlLSKvG)R8xCQ# zg4*k?PUQUgd{>AiqH9Fbwqa^pWs!Z@)%xf0wa6%jYXe-mAZMdTZiM~YkLDxddD$we|ikjNdYLqI@9QdphT?vsvppv#&Ggc#Tj0{=;yq2REA*uq!Ki zJNMZ!4>mNMc&@iT$1LtT=f~VUu+!K-g4T7S1@Zy;J1+kyFnvVJI(q%36v3{eYi2VidCy{qD&4(Xy~R7$*r;XU=ZM zyt#0g$&loeNz=>P?^L9A{T_;QL|&N)Ys^qzNSrp!2mY>0_IMb26ncd4{x!xHwhZCz z&hgugM8Y0oR0Ubhf%A_zS0U%W_N5K((IvUTT%;a*;6Sg%(5}t(lK6?BX-9kh12lJ^ z;bMHuIrVQ9)9ocX9cJak0F`q^DD`3W?*ri-1)J+DV#Ef<49DVqk_9yW2Ox2^)F*Xur5MCDA2y+2Ya#Q5165WM4W*z)YVB1&KDg_s zC-gov+90sHqG``%(AcW=Yrd?w_*mz5qbmQ%Q6J z{L9aZEHmN*$au#f_@_Zc>&&BrM#t--&kLxaiA_!O)l7{Uvs^R%W8H81jMAxpM3d>! znGvZ9J#N33LoC%RNX2N)@5E@~RIkmbqEMjqC8@4hcq#Kirb!T(xELn=Bfbt?Cq~ri z9O`By8O(VFvR7F0;jb@eeC4kmog*ke3)NXD&Y=}oNDp`>mg0sI?v=HU~)@C z`8~vXuYf;U1}asmy^Dhx2PIh)>xY1Rh}F+7{KssPXfg05l1FokERD(!xL=e z+A|cT>$#31xp6!-2*nwFMuSGEDhr|V^n#vrDsdaVg&eYyDzkvmsqhWwa{yUywVFSAGY@)J zLf(&HIF&C@ZjMx%xR>wrEr;U$*ga!3m+i!3CVfw>U*I~D_2rE`cTy*kF}Zj@i>@~R ze4|(E=-=9zJrrHxup$rjd17OzE`IC|P4X%5UEG=JZO7zjDD|&(uD#m)fifbLC2w%p zBo1@QcNpFCg=-Q(#QtmV;nywd$y5klE%B?bG*;v`y z2ba)^md0>3F;bWyc9$e96kJnEaGzQZhP)AZXzl!K?4);lAdyLh-X)%};(*BdMxl5^E_IdWQlW!HN(f1{X27RR?VU^Ytfj1a-2 zDL8fne}8sg2J=?XKGUz2XfC%T->v>Z1*N*HPXb)rmV2KZFIKN$6v}R&;i(*1@Xmvw zicp+R3t0)>X^P$^R^GgAA3m;adHEnS`{CHji$hIf>E^$n`Bv@Ow?$vK8WuPIRC{xy z3RQBcu`T_!>bKtZbWSp0dSsmwp=R(7jgsC?J~5m&U|)DMY7w3t#9C@9UryP_mO=D@ zzhk20c+J5D?3O;QTB?|Ditf&?=8`53Vs8R2DlE$F{1&_1F2)8m$Z(^7xK@5dL_-LD z?FhoCylCe=nf#GqUlopF(^!&Z^Y^HzCY9zZj<*qkTsb+e8}jpi+?H=Y7-rA}MpH=Y zMS3z{QL}3Vs|Sz-qs~}_$|r?fcM$`3sQQYu*WiB?qSV6kHRb#x9BqOgD* z966T*1ws_Ge)jX;%{(CGUX4!zl+VbiA=mYLz;(j zmAR_8zJbyBU%9u@R&`6(pf4>Z=W-XW{~XehkJ zWAw^VGPpgbnA=kPmUEVx$=@x`tq3d!Wl5~7#hu=0<8aw-P|=epekYRVOfI+j#bqtO zf%4dOK`va53`zUc1&haTF7;@GylpR2F}{UL%l)*|R@jl;8>|{w!DkAE{;CPCRWtT0 zU>6U_uacGZ_UrjU$~QcfZJju4#1mZ$YcM0jeSQ1|joOP*gMZWyo3nyib_0EKS9_)2 zRZZAxb7e^I_f0ZXZ`s%?TiOZ!*7&(f6r8&*ZA{5eFvS+x^!(%YpVOVF=|Yu!TC!O` z4nZ!Nvqn~zmo~wp_;WyvCqt3rrhq>U?i~)ID02<1|Ko+H?ll#**o2_S6<4ElaSNV)N6K!;HE{WVRcIMY7=|+?e@n+IIuoCM-z)vuZhL$=3 zmO>9cWi3_2d98f4E=jsNe02af100EL2_F(r(fQsfk_Wwzw_*`~IrRGS7ncmD3zG=j z7Fmfi>OXTrS;>KX-$n;>CkH1I^`)hKVQ}P!zc$6%3QotFX6CmddfSsW=_Eo`O$n>` z7;^W%VGg;S;~!$}cpXLg*UqbUr_$oGudfC7FiSkO2Sw6J2jMay1~;=?oUhZKm5@)( zh;#G#8o2$|KdQGMDKKpnmILt*u9@R`+9Yp#!^9);*2c7SB)>1!F#wi}_)1!|Kr9Kh=*e?RwFNp(V6%QWhT@q(MRBvkTD^xnH zaI^%oN=}-*73MplmSe3Z9G+UJp3L=}*WcYRp(&Krft1TA*guF{-rxNbg(SdhGLAf6 zs`u*T)&7x{kjwe7?mupJk~X6xzR)D^blP~vD8&(aR@>jK-65BZY_=h-WOdCXopJPrw)E>#VP7&HWvA|SQ7Y{72Ahhq-NwWW1M)m7 z#5PRcH{v2s23UQp=QooU$OeylNXP%y=i4G?`;|T%K7H=|1vOk%HMMnNiP3*k)4}Tp zBF#WSHE^W0j}h;?55y^Pbx;7dAF~sgE$FBCw>*C(bGcTPvhgt2=IEKK?Yix@8!r%n zAYjAU(a)Gq?=*2A(W<@kdr1c8S&&TPEe*rM#|skIflPle*hAeE}90<-TfHJ)V%>=NAPt3-#0Uh`x2j4-o-mAE3n3Me$s-X8Wj6+^Zt?Z zb;MhTVu5+yl%g1<>(xvbcjcK`sdZ^1yGP1wT6A3&uF0h)SQ7N8Mrjl+%ol#&u%A3| zp@3@72`LmNLenF?znDCq%H(vqmHk-pT4U{ym>UkGOMQjCE!}40!Y$Y#x9wO0e5bRX zwKKn%I==ak+bTjEsrxNaSk~>CTqYILLPvRyQhu=zy%`v2hF0#lLr!3@Q9}URtowMc ztGYS@E}dc;7PRv+Y=HN?wd-esZBeqSxM)XxZnxPq6m;&3Nw4v6rGx% zz(o>PCCOi;yYJrbWBFt}a^Y~|MyFO2B02$-S*2>;c$EOt4>=I9r(>0{7Sd1R#B_5A z%;>@h?npV&KWm%;S>tDu)Grr^V@Kr!_dA<5P5GnJt#yu5niN=iv?IcP1n3#qaZd7F zU@x%%sz~r=1v?n%-NJrTkh7mPl5rPC3T0# z%nOr82+K@Q&W9TAiRsR3gt)jD#sR>Hf6v4Rko+-6tkatl%p3WnVOxoFg88$GZjpF0 zDz<8O&b8Hj!Q$cSL#U?8nYHno2{_J0gX|Re7ZdkY&5{SXmL1a@Cev?!mDUCoG`nf1mv!>;32#UURjmm@i2sH#1{s?vG<#4I@I7^ile~ zHT(JW+9DVS%>B_aoi#lMZ7d4*^-=slbk+HTYS8I}YNN8Ni_C|Cqbl;O3wAdpOD2mq zsFb^&6~4$?O}s78$I1a_nFHG7rD>s~@cS1;iHkiV1V-8yP!rl{NQf#*sPmkd^y?+cSRF~iQivPz^2sQ5UN@0SfXE7r$SbgkVkyyo`orFcF)R&em06Kt!}&EXdCKY9*#BtIiw z7Ng3!V3^k)Z(*F3ECU0h71RvyfN<%rFO#2IOG>c!(z#&fw?D%YMk4>4YJ*)F5V;>@ zw5O*P?v@*I`i2iUZ`~-`aY@b3^U9$rQByK8B zdbOzU;B6pphA0}hai5RFAy=xPAyenH@gj+5hvHK^PV+qs7p<1m71I>snR3hMm|{g# zR(qpm@&*3|*5Ux?|I^h}*fR<}aYii>IkLwN_$g^FqKz;Jz+Vo~tHR|kZU6%1DHTwY zn(WG)XtE>W%%Rxt>hC^0UGa0Fck}7J!4fikKFAzdamt&v$>q+h{)myC|H8EtMAA-4 z$-Y#Uu={Ura&MMlimej5Xk+}Yu~YX&QP(f8c>d5n1Iv0km1%A~ z88t+0z`9YyeaSop`5K8YzVEo!+Ufi6!zxuu)y)-50o($i{&Gug-$1$fySZ}P6B5gP zRz345-`t>j<&nz?K5VE$O%@m8?acUj|MI%}(G(37N`ukyV*vX2z6CjcEQr@nX`}P7 zydX|)j`NbW)?)rrb8yVJugIFpoW3VY`}o!6Cpd%E^f9J;?SBU09c(*pIEvE9pYjhq zdljPOE7#7#Blt=49IoZODy8xz-rQ$zkIk>lk&)TFz6UtrZv5TzJHxk^FmW!{6CdBo_m#3IY7el zKtHc>%5T3c@me7)?gOZ2e^-eH+x&8?hFm1S-uXelp~*e?{8eQ9J4-gXT-j9*{ijM} zK`<1~FfQcd`*iy`pwBx|s>{vden)<7?IA_PclFlC$R6Y-7N+sReShx)Zr%MVv!-Uo z#_wXOvYMh83w_aqcfuI0nJO{u3+9){$9uG9G3KI>0nsV}J^fhE_nZaSA0bXmFA33| zN5Wchb61WKuWxFld}_u1>i56>p)yMC^128Wk(m6GcM9u}MX4fZRp2M#F{NB1XNP2X zbSCawzVhBDM2Gqi{>@Q0C^iGYIw8!fP-l#GoO4{h~MuS6-CYw9Z zxW_negGjgHUY46_;>H;lIJz@brk|lLIOpgv;3Ody=uvvECg_pV4bj6^F?7XxTfcO$ z8Z$%w^z?5f`Edg`M&xSwz)eFJH%b+7Ro~h?zft3lV?9PFdvvr_P!}pBr5_p<;6f57 zcBSaNIvv1t3qMvP?*vxjq2^CY>{*Tt86FdNYx_Q<<55?Sv)vpsf=&*ZwSl5bLrZ_I zsZ5dWcJEZrafX)}Ku)@%s-{NxEsWLjQd_zCdo|%vmAlnxU7H^zLYbzmJ(KSmnjQ!H zZ=J_($xE0tvr87GxApYSzakqNFBgQSb{q=Hx+VZBI)lX@zP?@(^yvR8Mc0s7 zl7>nfMb-llV8jm#GogxCd9s%h+ma;-x2m1TEf*mJl0j*ORx-&uMV$cpQX)&6u{%-=52Nnx3f4Pj1wR6;4jN%Y6Q>!4Ey&XOr{!f7`n5nZz$ccYS-qmrrM6#%7T*L~ zt5z^TiY>G1!LHME<9q~lBr1wrKY>0bM>V0$-bwid{HlEg@ABkGm14VLqWvqYtET{^ zG6uC}J>|IK4Y6M@9&c%fTBJl?=lB=ScX#3FUYS@6_%g`E#eSr9B>TY=R!}OQSH$<2 zP{h12(Gq>{f;IW+@WO%w(jt64LdNhnu?{(p%@O^`RR0rCP+K$yXsPv5gt+MbIGdqX z9myhicIUf?0b|E`+!-TfGdU%nDn`(iPCu zp`bI8x`ljkJqMwzScPH&EWJ#pD?9jP$_(s_Sky(y$XxV2HOtZI26}sD=b})?^8I}Cw>qldzB=93b8LOjYxZf-6Q}xf@DahM^{4C@=H!J4kNtnXO(MLLdeO$dXFjUpmG9M^*Z0kb z;3v}KzunVQd?P-U4GiF$LQR%$7O@(W`2 zd>itAMvpvcA{-`>0`9#Q)BhWOqizpj@-xDS4azO|v+&%+UE6{Cyz zhEwNuv5q-4j-dK|mWnBtx*)JV-_vA<5N-bY$HgcrmxrR1S9;&ds_- zgx`|e=vg>>c0dIWPBBOOhxGf6Uz^Je-d4Ftti$OKmvhk<__~OOr3vAOI-i5DI>q{= zP_ZP{2ho#4W5zaVw==y!_c9;I$w3SfQva&jaXc9tUK#y% z9N{baF{=tW*oLm@jJdDB=f4*M2z)B`Zq(2)ZTVj(5_H2%3ACTIk?+cJb>y72dP2yW zJVi1E_olGUt*d9L?7K^e&(*qdjz;z+-Gk7jmMNyIFVkTmATN(MCniRX5|n%OX`YyJ2SoJpj&?h{Hdwqh6;J@c5ZA(PU5iGU8 zN4SM7x&s5(@}KTkcJPLxWaPixKY9um5~gaWEh^`IKp8&YvOF(w$<-bJyiYJ@MV#KZ z5R$czA-&g9cx^xXfQ*KR0@(!C{BnNjhxqJcI{9957Bzru1zv?3QUAd34c#hkD610w z^7)T@3XLvx;%j_w#lGSgx^@1w`e{1s>NIrCVHnbxA!GXyB(b}(<&MLsLlo3I9}Ox* z0)ORTld02voj{{$tPKX9TEC;7|bfF#-6_OGrgb#3cQK!Pmh?yD2sZprHTd~jT zyWM^c!Q7k&V$3(}>&H!Ypt$IZ`F^2O$1k`*Swf2dQ$^IcnPG|UaZH7Lt$sZ$>3Yrg z8I9Ad{SgV2UwXr} zsMEt}90vtHysjAR!#dzbn%H+tK!TXw*0|_mlNR7^Aho$m-Me?8+cm96zppHGZJqiO z_1SmsrbP}@3tkjMAnf&WkaylW3Zm83o}zxi+gXi9b>5ZnNJDnGc|C(t^pg*7c7-k6 z5vF4?K65Tm#my^-goEoQTrb=l?X}kNQguAkhFlWqPQ#ouEj71WG$P3{Y|=R)2VqCK zG~3p~)$)(v`Xh zQSj^wl@>wB!3O96C= z5Ql?3?J+RGC&aqr=GFMLCtXC}M*W8zch4=hXV^;cMWQ>vw6NBCOO-L7kdL2-cRm&1 z``DZcLfSG6vGEPW9FY&z+45V-@b@y}MFJfvr|3*Ve& zC113jwE#^i)N4H<`YIO~9Z3e&qr2d$=cN8?g4dCi6)Nkbi=i5mpN}5<;hw&>C1Lnn zv^w+z#6I-MFFKXLwiJQ26ET~6$8t0FAK@TRtv$&wz`(b|MpjFM6KP`~Uq!GiUo0~= zw!%@Mw(T{wKmnU|Y>Rk;j$^w6;>{S`+?Q1HRxx7lz8b^snG>97z|rwI=f32V`stuM zM9L9x*!P3t@aW2ny*j#J2cc%QKsHaHC(eW%;8)rv^ z336bffCJ;CwH%82R@Gt-&Sh-j)Lz(@{v6=TbK8V~r8e^fF6>l1ySyS2)r1)0UytAs zW2x*nouqQzj|f^n5$t>P2XC(h=WsI5>gnhSI{ep*YZZwx$Uadbog-tlvi(jYAM}>Y za?XdFprx=73$~L{-uK$~)>uW1RFArxzA=%rY!eH1yuB8TmE_dJx1JInn)6>8a~6{tG}9&|CmM#X9yTKCx1_w8JIBMHUKsEE zT_nz_id08AxjdGpN+7)znpzsF>udh+)Y(j5_7i7U)>^;eFZl5HrL73X?L$_h;TrfY z(q53d?vqlU>W%x;o$~y{U*DCnSAMa#yp2f2Q(m9E?6 zxWvC?!6u`KAPCsbZJEr#28~NYJK2^GWszjN8AQgzkk8qNnDB_Nw-2wfmX6*pl)*wB zS|O69(%X*mMGA6QSVs#neEUKT`@H2rzRs?0wD70-nM+5vC}Z`wM}1{U#4Y=t&kP*O zH+|9+!Bv)Pr$x`gSm$s{pFAFN&xB0qnRKo}4Xp z5ATS`spzgHz-20b>s6pLkKY4ACbt_k+fO5fay+G<{+a)$#9e=@EaaO1kifqkXO!|p zC9+C_gUscJX(ykJ5Y}^esyr4CjCR*v$b1+yFP~Meq$u0zFQ9 zLVm3R0zIas!1`sVH?F6?is2xQ>ggf1NQl^BIo+H`<6ykxu8>sqvL{SFOHU_H!zw{x z<$)4Y2~$vQ93TQ&?NGft?H}3O&yjM&LGV%4Ekpb>4#8m!ZNj9BY;CZ^#Jx_4#iab( zFLs(DrAn|~-92ZO>3Qvfj_+V}$?yKKvKKxph<_R;FNb~kL&I4Au#p1xF@^5942}fz z0uk?Q8vP-KYk6VoC`Ump4*%2F4iLFce;_mUca6`L>p(VF2*Ws3wICvtaF*-4|D9n) zoQ02HkW))O%XqLDQ*09-O}OuQRr9$?~LFM=U-nT zx2y{YaS?Jjx=sUsG_s7XVrM~WZ~YT%n^+ZHe3x!Y4T5!eeS6>hg-eUci*v$c_l%lcu9-F_ioaDn(=rVxAas+GO= zMre)BR6&wLv`cRquNwW=+@S^`h-nX^>mk**IySBws@gY{YSU$%@uJUSL>tX7mpdY; z7U=3v*L7ILi8D~LRb(*{PzY)HgD|Iymn;%`0Nl;hnh*Jcrfn0P2k znlxw3ZQcgrR>85(gpo%- zV^EDY5TCXEUy$c-I?x5ZjBd^WRZG^5rkF+H6CEbKwqb3wzwgne1E^jN+HnKi2GFSf zpB3F8Eke5PqIxyfsjf&)x@*)K(@(B=6;jc!vY_7u9Dj=t=k1>Q<5yMyz=Yc9Y}3is#>VmBMh@}V({l;QfH_BIEbya z+u4fhGZvE}@j98of9iSqOLmIZkp ztwPE~8iuHkd$2%GrH&=nZiCYDsg)B)&sTN|TKrZYtrH--AgR|MS9@6Q^r@_w%+(LZ zuoN9L%vfweh1)$P${Va>Ts?hTz61Jm?+&_91;p)>X*mrTI+wKQL?@FZx&7N9U4<<^ zRaEfI5OB$;+4*NnRQq+pyyb6gESz|q9@5h=cH^_tb0IopB>Sw)x*}XyJReQ!yll?O ziN8w&{@pnLb-dlem2=R<{BXgR9&nvf5$;g1rm5e1(yNW8nrQx@%vw|SBYt>{&JjORHIX7 z*|2t}e~4Ruh@iI3kv*SjemZ;a^rorqbUiGj$Mhez3*W<;YeNzg9mIHO&KvK3Gxe(Y z-w|fux1q_SL9TLeU;E*q<}tKXd7Y3qYdUIS8Cbvh(@&wNn<(x{EGsxlA4fUa8uXNk# zeGfW?->Pu$Q#!vgw_wM)^~X;0cc-i&jO}+F@UGJNosK#lSAMErVaZ;#Okxvr=g2~V zlY>Y#@T-$~TjBEm$H<`psElrOoC|bB{K``G12ry6?&+2FBRfFGE0+OnGmp2>-Y@QW z3^KPDEig%zjP%%llYQv~`a{im<6ZZl&MWr-y;a25PUe#18tPf3=T?+ZHLsl%k(FaN z5h=d+xLUmJMoGi8&`qfBh|EA3`*CZ1d!#2ixnsJA27S7RT|0lClr_V?B=lcw?zgQ# zuWbMFh6-uPQ;1&@o>I_PXN%kljhu2U(+ECYU;_F>%srg8{rRTaLJ@Ck$XV$LBj2Tj z$7;;#8Wn6ki>?FUCc2-cY`dmWNZ!(T_8=6UE3d6iwp(aHphw_GB5}>FFRpn*>G zn`DL}AIrN@fG!FyQ$GdGjqyKZ)z^5+^o zmtpeCW&2r<2ul$mdH<%Eqiv}gd*;HpTe~lxjv559p3M1b$=C~qb#49y|mudsl$tS^B`_; zya)AY#q&ulw-|YJF9sTS%ER@a_u>dMV zi3b#PRqMix*is zJom;zG$T$NGb^87>esSB>nlqCAzSj_sj)lHdcKNrrFw!K!x3ZZTDuxKsZG04*Z$|I zZ%Dl{fG*_59Qb@e4(8khadzXA4`kD<9Sp!ic@yv=-0sg4W4>0gHC1p{l|e;e?!0(! z4DGR+lPyd7x8LOfx8vmi!MRp-?Kve?DBk_V7B{Cl!SC$?5E%qThP;a9yO$_hZnWT`<&gy>D=J6d)s}=$&$r7N zDi41Z@K`Bt>8xYOHlxT`Hlyi8ap3qZAmxSEu8j z?y;wjgU3?Gl9`6?i5tO*;HQ+BhuuYchpR8UPY12@7A@L%*{XR!(k1V4sUybyfEnwG zuR=B695ppO#=BY09SIf#xFBxH$?+o0ZgR(f6vk>@2x4z4m1bk(X~EJ<&;93wkhPZQ zFRNB4zFlSoGIf*6eN^R*HKI|&KP9V0gSyr?t;;9?jh7*HES z7FoY_Hn~(cIM(wwf-4AotF~`VQp#Pg23=}DJpx8-s8<3!BQPJH*5r)YeokRkI$a_C zR8+LS9O>)?;D^Y`{an-7xZf_J+@@UgsV#j1co2Sgt4Fr&u;rDW;6`WSS60C=)Yfhq zdP{Wt&$BN!nKrKf!ZTr*%L%_*Y(tI(C(I;u_T6-S6(Y40VSl8xS%u;25zrf8^SJv2 z^j+SU9F#3qMS`Vwc)B+Gykeek*6;KfJu)LCHSuD0fU^K~ygNNXjGuNxeRO(E3GwSY zKuhtxOmIKmHl&6xss?ymrTVVty9L+B@Z7zr2=Bv+T`3r~ub+Mso$JRghZj!(B|N;d5{08!FH{{5 zd4NsRPy+dPwR@fAfZzmU7NgxWM&5Maxs@i4tEzw(4{v}@#2lRtax<(i)OO6veWbxa zwF{nVziI_gGF-r5DNqVS_f08z&h4VGGi=}n*n`+&7=JU~wT{Hl7JX}qem!5HhTQs3 zDFs4dy0pJYX}4Yg&aur}v1|f@sXu;u>Ub%)75-F<-tX2`m?c`+v1|dbyBiJ~*A&QV z1wziV*9G}o1YG_T{tq)=y5^Bv<|i44Rt?=&lZ<)SAmUqP_x!p<2H!1(p*I6QRXTOK z>L6LDjF-TD(c;)eY@H&@BLBQ8GqX|Y?v3S@d1UJ7r&B2%Zn)3l7i>k&GwWrD2D*s< z$I)3hH2HX4oR*d$DY-F_7%d&rX)s_kD5GnXv?3reMhzGvRZ?(-bYlP`MhHlbP=SGx zB4PV|pWpjGJaO;2=X}n=vAnvg^RIc$1rO61;vKfPxDVMrTb~iO87F&)>_EPN0 z`DJf=qZjr9P7 z%)DtkUX|C*13V1)7=MhDqjp(ir(XVpaMXHEcq0MkV4m5=KJDC?r`r&>a&LuO&zgKq z!v3RYpWSqCq=U$TtLq*#H#uCaQm8$Ta=F2bEyovgykNW?;M}T#rQL*FFw;ZAMG!Q< zLFRNZVU;&stPph#?t*puuGbYaNcJK#nAVT!Sc(9ATy*g5^j#G_)yFHORBGOJ*$Cl>e+_2>9xA5ks;bVWNKD+MQXWYGenO?BRDsfH0yhvHw8Wk~n%29B_ zU9F{jBs;c??tME6&EzRZj_mj8%3u{PI25)@4LEgJlEtG5}^(m+DZ>#~OBe{W1Bh?Yq?2aFxJ=jenK4Nyiiz@Si>WkIIp{ z{UC=(SLmcGe}=tJ=5;094>jbXP;49Qn#ZSQKSzw(SgQH&X$1+m8dsZW_)YkM3Z{p( zwsd#h1ne(0bxt*BYcXOr=tFuJxKjVtv^qah=JlJA&nq^&Mn+xg`LNl>wOxx~jW8~X z3@1K$O?(!w<8Pby6t4+?kA7jdJFi_0TP>XH-_!`(xt_EoJTP71Pj-k=Qk(#nqYvFI!JJ~TjM zzWU6sO|*AkJ^As%Mu#zfQkfAeMoCV{7iOv)?xdRSJiu56pGOEuIdge|g+p{J&*H3x zn-@$xjf5K1B0labDc-a(p)v3RXkm%6$Xko6k#3dxcTOMZ!#n=+yM~aRU&$z<%)zzF znSJ8zVNRY{6Fm^W#V5|qOj`7mXs&Arzb4Rbk&4n~LHsXbCL0Pb7yDLF-e@WmAg8zXq@}b2>w`g;4-FkA z9V0jAJfT+~J`J4M9jKAwvzRrmkP;l3o!A4~TMj23<8loaLEqtGF~44YlU#jVSo-=q z1dc2GMlq%aYL^%FhSE}xrpBOjW1mo5Saz4P?B;c!OVXIKASuc^#X z>z@;tNmCH)a@=N76=c*=$Vkl?T7}=wU|8uCL3$$nW5nxf$yn@L)MulRFw{B0CHa}6 zq8CizLPp=a)SVBTZM8|_w^gCOq+oYU@a7pS4TW|faX(*mUZ*+Q3qo7>m86@9n+dvn#bY96ZcBdVLPK&qGitBEx zoVy3IIT$uk>Pg#(G?M-z9kXwu*g1#CGKUG)^sY}`-M1yzUx}IR zJUA=`Ffo3fSlNDy-QlvoPg6SDVEH~B;KHE7I?W93EJHYJ0sXzKaz1C-RpO#!2M6w+ zlAd^bA6Wgu)jxOi4$S)U(^cc8C=t_+D|x=|_aO4Bimu&sc8d)PD?FA)NElGU){Lla z`a>}lJs1o66uEl=n@}ZpUsVh$&z@-lp9DMAR2Gj}45H1L=lXg$QVlYuoh7CrGOp+- zkI#|7SL?(&YjGU*u!&dAPEuyn6#O2?iC%N@7P{xwJqDciVLg_*EDixq zE2>@Wt`{fzCIJ1aMnD3rDB~0m`};}w_FuxM?#;RC|fn%c~SF+GCVYCoSjImr3s-1$um$J;^1OAt$i0VfX^WOae-9Bg8VNLI$~D zF0LI4;>cP$m5?yL8iJX@AVGqY^aJ@<#ADO@x32}wQmYDW`opT{RZMk^jf|INe?~ce zu?J97T-T2+RrEkEoCUL>$k06td~5&pMh7J~BQcP}#^S?08JDGidjrDY|EPK-ctoy5 zHD#J3M2Wk`L4fLa6@B3ep6YMfC*HC|m|EDYIvNGxT30r&1uaWW!6r? zQ73;fdlb+63gecng}e=0Uq%IO?YiX_r$h?9i_)H)@X#D;Ntj4I&(`p)CFg*)&w4)( ztK<%Q1=d8JMTKzV>;0V+nVmFhLE{lGQ5SIQsnnl-r{--F{eSDLN`%UC4eZP##k&7E zL{-ktyFnpFN{l;^pHPyFB+aa9WBifu2Ln}N1Bf3?J*5>9E98Z#?)=0_^U?l+z>5H8 z+v7;68WT`#k`aa|@~X|#!t7%vCR!()Qd{|@8I-{9qI|N2b1Zh=avP!Scv7Fv*35oi9q0Ay2h#3?c@fCJmX!tcUuf z$rPsl#@a~dz)I#o?P(8dNF<&C_UY*FV=B~R(rX20sp;RG9&J~>>DoCya`bQNRB`7Y z66*0nQMonjuQkY=}~!*D1mhgXXR z1Z4xxMN@+$!>nJ>&Egqo7s_Na`Uw#Qu+L73;WDrN0qK>4xax%*o0;&efq zuVR{Fgk00ltE(WrW>P{=BSo+C$E!Wq|4z;s54KsLZ#mYCFhmoJ7yhkp`JFe4H5a>M z<_xRWVn~}`F-c2Kzg@ViICsB4+;&V3t5i}rjUCJNEe~Ess|A!wiw@q6 zpbjq&T)Lb>lhd2n)Q^>|qvknzz#;gzn&H!gKkX1%?=l^y%Nl{+=@5LU^2>G|A>W&A z^BCcjqqvxbs(-&^%sqc*xGXGw=(_il+<&LVR9CT?_oKx#^;L7aAa=oF!(nV7L#5_V zMn#qXV}g{B>(hnlV79ebUBV_Omgfn}$YO$37~;d^p%dAex&}I+vKilDdyI z)9${o?D(Y5mvO0gEnbq*pE<$IX{8+Y?$$M$v$k_7ps1p5+mKn zvm)dxMR@w}`X1If2D9JiXvNdfzZ50vd!i&bRQiI-z(jQwzcC)H-#w#=tTnY`GICZb zism@F<~4m@v)+Did|j?tzkvpFB}V7osZDNFL=GSp`?+PG_uYe!bCqtdhRV=|s1TQZ z|AK`csu$rW9m<3WDrVxF}c@@2$C6|>Q3p`V}bzcYpzN@kx%<0D5p;!}OFOoC~2 zCCB=9O$_@?{{!`2*v#0KbU{bJZ-OueR=2Lmf^=#M3k5l35io=mHg@tR<<*j-=Yk>!eS%jcb4Zf059!{K{EX2h;Je^uH{>@3Wx!TkdIrDuo@T1~7iioxf2hnsgv z%-Tf$9F}fbj&Z?0bJb3qJ*tD2E8+gnElwVNAwk7tWKiM!*QSX2z?N&WgO0z_?;Bev zyYl7o*ctNR%|!|xjLu1pT>P+7outFev$V&x{*|N|bA#+d;bs7;k@sN_R!xa2q<7P( zTbNj=raf0+IVyBTb*O#P7N$$=7l~(dRb<#SRzqRY;A8u^8!+~p-7-=YbQBz=>$9=Lc|M{5=^N7qS z|GyA1a!gj~y>-J>%G1?{$+$mre1)oZkH{VA)z^e)&^hlh%&jJ);)AaB#k~V{9htRE z7BtGdHaT1dP0OV0JvhctaFVun$+)`WisV?$uJ)wZu-(G+c=FS`*TqhIi5^bH?SZf0 zA&g_R;_r&XiSNY^#i1eQOx!vfq0Nt&`yllKmep7)R9D6i*I)QrZcyC~=}aV85|TS& zBRiE79tWCj7G!PBQ44yDM{m7hW4HK>gK~Etbf16hc%G-$ zCAlh-^-eP9K%X(^n`@e)>%(nzK#wP9aCzP{f@%n;ioJPN0NnOsG%^b=wac(-XtoTo z+SNis25IjI<$(m)dIp4UV_Nz4YVmaja{{9Zyk6dbCqRAJVirUr`!`AxS^0sC9ZNNtt)Z1HtAxyaF74x82`~C2d<*dGwi@MgmG^4?PVYGFtE_b^7 z*bCu)^ekp5psxR=CT?4tj7!X*PCYiorJeqT(+E}Y9oZ$X zqRq@2-_kn_Zx-FG?#uCc!Q)O?u?^eSwf{J{c9*;O8h2K^&1kf9QGD1UxJF9VE8d#( z!KInbhStpM@fNDX#vxCew+E2JC8uQr}G^H%(gd$vF>OocZ@0` z|7UK*5(Js`A(MYz(~S{r37z(q9K$v}s>q|EjJomYmw}#;e$OsY#~-nruzol|5I2DR zS+U{XzJ4=HmaS4;u#;?fO~l`xlo69>_@E^_Ad{Z>3y(K7g~KJWWm;FzcLg#c)z2RQ z6}|<3TG^x!E!1ER9*Ms8cZqElh``D!D@9SFuUGeDrWu1r3^Zq2*H@9kJvijf_kuDr@-P%ml=vvUr z$n$sNi-g}6XerNT3w=mW(^irvw5qDMhHRS%q67TCA>0)&ycIGVGmR2@OaYgRQ#~z$ z(q0L5R$`Kq>2r`7SFfMVDe{4OL{($*@O=9zmzxCfkIwYt2va!4D&6(z+SG6R%BBtn2!KfLz%T6>XT%RX zX(-SbBkxLn%^JqMiTNh%o*X|PoDg`Ab5hITysM&Msy*yrd#{7T`4($l;6Fbw78D1U z0JryG6>=8zUN7Z(stJ3t zibWB0#+1qfu3xlR`(BN!nUadn25sK?U0~PHQGZ8k^8QFs{rd=k*cVFcc-;!OhP%A> zZoj7DKMJkf@mU9^v%qe?xI33ndZ z24yRlDZephtt!a4&}6|ya4o>cE?$iVucmn)V(cgjLv{@Ui=U zg2*#}xN2cF$Mh(T?F08yg^fF)Fnc}M1LLGM06%Pcd#gpZJeNBBP|?QSwp!Dvvh(vK zG#(fQDg%#H?46UWv!AxV#(}(EV7qv9EXN;StGxrCccM`Z!+zc0>_0ZEEuuhJPyjI) zHs1ZbhNnx;y7wSx$7xt)2_R;sX`#$wmP_r3$6hdaB#X+L*+ zN};Z(Ns_8Allw5N?Y02qHI=PK#Gy4{FPUMpX6t@DbFi{I&$soHh(G{SoUkG0_djNk znI{q?&+8RHH|QQp;n=5h;%B0?8%~E3Gm@C3%qckvnLeLBw!Uay)q#21tw9_!E*h;3 zmMulo*@o9@4~@j~z3zJ&h8mOijZ4ghSIxqB0(w(8Uh*ZdjVj;@wYr>SZR@s~-zs6v zT)LT4xAXk1YWc50+V#3{o{i}hIRO@KA?VATS1!&)v8HE`lU$_sKVH-s)zqIVPrGkx z>zhddFEd~M`0d=tQ45z?L}E5M*OO$S%I3T!&(uPri|L30fuwnZ?);x7p#q~FgWFDi zOfN=GI60v#Liq)2)hoqR5Na@Ymm=@Neb5jKH516o6Eto~;dC(`FLHTw$Ct6fuAOM2pU!ck;;-`-oq0BA?3X{g1aFG+nPR}=k}R&2<| z5d$@W_Spn62)e4hX(I`paarkSPPsMg73beNo<;598!FUAM+X>5wfgT?vadvv7$#10 zB|zbVJ)wHeKJs%3oUfH=)_QvSbb)HsJ-xFN>V8KYbJ@)NaT}8m}fzMYzvVMr6 z=GU$^9&)SP?Oc98&tr|yOzHSlD(Jpq#<6!v?6ZbU%Rt$F}Y+`4%xf^@X?;rCblBq zFK>>$Z$J`EATUS&4Iv#1UtDPZuk(Dss6aPxv!++e8Cu#cYdtf`%`v88q?q_owUGLe zVdH6f^(%1pY_FU(_~_W-u{jj(Brdu$E)vy37qM#CZe*$$+#TD8cP!v|-_BJ9VjEdA zio+L+m4NX4%<^hh+Ojav?DhMNmbc+9MlQtt8{EM3Su2V@icjLe~Rgd13_aUY*DFxgljlSf6#|b8Q#7Gd9U&+z`Nb zyi84fn$T&;Hoq%|hd4BsoMZSeo zBC#z%+5M~4s0+>*tDsJ$teWoSLtq$bxV}VGsV!pcUY)=w)tv?A;l#90(DSO`Gffg< zB(nMKxC6vRj5X zZqQ+ij9sG-FLVIF0bhJH3FC0;pXn2lY{R;8l_*vu`=<|UkbTGiJ!+5mJ$Z6;5tO3rW}$Z64ys0wMv=7u>o%iGqso!vtx+JwFLT!TFAsz_I*L#3lh z9v$hAS6{R3bLBs*ku=@C!wOVJt|fZ%VgimR6aMry`I801j#_Tq1-Fv(^xN9|Pxy|+ z3AeTzxuB*~q@_r^%`%)vZ5W{&D#fU*u-5ZZ9DVk{dR(xEFZV~P4fz>57c!A1nOOp0$~QnSmR|!S8z`#n8PAxrlj`4A)6oelFi?OmN?T zE8M*eBS`}C>q6!sd9j;)5ZD$9Tw!S_t z;5z)WVr7$IP=%C0AT4E*v!qMvpo*dQ4e^Xdg8oRo&;6XV`EbMGj8j*W6jza zoV!r~5P(~Y-umcH}tXob)P=z%~bv>K@6EVELkU<@54TmU)0srzJmQaE)71y|2!`2Y4z-gU+am3n4H5Ky9Gys% z`<}c7qe(0HpQHS#VQZvZSmeWH*k9GH185%K9{M)CGellBz(E_Y5ujST%j(f_D0eq$ z%{i~}z9Lbm#fxFMbiu~Uc4qAT+=z2Prh3s=rxd5L>AR9;rqjt$D(lbpTn_dT=si|H zv!jn{VdwSZH2g11y-?F9-Ie=ivfQ6iJ{Ea_NXzM$D+)E6275hl6)Wt{jWW?JT}}>- zMnrB{m}T2(n#3-MLiBC7QNVe$_fdcNFyO>SF@!sMz4BG+{<=r>Hqa>*oFReM)O1z9 zM>V=xe7hy90X^z=F8Jw}at|vwU!#X&sTz&{u zgy;=AwlFGV>hBM2F9ob0iqf@~tEDM1fc{nJZL~-VzG@Aqb`rHo{(FbafWqnJ4hEQ^P1m{d)GsMu$o(Y^mUlk(??P ze^T5=?R*tb*J=vgF5<~ zXPRYpP6XZrv%!7MH$9`j0Gl5?H)oM(%|qXXzgf_vF4Vy61k`l^ z6*5U#tO9+Dos&vhHTw1SC}MkI?&9;g4Pwb^N_H5;gL;WPS=j4jE6|=)#1>(nEU6cI z0ZW^NW}@gbm~lQxAE~~zyau&rB!7>@BcW2AcIjbG?eSfgBfa_WbEBfU+?kG+FE8ocO25S#8r>A8w;HT-?X>9O zJk`No)k&g=dBmHx_MSEhMitTqc}Ij$@*@Z>Eb26nURtB zUAei*6!fWiaG)J}gr7l)=CADZ&A$$!&})1Xt*#Hpt}15!`8=ZLJegQE2nU1P)9F0H zaBS*(%CMEcS)b+Zt0YB|BTnj?_dZ;FNALq3zy8yBH(OT7o4XNI2@r~2wPXAqedm!U zHBUg$)O=#l>!Mua15xYY!!AW&xRYVwGm;cVqmP?i`iL;Lc=XQvlXXp}$)9GN)Jsdg~tSwPR!>JhvyNEw(PV z>?daSYh}u$V3j|;)YVUi@r-PgccecYDvK9E!oaOw{L>Fnmc@f}QFmS?y*86=aX;@J z{hRJP-QjX_qxwm(x=Ql@%oX7mR%!&`6(>$6fL^zSMldr~<*1_CP0U#s8wJ8|FmU@x z{$A4QTh|L{;Py2ogAb!)XFYu4Pvt#C1AskHcBgm0uXn~=2tI6J4`Ph8ufGE)od>-b zr)2-F;8{u|^l4K-_wwH6fUgt`YNf0W&@Eh{3Lg*J58SndNO&3sy%CF&x3BOhugI&c z+{9~n$k8qU+?bWy{+da>R&{&^`*#D?RF4e`wwDc+Ees5tEipTx8$^9BXA zeC0V7uIW*`!WG;mfXe*YB=@evgAGdL!atMBnskkB97E(O6XaDShKJ75HrHCbs%jF# zfh<`>VN@7tLA7<(U3S(|XwV^W0>GWV!q&uW^GAA#7dLzw>RItBb(W|tzKF`2E$C-K zzitWOG!(Tp?LasFM`igjvstj~veacK71sRgHmt_DXM#d>;f@F^+iyEOlmABdHd;4S zO2^4GnU|&>dr`@e=C`4B?nOwlg~S8FsGQLrlsOSOgTrk04d7L7wlF6O2fp-qG?#JH z+B~QNmr%;P6;;8}HMef1{hG^`FmbfWS^(inE#Si{`XrGat1L zWgNXBCgnzRxbWdT2B-vz|P z@!Nb4DpSoWWg4#W=(gOy5MqPF>4o^ps@2%73maVhLunO+^hOkNU0^7$zA!1IK_-J` zm4NQNA&_~zAI4-{07~5y*W2AFo$WhXX0re7+xNq)z z1zQcNU7&-jN_}TpzgGf4<0jvxgowKy*M>(UCbP!oOgOV@ep!9Y3^o;uibO2LGA6#0PpNDk!he~aqP z-Lcc=RQ--YhpLR#xRz!nR@(50+{h=3h|ZSh*<;~5GF`kWzwiZyR&ZlK5vhXLT+-PV z&JyI+`$36Xv5vXMHBBCMHPiw@*RF}A(H8)_m@W8@Y1i@ef$KBmg3K4z0Eupo-m*&_ zgQgL9X$SW|TUCB<{){t#MbEQY?6*x-bISI?cp5$v#fMcn0l=4%ZoXwC#MCcgy-gVU zj_CS;KClGeD*el0m)+*m=IGqOW!Jz`pHew@<89R-@}9BhB}t0Dcu!j-RL5?`n4MOyY4tm$?J)T#()!=~_#uRY|>>xnO4rX@Y~Vb|Dh*Larl z0VPvKaUx=GdV&StXj=|v68s+LsqAU*u*%J9UG*i2^$$>(4dJ(KJ3o;A zutozm+QN+=1U(*O-x0FQKcVJ`WE)}2JZw76#n9%eRl44B+2sh zQ=fbd%|*Z1Mj~or^ZZd5gP>k=-;W#Vw6TLpx2pau4skIfs04?6zn8z1$WxS8Fg`V( zCr?C@a~cXtyz6|WrIpb=CSl?EYChcC3okp*t*6PAPh*!oSX)SIavv=xkDb{vh>V4b zxiN3#01f@6n(ykwN7;i0o9X+ThI}|9yY7$0=Y>|%;p ztG9hAZb(FU8s0a!$-cD`b*!&21S;rEcb+%IOd5s3iBjIM0mHX|wve1!DTNN_qAl)J zN7k4#2X&{vF|y-v7kYQ%<;Wx#<9BLe{0}n=W=S-S@@Y>rX=X$l9Bzn^+n}4w_v&O~ zyaHGH@Gn?rCb*IeC2n^@Z=2+kE=lePR|$Vj3&8JCar0Mw7~p;S&38LYrXJHlX33_1$=6xWwNPblvEZLSS^Z6R94i8P-F7^x|kkE9qC@USzj~j>p9`Yk#T=fgDNG)OqX- z-EEyxhg@S3#%v#bg}I%nqP|>yiFT>cuN_YCF$ zs0&LqC;E=YsqZ+3^G7B(g2@fEdzABZn#_3E`X22go*XV#vD3IiJLq9_U#>XhAV-aW zF}xn-eHixXGaT7z-_v8-XxI|9z9|=MAPG?QyJAG?o|P81Cw5&XxcU}U@CcS`!!A7H^V`o$X=WlwD+IO*ki_l>IT)@o|n`F+C))qK+*|@`ig-$d&5Qi*HQ=%!4Hj) zhQ3tYYXd6tQR96=5 z>7>b?fxSzhd_)^6>WPV8tS%A4KU!Cn>fE!{EAq@AoD^-?9R&&`l@P`yYBfAFH?c-^ z4yi}~Q5iJYF8$MUFv&A3`{TP6SK7Y_C7Yv!!{_~|k&IQRuU6b~Of zl+iva`nYn7>A(!x9oP6PcCjZ%`crX)Vhm`-dQeoXP2kzJQK1PT9%*P$ z(FfeKw3eWXun9FLf z%I~N~1zpNMs&28(9T&99dK#v@(*=lOE&OaMh{2F_TBOp5Yr#|c>O7qS4GWRkRe{1N z8(D**_s!VDKc9}kU1@I(pIgE+tHdh=jp$46_*6K9-e)4;A;Y7F{QH` z#e5BhIl1X;(A)Njj|!pHE`00e2{40yzyp`t;LP%l{GU_aSgOK-mF z=CWS+Mu)xa3N+ru-PVfn!XbG;=u0lfqW-YEs@?R9h=l{8|9VT{R(EGn*rc{4xqTcu zJJBiD`HAr`RQP=;k*mIH`)S+s1iv8{baSIEo-*Cox`5EKwPWI=q|u<$+V>iFj03HK zdi0O&UZtNMYIMMCM(r0AsiWT64M3c6>`+Z1Fn#g3At}|g)xP$l3s52NRlg`SGf^7R z)eAjVlzVOQc{m@SWo8e~9`x{rO)&0P_@D66RE1fKQk}BBXo2Z&qeEm>T|3?XmTS)OPR^M_rR`20f)8O?))yan4?^tT3)T0VKB$; zbHnl+$np6}8N@m^Qgj2?mH|GnrIn{R_2qohP|BL#K)SQq6()MUaSP+%h@qYUHVY-V zd8^W@>tuj*=~aJ+A<=K^5ic;`46avjtlg;I2@_VAkTCmGKICm&G@(GQski1mHN^cq z{Nw24^z(XffvwE~7m@Fcy~$GiFzQzA=juMc(dhO5t)!+Q zOPe%odZH7Ydnq*ZICu|%d|q3k-YI&KJ}Gz0f4|ntZzXK4zJ5lwZ!<}MO!e=!!|%G5 zZaI)1>iVSv{basfJz`dWox)?1xx3MnZM+7QLg))keGHH zKg@=wu!Q`gH0G2fWe#wXZamgJcItQf^&?tpCuG}AF7o$A!R*PLx$uN!Jg#SAa4Z@7 zbGBJI5+03jy>m_E8f#ZPwij!k`r|d=kfVIZy3`Qdg|MUTynjW_$@)UZQdH@0LyfeD z{tEn~Xz-YZiyYfNb|r%**Q{jMo8CDw!0r@^o$)9x4gkYGSF*hWre;L11O8Am zTd+1#Tp=r^yStvKL7j4R+V*HRHw4i8p|zRJ|54R;f-3 z$kE83TA7cN^<4I7evR?^J(6G7a{@x`yrbK+>VHFYfrf~Aa zWWsr$8PDzkMQ>=zH#{19ORyB&j5(O_&$y}|M%mvAtDa{K6x*~Ch_a&CQOo?@_*c!z zR#o(>Mbvf2FdJv_ns(2Jmuk1&Utj;V(=oT5p*PwT>C&?*1Izj{?#Xx3^v zvL<^_4Lhr9Ypw?c?)rDMcX0B}Gaei(zETpVL-imQ#{oznGoKz*MAE(WpKLZ?Q>J}w z$*b0<9<_O3z}nZ{-F&W@BM_7{tk|;N!TGvQi|=(*Y^N-nRtmpS7}rq1Y3Rn&K^9Ae zxlti0uN700>$;_X2f!W%O96e)%apZuZ;@O9*JVJq95?MOWTPXp1-`>NO9SfiG)KTC zALd2{y!Vc7W?GH93L#k2w2>0qA1_XBwpHY0A)lI2lJ%e@u^u2b^AKV57-c13{#VBr z#$*D@0?1%;0HI21!zrs^RV!4nt0O7pIi%3niV=U}-XDe9x04VmHZjns49wYpq7m6; zzND{HsWfgxptrqltJ_mCZ>DqNfs8|DodNu{0{%cJ>#eu!SS!*B8}9rjk7R1uUXyb@ zGG#q)6oXK8$~Ni!j5&I*vNqX)9tqg1t`)ZD!I|{|1zER<;4AZ9g5`$coQqNm9M&U_ zkwu}Q2ThUpUuL;!i%Zp@(OzBu+d|)C>F+<*X?YhcdGdB1(HRI9)p{|C`?hm--ZW{$ z=Ysvr$unKoti3p=seRERXjs!mE)CL6M; z{vDZ+r}lXIQ1xj;8GScOkJyf`7W>QdE}WUscTfDAYvXk_mV#x_y&rNBZGkPUZ*f#+ zeMUS-ysmuNt>&s4t)!pE05vzl5N;v%O9Kj9=J@p0lH1f&>>Zr7T%4`y6~8)5O`v0Q zp6L#lSv9zS6*`H&k%y;;e5F8nZ_YqRgK}p9k~l!ah9o;7W*y2 z>W%)xNgILHa)DF9ao=Uk8YIA-`(AtU%oD1O5AL77A5=;YVhrn8>znVmt~hkuos`O)p_iTG85t@9X1{WU3@8w@AYkS2ei#P%NLQ|inZk7zTd&-=m zI=lcimd$hO4%~edmLwKXX!QbKx09j3X0qIu(K?nwa=7RMW#9W~k3!f1ollwurN zx29DK5fih{T615TTAW`=bjxxn(%cFf_&k`a0C|(g(9>_mv;Q9zl4hG(dl0aSH=qF` z%;iPBLEV?q4C_%J(JE8;waP@){~!|oG-o|p#U>MaPvn_J2X*B<9beN4#&-vV+pO!G zxIO%j%3Sioxo1G8#{XNu{`VU(Z?YMT#HJ>Db*0jvNS~=cAC8Tqaxdw|I>Ub@&XXHbj85qVG2piN6(wmuFG6k*j zyYB3Kt(>!Gv=F!Ap~!fHDDuwqG~IvQfnQR(BjAZoBSsA1^<3iv+C=3jax;JDsjr+~ z_L2FwO+R(25iVNV_JgB5+q}qhaR+cUB}bLS=#$tmQ*nw=#g18;oEwE;&VGGM zH~_Q$DcHH(AMFF_^M>kVpW|8hwHjLb7CD!>pKFWM z;Zv}8Ji6pnZ)&aKn5rO*$AUws6FV?xtu{VKWtrzfA37*fBYf`wL!(i)O}^;Y@fE9U zfN*kv$gdT6!zS}F!_h>`keqAQ2;-_ce7)j`Vj8(vV&RrbsS*gNxg&RAl&#b9454864S+p8G0z}XU-D<{X#0diP|oK=nVZUrqIu?}U4`Abj3Xqt7;qAmDdSMQ)!N=C zYSJ&AI5;3?kbPKo%ueiwa$o=i!^B#l$!#03>9oZQv)IsgjhCNsJh4HM`b2 z^=(s2FcVwFram;EDt7i67c&rrLF(CGaux+Xgc)rcNdw0B^bA2fJ|6+Qk@+1f2%Mt( zt|olUz%W?pWT2{0Z6C6{RxZ90mPgfZl0XLHOZ{VQ-bZ>UVVCvKEO&7|u`@I<8i=HX z;H6^f2*8retYy}E@oJv!>4q({_6k<`b2(kyT??vaIa{g`Z#y)=ia~0+%@!Vbz2`y| zJrLD+aCiO%&0?RfC;bK&vr&adN73sXBm+zqxN~yIg`9`#@n)PCBs_H4$kUgYKA9@* z2xC%vD4Dl@j7$J(7O1=F4KT)~a`1Dk{E2@8PrPJjoMeihSaZ|CIkV>C*tUc)ysvlO z&r&1i-D60~OR|jVpk#hz80B&c6=b(4?AJE1sswTNwI-p0V>sx-y{10PG4f@op?hZ( zM#&JpwO538>hrK)bypYvqw;f;qETDj)Z=KzdxEenr(VX;?0bA>EDEo^q8iH@5tBH( zNk{a1T-8&-m2TudAh?9#%Y3UcjlwmYb{Ad!Y@J5}s@rRH zO(>UnYy9&;G1?HZ(8!>(Ua(tsxp)o7r1s`gr0WweXHONQT?;KKj0P>+5IJ)1!+bG! zV5&aZ#qjW=_w!DZ;y72Bv-n2%)cTuHtAjj?%*6>@&f_1hf+w=tsi9-nCWYnZ$awSX zC{7o9^P{7VzcN>oJwx(*z@W?RPiX(Iqw@}D^L_iUDr%P4n*^;r(pp7p#7vFYyA`AM ztgVU~5t~S?s##kJv31x4B{gHTW@{IvyTAAOzJL3};Yd8seP7q-bDrjd{1zY@&k}zZ znZu68R*#I!#J3`Tol$fPiY679X;1eOS3*ibL|Su1M~7{#oGOpN0J!jX+Gg{xxg~qZ zh?rmXd|-8+6)$@4Vdh!ZqX5N^Y2xFy9YZqG%A8KMCxpky3=NpOD5kufM@K&A382Nq z2FR)bq&0{XKfE7mBJR`IT;hTkXt~RENW?8+B_->x$GP%GDP*hJaMI;u`j}0Q!g+MD z8_1U4HE-V<@ZD*n1OQS{?VjLt|F3^J@a$)|JY)Hg%18pr+5d1r#?4n^@2wjfH_T|o zdHu6f5VDIDH));&5}aOS{nXmcX{clwxUO~!64X}vq&C{U^1M@1TN@&)8%`O19GWlP zqA=W=3!bBD*7>-aeU+ucud`La)avp;w?~x^;V7 zQq7!`u^k#d0_+D#pK2uIAyO?ng4Uzajd<@?eZ3JKMCcMzXy3re0-NMhg8kXJa z+@tJmH;Xjm(3esu+BZnxhXldMm;4pXkCr6wje zQB3aaAyRXn3u2yvs}qi@5lETC(O~O!YVvEPnV{uS(2m5lps48Qk6pYj!&%%XjsJ5n z+0kvS?oLvdcx6+hJv34dx-4n&PWy!goHIM~%h>%O{_5WA7lJGJU6N7l_JpnoN5x&N zb+(nDmGF=m=GM8|FTPhCg&v%}qDh}=1|}E7@pc47CjERmSP)L?(_cde4?FIxvptGL zv~uP^XK4R)=?Z8RzFna-2Gc1l+L6?6_41~Fa2xi=@5p78Q_H&^FTw+1UCMii07_SO z`E}j^2|Bm3NF)mrO&ZqH7qyg6S{)AgW3lw8qeuZ`qy=RimH&>O6$pE~krF_ZeI$st zbDwJ$VRukPf8-4!=8%-r_?p!ke%w?Zmp(nnUWaFi)+giC%&3>&rL z5!!=D*H+(g;^Rk*w+NIKIv#4^E}J8oz--Sgg;`nRnVJQYD&~^Js?)VfcBfDYIhC2`wb9WfFL+U^0SJBV8rQ~rq5i5WR~S>_#;F9-DPTV#7BKwlY9 zGM^+9F`|Xf9RQ$HQ3`ghW8O!#bV4$x9U>!(aLJ}f^TN+OO&Iy*g5!N4hQ~+m=$;9M zu;zCcuZ*$>*+_n_k)T|ANu+G+e0Blc$uz8bJ{?YwgqVm8^A5!x>vHwzF^7wpu@&g) z9UgYqi|jE*mtY>=1u7oRM6KnCxbHcXC#;m8cYcpCWDC{_GcYsNUU#Eji2cSW66B$| zGIi}%Gw%$q?2B)unhJTjX2I%pymuM*_4e&#SKR=fZ}i&t<9Ct5rV zYX?wDtzKL{K<(0;>($E6oRyt?wovZ54?c^e)yK3kxB9_F$O^%zwG)3aO|rWX!=>5P z8@?aySbR$0mu1)ZnstlY0?)qx`=%)&!w%ZT$)8nx&;!61+Qw_m{#A^+n?HWlGS6#v zYP{~W8oSekSa>ys*Vng%Syp!$yeW=7L7qP_U5UDVA<&*ZXZ~T#^~OwO8<&(ESH^*D zb!`Z!L#tNsxb^Z*tC-dUOz@?@EG;MRxTFYp>GLY%;*$obiDZwm{wOt!bQn{D>b$}w zcUjwH<0EHy!<k#RB z%>XsIk*immm!_Z!iH%8QtDN>{%jIAw zeSDYOd2x0>O7;<1526M=qNm+|c^(FciTo+!UD?!-Qi+jCGq%Ny)xV&! zOW(^fjg)w3%2d-NqSkyAOmumliVHOL-r9*h@%|vf#C#SlwtGrHc|XJF!-tde=eSE5 zbKZm}h4!k&xCJ)`{VKUEB`YALU^y&8g}dx_w63!(r%&w<+X!Z0)1K$dahKQ9Tez~* zWs}C$AQsum+F9H^CtG_IOG?6|0gxij-O0Gl{HwH`K9Ur0yvPwmleWK;l`b*1zMV^~ z{z{ZIJ1(m}-rz<1{~O^5N0ZjSY8j%f*G_~ByjE55Su+4q@5A*gm{`ed7rwTT@Ni-C zo4tisS(eFD-+HJCe?Jausz%~}-I-6=?RrWw<9n(s{yn$ly83`>@Ay?lKeAN68=J$X zsGAp^L@P6n$LzXe1(Wtagv|M- zcyq4WfINaP!)2#$WTzW_lBy=4*UR0Q6sQ-&-YYAc3lEDN`U@fjkyyiIfiuptbky4I*-CHd#f^}ZnKozz*^)DCPP*aPwqrp`2-FJNTwKu@dK}J+j5TP{3 z;Cm(i8L3^TI{E2Mwghbm79J=_RIUb)CdGcL7OA>7$at0C4rsj}$2NJ?8d~!#bAsle zCuPh}Lz;|p4Z&nR8%8zs?56QLTBhwt4(+nULMU?tge$x$XLWMv$>v!R7t&*_)*P+r ztwfjn=CEU~Z!ZmpJsZh->J@hO^Nl{<^;Ku_H7Y+(uM|Yf0gHX|JYG8Ikcff4X+VD& zdD-i2ug&8%_H^V5=b8KT!fB7yjS*(azhcWJ+t(YNS~dw8i3zhHj|r#JYEPfXiBJsY zGu1PuZiBQq{O3nTO@^V;t}=^kY+1)n+^v0XM89Tb*F6}xn(YjVb`HrQGHXx#bZ|#` z01@ECq1Xn=dfyt8ThABIQYd8?E)=cOs=%sVhfr4Xc;Lz&oCEJNA|Y~hbMW)~Fs`KF1p7^h?rKjpof=zBM>49ZnM zHrGz7PEYwCg~2WoM(fXgOm-AiTG>0$TO!MPlyZ+TsN}8w32*!AU_O#8Us|EnmAu*+ zxY>$2sMD-uxx&*lu@%PL?^i#uWHBhb`*m^1G;;DVKMyUGV|^AV}=ba@S8 zf$&oUxBOAA6PU!8U+A%Vk?O|G57L1_+wZ!hn~Ht;WL_d!Cz;}DQGe5HUnvO4AUM`N zM`nfSm1=iuY0I-OlX!%#orXdu)2+U2WXcF@D`dbrTK(K)HvcYF!$tpDnVMN$;~vqE zlLv(=3;aDWrJRS&CeEhruuZHle(D&nuT9TeWpOaE2`Em>1Lm$WmiHYL+5x&?=&{42 zJ81N)oBUgoYR#Xp_yz<|1bQ9v);T}jX1P^c8;1BFg}roT=mot*K>~OvGVvAe=)sqnbYA&mWwrg!7@}T{?R#-ca0?u9ArTEbYIxcmICQROO!v z5G^W9w{Uc3JT+HUVp9B)(uQLt?NY)S4jSZV`3#mIGBP=^%;|lnGX?AM53f5X>&+ue z@ggAZrf>ACIp~sX0#(kmHtZ4hxak0w6C3))=m&8^71qgB{ursUjhmo_#mslLmze3; zA#UdF@KqCrN7K+i_sD0Xo}^$-${Ph4ooNitLDnK_$G$2JTXK@`20Qo@hac;SUuH7=UPz z?dpyClNmESf1oCV(Bf-g~rsCN!RC#9v*HiNulFqIXg1<^8E{mLG2{*9#Fe=RM9`5{roJN2PSXeno zFu!2L{fc_-Vc?iqwj)8i)m|(S9&H!i^!)Kr!VKW4t?%i-8WAXJ7rxV#;~_{3eI}AL z#*UsE<7x{x7mgKY57HdoufNu6Aos0I1E~pe*Bnd@2`}HOEBTt?x_$f%{E{2&)WE9Ip)M{O5;gLeA75)qrYR6 zQvDmm6XEofw&hddMEq`hzfxIo&;a6EiSV>&x%YR4OlSW$cDCww7UzE90o{*rvqbaDcdS~bTt{6=_H3Na7m&?V~~{%($cn!?T$vLm=n<@P@c z{nRVH1^Dl1>h8DMVMWD_qk%J4hBz#nEcJfRnfHg4sP+qiB zFYNG;E4?!BHopQg@H1_Y&W*8dJ;#QZ?}(=Cr-}mu}iW_ z!Ui$CUOL_d50(l}J&g|fW2UGo_z=QFt6!W%l;nHF`9L}UA7>NC<0J+vZEMuI5*1|9 z^<#es!NP%We5*S1lrQmGkkqg)>sjM~b;imEVLT{FcSKop%SW+ZcWgXMJVe>NozvTP zTI;UGzF0x0Xt8=FmLx>Kz+UHgJXKuBm;3sIn-ZrhWyiL8fH;zW`N{T`$fcuRHIG0o z;i+AJ>5d;c)Z$CYE5SKV!L(s1JLVolf1u1JZB~eJyP>9q-15FLQlGt-7g#6tH){=_psvGMz~@okI_-u7v!qh=)0z zhX;u=s$6RXR*e73fvh1;$^7eOe&yrYQ9NIYT%+T}jLRUdXzp5nL2uHP{W7O*r(!e3 zj;9R^@nMDdzqCl@jP52OEA2`3<=|h2_KYe{WXQ4BjrSt}MDIp-;uFg&9N(Gco<>o3 zw>=dimvM!#oMo{i{B|{;@|ejz!pTL&Ev)>WkudhRv{&oZUA)MqGCq&$ccXXg?(TWk z#OV|8`B&vz1pN-mUAl5^kgS_g{qLkNK1FcsS9iA3!P9gWN?G^p5aE{F{S{ODO~a$2 ziOz!WXKEEYPaRO6TZd=$hW*Dt=+#V_x#33z^+JB-)S|ca8=FgE^9xJV_w%sl?8%0F zZN>fCmo~i5(D3HT2a!&p^6m{q!vgM(1e`-Vie^EuJlyHq#jU{C&n0vZGV3v@QDnG7 zAdcL#JT4kK`_p6-{7%ZOO;i%QK;5JagIyAqH z_${y7cpVIEH0Iy2)c88v@%#gngIV*j+jdoz|16a_r)MWc$ip78k>YdrgLJkBO?|ae z6|$~NN*`EF)K%A{>oFKvzeP)h8?5WxnR=MelPf3*>+?!b~R&{y;9(wW7`}+tLxHO{Jvz@5JacIv8k_bI`sE zqCIN%iTEpd3i$Wv%e&rGb_yB2QsaFw4VtlvR8I;IUHfxqQTn;UR7)=BE1n7nSiI#1 z!KtB0JsHr#z+?_DyEX~By>|{nLrZ%~fO#%)P2cl)T;ErZAxIMVst_-0F9CK<04Y*IC}5Am}Fh)#<@R zxK}sFL?uU7*kP(~J014?rGi6-`Jr%WcN{XNS(iMRFbbQ?1&D-)M~9sRtkv|G*S6d= zH7F9l8=8MEwWMfSs;^+;l=E&mAiMtU84$4l^Zo$3z-h?uoe1;aDqf0rDXfs7O_Nz% z`*N%~JGKIUc3Z!|m`X8MgJlvasyFBp`uaM4vR**QiBOY18H~00W!_;`4;F50Pk<+- ze&_OGB3dH3cQRGPvOI5!O;RrpHf3|nox+ra6c_cLM07?GtrYQ~bV&&!a0cEUQovma zm9))NYN`R@#8JB^T;Grl(^8|mG*HGe?iF&d`3(W#NAhVFYuJNdE&nC^>C_2qSF(y+ zeEd&B>-8N?oQ@AINJy)4f--);TjkRquTale+ zD}g1#LsyQ%fu(gK8(jzzAoD%w1_TnQ;k_?I)iUL}g})YB^o+$vTm|3Do{IARLaTvg z5|f0nYE>uS?f{4MWl_|#%hoJ{M^l|WDs;Yn~g7p1KaG?)WYV%QEnnkH7Vd(>h?mvzGiABFVyttW@Rzp+WE z9Fwfob1I$uD77{e)!9%lvwM{hnCnTk(E{hpd69Z99y!LBB7rN*b{=z`{DcGtE&i!A z=0{Z>=jnR#X;eBr2rL37^$?o;Y(O|Vx+%VqzId#$uf*VRiA8?nwue@ z-WvG~3?Y1##XHvb%IYB4+YBlG;U4+4%A$t#Tr#ns*GPV&S%s~X;3PTUCD=oh-#Jcs zbAQ;r-Y(Oy?}g$l`OxV=x@Wl|MRyo3Uw9uzb6@r@*0ICF1!3~|8V2?+Naqt!FA{Kf*;oQ*Jyky;}!Cf7700Joghic!b5>QZge|HrIUj&kXClkSJHo zSjS&CwdPnpQWO48e4d|+gC`pc53?k;sFeQ$<7?mhovV)1e~nsM28{%5Z;FOHD!mEY zfp{9h(ZPHze8^68tD{Gx0Zh*vle{cwau0A$ge`i=GgXAO{1N)^qqdK-+azno`ZB(H zLn5T!V5??TI8W5|+4&7ZX8!c@V^&i3KR8&&SMW|)C@kBH`8)h*vhUXr_)gx2i-@wVJ6UU(`w1G)DfR>p{naQ6!1XF&aIoAS~MStDwGqE2)o@i*P<2uU` z+jnUFyix~yq<=2Se9x$&wgi>_TSEt^SX{NSdEHYO;xUyRaG+0x^A+jRpDr~!;nW9`$QZhUX!ar6Q?2GQSF>*d2QpPw^xmfljvV zZ=Z1_ES~XZu*~J~N77aI|51cqHE`@eQ}>+xuH{`_ z0F3usT4e9_c2k6(25e#as%ObFR9^VK>IlN)zdaiEQJEE3{l?^RgK{Wevmn)a(r%PF z(__oibp4yH#D0gMtENI2KW(^Xo2|Nn<0tT%j>yqLDjNh zV932kb<}opd>u}&Da+W5MJ+cqUgN(u0{oK1lC5_7)jsn^J}=EQOiKP^PzJvaA~45J zp8R+7pj2YqGt7mK*^^6GB(pp{tWq#+;_^Erh$G=jkpoI7sn&|el43OXzyXD0N7Q*U zcEsiv-XLnrhNUu}*bkd$0_=FEB@a9F6n9cDB6s8NtPCqlUpIQSkB$ZLX1E=6STP~W zI_||(Gm)TG6WvS){Q;shSQRA}L~Ezn)E0rK=3sRq)ktmMY-Q+{V@ zWT5@m=uAevAK|w=xXW)n-3GGje6yBL^*H%idQ(+ki#vbESN|$4mz;W$T!@rG zgkze%@cY30)`(_NHscs8YWIZ_|4ApCrncvBgekX0=ErFkwujExPy0buzUi(Q{}oiK zQ}-VSY%OEF9rvm=S@{;T54mmn1>~MIP;-&Vz;~?_KV=^qY8f=()y77YpZ5-Do>aTX zOxQGvoW+B)jmoOq4I&r=)?ZFFxX^Zwh_$gE2Oqo7PU8J2E07Q=K87&YjHzU~%Zix~ zAG$0-z9TGol;8Vh@dV?>Jh)ksZ%lV_QeWUVv3l#VFJ70o3|zr1iT;q)@H>_S%-+8G zGb8i2tbULpeP1`Op$C~K+UTG2hssG|(^|6Hhglr6OpN(Co+K#`i8>-ksn}vzOFT~2Kz~2 z!Zt7b6Op&31B){-(9;oaH&IBjiTvQ+%6(nB?V(ZzTHwIer`Q8R z?Zuyw($ve&vS1On$fTK3={FQRtaPqaQO`n}$#H69C1#cTH56iLYWO6^knJ#<5oV*g zWzn2;(CCHziIJkS_bt`R61ZH`TP$)l&B_U1%K{poSor>L`#)g={JocO#9$NIJM{AdV=Lz#)e%;3dvVfQ zexppIn%4F3$pr4b$)BpvP`K#-*nX1Zw~~fsy}13tHr^!UD}i!`O~3(4{QVO%$vyh? z6OOCjf3vSl*8eoNGzaP9&lA=CY&=10k=1Wd=np!=;Tr&ZG0sI35NQ&({462 z9tyzuu4T}4d&`c~x4ZZI#mn^-CM!72sCR7Oo!ogp3;njGH7|cYdsEZk1;s5>)$uSp zd1Byk06J+q7vrVl$){01T=-A2zL?hQ50)nZHx1h5UpfxAeu=gH+Wy4lb%9gfl6 zGtQgBr44)$sRdL%c{%pN!(QQ)-t{8liy%K4!Pal#0DxzaHx1dYshs`W>~^@WiH>ka zRwgjcsaZl<2#9fLs6HUlwsc?rABCP2!S`ZsU;26wD`l6BO>;*X4>O^V3ilwe%yYQ8 z`>InRB@Vsr#;^pt4r7>%e;rJvxv6R(jW)UzKoos=v4s!ZfA?2rLwUUymj2oI>7iMy4GIUn@x2d#qJ?6WZRVUdx{J zHqihd{=>{UGeAQ)zcNTkU`&L>>h~D49Kmp1Fxg$vDW6!7*qtxTr7TmC0OZJlYN!0V zGS|qwl9Sn(Y2Zrm@Ri(mKx;JCA8~=Wu?lhK@YE5_l11z|o`nwIR@nI;1q@p)w$4A$ zsJPBw`K$Js?FO#EjJlvrIQOu-SDf3Iaxy-qy!j%fj`F8|VsM#X`3i2`AzP%#wu+S% z44xd4x@J{&LDmxgM6zKwvAI3iz4esbw@8X=s6Be4I4r?J^quv`-V#_@OyP>j-+#Hx zGNNs{6K3TaoG47o9tl;#977yKrpCqaHF8NbY&cwJ;CB$y; zK%@L8ofdFc)W=~oty^V>7N{UGsvtr(qEoa~KjL4}I+gQ$L?u}1DsY5?1Nbc7glwf? zOsR~w_}IMP(&O=OgUYU6od65rT<(uk`3tF`tPFf` z`gM{p-qzK{qgRstpQ%tWC=VC+AH!54S^RkSop(Ca&$Y|UhBdfIN1>C7iE)&D0fikO zIrytFMpv)CR{2Z&6VO66uTKEh%?1V^@dUkO&7CX6P0jnjlT2SaEH4lYo43Bx@a0HC zwv({XCbrqiL#?awagvaf`FsZqmeT5iPU_kv8&nBn@7Dm1oA70pg0xKsyE>UuT|bK?DGgX@i;H+u)F zsQ3R$vNOm%`pqJ(O6ZN)1n6($xoat4EmxzbD&BP$Cr8p_s z_n(<-sjmh=rXSokQ|y1yf}p!b_(4z6s^0&Co)Uk(d^J?RYzEx|@Eq$S>P z*%4z9|CggF%Gn;R97_uZ{~Ef7lx}+nTKU@$49ZYpj7~{-ho4o92Ql9CtFlhJkaNb? zw4CpMSn+*%b9vRAQ6z+E=Lhtg`koBa^R-sK5aCL0qUjDFgF)6Ug`nZZI~_z!wVZUD z(;!VJF8ILGPV|El_)5mwOWUDf_V^CIuxEbLj(kgL(xIU2%O@T}yZ;jDVZXg3uk-gN zjdgt&wpZDtLnEY;KM%+;Z1lTZxH3s=U4QGkd=zt{>@0!KyML1%c~|{~(VR#g?*meP zEA9D@2jm1*$?LYTp^(H3@~=RmNYp*Pp;JQfB@^GCYeS>OA;>6di#o>28M(!dP! z$amRe>l}DXZ=t=)z~_2uS)_b3-mq#uSTolyWRsvO+ISO-)d8_8@D;7^U?mr^*}3%Q zEQuYC>6GfP^LgYrzKqv-q<42DEdNTI=}`dd{j;LW2V7ozLOMYHHF(5z8tSNVUp%?l zJN17QO5-3pzaih~=tcEDhRZ2^I{{tBMD{biKsRyXn^#d^iox^bl(XRYp%jIQtp&Mo z>gf)r;&ObjRNIw6A>@}`I|WF3#ZIpZE|_-IT|8&li)rO=EpMs8Pi=UjKH;68ovUNm zc&ra}_bAF*kv~sq#N~*FyR)+?r=X5BZpI$d{XRb80mpQ6hiwrOT>}F@D&RWHF}e1+w29Q0E|z)q_Y=cSk16PP^|Bdh$fr7e=LreQ`#v zuVt(2rNxAGT1rVQK%Od8Sloji9SLETDkx@=yJkM|a=c!|YwIj9@6pqR)%`{*oAGHn zs>=n`^-rhao2^DY25xtP6mm(FJ|+4E3c%j{mH8-#W=>r88cx|Ov|c*7Cppp;PoH)3 zq&*5luJ(PUqx18X;)<8Si{j)9LEWDVG#S+b-TM24H?0a#4h}}pPgOnZm9C>TK)BIB zEs_|R{9*b!)z%j$ZW`rUuyCGS1As|Nhb0;`$Km^Hxm^-EpezCzt;Ye{le$lYfbWMW zJ_jV<)fOt|U2Ny+k!hYQ)ePPQFd|kw9XgC=Of6S5h8&eIgbAWS6H3|JYbaKlacS2_ zvYQhLB{}bR%sEsYnI;8v7oOQGvJTsUlQden(tV zUds9z3h3l8>U$P$LY!h#tS1q3cI+7ZN(t2I%RAm;PZ!|{g>!e}J67{SVq(g-he{j3 zHaFwjxgh}zkyQ>46}Q)}2}<$tqN8(45u~57qnGb6CkDy4p8EYYNt4EWriLl~d`lP} z>iR3rH9={6Bt2m6u&1SOgjl9C;z< zaK1H;uC15{) zF!Ie-y2LDUz02q3XNf*6C&E{MNsxUiH}cj-Wga;7WYsP0<|^DtwJE#J&5fgZt}J5*?Mp;Gw4d$L<*e zl~`3XzPqzed!F^oYj{#rW@b8)hB5v}&{OZlYaQ6fy6!R2vYu6Z1!?$$$-`HO3b$$r zdOC)?d{ux>1T=*(kzWz2*Vzbdv=tC@uTVu9k&wX4!oaMgzd`T#eejpzcu-9iIE2{; zA0H-r6$?*~)_`?ymL!HKaFh)7aF@#nueijam-VI4pL0)bb2)2!uF6!a?tDXk85lGL zicwO9_~wWjK-B`XaqN+}9TM4BeX7Nr*Tw$4JZ5SYs50_csj?LOu0FEML7kOJCZO=Y z7G)Hab4NqBVY-)){QYvDSCpNC09ok6?1BYZ*66mnZ|jqcDU@ zM!K7W8F9UhO)Pl!6t1{!=cEAT+wifG{s?DZ(p{o zzyAZnAhQu!7O9B9nJykqq>yIrypP_oo^ z%C)iKlXhHaFl>5S64&#dTr2Q`Yrl@+fD@_d^z=kC%wJ1zM%6+LiI84?eZAbh_kFY_ zwegv=*L-r51R8e*7_hDwEkzLiM4v;2|F6sASm+P1E;h8gN%ceE<XmBh0Fs>QZ^HuA%t6z0H`O0|jJWTNy5+n6x zyVr}`Nba+%wBN_o?qve+J>6m5HcS;xr9)e0;D;12#X)NMm5u)yMA|ZgLhEgcO7EcU zs_ELe{8uaf9z3tVQC@Qv6|Iyc))gT8hhtu;)iw8Fmi!PjC-?$aEm`$}F*iHTKm@zT z|3t0TJ^@PtXA1XhY=OfeQ}WLjSu%ZJcM_=WdF_zJKGKWS{m&Qge6}VNaa!D(zG54CAyI;8*3d8aq`#4NVSuG6sZ2&1=k29GWo#2vk+@dl!4`8W|qAe(wq+crL?MU zps~4EN7nlKx~_e_Z#^zMwGaF@TJz;Fs9XRD3J+)g%nODYxB z{hYH^M{lk|Qz@0lHK0b|z{f`IcD3bP57M)4t7{rwa*u;3Eqjm^-zAx>N);2--5RaZ zoN3!IDDolWw^pXqivq0GOq(T~1Ez$+P%mda8C`9+A|-ySRG`gxsn&E6{t5U%oGa6- zD-(BeSGJJty(-P9@rN!NnZFH6!n-PYp9@*KFd>NT+?0CU$Nc=A&7qIm+!fV+YG#jy z{#hS!;wKkn@IJm62;yk}r1ZP%WH@B>+I?(Qb#A>@@D$tie=mm@3T2JKaj8_{bnd|i zH?4Q?snC$87j1u7Z%@LaoytMM_fBl*HPVKi6kT?>IE74@7WO$?Zy_ zO~S-om5Z`|!AV%iBj3&njtL&IW**oZojIpQ>u8^=nKQ}GE>c^UcV?EuL=o46Wi}lZ zv=~JMzB5AEa-lz%+6-8g(jdWyhg|_`J~v zGcucexA(2l$?CDH05$tFGrQHMhg$)yA$9If61Opzae6Sv&e1~Yg-slNR1m03^V%l7 z!rVB$LX7OK+8c?N^3^>O@OaoWLC<*A6Q4ZgnX@&fmujK#0C$_TYdb*x* zmoc^%ccq>u?cE@!L#UM4<8%%W0usJpisi9<-A2dv*xC2Nks~e;DO1AYSA9zn##0Nx zN@0+a>#tO1A6X^tnhB+Sb>S+4bf`tIQ9U!^(o^%2QxEc2E4;!#A0-Rl$=o-W9d~W} z);y1I@HpcsiWnMz$B*nj)!zTMFy8!TUEdrhYpHoz_Mk8BZHxg!uhBEwI>rZ)oZA;G zrW(?BwLp>Qd{uI^;j;M+qeJ@}`jom6J3pGUl4%WYarMQQOHozJIwORPDD=jTcSVk( zSZs53s%zRKiJ$h_7g29KyW12RjI@Q?PJ|!sYgXt0oHotj7nnABYJQFNZ6^N*r>HoU z*l%`~8Dsd6aA1=YewOL+%goRe{zNnN?EIcNow(=w^F*Y2k_fVUU$&y+`2@alxIG9E z-i{ePKbEd9NH$pYI|W`;Sk6>d>b&8p^=A(hB8fI!<=kf#jF7Wm6$zeSuTM2MDl0gV zHP?!tCRpd3L^sB#Q1Zd+t_Gh&nD+lt&!x%#6Jpm&+0XtT1z)z}Iv*@LoASP0(v{F* zGCNb~7e3G31cU8BsT8@;TD1%-;5edpyDgs(k5%5!i6Go=`7Z{hWvQ~O&?)m8zmZ2u z_6F)ZAV;v@bd`;`iG77|?u_*G`Vi;sCy#KLxLA*Y*3nmj7f8c5c{}Rs_;}IK`$6ju zD*Ppfa>iL!5!YjDG^)x_=>#FF0`(mb!^Pzbr_Mnvl83L93g5MSx)lm>;#vZJ`2}A4(iY%nIR;CYZ^n8+i z2f-@&v7l)DKLCPyWIHOE*Bda<<}m`!cF%GjB*6fb-t zO8rwPov`Otnrnj|sUr0U;uB+o>1fnDL9yGK-A(P0*)s2OieoJgY#5ibCD@*}m)R!6lUMrD`=7mE zvQC|ZHW*xVXX}~Y6EAc5?r+wj^0cSv>QnI@cIrv>zA-M(^|Pb`*bbyqt`RjZKg!R) zoK|RW?x=h61SJBwXqID5VsDjo<6bQj8m*>LKKo$?;NwQYbexu;ab@`|pP@8uT{7g? z7#@>#oInHaES}1;i4=Cp_M0|zTEcIOTCZFOXcztUzlk;UN|tziJEghG z|s!_Gu48XzVj=aAm2 z+#?!^37XWd31lpX*$_)MKSW0wr|z7uBv}N_8XwXlai@;X_SX3@m>8QuIl8GFn9(x) zgJPA`GF6&R&3v6bL|V^piBt#_fbQFxe^%{VY~|^(Y%!&pvGA4P!)yK_+sXhzr{CA< zr|j6hy@#HQ(wHvQUOu9anG#r{XuG%hiruZ-#Mp}a`LNJaLZ^(`dyu`kQ{2hD>ly~U z%Q7OeqwAU^i}p6Z`zZ8^t%^dFHL@fL;oGb}q^;EQR50J#7#8g3bwu3ZBoC-Hh1-5f zuhXVW-he=-o+6}&--F>#ta#XUx4#?q%AUUSZuA1Hpt;f%t9{cQm+m=>S3gk@j?~DB z91mxpIN1ci8OF>C=}GL>pO27%-vZxR!Ee+Pfr_vnBlTtMypm+Sy{)+T-caJpk|EyN zk9}P?^rW&etp*5ti1FK=q}KqB!9~@jYb-Gf6yPD=o@YMtxY|g^*Lpc&#p=D7fLO)S zZS{D#K7ex zMwxOrk4b;v!Ij^e7kJSAvx9Q!N85_z|nQ6YHMV9J40-y+$8?@j8{|Q|e$tDZr zPs>2RiWgIH9B-&!ijS1i9Z0zIpxy}QtvIcmM3#O}1fUp&Te+C#EI;Psg* zDflOXuK1;mfk+_8N%$fyP)k7l9#K^2j`r;8;uEybu5scAxT)gV&oQ`E+&RNN`|2CX zcVap+%5-}+-ua6>s9`wI2e?yAt1`##6AOOuN^ePt#}TACrwF9Nq@xDOCI`Kc!Bszd zX{1yz9z=@;TBF@kJGy;DoeYh@A%!&)g|+acQ~RpG5%vomak8*$fuXyFN0x!7MNRV= z*$$Q9tFc z`5Y|SR=T1T4sXK)?97QILywu}$)A2e`lZIpHTN!(|KvB9x=oHz*IpRdOh-WL@(KN! z0yUv}LZ_VvUJ{W-@a9B6>bNCDTJia{6sX0Ra5iR#_rJ*u4~L}j=mw%ZIEU8y3{w=V@Be!H)-UVbiQL<+>F_H90Hzo0^~5|xl5S0q z<5C*aO3SzUVO2!}hbF7VkSaX?NMOPWt$N#+b@EoJ-Dtcq85kSh$AX0_eSs zI`DiA*W7_yaN{?8QdMr5NeLVvtQah%IA7RtSXG~)qf!}%UcM<1UF-gx2O-XFf3vXH zeQY{dH@q0NY}Mu-!WqEKF~8S@wx#$-TY-6D(`4rJ8c)$;ev7QRv&^YW=m~-Am$%2{ z6+YTYk1?qy7@s8Figa=tbuhDnjt3Pw?(8|eD4m;|-U0vXMU3_R)GwS^WnpC+_Uk~o zj}9dm1xHui+Ht4s%hP}@a=Q2v9unR@d3GtB{ko+ry`^&?{tc1>uGq1wCH$j__!|M} zd$Ori6AjuT`V3_BjW~CS2eI4kxMaQ~HsYQoX6|bzjyaWPP-~{72MOxD@gX{^GAhGV zsv53H8|kj)@Mmjd)!_$lcFgbF$27_6e<4?NwHtmwPqQQQ?^yEPdAKlD@qut& zp!-x{*){$*NZ}#V%}apvIlR9a-`s}Vj8Eb3&;9F0uZtz|uX&2D1^hA)WjzY(Nxe#^ zG2ql(p|$Eg-4W^Ls_!7y_L}p)(<|>Y@4f%ejJ0`!Rw>m2Cq6mSMXu-HQTem%w{aHf zzp7z$m0jt+b$-nz@DgUAQa&7-*f?c&pGUdgK-V^Pr8Melw%#t5@&!=O9UA#AKJ=;^pknk?R(zU7$yX2~UMxbg!g>fIq#U0xNcYS;8}e^} z(hASz>yWQgQpOr?bZnl;HUhUTfAxy9E#t^dbKmGNCWu6cjn_@`ux{#N05} z{O}D&y|!6F1~5MY%(9|x-y_#uJ{gGeC{<{Ok;lN9oReHp9m1K5XykJ6cj3eav94s> eqvO!Rn{1J;6sep(*n%del0}CwUy$klmj4fGKZ{8K literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/refresh-code.jpg b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/refresh-code.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8af7a04c2465d741f0d00ee68389b4bff9393957 GIT binary patch literal 128150 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≷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%0A7F}I3PPa3_45o@M}z~RXuPr}@-uEziT@xL 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/splash.png b/script.plexmod/resources/skins/Main/media/script.plex/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..e7a2a53ac5f5bca42c13de3624a4c304311e9bee GIT binary patch literal 9464 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 R2a<@0^t6mL8`T|O{STLR)H(nF literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/square-rounded-shadow.png b/script.plexmod/resources/skins/Main/media/script.plex/square-rounded-shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..e22480fdece3ae6c6548e3d029ececfb3557aea3 GIT binary patch literal 3941 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/stars/0.png b/script.plexmod/resources/skins/Main/media/script.plex/stars/0.png new file mode 100644 index 0000000000000000000000000000000000000000..fd047749a82a6602debc15f3dde6b9beb6d3872f GIT binary patch literal 679 zcmV;Y0$BZtP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00Iw5L_t(&-tE{wXjDNE$MN4B z2`X9`#J^~xrHvL53lS@um`1P>F(7vS!9uhU!BT63+FDrHNgz!S3&BTm!CY*$Sqysh;bU95dv(x~bi;ccPU zO<~-YG*V+C;g#S4e}Kgrx4!Ul_kauh8|P|BBD@kj;I&(Ls)j_u%iRNZ17F?3zk#7m zOd`AtyiS_WgOZL(T9))((x9ZXn^@rCW#A0}S0o*Eg<|e%N;;K(pOiEw>87N6z_29T z)l7Gjv|wiA>r`(;(&g~-_XO+$CfInK2F`cz+$6B0&DIuP0iHQvRMLbqrzO2lThFSQ z-AWbuJXP1Kq!W_PxH%Uky)iR7`1XZYiU$kQm)4-t~8l&(^@qlf> z12^d%u-C;0fVVFG2-w+2*Bo9+9&jm5oC6NDnjK&e_?BY#D?C<(myy@l;Fu#xGiEjq zJeBm!%vL0|{vX+I7s~{bwGq&n>i+?mvJT*Vwei z;R=!nuLKWxyyk5C%Eex;i9M_!k?>0JfY~(Z7jR>p_!zK|p7~ipBH`uk0VjcF;B&ie zCY_l-q{WB(NFuxvJm5O;qKg+92cGniNO&c9z@8pnW_YP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00JaQL_t(&-tE^vXcR#d$MN4g z5>&KE5dTCJL`xejA{HW6HkwAT5m693|6n0nh+wI;L2WH8>?DvTh=pJ)hS(@5S{MQn z!9p-x+^@|9hvm5J?QLdv;SDUi?Ci~FAH03{Mk+V}12!wsaIapkGr-!1Buy#ZaIZ#h zki@tl>2$(C+-rje`~`j`EPd`Z-2=|>f1FGZgnMo9fEUria|r@*ujw8z27HMY{sW9} zU=U-#C->_0iZq`SlJN6C0S|6Os-}T9NeCy?VS6;DV$BQKDFMWRi}C>o}2a z1Cx@7jx3x_(z2ON_sHIkr1J&5j-**hi;}Lnm);Yw4Va<2F$-+zQ`(Ap$ADAr)#F(N zOi7vWz%3wi zuVxR}87-8B^EY52cMo811wq8#?;c*)y#{!|gIr~J9?d<=&E2aY5ck^P0pG)qegao} z%wGbQ!!tiB2*kand%zK31^Cdf%!EDj+pzfL5J9-t1`oIbJRRUgrh$h;1ma#BJYai? im)Qka$w1s|p!W})8x57wu);wA0000e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00JXPL_t(&-tE^vXcR#d$MN4g z5>&J>h<{NKEp4=jScq8JXd1yrL_zHQgN0}zf~D35wM}7RCxJ9UECgFI#705U!Vr)X zECj>F{aR$i@w{Aa?>0NT};a*y=kt6p3Nnboy$wlcE9f;OO-Y)Qbj3Y21#AK)DK4gf4PBd%y_rx{pyi1MKQ!VU*Hq z0T;Vmd)~c&Z&(N1&he7&0viWdHK+Do09&K>A>g@t%L8Y6cuBVk+*YOX=71f47IVNb z@L{ccjTN>zE5)9Iw^b>;Su>jl9!Pp9%67iFX}%7a8-w4Ip#x z|D@ZZL|OR#49vFu2e7+e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00JRNL_t(&-tE^vNL67N$MN5D zQ7mdmq(4SM)aasv(Gb$qqAo#8M1i#RhlbEW1jm|_YHet63&BOiL2#ACmV%;&L=c09 zAh~wF4ZY&a<#Iju-sAB-ocDplIo$W$_j8`Z`#$G=rIY~}a7;Nx^p4i6G|_jTq*3J; z(K|w~nSt>{(r}K6M6U=Q@E7=%W9f@t=pHb_e%#0*iRcx<17^LB7jj4>dZBy3Dd4Nu z@gJc35R)i__c?Sg&Em6H(j|ADNa~a{bch4I4BizU98jC0+Igig`yO>8iW- z2hun&C<*UK+}R{;o7qgA(OZ#pCwi(#nwPX8=~0NDfRn%+*~L6?yg_M;-v77;+ziz- z4;Ym+*JjzeCF#AHk>cA|Hg8SRvMc4gX7?n>&HbUio^=mu6>m_=*A`4$#N zW%8=PSc7}-1?>S{z+@9IZ5lYy#;Un&-V$)yYwrLS3*!N|Q@pf^47XKf@iu^Sdy7Y) z6ZjIES2>pcZNdB!I23`m0a zfHPi4i93G>)@yzPxR5~-W%7R4@v4RJfaf(c=bhK~wx(?=gG8cN1P}P({`3=gSf~9y zuI${>;Gh3)|Zzz*=SQJHaj<`viZU>iw9uLvIS0C>~HgUkRg+DIgNMeu;079Qp- fU@ayRy#T#`aS}nLd3CgV00000NkvXXu0mjf0~$Kd literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/stars/4.png b/script.plexmod/resources/skins/Main/media/script.plex/stars/4.png new file mode 100644 index 0000000000000000000000000000000000000000..b90e683bbef0ab0ac336f948df036a93bbc99c48 GIT binary patch literal 686 zcmV;f0#W^mP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00I_CL_t(&-tE{uXcR#h#_?y4 z1Qjh3M5AIrw6wB_Sc#QQOp(GSh(buGh(*vs1WRo-_)%Jx?JJ_H!r<+PST#FZ?WDGa6{7BV4%3*$Ru6#*Wp0A z4@^iRI5K~Bl6IYQ3vEVkL(+_Sm3s|I%aXPv-HGu8908U{SIfYm4pWY$m2aE!11p<5oP8C=fnOC0I1ZF!tdoz~@ z8~`5X2=N#=+{3EbymGyFz_Flx2v{xb0oNl!JV>~$GOrwO3pf#cN``?i-MmJZZBDlu zPrR)%FTJyn*oU0h@ub4a@^sZVxyfbd>q?cVMIC z9>D1YA~6EhBj`XnWJr_9#IR^XlLMKm3n=0=L_=-vW01Gdl@_m^bJi zZ~@o@K6RRA{GR!P?|h<%5a!jv1LlBNIbLJ|c-lh{^XlLMM+>~nSnOZ7=GDXd2jXj+ Uido|yr~m)}07*qoM6N<$f(OJZ)Bpeg literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/stars/5.png b/script.plexmod/resources/skins/Main/media/script.plex/stars/5.png new file mode 100644 index 0000000000000000000000000000000000000000..ab646cf5cea02915ed4c50279c06fb40483c231a GIT binary patch literal 568 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

    * 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 K=T`3$mi=Ec5D>%w literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/movie.png b/script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/movie.png new file mode 100644 index 0000000000000000000000000000000000000000..e847163b8c4cde650ea6c6891c0d334e4bb5f8b7 GIT binary patch literal 13306 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 Eg1MC)mjD0& literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/movie16x9.png b/script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/movie16x9.png new file mode 100644 index 0000000000000000000000000000000000000000..7c2c92942de28bcc5b07416cd41cf0ad261d9f7e GIT binary patch literal 17652 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 npw$Pw)T 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 JQzHcp`5!_vYB&G@ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/photo.png b/script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..ecaff1e927fb657a30995f1fa932208ceddde4bd GIT binary patch literal 16984 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 U=lNd!TL1t607*qoM6N<$g30+WhX4Qo literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/show.png b/script.plexmod/resources/skins/Main/media/script.plex/thumb_fallbacks/show.png new file mode 100644 index 0000000000000000000000000000000000000000..b4eecad88ef726bfa675e9a3e98e9153d809993e GIT binary patch literal 12438 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/user_select/admin-back.png b/script.plexmod/resources/skins/Main/media/script.plex/user_select/admin-back.png new file mode 100644 index 0000000000000000000000000000000000000000..2335b53bc9144fceaeef0a7af2689b820ec23659 GIT binary patch literal 719 zcmV;=0xe zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00K8jL_t(&-sPIVQW{|t#ee7P zGNdGJQrcOVl94VBJcFsM@;3Ma`XJirP->CRGPF{Xv5F_felWP=vWyJuUVjZcJFvTl zbNBmm?-g6XHj?JYhd>WF0uF$$Ko|Iwzy1VFfeG*c+yi4tzsuL!JGOhaFZ_NkZ1?sp zMz(+2o_YJs^0l=qG4s!XcgJA)-gVK2!n(j+es6Zk1o$p#TK5NO1DB40$32K5-}5m) zLoN5#3X_EG5pdIhaq7nQsLrUV8g5+yKWG-$z)6+BR26;=6-9ogtE#X}Yr?OIq88$+ z!cuQIcHEG6st$cgx0S-Ot=&BOwTUmlblJUB4#7N6wT-)SNT!lwgFVet@1E!8E0kBE znAc^`w3{T!WyelwKc}l4n*p7c3;QeSGeELU-UD?4IM&H~LsA}1&WOXAq#_i(>1LwM3H5U#w1aca-#8&DC$$uxKF@1ps;b=ZA(7B45aIFks635%y!^p&eF+W z0o+<>h@UXcCx$H+HJpoj;nSHx9G(CG002ovPDHLkV1hE# BN5KF9 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/user_select/admin-icon.png b/script.plexmod/resources/skins/Main/media/script.plex/user_select/admin-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f98f6513626063e2dd86d20cc1b5f09ef76bbedd GIT binary patch literal 954 zcmV;r14aCaP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00SaPL_t(&-tE}SiyT!H$MMfx z9IdE~M)3g}GtnrCB!Ups_=rM9F$>+eml$^;poqE=gDVwGR5T#C5E1<&e3atGWDFS4 zMdAxWe2n1WK%(YmCf2yQ14Yr((`l=_ai}l!rn;-n`Q3BwxxZ>!T3T9KT3T9KS~@c} zj3BWH+p!Bb;tL$e^78xtwXj%(tMDEkNS7Ay2A z6PV5N^7KGjF&5zwe1MPfS}ej1J>Gf^ZchujEf(SY9^>VBC&ha!7GX={6^lif#4{;D zxEZHn5uVHPvRvl&+pxF@TX8*(Efa4wp1?!t(#Et;A8Wc|t1HPZ?$7nOV3`C1?ymf9 z4esh8-UK$(;%yj2D;~#3mFadCM|!W&{T|T2V=A@D=CqQ}r=+S}UTZ^@cDy$hVZ0`4 zwqGScFHhFSYhqEynavoJWNd_$rP3>PWsH*To`iPQsS5 zZR6OU1n$8VweSB)Z8$e{uNaH)RN51rDt|hiUER83KIPD9foJe=mX`-d;qIsK#}ePI z>f!n0UApGmPE&JO!j7c`nq~oqF*_<@v-q;&4w_;PQ$2Xl!3ax%4_3y0Q~Z)9;z-}1 zkKosag&oCDqZT&PWq|a{begKedxP%48GM328xmFGaB?@J{m&y7VNDl@(bwUh<>kqd z3X4UUz?;d%H^tj{`M*@HiB=5B=uS2$Y+Vyctw>g^uqIk@0iUO_-xObKX=!O`X=!O` cX&Dgz0tKVpYTP;VrvLx|07*qoM6N<$f`y2`;s5{u literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/user_select/avatar-background.png b/script.plexmod/resources/skins/Main/media/script.plex/user_select/avatar-background.png new file mode 100644 index 0000000000000000000000000000000000000000..03926d8f23e898d832e6ea8d87ef329210c6163d GIT binary patch literal 3476 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 YuE054T{#{p{8<9roV^G&jv;CP2ZG~DegFUf literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/user_select/avatar-diffuse.png b/script.plexmod/resources/skins/Main/media/script.plex/user_select/avatar-diffuse.png new file mode 100644 index 0000000000000000000000000000000000000000..b375889ef74cf7c505c9ebbb74d654d18187ae70 GIT binary patch literal 3224 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 Q{V)KYu0Of7{zyIdU;kIMq5uE@ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/user_select/backspace.png b/script.plexmod/resources/skins/Main/media/script.plex/user_select/backspace.png new file mode 100644 index 0000000000000000000000000000000000000000..c5324296fa81e6d97f9fa2635efc3e1681428a59 GIT binary patch literal 966 zcmeAS@N?(olHy`uVBq!ia0vp^-a!1GgAGXTI;<%Kq}Y|gW!U_%O?XxI14-? ziy0XBj({-ZRBb+KpdfpRr>`sf0~Qt$K`xF!M{%H#WQl7;iF1B#Zfaf$gL6@8Vo7R> zLV0FMhJw4NZ$Nk>A5amqo~MgrNX4zU*X%Rql*%0ccz*Khn<_W9xUN3=KuJU?!VyS0 ziBH_&vZT4$Tej=cR;7g{T}!*0`INRa2b2cduy$IBxJ(FB(&}CNNM2(~+}hSBm*VuF zRaMIP1$1ii*`B<5y}G9EgUyFWzirNMpD|lbdvX0$2BwG&2?v{4xfyl9j8+CQFvE#~ z8_ZB_US*1pnI*!b(4+Q*-K_kVv=qYdQvoVgPG z`&CqZ^4vc^x9_QX#?zTw zPN|&S=bnGwA@GanwPpVwDbD}DWsdm0SfAB*TdO|IyZz}1^WU#r-(+4_EkC2JzV69e z{aKp-cbG-!7FA?L$N%Fs|5`MQ@4Vj9doTXH{dMr<+MUJTtYMMUem*%<)HgrtSbbL+FU zk@fvk(aUH3{5Sn|_POKkt1DL>?|$*8b?TLUdAT)f8W){-vhJbJJE?Q&_Bzi`xcA1y z{3^b)Z}*LJCjutkeY`i?%{;t&UgFmr&Dxab30ddwPPG+2{PXpz$`{RUVzXrLuQ5%I z)+~CkacyPg`ENX7yHnPd%@n^M-BP+()B4vL*_&opSZ7;rpTzGU-@G;M@#3p{e!l7J z;VC;9_x}sf6GGRj?%D>O^bWoqtT~Ch*U#=>ndG(Jsvq~x-rQg9J?Y6@{n@pxp=W&i zr(QfZ2be-wAjyLhl3IiyiANQZmb@WpV;VH6fKnGw8HA*g#=ri*WcR#VD$#K+WCk#M OF?hQAxvX|gW!U_%O?XxI14-? ziy0XBj({-ZRBb+KpdfpRr>`sf0~Qt$9_GG>Q`ZB9BuiW)N}Tg^b5rw57@Uhz6H8K4 z6v{J8G8EiBeFMT9`NSC*n1wuD978H@y}hTWzoYSYr)%@kPulL<8;rFY(`~9(H-27dy zs$$;1F0PGYV`Hmx`@brTWkbTjCRT1SrU(dwQ3uRuWe@{1oEW&l48;bZ8lZ^40gz&y z2o8uY9V%--nBNzwH$8a$_2AW4_x-uIG)VJnl`Rkz7Z=}`&d$lvnd+tLSyWJvu*q)K z{{8k>vrJo^6wAxYEiEk@zxs=IAH9;bwWO>}&9kh${PUkbJg?vP_V=gf=j+GD#(GZb z?(UY6ldId!yKn7G^Zfk$^RHfIiHVC}zV+*Qb!AP>nOnDRZT};^&9rz{-Jc&5=gph9 zKPEmt{`}jwx@(*kPB?k;oa*IUy}ef|EG{3bRwf1av;UzV_U z&z>hQUTC5`}_MI&bn1zTvj%1=FFKu z5ANB!SJg8rDr(c-y?@{FzYLi5Jg`{5W~ilEsUaqoboY*v;Owbm`JN z_wTEFy1Ba>TU&F#UaY6Dzj?!k32uugszgRcdPYY}uj${lbEoIhpp&m(XIE8M8=IQ4 zzTSN9{Q2OuVUtxpfBt-*YjtWu!h`fL)qcQuhs6E{7D%e#1gDLILXb403Q0oVkc2c1 knnJ*-i&`50ssCkUjhrwouG7B=n1vWTUHx3vIVCg!0Li$B;{X5v literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/user_select/item-background-bottom.png b/script.plexmod/resources/skins/Main/media/script.plex/user_select/item-background-bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..f39ea934a3a1b70ac03d6d8b2f4eaface8b47c2e GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0y~yVAKJ!y*b!`)^mS!_z``VE#THmm{TwJHS>hT|;+&tGo0?a`;9QiN zSdyBeP@Y+mq2TW68xY>eCl0ia*VDx@q~g}wYleb{9e7+WUfp_7*g#RhOs#;$M|tnZ z9br=K4qErmRL{Mo`)|dr-OL*r5}6z}FtBh7=r9~)63_v&fdq&RBv`nKlq6aqUMp~$ z((u2jbQWX80n14;Wej2kJt~*^4lq4ivC8&j8ux=^+g9CrU0(WK`=s?r7nc6VXmW?*4pOZeH|4iw=m z@Q5sCVBk9f!i-b3`J{n@>?NMQuIvw3n8ZvB%iTVw0fi(>Tq8=H^K)}k^GX<;i&7Iy zQd1PlGfOfQ+&z5*!W;R-85o!?JY5_^DsH{K;aKS8DB^Ol?xq`mbq))oA%l?+GY5mD z0@t;(&#DtvSh+jt=k1+&a@kw|N%vKDtK4U-*k3*A^O=~*Dcd6cs#@M+i@5Ut%$&5{ zYxKS`h?URSwq2zy<`vEf=gQu&X%Q~loCIGNp>W2UT literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/user_select/item-background.png b/script.plexmod/resources/skins/Main/media/script.plex/user_select/item-background.png new file mode 100644 index 0000000000000000000000000000000000000000..82f2aa60596ed94f3198a04798ee4a3e4af5d666 GIT binary patch literal 1022 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4mO}jWo=(6kYY>nc6VXmW?*4pOZeH|4iw=m z@Q5sCVBk9f!i-b3`J{n@>?NMQuIvw3m_(FyQyu+85eUCdVd4T&!vI}&a8=cCYu$^E~J2$M~cEyoz_|TF;>BHTx#j++vfs z5)=CUR(=?NHAD0774QD}6>VfS`1N_iuHWka)--&~y?Qs7{Q-xXFhdioLPSFXBZnA} z0I`7rU^a&sm`#i%(F*ZeF=`6-pdUuz!ZD4L;UJTMj>8597H%K`Vgm^Z(E_+h+q~b}FYa1AC fChPn@s+IqzSf}{y>W-PfY{}s1>gTe~DWM4f;;;)k literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/user_select/plex.png b/script.plexmod/resources/skins/Main/media/script.plex/user_select/plex.png new file mode 100644 index 0000000000000000000000000000000000000000..2fbd92adff07dca33b6b5297f372c44fe9443850 GIT binary patch literal 5374 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/user_select/protected-back.png b/script.plexmod/resources/skins/Main/media/script.plex/user_select/protected-back.png new file mode 100644 index 0000000000000000000000000000000000000000..a318164bd4bbbe11f559ee2affac9afdb3816509 GIT binary patch literal 719 zcmV;=0xe zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00K8jL_t(&-sPIVQW{|t#ee7P zGNdGJQrcOVl94VBJcFsM@;3Ma`XJirP->CRGPF{Xv5F_felWP=vWyJuUVjZcJFvTl zbNBmm?-g6XHj?JYhd>WF0uF$$Ko|Iwzy1VFfeG*c+yi4tzsuL!JGOhaFZ_NkZ1?sp zMz(+2o_YJs^0l=qG4s!XcgJA)-gVK2!n(j+es6Zk1o$p#TK5NO1DB40$32K5-}5m) zLoN5#3X_EG5pdIhaq7nQsLrUV8g5+yKWG-$z)6+BR26;=6-9ogtE#X}Yr?OIq88$+ z!cuQIcHEG6st$cgx0S-Ot=&BOwTUmlblJUB4#7N6wT-)SNT!lwgFVet@1E!8E0kBE znAc^`w3{T!WyelwKc}l4n*p7c3;QeSGeELU-UD?4IM&H~LsA}1&WOXAq#_i(>1LwM3H5U#w1aca-#8&DC$$uxKF@1ps;b=ZA(7B45aIFks635%y!^p&eF+W z0o+<>h@UXcCx$H+HJpoj;nSHx9G(CG002ovPDHLkV1n{Q BN2dS) literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/user_select/protected-icon.png b/script.plexmod/resources/skins/Main/media/script.plex/user_select/protected-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d6188176d3d96d295a6549a695a5a4eed8c082c6 GIT binary patch literal 688 zcmV;h0#E&kP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00J0EL_t(&-tF1FYZOrw#^EP1 zCh;3df&oPkMI#6nL9tO3v=|Eo3q@}sR*EPFOlc=rXdzfwiQV`g=oEsY)+vNQK+#S? zQ2aoYXv|tT3q#n1d`vdG>;1trvwP2-mwV28?wuhLi9{liNF)-eOl&tdpCJiwhaNyo|()?QMaOSp+W^N6_?=W!!s zVQ0e#3t32T6+H{goa4A0vd~qAu#N?a>c$ytp7PTxyv);Vx_LL@0G1cToyNobS~_9a zmK#N}R$t>Hp5f07E3^jJ^3|@6Ux$Ms3y;zytt_RmeypEzZwxQeB%PRHTm@f479Qt@ zv$`O7d+w&=OIc%`HDdhC?R++TukqjRGTgc>S8TWz)QG}FVgIABdF6A+!ftHEUJRkw zRG;H6e$OJ*E)3_^Uu6Wh@d;1TB>h!SyC25Mf-@G`k9~7=)*^$rj~_UJr}Y%pTjPO> zS)5JEBRis=~rwNx6&l7ig_Ed(2MI> z*32vR1@EWadxwc;PsIToE%d*h{Fu|#?85pm6tYk~h@QgPR@qW*EX=b($#2GDA6o=g z;z-ECo4n>)Mp$3Ishupm0%!?guqvL%qOiqD#Zl~7Wb6Lu--nAxBoc{4B9Ta>RQ>{t WOJqz^qWp^h0000148Tn*JgfQ_x$`ZwSG|n1tumJhXxJ~ z0Y*k8+Ot1>P)O!kT@$>0+dY+^yY}38|K0Ob*1E6OxwSXLcU8Y!{cMiyu@@@mywcCz zG>=-fo8PmpGERQc{HZE;|ISOv?%%x)=<%QKwbN5Jp8RXz$F}nH?aR-zr$4bgIeBi_ dduWK&GjLS3zWB1dQ4APk44$rjF6*2UngEAQ%k}^O literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/white-square-1px.png b/script.plexmod/resources/skins/Main/media/script.plex/white-square-1px.png new file mode 100644 index 0000000000000000000000000000000000000000..d81bd9903be5c90adff57c7f9a763a52d489cd95 GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryoCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#0Xw^phM2RDWgbvSvcxr_#5q4VH#M(>!MP|ku_QG`p**uBL&4qCHz2%`PaLR- l$J50zgyVYhkN^Me8Cd@@{kwA}@;OkP!PC{xWt~$(698CrB-{W1 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/white-square-6px.png b/script.plexmod/resources/skins/Main/media/script.plex/white-square-6px.png new file mode 100644 index 0000000000000000000000000000000000000000..5a1083bec31b5302f7501aa3753aacd003efc0a9 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_|R1SIpFdh=fSp}PUNcp9OFB?Uvcxr_#5q4VH#M(>!MP|ku_QG`p**uBL&4qCHz2%`PaLR7 u)YHW=gyVYhpa1{unY9v<4lrC1VPXip%gm{=E@diE0fVQjpUXO@geCxW(#ggMiCL!-caKFg({gI(3Iuc~X&AV~HnU z=Zpil9{d%0_VU}ZKOv#jlXOo`O6k+fmlF7{;y&rBimij6gzc_gW7fsoCw>@Td72V> z^)&lE?j>g~yiVclXkZW&P+($macJP6HJd|#5op&h=_k2uaSHy%UzjYf4u_bxCyDx`7I;J! zGcfQS0b$0e+I-SLLG}_)Usv`A?2>{OTwc6x=<11Hv2m#DR)@JY5_^Brf+}*eKdyz;h(vDDws{x9@C`n);CrCL#e0|F*8P zWVo_!*{&L|t;OBT-Y>hgGpv5oN^XlE+h%LAItDWAzVMd8O;P4+^{V#y(W<-dPbivf Q1T>ey)78&qol`;+0N@%);{X5v literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/white-square-rounded-top-padded.png b/script.plexmod/resources/skins/Main/media/script.plex/white-square-rounded-top-padded.png new file mode 100644 index 0000000000000000000000000000000000000000..d886c3b15385a49bf64c58270e62c9d196c68fbd GIT binary patch literal 464 zcmeAS@N?(olHy`uVBq!ia0vp^DL|ag!3HG1l|BCjq}Y|gW!U_%O?XxI14-? ziy0WWg+Z8+Vb&Z8pdfpRr>`sfBSt1BM#Zq>EXhD2$r9Iy66gHf+|;}h2Ir#G#FEq$ zh4Rdj3F!Z?A65Jrp3)`mi{5lMCB|zMDrT8?a5T5cWCC zAgPp>FEznKR?+&>_wu^+*7KiC_qeowWt{!4-*ZyDihPO;&fngxI&<}_Puxp(+fO>< z=_Z|fX;R9nRqNGHh#vc<5n3uGw_j7@wt3n2ox7?%KV|mU?$Nw@_rBbRyIaD_x66LJ zoWP{O#N^`8z`-HF$f!gg_6vQ5)skhGtyFg2PBg#UuCiIS>~f6frMuTv7TcQTu3UBb zbKv|*I%YTd9w$zyvVHsR^W#S|o+K>aUhZuae)VbP2j(l57VowRf9(MVG=rzBpUXO@ GgeCyKeVb+g literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/white-square-rounded-with-shadow.png b/script.plexmod/resources/skins/Main/media/script.plex/white-square-rounded-with-shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..4bab599d31e50d0644470348e7bc5f3251131f61 GIT binary patch literal 3060 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/white-square.png b/script.plexmod/resources/skins/Main/media/script.plex/white-square.png new file mode 100644 index 0000000000000000000000000000000000000000..52065d4eca006a3d8ab730947a57b43d5aad0b6e GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V6Od#Ih`sfT^JBuiW)N}Tg^b5rw57@Uhz6H8K46v{J8G8EiBeFMT9`NV;W vL_J*`LnNjq|M~ylo;mM8i+di6H#5W1$IODy*p;^f6) + + 1080i + 1080i + 1.0 + + + 0 + + + Main + Plex + + \ No newline at end of file diff --git a/script.plexmod/screensaver.py b/script.plexmod/screensaver.py new file mode 100644 index 0000000000..8e15051bcc --- /dev/null +++ b/script.plexmod/screensaver.py @@ -0,0 +1,24 @@ +import xbmc + +from lib import plex, util + +from lib.windows import slidehshow + +class ScreensaverMonitor(xbmc.Monitor): + def __init__( self, *args, **kwargs ): + self.action = kwargs['action'] + + def onScreensaverDeactivated(self): + self.action() + +def main(): + util.DEBUG_LOG("[SS] Starting") + if plex.init(): + with util.Cron(1): + ss = slidehshow.Slideshow.create() + ss.monitor = ScreensaverMonitor(action = ss.close) + ss.modal() + del ss + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/script.plexmod/service.py b/script.plexmod/service.py new file mode 100644 index 0000000000..1698e97836 --- /dev/null +++ b/script.plexmod/service.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from kodi_six import xbmc +from kodi_six import xbmcgui +from kodi_six import xbmcaddon + + +def main(): + if xbmc.getInfoLabel('Window(10000).Property(script.plex.service.started)'): + # Prevent add-on updates from starting a new version of the addon + return + + xbmcgui.Window(10000).setProperty('script.plex.service.started', '1') + + if xbmcaddon.Addon().getSetting('kiosk.mode') == 'true': + xbmc.log('script.plex: Starting from service (Kiosk Mode)', xbmc.LOGINFO) + xbmc.executebuiltin('RunScript(script.plexmod)') + + +if __name__ == '__main__': + main()

    j-HIX0O3AX@Kx6(5$ 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

  • 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 axeV-gTQ3YENSp+j6bKQu#B=_A{{H|$qnl^| literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/0.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/0.png new file mode 100644 index 0000000000000000000000000000000000000000..e04b08334bfe1568010fea3b1938ee589ba7ea38 GIT binary patch literal 4573 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/1.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/1.png new file mode 100644 index 0000000000000000000000000000000000000000..75318efd6da3ba48d9eecd6b01bc9b616e5ac214 GIT binary patch literal 713 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST~P>foX!Li(^Q|oVT}c=Sl@KxCW|u zamsz()F@T(Uv&x3?NpyS<&@l$U5OQILK(huY-u$q5a$MJ#seDOOFonPaCsgO^c{cv z@vVIO;fEh4r}G>xD1R><|J(L^!+*oR#}!hC>-OJ2zqk8$p>bo+V~c%rZ@ewry|cXV z{yL)x&w=2wL|lA){PTN9AJ4R%@U&>BP4B~}PoJi~i`@_rV=>`s)>fY$0|C%E_IYXoh6e4cd0cp6x^FTIGGBkQsIj9l zx_Fzzkps3B9kUDVYjxgB4l0;i~P2LZ-MipYh d11T}ByAaQHdaL!EmTWnYsHdx+%Q~loCIEBU+&lmP literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/2.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/2.png new file mode 100644 index 0000000000000000000000000000000000000000..f3a4f64065fb35623e7e383bfb870b6e98cac170 GIT binary patch literal 3368 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 CbTqO6 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/3.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/3.png new file mode 100644 index 0000000000000000000000000000000000000000..21897e381aab8c869d8734a9f034c01607080be2 GIT binary patch literal 4067 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 xakq8Ty9d`TA>xfB~M5z%igpjOL4I;{9 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 Al>h($ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/6.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/6.png new file mode 100644 index 0000000000000000000000000000000000000000..061359615b000322caa81f883b14dd40853dc293 GIT binary patch literal 5154 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/7.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/7.png new file mode 100644 index 0000000000000000000000000000000000000000..a9e573d2095bd5c85a89df0dccef2c089d810af0 GIT binary patch literal 2246 zcmb7GdpOkj8Xwolwb-?zS*ElnEk}(@WYM_f5^_uIVP?WHvcwr|Yf4xs_R3S#3`)od_YTh}>^O`+n!=pYxo*&gXgXJo9^h@B4l}@8^9-lKpuLsr`!k zaX6fmm8F>@{C$dk#6;nDm1}hY4kwmkWoCRKEdS%1;lSQadwz^?%f^Q3NeZ@+Kv6SC3HP!K|3#JNI3?o{vYV55$A3R(&@>%@iaLxVb9%A zX3Uo%JEF1kEOM-dtk~}&f&$HCB3VI9ct$V|MG7Y;*JpLlHZ+o+Fh?Jx^#?h~pkGqV7aTa+Bqx0Pg|3<=s}3+BO_*WRuo;UFy(a ze}BKcG_&);kh+?hnu>Io$8f`yVVm;0x;iZ#9i4$yN-Vd|=Xt?#q5GAUl_61bL{jMd zNK=nqZ*Nd=a4=;|#4=z1#}65rsnY;^Rr%$y=w@H*caS|5yL= zNYIqls_X6TwHXQ(IJiFl=201oQ(9WuwQ3v7%{cBLe1Wwxp!wEZ)-B*Z2PHBU}=X$BXnP(COa;suu*0J^*Ae`UeIEn%czK zme$tRH_bT?-o^n7h$teu9pKsa~qT=MLr*ldx6$CsR(oYFPf&+eR{U4_!MVT%*L z@EHaL1-V1-8F%j7QJcK%@9!@unh+_axEMI|d!cCzZ)4FE|FkV?d#$NWg8i!b$JvYC zgcp~!bF;FtrnfZ66YpP^*=5FEaCUY^-DGR|^bt_AYA)68@6q!b+E)&npWb#di;Iho zf+i$TjMjdF))wg?8Z`H+)(f>f2p>`L%$)!9-*+l&hC+=I>+=+E!a7h{*!m0Eb7|_= z^h`!}&Xtiy1_z0vVv$O4=vw?Z{4h{RRPw9wEe#@F8~`uG)JRVC=4kmKR+X-`o{4B8 zb8~b4Xd=1+BaMYDPFq`B0j-Ov(3Sf2cWZwXO>;j~cLWc$V-FH5nrj-b+;05lQ}N^^)6-U8fZ?dj=Rgj`etBMbqk z^50MeNgTU8y7C1K99>*o%J?Fvz=B!hnRw8F?_aC|q#CU5DQ_ZD!f&XWQh_NkwFUxY zG7MsNd8gr(C)^~tW8Z?j!(h0pNM5G&*ZRd+W`Zz(J*Z0(}^$aLMF*g{7$TL&la{ z0+R3%P%gnDj>w7$1Bpcwj77YN#Fu;KYXY7kSPKboSb6ARVKzB+<#oLkTDKM`iS{}S z4v`8LszvY3F5D}Q#<6EqwB~+(eifRs$Wc0egOv_@Do`ktDr`b3Dk`RXvu7|Ewfbxp zizNw!ND_%Ag>X6P-UK*W1IS(IuA+VZLSA0J5gI6m!;4La6g2hp)?EPB>Qy+zPFPYi zqO6!UKy~s`A1>zDe6)G+E^l+WJ5Bivbu;&t<LK!@m^-_qj#(ekRQDrXeiaV9D6vtFs)JtNAFP{1*}0t0-CIj3hx zIA0G&&v^F|EjTB1VYKy3)Ygg>%C`~2{l%iPrKQDSRi<&V`*aIqcCgB=rwn-IO+S(3^|k&R0_o0Ejma)3S7yCa|h_B0x;CNlh_Pizdw&B*v?_(nTslYP>7 zGuInHr}G&^tj&FoG4LAih!cXWfA7P6zW8wa#=n0Uc;FoAC%bV-2AU{GiT>wbfyEiS XE8;wgK)7xgdS-R@yjiu$rT9Mq`Y|CP literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/8.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/8.png new file mode 100644 index 0000000000000000000000000000000000000000..d4f827e6eb644ea4276f2a4b7901ba3038a3e148 GIT binary patch literal 5382 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/A.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/A.png new file mode 100644 index 0000000000000000000000000000000000000000..f674ffbb1c766d4abb87b9ed82d1de510518cd40 GIT binary patch literal 4290 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 HT}k*Ke^#3% literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/B.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/B.png new file mode 100644 index 0000000000000000000000000000000000000000..c31c541e42d9b28609dbb2b279d5ca5a4dabbdca GIT binary patch literal 3575 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/C.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/C.png new file mode 100644 index 0000000000000000000000000000000000000000..551976f503ff85eb88536e06c7905eaf9f6b3261 GIT binary patch literal 4192 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 MHL@hq4PD6p1w5-7djJ3c literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/E.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/E.png new file mode 100644 index 0000000000000000000000000000000000000000..565e1ec3b356dcb9adb8dfdeea5dab7c7ec550b8 GIT binary patch literal 552 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST~P>f$_bki(^Q|oVT|PyO<4l7!JNT z@qhoCDd8;BSa|#lKQkl>bZgnm0hQwe_h(K%TvqOXZt>YO7yo{I_x>C6gXx?sO%4hi z1c*bQzcF|5JKlNLbP0l+XkK DPEUGx literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/F.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/F.png new file mode 100644 index 0000000000000000000000000000000000000000..fd23c2b460135913a09a5a3ac0c9bc6211257c7d GIT binary patch literal 539 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST~P>f$@>2i(^Q|oVT|Ravm|@VL151 z@3pT*Mc;3%CDz`8`Ed(=cpS;p<6voY5Eudk cQgnTAs;~9q)bHB+JQXDB>FVdQ&MBb@02AMIYXATM literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/G.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/G.png new file mode 100644 index 0000000000000000000000000000000000000000..e0a4584390aba1bfd4b3b398570d9d7b1f455f27 GIT binary patch literal 4383 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 literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/H.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/H.png new file mode 100644 index 0000000000000000000000000000000000000000..5f8e41fe276ea2824d4bcca782a2645939a7a03b GIT binary patch literal 537 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST~P>f$@Q-i(^Q|oVT|xaxyE5xE`!k z{JTBJ%0eI_%rlK^LU+N3)32F;s_}py=k8SAh|0cOdGE}fUGJywc%8ndjK5(rCrguq z0>>aC_LTE$WUt*?&HVo?Hf$^B9i(^Q|oVS-Zavm@cU~xSC z_xqoB362UInr1Tfd4H<}s>BDrt(lx`Y^?tMT9o_$gX_M(XD%>qbP(WR86{{P21v0Y Z{)=HE535Syj)R&YQBPMtmvv4FO#oGiW|aT{ literal 0 HcmV?d00001 diff --git a/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/J.png b/script.plexmod/resources/skins/Main/media/script.plex/sign_in/digits/J.png new file mode 100644 index 0000000000000000000000000000000000000000..e0c6c3a98c81e29cc6aa3e0d9a768cc3bec88392 GIT binary patch literal 1134 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST~P>fyLC*#WAE}&fB}TD`Y|?jz9dK z@j~D-{If9rZ5Rx+3Lm(>Qg`d&s`s@IcKAnUFK0W~ zyf$xBbb@)KgMt7D3)3itI|y`yJl^lE6tHmdUaN4N?fmQJ=Lf^ut2(~k=GxXM-B2vR zF^%iVw}YSmN!jpki_)54&368G?FXA1St}jh$=JL~T9@&50& zRlDjRoOmCdUC$2`(%sl(6BDXz|L))01Cau{f+v!jpVyjK$i3O(qR`Jj@B3MxotM`% z=IrzQapl2Aaklf#bDzaI`tjBAFX3)cJu7>{7^wbk)NY#!wKpcw3VXjRhnA*&xN)BS zd~?P*(I+og?JECp<~&ea#?hHlr}GW&ks+Sr&E`3L{|w0o}4udDD5mAxC|{{6+X zWF`KPtF@t}pXJK#uD@J`W1N(2XC$?10&0f3rQdIH#;;`ql-Y+?yv8(kU_u8%fwz?6kYu75w54o!RDB