├── .coveralls.yml
├── .dockerignore
├── .gitignore
├── .ruby-gemset
├── .ruby-version
├── .travis.yml
├── CHANGELOG.md
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── Rakefile
├── app
├── assets
│ ├── fonts
│ │ ├── glyphicons-halflings-regular.eot
│ │ ├── glyphicons-halflings-regular.svg
│ │ ├── glyphicons-halflings-regular.ttf
│ │ ├── glyphicons-halflings-regular.woff
│ │ └── glyphicons-halflings-regular.woff2
│ ├── images
│ │ └── .keep
│ ├── javascripts
│ │ ├── application.js
│ │ ├── carousel.js
│ │ ├── notification_handler.js.coffee.erb
│ │ ├── services.coffee
│ │ └── skycons.js
│ └── stylesheets
│ │ ├── application.scss
│ │ ├── carousel.scss
│ │ └── custom.scss
├── controllers
│ ├── application_controller.rb
│ ├── concerns
│ │ └── .keep
│ ├── info_controller.rb
│ ├── notifications_controller.rb
│ ├── plex_services_controller.rb
│ ├── services_controller.rb
│ └── weather_controller.rb
├── helpers
│ ├── api_helper.rb
│ ├── application_helper.rb
│ ├── notifications_helper.rb
│ ├── plex_object_helper.rb
│ ├── plex_service_helper.rb
│ ├── plex_session_helper.rb
│ ├── plex_user.rb
│ ├── service_helper.rb
│ └── weather_helper.rb
├── mailers
│ └── .keep
├── models
│ ├── .keep
│ ├── application_record.rb
│ ├── concerns
│ │ └── .keep
│ ├── plex_object.rb
│ ├── plex_recently_added.rb
│ ├── plex_service.rb
│ ├── plex_session.rb
│ ├── server_load.rb
│ ├── service.rb
│ └── weather.rb
└── views
│ ├── info
│ ├── _weatherform.html.erb
│ ├── about.html.erb
│ ├── configuration.html.erb
│ └── new_weather.html.erb
│ ├── layouts
│ ├── _footer.html.erb
│ ├── _header.html.erb
│ ├── _navbar.html.erb
│ ├── _rightbar.html.erb
│ ├── _servicepanel.html.erb
│ └── application.html.erb
│ ├── plex_recently_addeds
│ ├── _plex_recently_added.html.erb
│ └── _plex_recently_added.json.jbuilder
│ ├── plex_services
│ ├── _now_playing.html.erb
│ ├── _now_playing_navbar.html.erb
│ ├── _plex_session.html.erb
│ ├── _plex_session.json.jbuilder
│ ├── _plexserviceform.html.erb
│ ├── _recently_added.html.erb
│ ├── all_plex_services.html.erb
│ ├── edit.html.erb
│ ├── new.html.erb
│ └── show.html.erb
│ ├── services
│ ├── _service.html.erb
│ ├── _service.json.jbuilder
│ ├── _serviceform.html.erb
│ ├── all_services.html.erb
│ ├── choose_service_type.html.erb
│ ├── edit.html.erb
│ ├── index.html.erb
│ ├── index.json.jbuilder
│ ├── new.html.erb
│ ├── show.html.erb
│ └── show.json.jbuilder
│ ├── shared
│ ├── _error_messages.html.erb
│ └── _plex_object.json.jbuilder
│ └── weathers
│ ├── _weather.html.erb
│ └── _weather.json.jbuilder
├── bin
├── bundle
├── rails
├── rake
├── setup
├── spring
├── update
└── yarn
├── config.ru
├── config
├── application.rb
├── boot.rb
├── cable.yml
├── database.yml
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── initializers
│ ├── application_controller_renderer.rb
│ ├── assets.rb
│ ├── backtrace_silencers.rb
│ ├── cookies_serializer.rb
│ ├── filter_parameter_logging.rb
│ ├── geocoder.rb
│ ├── inflections.rb
│ ├── lograge.rb
│ ├── mime_types.rb
│ ├── new_framework_defaults_5_1.rb
│ ├── server_config.rb
│ ├── session_store.rb
│ ├── simple_form.rb
│ ├── simple_form_bootstrap.rb
│ ├── version.rb
│ └── wrap_parameters.rb
├── locales
│ ├── en.yml
│ └── simple_form.en.yml
├── puma.rb
├── routes.rb
└── spring.rb
├── db
├── migrate
│ ├── 20151123041100_create_services.rb
│ ├── 20151123041932_create_plex_services.rb
│ ├── 20151123042532_create_plex_objects.rb
│ ├── 20151123051045_create_plex_sessions.rb
│ ├── 20151124030511_add_plex_service_reference_to_plex_objects.rb
│ ├── 20151124030640_add_index_to_service_flavors_for_services.rb
│ ├── 20151124041208_add_polymorphic_columns_to_plex_objects.rb
│ ├── 20151125020147_add_media_title_to_plex_object.rb
│ ├── 20151125020347_add_session_key_to_plex_session.rb
│ ├── 20151125020455_remove_plex_user_name_from_plex_objects.rb
│ ├── 20151125020909_remove_columns_from_plex_objects.rb
│ ├── 20151125021341_add_index_to_plex_objects.rb
│ ├── 20151125021356_add_index_to_plex_sessions.rb
│ ├── 20151205191615_add_added_date_to_plex_recently_added.rb
│ ├── 20151206220720_add_plex_object_to_plex_service.rb
│ ├── 20151208024529_remove_plex_service_from_plex_object.rb
│ ├── 20151208024559_remove_plex_object_from_plex_service.rb
│ ├── 20151208025103_add_plex_service_to_plex_recently_added.rb
│ ├── 20151208025136_add_plex_service_to_plex_session.rb
│ ├── 20151227040353_add_uuid_to_plex_recently_added.rb
│ ├── 20151230044756_add_auth_successful_to_plex_service.rb
│ ├── 20160121032317_rename_auth_successful_to_api_error.rb
│ ├── 20160124024211_remove_username_from_plex_service.rb
│ ├── 20160124024307_remove_password_from_plex_service.rb
│ ├── 20160124033003_remove_api_error_from_plex_service.rb
│ ├── 20160318030058_create_server_loads.rb
│ ├── 20160507224352_create_weathers.rb
│ ├── 20160507224801_add_address_to_weather.rb
│ ├── 20160510020651_add_units_to_weather.rb
│ ├── 20160513022103_change_weather_units_from_string_to_text.rb
│ ├── 20160707043046_add_city_to_weather.rb
│ ├── 20160707043058_add_state_to_weather.rb
│ ├── 20170325204752_remove_online_status_from_service.rb
│ ├── 20170329020117_add_stream_type_to_plex_session.rb
│ ├── 20170404205426_remove_last_seen_from_services.rb
│ └── 20170428012623_add_null_false_to_database_fields.rb
├── schema.rb
└── seeds.rb
├── example.server_config.yml
├── example.windows.server_config.yml
├── lib
├── assets
│ └── .keep
├── tasks
│ ├── .keep
│ └── version.rake
└── templates
│ └── erb
│ └── scaffold
│ └── _form.html.erb
├── public
├── 404.html
├── 422.html
├── 500.html
├── favicon.ico
├── placeholder.png
└── robots.txt
├── serverSetup.sh
├── startServer.sh
├── stopServer.sh
├── test
├── controllers
│ ├── .keep
│ ├── info_controller_test.rb
│ ├── notifications_controller_test.rb
│ ├── plex_services_controller_test.rb
│ ├── services_controller_test.rb
│ └── weather_controller_test.rb
├── fabricators
│ ├── fabrication.rb
│ ├── plex_object_fabricator.rb
│ ├── plex_recently_added_fabricator.rb
│ ├── plex_service_fabricator.rb
│ ├── plex_session_fabricator.rb
│ ├── server_load_fabricator.rb
│ ├── service_fabricator.rb
│ └── weather_fabricator.rb
├── fixtures
│ ├── .keep
│ ├── JSON
│ │ ├── forecast.json
│ │ ├── google_location_api.json
│ │ ├── plex_one_session.json
│ │ ├── plex_one_session_updated_viewOffset.json
│ │ ├── plex_recently_added_all.json
│ │ ├── plex_recently_added_movie.json
│ │ ├── plex_recently_added_tv_show.json
│ │ ├── plex_two_sessions.json
│ │ └── sign_in.json
│ ├── images
│ │ └── placeholder.png
│ ├── plex404.html
│ ├── plex_objects.yml
│ ├── plex_recently_addeds.yml
│ ├── plex_services.yml
│ ├── plex_sessions.yml
│ └── services.yml
├── helpers
│ ├── .keep
│ └── webmock_helper.rb
├── integration
│ ├── .keep
│ ├── behavior_test.rb
│ └── site_layout_test.rb
├── integration_test_config_files
│ └── example_service_test_config.yml
├── mailers
│ └── .keep
├── models
│ ├── .keep
│ ├── plex_object_test.rb
│ ├── plex_recently_added_test.rb
│ ├── plex_service_test.rb
│ ├── plex_session_test.rb
│ ├── server_load_test.rb
│ ├── service_test.rb
│ └── weather_test.rb
└── test_helper.rb
├── travisSetup.sh
├── update.sh
└── vendor
└── assets
├── javascripts
└── .keep
└── stylesheets
└── .keep
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | service_name: travis-ci
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | .dockerignore
3 | config/secrets.yml
4 | coverage/
5 | .bundle/
6 | tmp/
7 | public/images/
8 | public/assets/
9 | test/
10 | log/*
11 | db/*.sqlite3
12 | server_config.yml
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | /.bundle
9 |
10 | # Ignore the default SQLite database.
11 | /db/*.sqlite3
12 | /db/*.sqlite3-journal
13 | /coverage
14 | # Ignore all logfiles, tempfiles and secrets.yml
15 | /log/*
16 | !/log/.keep
17 | /tmp
18 | /config/secrets.yml
19 | server_config.yml
20 |
21 | #Ignore public/images
22 | /public/images/*
23 | /public/assets
24 | #Ignore Spring files.
25 | /spring/*.pid
26 | /.idea/
27 |
28 | #Ignore test images
29 | /test/test_images/*.jpeg
30 | /test/test_images/*.png
31 |
32 | #Ignore service_test_config.yml to keep private safe
33 | /test/integration_test_config_files/service_test_config.yml
--------------------------------------------------------------------------------
/.ruby-gemset:
--------------------------------------------------------------------------------
1 | plexdashboard
2 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.4.2
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | dist: trusty
3 | sudo: false
4 | services:
5 | - redis
6 | rvm:
7 | - 2.3.0
8 | - 2.3.4
9 | - 2.4.0
10 | - 2.4.2
11 | cache: bundler
12 |
13 | script:
14 | - /bin/bash travisSetup.sh
15 | - bundle exec rake
16 |
17 | notifications:
18 | webhooks:
19 | urls:
20 | - https://webhooks.gitter.im/e/b32edaad628354a304be
21 | on_success: change # options: [always|never|change] default: always
22 | on_failure: always # options: [always|never|change] default: always
23 | on_start: never # options: [always|never|change] default: always
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Base our image on an official, minimal image of our preferred Ruby
2 | FROM ruby:2.4.1-slim
3 |
4 | ENV RAILS_ROOT /app
5 | ENV RAILS_ENV production
6 | ENV DOCKER true
7 | ENV LOG_TO_STDOUT true
8 |
9 | # Install essential Linux packages
10 | RUN apt-get update -qq \
11 | && apt-get install -y \
12 | bundler \
13 | nodejs \
14 | libsqlite3-dev \
15 | && rm -rf /var/lib/apt/lists/*
16 |
17 | # Set our working directory inside the image
18 | RUN mkdir $RAILS_ROOT
19 | WORKDIR $RAILS_ROOT
20 |
21 | # Use the Gemfiles as Docker cache markers. Always bundle before copying app src.
22 | # (the src likely changed and we don't want to invalidate Docker's cache too early)
23 | # http://ilikestuffblog.com/2014/01/06/how-to-skip-bundle-install-when-deploying-a-rails-app-to-docker/
24 | COPY Gemfile Gemfile
25 |
26 | COPY Gemfile.lock Gemfile.lock
27 |
28 | # Prevent bundler warnings; ensure that the bundler version executed is >= that which created Gemfile.lock
29 | RUN gem install bundler rake \
30 | && bundle install --jobs=5 --without development test \
31 | && bundle clean --force
32 |
33 | # Copy the Rails application into place
34 | COPY . .
35 |
36 | RUN $RAILS_ROOT/serverSetup.sh
37 |
38 | EXPOSE 3000
39 |
40 | # Define the script we want run once the container boots
41 | # Use the "exec" form of CMD so our script shuts down gracefully on SIGTERM (i.e. `docker stop`)
42 | CMD exec bundle exec puma -e production -C $RAILS_ROOT/config/puma.rb $RAILS_ROOT/config.ru
43 |
44 | VOLUME $RAILS_ROOT/db/
45 |
46 |
47 | # Notes to remind me how to build this thing when I forget
48 | # docker build -t plex-board .
49 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | gem 'rails', '5.1.4'
3 | gem 'rake', '~> 12.1.0'
4 | gem 'sqlite3', '~> 1.3.13'
5 | gem 'sass-rails', '~> 5.0.6'
6 | gem 'uglifier', '~> 3.1.9'
7 | gem 'coffee-rails', '~> 4.2.1'
8 | gem 'jquery-rails', '~> 4.3.1'
9 | gem 'turbolinks', '~> 5.0.0'
10 | gem 'autoprefixer-rails', '~> 6.7.7.1'
11 | gem 'jbuilder', '~> 2.6.3'
12 | gem 'bootstrap-sass', '~> 3.3.7'
13 | gem 'sprockets-rails', '~> 3.2.0'
14 | gem 'simple_form', '~> 3.5.0'
15 | gem 'strip_attributes', '~> 1.8.0'
16 | gem 'rest-client', '~> 2.0.2'
17 | gem 'json', '~> 2.1.0'
18 | gem 'sass', '~> 3.4.23'
19 | gem 'execjs', '~> 2.7.0'
20 | gem 'parallel', '~> 1.11.1'
21 | gem 'forecast_io', '~> 2.0'
22 | gem 'geocoder', '~> 1.4.3'
23 | gem 'tzinfo', '~> 1.2.3'
24 | gem 'lograge', '~> 0.6.0'
25 | # gem 'browserlog', git: 'https://github.com/scytherswings/browserlog'
26 |
27 | group :development, :test do
28 | gem 'spring', '~> 2.0.1'
29 | gem 'parallel_tests', '~> 2.14.0'
30 | end
31 |
32 | group :development do
33 | gem 'annotate', require: false
34 | # gem 'web-console', '~> 2.0'
35 | end
36 |
37 | group :test do
38 | gem 'rails-controller-testing', '~> 1.0.1'
39 | gem 'simplecov', '~> 0.14.1'
40 | gem 'coveralls', '~> 0.8.21'
41 | gem 'minitest-reporters', '~> 1.1.14'
42 | gem 'webmock', '~> 2.3.2'
43 | gem 'vcr', '~> 3.0.3'
44 | gem 'minitest-vcr', '~> 1.4.0'
45 | gem 'faker', '~> 1.8.4'
46 | gem 'fabrication', '~> 2.16.1'
47 | end
48 |
49 | group :production do
50 | gem 'puma', '~> 3.10'
51 | end
52 |
53 | gem 'tzinfo-data'
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 scytherswings
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require File.expand_path('../config/application', __FILE__)
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/app/assets/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/app/assets/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/app/assets/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/app/assets/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/app/assets/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/app/assets/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/app/assets/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/app/assets/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/app/assets/images/.keep
--------------------------------------------------------------------------------
/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file.
9 | //
10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require jquery
14 | //= require jquery_ujs
15 | //= require turbolinks
16 | //= require bootstrap-sprockets
17 | //= require_tree .
18 |
--------------------------------------------------------------------------------
/app/assets/javascripts/carousel.js:
--------------------------------------------------------------------------------
1 | // Carousel Auto-Cycle
2 | // Interval controls how fast the carousel revolves
3 | $(document).ready(function() {
4 | $('.carousel').carousel({
5 | interval: 8000
6 | });
7 | });
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/assets/javascripts/notification_handler.js.coffee.erb:
--------------------------------------------------------------------------------
1 | "<% require 'yaml' %>"
2 | # Yes, this will blow up if server_config.yml doesn't exist. Sucks to suck. RTFM
3 | source = new EventSource("<%= (YAML.load_file(Rails.root.join 'server_config.yml')['relative_root'] || '') + '/notifications' %>")
4 |
5 | ########### Service Online Status ############
6 |
7 | source.addEventListener 'online_status', (e) ->
8 | service = $.parseJSON(e.data)
9 | # console.log(service)
10 | $('#service_' + service.id).replaceWith(service.html)
11 |
12 | # $.get service.self_uri, (data) ->
13 | # $('#service_' + service.id).replaceWith(data)
14 | # console.log(data)
15 | # return
16 |
17 | ############# Plex Now Playing ################
18 |
19 | source.addEventListener 'plex_now_playing', (e) ->
20 | plex_now_playing_data = $.parseJSON(e.data)
21 | # console.log plex_now_playing_data
22 | # console.log "Plex - Now Playing - session #{plex_session.session_id}"
23 | # console.log $('[id^="streams_for_plex_service_"]').length && plex_now_playing_data.active_streams_html && plex_now_playing_data.active_streams_html.length
24 |
25 | if $('[id^="streams_for_plex_service_"]').length && plex_now_playing_data.active_streams_html && plex_now_playing_data.active_streams_html.length
26 | console.log "Updating Active Streams"
27 | $('#streams_for_plex_service_' + plex_now_playing_data.plex_service_id).replaceWith(plex_now_playing_data.active_streams_html)
28 | $('#streams_for_plex_service_' + plex_now_playing_data.plex_service_id).show()
29 | else if $('[id^="streams_for_plex_service_"]').length
30 | console.log "Hiding active stream"
31 | $('[id^="streams_for_plex_service_"]').hide()
32 | else if plex_now_playing_data.active_streams_html && plex_now_playing_data.active_streams_html.length
33 | console.log "Adding new active stream"
34 | $('#navbar_links').prepend('
' + plex_now_playing_data.active_streams_html + '
')
35 |
36 | updated_progressbar = """
37 |
43 | """
44 | if $('#plex_session_' + plex_now_playing_data.session_id).length
45 | # console.log "Updating progress bar"
46 | $('#plex_progressbar_' + plex_now_playing_data.session_id).replaceWith(updated_progressbar)
47 | else
48 | # console.log "Didn't find the element \"session #{plex_session.session_id}\""
49 | # console.log "Adding new session element.."
50 | if $("[id^=plex_recently_added_]")
51 | $("[id^=plex_recently_added_]").last().after(plex_now_playing_data.html)
52 | else if $("[id^=plex_session_]")
53 | $("[id^=plex_session_]").last().after(plex_now_playing_data.html)
54 | else
55 | $("[id^=carousel-inner]").append(plex_now_playing_data.html)
56 |
57 | #Find all the existing elements on the page and compare them to the active ids we got in the SSE
58 |
59 | #set every plex_session as stale so we can remove the sessions that aren't found in the active sessions from the server
60 | stale_sessions = $.find("[id^=plex_session_]")
61 | #iterate over known sessions
62 | if plex_now_playing_data.active_sessions
63 | for i in [0...plex_now_playing_data.active_sessions.length]
64 | #console.log "Active session is: plex_session_" + plex_session.active_sessions[i]
65 | for j in [0...stale_sessions.length]
66 | #console.log "Matching active session against: " + stale_sessions[j].id
67 | if stale_sessions[j].id == ("plex_session_" + plex_now_playing_data.active_sessions[i])
68 | #at position i, remove one element from the array
69 | stale_sessions.splice(j, 1)
70 | #console.log "Updated stale sessions length should be one less: " + stale_sessions.length
71 | break
72 | for k in [0...stale_sessions.length]
73 | #find the elements by id and remove them from the page
74 | if !$("##{stale_sessions[k].id}").hasClass("active") && !$("##{stale_sessions[k].id}").hasClass("next")
75 | #console.log "Stale element found, removing.."
76 | console.log "Removing element " + stale_sessions[k].id
77 | $("#" + stale_sessions[k].id).remove()
78 |
79 | source.addEventListener 'plex_recently_added', (e) ->
80 | pra = $.parseJSON(e.data)
81 | if $('div[id^=plex_session_]').length < 3
82 | #console.log "There were less than 3 plex_sessions, adding plex recently added"
83 | if $('#plex_recently_added_' + pra.id).length
84 | #console.log "The PRA element was found. Not adding it again."
85 | else
86 | console.log "ID of new pra: #{pra.id}"
87 |
88 | if $("[id^=plex_session_]")
89 | $("[id^=plex_session_]").last().after(pra.html)
90 | else if $("[id^=plex_recently_added_]")
91 | $("[id^=plex_recently_added_]").last().after(pra.html)
92 | else
93 | $("[id^=carousel-inner]").append(pra.html)
94 | # else
95 | # console.log "There were more than three PlexSessions, not showing RecentlyAdded"
96 |
97 |
98 | ############# Weather ################
99 |
100 | source.addEventListener 'weathers', (e) ->
101 | weather = $.parseJSON(e.data)
102 | console.log("Here's the weather object id we got: " + weather.id)
103 | console.log(weather)
104 | $.get weather.self_uri, (data) ->
105 | $('#weather_' + weather.id).replaceWith(data)
106 | console.log(data)
107 | return
--------------------------------------------------------------------------------
/app/assets/javascripts/services.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
5 | $.rails.allowAction = (link) ->
6 | return true unless link.attr('data-confirm')
7 | $.rails.showConfirmDialog(link)
8 | false
9 |
10 | $.rails.confirmed = (link) ->
11 | link.removeAttr('data-confirm')
12 | link.trigger('click.rails')
13 |
14 | $.rails.showConfirmDialog = (link) ->
15 | message = link.attr 'data-confirm'
16 | html = """
17 |
Plex-Board is an open-source project meant to provide a simple-to-use dashboard for administrators and users of Plex servers.
8 | Monitors of services is done by opening a TCP socket to the port you specify when configuring them.
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/public/favicon.ico
--------------------------------------------------------------------------------
/public/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/public/placeholder.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/serverSetup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | case "$(uname -s)" in
5 |
6 | Darwin)
7 | OS="Mac OSX"
8 | ;;
9 |
10 | Linux)
11 | OS="Linux"
12 | ;;
13 |
14 | CYGWIN*|MINGW32*|MSYS*)
15 | OS="Windows"
16 | ;;
17 |
18 | *)
19 | OS="Unknown"
20 | ;;
21 | esac
22 |
23 | printf "\nThe current operating system was detected as: ${OS}."
24 |
25 | cd "$(dirname "$0")"
26 | if [[ "$OS" != "Windows" ]]; then
27 | printf "\nStopping server if it's running.\n"
28 | source stopServer.sh
29 | fi
30 |
31 | printf "\nDestroying tmp folder to clear caches and leftover pidfiles.\n"
32 | rm -rf tmp
33 |
34 | printf "\nDestroying public/images to clear leftover images.\n"
35 | rm -rf public/images
36 |
37 | HOME_RVM=$HOME/.rvm/scripts/rvm
38 | ROOT_RVM="/usr/local/rvm/scripts/rvm"
39 | UBUNTU_RVM="/usr/share/rvm/bin/rvm"
40 |
41 | RUBY_VERSION="2.4.1"
42 |
43 | # Load RVM into a shell session *as a function*
44 | if [[ -s ${HOME_RVM} ]] ; then
45 | # First try to load from a user install
46 | source ${HOME_RVM} \
47 | && printf "\nRVM successfully loaded from $HOME_RVM\n" \
48 | && printf "\nInstalling ruby-$RUBY_VERSION if it isn't already installed. This could take a while...\n" \
49 | && rvm install ruby-${RUBY_VERSION} \
50 | && rvm use gemset ruby-${RUBY_VERSION}@plexdashboard
51 |
52 | elif [[ -s ${UBUNTU_RVM} ]] ; then
53 | # Second try to use RVM in an Ubuntu install
54 | printf "\nRVM should already be loaded from $UBUNTU_RVM\n" \
55 | && printf "\nInstalling ruby-$RUBY_VERSION if it isn't already installed. This could take a while...\n" \
56 | && rvm install ruby-${RUBY_VERSION} \
57 | && rvm use gemset ruby-${RUBY_VERSION}@plexdashboard
58 |
59 | elif [[ -s ${ROOT_RVM} ]] ; then
60 | # Then try to load from a root install
61 | source ${ROOT_RVM} \
62 | && printf "\nRVM successfully loaded from $ROOT_RVM\n" \
63 | && printf "\nInstalling ruby-$RUBY_VERSION if it isn't already installed. This could take a while...\n" \
64 | && rvm install ruby-${RUBY_VERSION} \
65 | && rvm use gemset ruby-${RUBY_VERSION}@plexdashboard
66 |
67 | else
68 | if [[ "$OS" == "Windows" ]]; then
69 | printf "\nUsing system Ruby because we're on Windows...\n"
70 | else
71 | printf "\nWARNING: A RVM installation was not found. Did you follow the instructions correctly? Attempting to use system Ruby...\n"
72 | fi
73 | fi
74 |
75 | INSTALLED_RUBY_VERSION="$(ruby -v)"
76 |
77 | if ! [[ ${INSTALLED_RUBY_VERSION} =~ 2\.[3-4]\.[0-9]+ ]]; then
78 | printf "\nERROR: The required version of Ruby was not installed. This application will not work with any Ruby < 2.3.x"
79 | printf "\nFound: ${INSTALLED_RUBY_VERSION}\n"
80 | exit 1
81 | fi
82 |
83 | gem install bundler rake --no-ri --no-rdoc
84 |
85 | printf "\nInstalling Gems. This could take a while depending on how powerful your CPU is...\n"
86 | bundle install --without development test
87 |
88 | EXAMPLE_WINDOWS_CONFIG_FILE="example.windows.server_config.yml"
89 | EXAMPLE_CONFIG_FILE="example.server_config.yml"
90 | SERVER_CONFIG_FILE="server_config.yml"
91 | SECRETS="config/secrets.yml"
92 | SECRET="$(rake secret)"
93 | BOGUS="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
94 |
95 | printf "\nRemoving old secrets.yml file if it exists. Creating a fresh one with new secrets.\n"
96 | if [ -f ${SECRETS} ] ; then
97 | rm ${SECRETS}
98 | fi
99 |
100 | echo -e "development:\n secret_key_base:" ${BOGUS} "\n" >> ${SECRETS}
101 | echo -e "test:\n secret_key_base:" ${BOGUS} "\n" >> ${SECRETS}
102 | echo -e "production:\n secret_key_base:" ${SECRET} >> ${SECRETS}
103 |
104 | if [ ! -f ${SERVER_CONFIG_FILE} ]; then
105 | if [[ "$OS" == "Windows" ]]; then
106 | printf "\nSince windows is being used we'll use 127.0.0.1:3000 as the default host."
107 | printf "\nYou'll need to configure server_config.yml in order to accept traffic from external hosts.\n"
108 | EXAMPLE_CONFIG_FILE=${EXAMPLE_WINDOWS_CONFIG_FILE}
109 | fi
110 |
111 | if cp ${EXAMPLE_CONFIG_FILE} ${SERVER_CONFIG_FILE} 2>&1; then
112 | printf "\nCreated server_config.yml since it didn't exist."
113 | fi
114 | else
115 | printf "\nserver_config.yml exists, not creating."
116 | fi
117 |
118 | printf "\nCreating and setting up the database for production.\n"
119 | bundle exec rake db:create RAILS_ENV=production
120 | bundle exec rake db:migrate RAILS_ENV=production
121 |
122 | printf "\nCompiling assets. This could take a while depending on CPU power...\n"
123 | bundle exec rake assets:clobber assets:precompile RAILS_ENV=production
124 |
125 | printf "\nCreating images directory.\n"
126 | mkdir -p public/images
127 |
128 | printf "\nFinished. Run ./startServer.sh to start the server!\n\n"
129 |
--------------------------------------------------------------------------------
/startServer.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | cd "$(dirname "$0")"
5 |
6 | case "$(uname -s)" in
7 |
8 | Darwin)
9 | OS="Mac OSX"
10 | ;;
11 |
12 | Linux)
13 | OS="Linux"
14 | ;;
15 |
16 | CYGWIN*|MINGW32*|MSYS*)
17 | OS="Windows"
18 | ;;
19 |
20 | *)
21 | OS="Unknown"
22 | ;;
23 | esac
24 |
25 | if [[ "$OS" == "Windows" ]]; then
26 | printf "\nNot creating pid files etc. since we're on Windows. Starting puma.\n"
27 | bundle exec puma -e production -C config/puma.rb config.ru
28 | else
29 | HOME_RVM=$HOME/.rvm/scripts/rvm
30 | ROOT_RVM="/usr/local/rvm/scripts/rvm"
31 | UBUNTU_RVM="/usr/share/rvm/bin/rvm"
32 |
33 | # Load RVM into a shell session *as a function*
34 | if [[ -s ${HOME_RVM} ]] ; then
35 | # First try to load from a user install
36 | source ${HOME_RVM} \
37 | && printf "\nRVM successfully loaded from $HOME_RVM\n"
38 |
39 | elif [[ -s ${UBUNTU_RVM} ]] ; then
40 | # Second try to load from an Ubuntu install
41 | source ${UBUNTU_RVM} \
42 | && printf "\nRVM successfully loaded from $UBUNTU_RVM\n"
43 |
44 | elif [[ -s ${ROOT_RVM} ]] ; then
45 | # Then try to load from a root install
46 | source ${ROOT_RVM} \
47 | && printf "\nRVM successfully loaded from $ROOT_RVM\n"
48 |
49 | else
50 | printf "\nWARNING: An RVM installation was not found. Did you follow the instructions correctly? Attempting to use system Ruby...\n"
51 | fi
52 |
53 | printf "\nIf you run into any issues, check the error logs in: log/production.stderr.log, log/production.stdout.log, and log/production.log\n\n"
54 |
55 | mkdir -p tmp/pids \
56 | && mkdir -p tmp/sockets \
57 | && touch tmp/pids/puma.pid \
58 | && touch tmp/pids/puma.state \
59 | && touch tmp/sockets/puma.socket \
60 | && exec bundle exec puma -e production -C config/puma.rb config.ru
61 |
62 | fi
--------------------------------------------------------------------------------
/stopServer.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | case "$(uname -s)" in
5 |
6 | Darwin)
7 | OS="Mac OSX"
8 | ;;
9 |
10 | Linux)
11 | OS="Linux"
12 | ;;
13 |
14 | CYGWIN*|MINGW32*|MSYS*)
15 | OS="Windows"
16 | ;;
17 |
18 | *)
19 | OS="Unknown"
20 | ;;
21 | esac
22 |
23 | if [[ "$OS" == "Windows" ]]; then
24 | printf "\nNo puma daemon to kill since we're on Windows.\n"
25 | else
26 | cd "$(dirname "$0")"
27 | PIDFILE="tmp/pids/puma.pid"
28 | STATEFILE="tmp/pids/puma.state"
29 |
30 | if [ -s ${PIDFILE} ]
31 | then
32 | PUMA_PID="$(cat ${PIDFILE})"
33 |
34 | printf "Attempting to kill puma with PID: $PUMA_PID" \
35 | && kill -9 ${PUMA_PID} \
36 | && printf "\nServer stopped.\n" \
37 | && rm ${PIDFILE} \
38 | && rm ${STATEFILE}
39 | else
40 | printf "It seems Puma isn't running right now. Nothing to kill.\n"
41 | fi
42 | fi
43 |
--------------------------------------------------------------------------------
/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/test/controllers/.keep
--------------------------------------------------------------------------------
/test/controllers/info_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class InfoControllerTest < ActionController::TestCase
4 |
5 | test "should get configuration" do
6 | get :configuration
7 | assert_response :success
8 | end
9 |
10 | test "should get about" do
11 | get :about
12 | assert_response :success
13 | end
14 |
15 | end
16 |
--------------------------------------------------------------------------------
/test/controllers/notifications_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 | require 'timeout'
3 |
4 | class NotificationsControllerTest < ActionController::TestCase
5 | # test 'Notifications returns 200 OK' do
6 | # begin
7 | # Timeout.timeout(1) do
8 | # get :notifications
9 | # end
10 | # rescue Timeout::Error
11 | # assert_response :success
12 | # end
13 | # end
14 | end
15 |
--------------------------------------------------------------------------------
/test/controllers/plex_services_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class PlexServicesControllerTest < ActionController::TestCase
4 |
5 | test 'should get edit' do
6 | get :edit, params: {id: @plex_service_one.id}
7 | assert_response :success
8 | assert_select 'title', "Plex-Board | Edit #{@plex_service_one.service.name}"
9 | end
10 |
11 | test 'should get show' do
12 | get :show, params: {id: @plex_service_one.id}
13 | assert_response :success
14 | assert_select 'title', "Plex-Board | #{@plex_service_one.service.name}"
15 | end
16 |
17 | test 'should get all_plex_services' do
18 | get :all_plex_services
19 | assert_response :success
20 | assert_select 'title', 'Plex-Board | All Plex Services'
21 | end
22 |
23 | test 'should get new' do
24 | get :new
25 | assert_response :success
26 | assert_select 'title', 'Plex-Board | New Plex Service'
27 | end
28 |
29 | test 'should update PlexService' do
30 | patch :update, params: {id: @plex_service_one.id, plex_service: {username: 'user', password: 'newpass'}}
31 | assert_redirected_to plex_service_path(assigns(:plex_service))
32 | end
33 |
34 | test 'should create plex_service' do
35 | assert_difference('PlexService.count') do
36 | post :create, params: {plex_service: {username: 'user', password: 'pass', token: 'garbage'}}
37 | end
38 |
39 | assert_redirected_to plex_service_path(assigns(:plex_service))
40 | end
41 |
42 | test 'should destroy plex_service' do
43 | assert_difference('PlexService.count', -1) do
44 | assert delete :destroy, params: {id: @plex_service_one.id}
45 | end
46 | assert_redirected_to root_url
47 | end
48 |
49 | end
50 |
--------------------------------------------------------------------------------
/test/controllers/services_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 | class ServicesControllerTest < ActionController::TestCase
3 |
4 | test 'should get index' do
5 | get :index
6 | assert_response :success
7 | assert_not_nil assigns(:services)
8 | assert_select 'title', 'Plex-Board'
9 | end
10 |
11 | test 'should get all_services' do
12 | get :all_services
13 | assert_response :success
14 | assert_not_nil assigns(:services)
15 | assert_select 'title', 'Plex-Board | All Services'
16 | end
17 |
18 | test 'should get choose_service_type' do
19 | get :choose_service_type
20 | assert_response :success
21 | assert_select 'title', 'Plex-Board | Choose Service Type'
22 | end
23 |
24 | test 'should get new' do
25 | get :new
26 | assert_response :success
27 | assert_select 'title', 'Plex-Board | New Service'
28 | end
29 |
30 | test 'should create service' do
31 | assert_difference('Service.count') do
32 | post :create, params: {service: { name: 'test_create', ip: '172.111.3.1', port: 80, dns_name: 'test_create', url: 'test_create'}}
33 | end
34 |
35 | assert_redirected_to service_path(assigns(:service))
36 | end
37 |
38 | test 'should show service' do
39 | get :show, params: {id: @generic_service_one.id}
40 | assert_response :success
41 | assert_select 'title', "Plex-Board | #{@generic_service_one.name}"
42 | end
43 |
44 | test 'should get edit' do
45 | get :edit, params:{id: @generic_service_one.id}
46 | assert_response :success
47 | assert_select 'title', "Plex-Board | Edit #{@generic_service_one.name}"
48 | end
49 |
50 | test 'should update service' do
51 | patch :update, params: {id: @generic_service_one.id, service: {name: 'test2', ip: '172.123.1.1', dns_name: 'test', url: 'test' }}
52 | assert_redirected_to service_path(assigns(:service))
53 | end
54 |
55 | test 'should destroy service' do
56 | assert_difference('Service.count', -1) do
57 | assert delete :destroy, params: {id: @generic_service_one.id}
58 | end
59 | assert_redirected_to root_url
60 | end
61 |
62 | # test 'Bad plex service port wont break page load' do
63 | # get :index
64 | # assert_response :success
65 | # assert_requested(:get, 'https://plex5:32400/status/sessions')
66 | # @plex_service_one.service.update(port: 32401)
67 | # get :index
68 | # assert_response :success
69 | # assert_requested(:get, 'https://plex5:32401/status/sessions')
70 | # end
71 |
72 | # This might take some tinkering
73 | # test 'should show service as online' do
74 |
75 | # end
76 |
77 |
78 | end
--------------------------------------------------------------------------------
/test/controllers/weather_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class WeatherControllerTest < ActionController::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/fabricators/fabrication.rb:
--------------------------------------------------------------------------------
1 | Fabrication.configure do |config|
2 | config.fabricator_path = 'test/fabricators'
3 | config.path_prefix = Rails.root
4 | config.sequence_start = 0
5 | end
6 |
--------------------------------------------------------------------------------
/test/fabricators/plex_object_fabricator.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_objects
4 | #
5 | # id :integer not null, primary key
6 | # image :string
7 | # thumb_url :string not null
8 | # description :text
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # plex_object_flavor_id :integer
12 | # plex_object_flavor_type :string
13 | # media_title :string not null
14 | #
15 |
16 | require 'test_helper'
17 |
18 | Fabricator(:plex_object) do
19 | media_title { Faker::Book.title } #Book title is the closest thing I found
20 | thumb_url '/test_images/placeholder.png'
21 | end
22 |
--------------------------------------------------------------------------------
/test/fabricators/plex_recently_added_fabricator.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_recently_addeds
4 | #
5 | # id :integer not null, primary key
6 | # added_date :datetime not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | # plex_service_id :integer
10 | # uuid :string not null
11 | #
12 |
13 | require 'test_helper'
14 |
15 | Fabricator(:plex_recently_added) do
16 | added_date { Faker::Date.backward(2) }
17 | uuid { SecureRandom.uuid }
18 | end
19 |
--------------------------------------------------------------------------------
/test/fabricators/plex_service_fabricator.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_services
4 | #
5 | # id :integer not null, primary key
6 | # token :string
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | #
10 |
11 | require 'test_helper'
12 |
13 | Fabricator(:plex_service) do
14 | transient :ps_token, sessions: 0, pras: 0
15 | token { |attrs| attrs[:ps_token] ? attrs[:ps_token] : Proc.new { rand(36**20).to_s(36) }.call } #generates random 20 character token
16 | service
17 | plex_sessions(count: 1)
18 | plex_recently_addeds(count: 1)
19 | end
20 |
--------------------------------------------------------------------------------
/test/fabricators/plex_session_fabricator.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_sessions
4 | #
5 | # id :integer not null, primary key
6 | # progress :integer not null
7 | # total_duration :integer not null
8 | # plex_user_name :string
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # session_key :string not null
12 | # plex_service_id :integer
13 | # stream_type :string not null
14 | #
15 |
16 | require 'test_helper'
17 |
18 | Fabricator(:plex_session) do
19 | plex_user_name { Faker::Internet::user_name }
20 | session_key { Faker::Number }
21 | stream_type { %w(Stream Transcode '').sample }
22 | plex_object
23 | end
24 |
--------------------------------------------------------------------------------
/test/fabricators/server_load_fabricator.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: server_loads
4 | #
5 | # id :integer not null, primary key
6 | # name :string not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | # service_host_id :integer
10 | #
11 |
12 | require 'test_helper'
13 | Fabricator(:server_load) do
14 | name "MyString"
15 | order 1
16 | end
17 |
--------------------------------------------------------------------------------
/test/fabricators/service_fabricator.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: services
4 | #
5 | # id :integer not null, primary key
6 | # name :string not null
7 | # dns_name :string
8 | # ip :string
9 | # url :string not null
10 | # port :integer not null
11 | # service_flavor_id :integer
12 | # service_flavor_type :string
13 | # created_at :datetime not null
14 | # updated_at :datetime not null
15 | #
16 |
17 | require 'test_helper'
18 |
19 | Fabricator(:service) do
20 | transient :s_name, :s_url, :s_dns_name, :s_ip, :s_port
21 | name { |attrs| attrs[:s_name] ? attrs[:s_name] : Faker::App.name + rand(10000).to_s }
22 | url { |attrs| attrs[:s_url] ? attrs[:s_url] : Faker::Internet.url }
23 | dns_name { |attrs| attrs[:s_dns_name] ? attrs[:s_dns_name] : Faker::Internet.domain_name + rand(10000).to_s }
24 | ip { |attrs| attrs[:s_ip] ? attrs[:s_ip] : Faker::Internet.ip_v4_address }
25 | port { |attrs| attrs[:s_port] ? attrs[:s_port] : Faker::Number.between(1, 65535) }
26 | end
27 |
--------------------------------------------------------------------------------
/test/fabricators/weather_fabricator.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: weathers
4 | #
5 | # id :integer not null, primary key
6 | # api_key :string
7 | # latitude :float
8 | # longitude :float
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # address :string
12 | # units :text
13 | # city :string
14 | # state :string
15 | #
16 |
17 | require 'test_helper'
18 |
19 | Fabricator(:weather) do
20 | transient :units
21 | api_key { Proc.new { rand(36**32).to_s(36) }.call }
22 | latitude { Proc.new { rand(-90.0..90.0).to_s }.call }
23 | longitude { Proc.new { rand(-180.0..180.0).to_s }.call }
24 | units { |attrs| attrs[:units] ? attrs[:units] : {'US Customary Units': 'us'} }
25 | # transient :address, :latitude, :longitude, :api_key
26 | # api_key { |attrs| attrs[:api_key] ? attrs[:api_key] : Proc.new { rand(36**32).to_s(36) }.call }
27 | # latitude { |attrs| attrs[:latitude] ? attrs[:latitude] : Proc.new { rand(-90.0..90.0).to_s }.call }
28 | # longitude { |attrs| attrs[:longitude] ? attrs[:longitude] : Proc.new { rand(-180.0..180.0).to_s }.call }
29 | end
30 |
31 |
32 |
--------------------------------------------------------------------------------
/test/fixtures/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/test/fixtures/.keep
--------------------------------------------------------------------------------
/test/fixtures/JSON/google_location_api.json:
--------------------------------------------------------------------------------
1 | {
2 | "results": [
3 | {
4 | "address_components": [
5 | {
6 | "long_name": "2300",
7 | "short_name": "2300",
8 | "types": [
9 | "street_number"
10 | ]
11 | },
12 | {
13 | "long_name": "Traverwood Drive",
14 | "short_name": "Traverwood Dr",
15 | "types": [
16 | "route"
17 | ]
18 | },
19 | {
20 | "long_name": "Logan",
21 | "short_name": "Logan",
22 | "types": [
23 | "neighborhood",
24 | "political"
25 | ]
26 | },
27 | {
28 | "long_name": "Ann Arbor",
29 | "short_name": "Ann Arbor",
30 | "types": [
31 | "locality",
32 | "political"
33 | ]
34 | },
35 | {
36 | "long_name": "Washtenaw County",
37 | "short_name": "Washtenaw County",
38 | "types": [
39 | "administrative_area_level_2",
40 | "political"
41 | ]
42 | },
43 | {
44 | "long_name": "Michigan",
45 | "short_name": "MI",
46 | "types": [
47 | "administrative_area_level_1",
48 | "political"
49 | ]
50 | },
51 | {
52 | "long_name": "United States",
53 | "short_name": "US",
54 | "types": [
55 | "country",
56 | "political"
57 | ]
58 | },
59 | {
60 | "long_name": "48105",
61 | "short_name": "48105",
62 | "types": [
63 | "postal_code"
64 | ]
65 | }
66 | ],
67 | "formatted_address": "2300 Traverwood Dr, Ann Arbor, MI 48105, USA",
68 | "geometry": {
69 | "location": {
70 | "lat": 42.306642,
71 | "lng": -83.71466199999999
72 | },
73 | "location_type": "ROOFTOP",
74 | "viewport": {
75 | "northeast": {
76 | "lat": 42.3079909802915,
77 | "lng": -83.71331301970849
78 | },
79 | "southwest": {
80 | "lat": 42.3052930197085,
81 | "lng": -83.7160109802915
82 | }
83 | }
84 | },
85 | "place_id": "ChIJaUsRICysPIgRtu8h-gpZ_pY",
86 | "types": [
87 | "street_address"
88 | ]
89 | }
90 | ],
91 | "status": "OK"
92 | }
--------------------------------------------------------------------------------
/test/fixtures/JSON/plex_recently_added_movie.json:
--------------------------------------------------------------------------------
1 | {
2 | "MediaContainer": {
3 | "size": 50,
4 | "allowSync": false,
5 | "identifier": "com.plexapp.plugins.library",
6 | "mediaTagPrefix": "/system/bundle/media/flags/",
7 | "mediaTagVersion": 1481837967,
8 | "mixedParents": true,
9 | "Metadata": [
10 | {
11 | "allowSync": true,
12 | "librarySectionID": 1,
13 | "librarySectionTitle": "Movies",
14 | "librarySectionUUID": "d370c316-f79b-4810-b0cc-fad49bef2af7",
15 | "ratingKey": "49724",
16 | "key": "/library/metadata/49724",
17 | "studio": "Fox 2000 Pictures",
18 | "type": "movie",
19 | "title": "Hidden Figures",
20 | "contentRating": "PG",
21 | "summary": "The incredible untold story of Katherine G. Johnson, Dorothy Vaughan and Mary Jackson - brilliant African-American women working at NASA, who served as the brains behind one of the greatest operations in history: the launch of astronaut John Glenn into orbit, a stunning achievement that restored the nation's confidence, turned around the Space Race, and galvanized the world. The visionary trio crossed all gender and race lines to inspire generations to dream big.",
22 | "rating": 9.3,
23 | "audienceRating": 9.4,
24 | "year": 2017,
25 | "tagline": "Meet the women you don't know, behind the mission you do.",
26 | "thumb": "/library/metadata/49724/thumb/1490327440",
27 | "art": "/library/metadata/49724/art/1490327440",
28 | "duration": 7603062,
29 | "originallyAvailableAt": "2017-01-06",
30 | "addedAt": 1490327405,
31 | "updatedAt": 1490327440,
32 | "audienceRatingImage": "rottentomatoes://image.rating.upright",
33 | "chapterSource": "media",
34 | "primaryExtraKey": "/library/metadata/49725",
35 | "ratingImage": "rottentomatoes://image.rating.certified",
36 | "Media": [
37 | {
38 | "videoResolution": "1080",
39 | "id": 135653,
40 | "duration": 7603062,
41 | "bitrate": 11111,
42 | "width": 1920,
43 | "height": 808,
44 | "aspectRatio": 2.35,
45 | "audioChannels": 6,
46 | "audioCodec": "dca",
47 | "videoCodec": "h264",
48 | "container": "mkv",
49 | "videoFrameRate": "24p",
50 | "audioProfile": "dts",
51 | "videoProfile": "high",
52 | "Part": [
53 | {
54 | "id": 136430,
55 | "key": "/library/parts/136430/1490335125/file.mkv",
56 | "duration": 7603062,
57 | "file": "/mnt/PLEX-MEDIA/Movies/Hidden Figures (2016)/Hidden Figures.mkv",
58 | "size": 10559697658,
59 | "audioProfile": "dts",
60 | "container": "mkv",
61 | "deepAnalysisVersion": "2",
62 | "indexes": "sd",
63 | "requiredBandwidths": "42252,29243,22270,16875,12600,12600,12600,12600",
64 | "videoProfile": "high"
65 | }
66 | ]
67 | }
68 | ],
69 | "Genre": [
70 | {
71 | "tag": "Biography"
72 | },
73 | {
74 | "tag": "History"
75 | },
76 | {
77 | "tag": "Drama"
78 | }
79 | ],
80 | "Director": [
81 | {
82 | "tag": "Theodore Melfi"
83 | }
84 | ],
85 | "Writer": [
86 | {
87 | "tag": "Allison Schroeder"
88 | },
89 | {
90 | "tag": "Theodore Melfi"
91 | }
92 | ],
93 | "Country": [
94 | {
95 | "tag": "USA"
96 | }
97 | ],
98 | "Role": [
99 | {
100 | "tag": "Taraji P. Henson"
101 | },
102 | {
103 | "tag": "Octavia Spencer"
104 | },
105 | {
106 | "tag": "Janelle Monae"
107 | }
108 | ]
109 | }
110 | ]
111 | }
112 | }
--------------------------------------------------------------------------------
/test/fixtures/JSON/plex_recently_added_tv_show.json:
--------------------------------------------------------------------------------
1 | {
2 | "MediaContainer": {
3 | "size": 1,
4 | "allowSync": false,
5 | "identifier": "com.plexapp.plugins.library",
6 | "mediaTagPrefix": "/system/bundle/media/flags/",
7 | "mediaTagVersion": 1481837967,
8 | "mixedParents": true,
9 | "Metadata": [
10 | {
11 | "allowSync": true,
12 | "librarySectionID": 1,
13 | "librarySectionTitle": "TV Shows",
14 | "librarySectionUUID": "b58dc19b-7a20-475b-adca-a4e26cb340bd",
15 | "ratingKey": "48181",
16 | "key": "/library/metadata/48181/children",
17 | "parentRatingKey": "40506",
18 | "type": "season",
19 | "title": "Season 2",
20 | "parentKey": "/library/metadata/40506",
21 | "parentTitle": "The Expanse",
22 | "parentSummary": "Two hundred years in the future, in a fully colonized solar system, police detective Josephus Miller is given the assignment to find a missing young woman, Julie Mao. Joining his task is James Holden, former first officer of an ice freighter who is involved in an incident caused by the tense relationship between Earth, Mars and the Belt. Far from their struggles in space, United Nations executive Chrisjen Avasarala works to prevent war between Earth and Mars. Soon the three find out that the missing woman is connected to a vast conspiracy that threatens all humanity.",
23 | "summary": "",
24 | "index": 2,
25 | "parentIndex": 1,
26 | "thumb": "/library/metadata/48181/thumb/1490253646",
27 | "art": "/library/metadata/40506/art/1490253646",
28 | "parentThumb": "/library/metadata/40506/thumb/1490253646",
29 | "parentTheme": "/library/metadata/40506/theme/1490253646",
30 | "leafCount": 8,
31 | "viewedLeafCount": 0,
32 | "addedAt": 1490253614,
33 | "updatedAt": 1490253646
34 | }
35 | ]
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/test/fixtures/JSON/sign_in.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": {
3 | "email": "user@example.com",
4 | "joined_at": "2013-02-10T02:34:58Z",
5 | "username": "Generic_User",
6 | "title": "Generic_User",
7 | "authentication_token": "zV75NzEnTA1migSb21ze",
8 | "subscription": {
9 | "active": true,
10 | "status": "Active",
11 | "plan": "lifetime",
12 | "features": [
13 | "pass",
14 | "sync",
15 | "cloudsync",
16 | "home"
17 | ]
18 | },
19 | "roles": {
20 | "roles": [
21 | "plexpass"
22 | ]
23 | },
24 | "entitlements": [
25 | "all",
26 | "roku",
27 | "android",
28 | "xbox_one",
29 | "xbox_360",
30 | "windows",
31 | "windows_phone",
32 | "ios"
33 | ],
34 | "confirmed_at": "2013-02-10T15:15:14Z",
35 | "forum_id": 0
36 | }
37 | }
--------------------------------------------------------------------------------
/test/fixtures/images/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/test/fixtures/images/placeholder.png
--------------------------------------------------------------------------------
/test/fixtures/plex404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | The page you were looking for doesn't exist (404)
8 |
9 |
10 |
11 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
Oops; a 404 error...
33 |
34 |
That's "page not found" in human language.
35 |
36 |
You may have mistyped the address or the page may have moved.
37 |
38 |
39 | Let us take you to the main page and we can start all over again, shall we?
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/test/fixtures/plex_objects.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_objects
4 | #
5 | # id :integer not null, primary key
6 | # image :string
7 | # thumb_url :string not null
8 | # description :text
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # plex_object_flavor_id :integer
12 | # plex_object_flavor_type :string
13 | # media_title :string not null
14 | #
15 |
16 | plex_object_session_1:
17 | image: placeholder.png
18 | media_title: Movie1
19 | description: .
20 | thumb_url: /library/metadata/38501/thumb/1444964730
21 | plex_object_flavor: plex_service_w1sess_session_1 (PlexSession)
22 |
23 | plex_object_session_2:
24 | image: placeholder.png
25 | media_title: Movie1
26 | description: .
27 | thumb_url: /library/metadata/38501/thumb/1444964730
28 | plex_object_flavor: plex_service_w2sess_session_1 (PlexSession)
29 |
30 | plex_object_session_3:
31 | image: placeholder.png
32 | media_title: Movie1
33 | description: .
34 | thumb_url: /library/metadata/38501/thumb/1444964730
35 | plex_object_flavor: plex_service_w2sess_session_2 (PlexSession)
36 |
37 | plex_object_recently_added_1:
38 | image: placeholder.png
39 | media_title: Movie1
40 | description: .
41 | thumb_url: /library/metadata/38501/thumb/1444964730
42 | plex_object_flavor: plex_service_w1ra_pra_1 (PlexRecentlyAdded)
43 |
--------------------------------------------------------------------------------
/test/fixtures/plex_recently_addeds.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_recently_addeds
4 | #
5 | # id :integer not null, primary key
6 | # added_date :datetime not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | # plex_service_id :integer
10 | # uuid :string not null
11 | #
12 |
13 | plex_service_w1ra_pra_1:
14 | plex_service: plex_service_with_one_recently_added
15 | added_date: <%= 5.day.ago.to_s(:db) %>
16 | uuid: c58dc19b-7a20-475b-adca-a4e26cb340bd
17 |
--------------------------------------------------------------------------------
/test/fixtures/plex_services.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_services
4 | #
5 | # id :integer not null, primary key
6 | # token :string
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | #
10 |
11 | plex_service_one:
12 | token: k3qRS5pJuWFz8U9tJp1d
13 |
14 | plex_service_with_no_token:
15 | token:
16 |
17 | plex_service_with_one_session:
18 | token: k3qRS5pJuWFz8U9tJp1d
19 |
20 | plex_service_with_two_sessions:
21 | token: k3qRS5pJuWFz8U9tJp1d
22 |
23 | plex_service_with_one_recently_added:
24 | token: k3qRS5pJuWFz8U9tJp1d
25 |
--------------------------------------------------------------------------------
/test/fixtures/plex_sessions.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_sessions
4 | #
5 | # id :integer not null, primary key
6 | # progress :integer not null
7 | # total_duration :integer not null
8 | # plex_user_name :string
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # session_key :string not null
12 | # plex_service_id :integer
13 | # stream_type :string not null
14 | #
15 |
16 | plex_service_w1sess_session_1:
17 | progress: 1
18 | total_duration: 100
19 | session_key: 1
20 | stream_type: Transcode
21 | plex_user_name: Generic_User
22 | plex_service: plex_service_with_one_session
23 |
24 | plex_service_w2sess_session_1:
25 | progress: 1
26 | total_duration: 100
27 | session_key: 1
28 | stream_type: Transcode
29 | plex_user_name: Generic_User
30 | plex_service: plex_service_with_two_sessions
31 |
32 | plex_service_w2sess_session_2:
33 | progress: 1
34 | total_duration: 100
35 | session_key: 2
36 | stream_type: Stream
37 | plex_user_name: Generic_User
38 | plex_service: plex_service_with_two_sessions
39 |
40 |
--------------------------------------------------------------------------------
/test/fixtures/services.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: services
4 | #
5 | # id :integer not null, primary key
6 | # name :string not null
7 | # dns_name :string
8 | # ip :string
9 | # url :string not null
10 | # port :integer not null
11 | # service_flavor_id :integer
12 | # service_flavor_type :string
13 | # created_at :datetime not null
14 | # updated_at :datetime not null
15 | #
16 |
17 | generic_service_one:
18 | name: Test Service One
19 | ip: 127.0.0.1
20 | dns_name: localhost1
21 | port: 80
22 | url: http://localhost1
23 |
24 | generic_service_two:
25 | name: Test Service Two
26 | ip: 127.0.0.2
27 | dns_name: localhost2
28 | port: 80
29 | url: http://localhost2
30 |
31 | plex_1:
32 | name: plex_service_one
33 | ip: 127.0.0.3
34 | dns_name: plex3
35 | port: 32400
36 | url: http://127.0.0.3
37 | service_flavor: plex_service_one (PlexService)
38 |
39 | plex_2:
40 | name: plex_service_no_token
41 | ip: 127.0.0.4
42 | dns_name: plex4
43 | port: 32400
44 | url: http://127.0.0.4
45 | service_flavor: plex_service_with_no_token (PlexService)
46 |
47 | plex_3:
48 | name: plex_service_with_one_session
49 | ip: 127.0.0.5
50 | dns_name: plex5
51 | port: 32400
52 | url: http://127.0.0.5
53 | service_flavor: plex_service_with_one_session (PlexService)
54 |
55 | plex_4:
56 | name: plex_service_with_two_sessions
57 | ip: 127.0.0.6
58 | dns_name: plex6
59 | port: 32400
60 | url: http://127.0.0.6
61 | service_flavor: plex_service_with_two_sessions (PlexService)
62 |
63 | plex_5:
64 | name: plex_service_with_one_recently_added
65 | ip: 127.0.0.7
66 | dns_name: plex7
67 | port: 32400
68 | url: http://127.0.0.7
69 | service_flavor: plex_service_with_one_recently_added (PlexService)
70 |
--------------------------------------------------------------------------------
/test/helpers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/test/helpers/.keep
--------------------------------------------------------------------------------
/test/helpers/webmock_helper.rb:
--------------------------------------------------------------------------------
1 | module WebmockHelper
2 | require 'webmock'
3 |
4 | HEADERS = {"Cache-Control" => "no-cache", "Connection" => "Keep-Alive",
5 | "Content-Type" => "application/json", "Keep-Alive" => "timeout=20",
6 | "X-Plex-Protocol" => "1.0"}
7 |
8 | AUTH_HEADERS = { "Content-Type" => "application/json; charset=utf-8", "Access-Control-Max-Age" => 86400 }
9 |
10 | TOKEN = 'zV75NzEnTA1migSb21ze'
11 |
12 | WebMock.disable_net_connect!(:allow_localhost => true)
13 |
14 | WebMock.stub_request(:post, "https://user:pass@my.plexapp.com/users/sign_in.json").
15 | with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'User-Agent'=>'Ruby', 'X-Plex-Client-Identifier'=>'Plex-Board'}).
16 | to_return(:status => 201, :body => File.open(Rails.root.join 'test/fixtures/JSON/', "sign_in.json").read, :headers => AUTH_HEADERS)
17 |
18 | WebMock.stub_request(:get, "https://plex5:32400/status/sessions").
19 | with(:headers => {'Accept'=>'application/json', 'Accept-Encoding'=>'gzip, deflate', 'User-Agent'=>'Ruby', 'X-Plex-Token'=>TOKEN}).
20 | to_return(:status => 200, :body => File.open(Rails.root.join 'test/fixtures/JSON/', "plex_one_session.json").read, :headers => HEADERS)
21 |
22 | WebMock.stub_request(:get, "https://plex5updated:32400/status/sessions").
23 | with(:headers => {'Accept'=>'application/json', 'Accept-Encoding'=>'gzip, deflate', 'User-Agent'=>'Ruby', 'X-Plex-Token'=>TOKEN}).
24 | to_return(:status => 200, :body => File.open(Rails.root.join 'test/fixtures/JSON/', "plex_one_session_updated_viewOffset.json").read, :headers => HEADERS)
25 |
26 | WebMock.stub_request(:get, "https://plexnosessions:32400/status/sessions").
27 | with(:headers => {'Accept'=>'application/json', 'Accept-Encoding'=>'gzip, deflate', 'User-Agent'=>'Ruby', 'X-Plex-Token'=>TOKEN}).
28 | to_return(:status => 200, :body => "{\"_elementType\": \"MediaContainer\",\"_children\": []}", :headers => HEADERS)
29 |
30 | WebMock.stub_request(:get, "https://plex6:32400/status/sessions").
31 | with(:headers => {'Accept'=>'application/json', 'Accept-Encoding'=>'gzip, deflate', 'User-Agent'=>'Ruby', 'X-Plex-Token'=>TOKEN}).
32 | to_return(:status => 200, :body => File.open(Rails.root.join 'test/fixtures/JSON/', "plex_two_sessions.json").read, :headers => HEADERS)
33 |
34 | WebMock.stub_request(:get, /https:\/\/plex(.*?):32400\/library\/metadata\/(\d*)\/thumb\/(\d*$)/).
35 | with(:headers => {'Accept'=>'image/jpeg', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby', 'X-Plex-Token'=>TOKEN}).
36 | to_return(:status => 200, :body => File.open(Rails.root.join 'test/fixtures/images/', 'placeholder.png').read, :headers => {"Content-Type" => "image/jpeg"})
37 |
38 | end
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/test/integration/.keep
--------------------------------------------------------------------------------
/test/integration/behavior_test.rb:
--------------------------------------------------------------------------------
1 | # require 'test_helper'
2 | #
3 | # class BehaviorTest < ActionDispatch::IntegrationTest
4 | # # These tests will ensure that the UI functions as designed.
5 | #
6 | # def teardown
7 | # super
8 | # Capybara.reset_sessions!
9 | # Capybara.use_default_driver
10 | # end
11 | #
12 | # # # Setup: At least one service in the online state.
13 | # # # Steps:
14 | # # # Action 1: The service will be taken offline
15 | # # # Result 1: The UI button will be updated by js to reflect the change
16 | # # test 'A service taken offline will have its button updated to reflect the change' do
17 | # # skip "Unfinished test"
18 | # # visit '/'
19 | # # end
20 | # #
21 | # # # Setup: At least one service in the offline state.
22 | # # # Steps:
23 | # # # Action 1: The service will be put back online
24 | # # # Result 1: The UI button will be updated by js to reflect the change
25 | # # test 'A newly onlined service will have its button updated to reflect the change' do
26 | # # skip "Unfinished test"
27 | # # visit '/'
28 | # # end
29 | # #
30 | # # # Setup: A Plex service in the online state.
31 | # # # Steps:
32 | # # # Action 1: A new session will started
33 | # # # Result 1: The UI will have the new session added to the carousel
34 | # # test 'A newly started Plex Session will show in the carousel' do
35 | # # skip "Unfinished test"
36 | # # visit '/'
37 | # # end
38 | # #
39 | # # # Setup: A Plex service in the online state. A session is in progress.
40 | # # # Steps:
41 | # # # Action 1: The session will be stopped
42 | # # # Result 1: The UI will have the session removed from the carousel
43 | # # test 'A stoppped Plex Session will be removed from the carousel' do
44 | # # skip "Unfinished test"
45 | # # visit '/'
46 | # # end
47 | # #
48 | # # # Setup: A Plex service in the online state.
49 | # # # Steps:
50 | # # # Action 1: Add content to the Plex server
51 | # # # Result 1: The UI will have the newly added content added to the carousel
52 | # # test 'A newly added Plex Media Item will show in the carousel' do
53 | # # skip "Unfinished test"
54 | # # visit '/'
55 | # # end
56 | #
57 | #
58 | # # # Setup: A Plex service in the online state. PS has a bad token.
59 | # # # Steps:
60 | # # # Action 1: update_plex_data from Plex server
61 | # # # Result 1: The server returns a 401. The UI displays an error message.
62 | # # test 'An expired token will raise an error in the UI' do
63 | # #
64 | # # end
65 | #
66 | #
67 | # end
68 |
--------------------------------------------------------------------------------
/test/integration/site_layout_test.rb:
--------------------------------------------------------------------------------
1 | # require 'test_helper'
2 | #
3 | #
4 | # class SiteLayoutTest < ActionDispatch::IntegrationTest
5 | # keywords = %w(Plex-Board Services Config Status About)
6 | #
7 | # def teardown
8 | # super
9 | # Capybara.reset_sessions!
10 | # Capybara.use_default_driver
11 | # end
12 | #
13 | #
14 | # # Capybara::Screenshot.screenshot_and_save_page
15 | #
16 | #
17 | # # test 'check index for all expected keywords' do
18 | # # skip 'This test ruins everything.'
19 | # # # begin
20 | # # VCR.insert_cassette 'check_index_for_all_expected_keywords'
21 | # # # skip 'Need to figure out fixtures first, and get vcr captures...'
22 | # # visit '/'
23 | # # keywords.each do |word|
24 | # # assert page.has_content?(word), "#{word} was missing from \"/\""
25 | # # end
26 | # # assert page.has_title?('Plex-Board'), '"Plex-Board" was not the title for "/"'
27 | # # # ensure
28 | # # Capybara::Screenshot.screenshot_and_save_page
29 | # # VCR.eject_cassette
30 | # # # end
31 | # # end
32 | #
33 | # # test 'Check carousel for carousel items' do
34 | # # visit '/'
35 | # # assert page.has_selector?('#carousel-inner'), '#Carousel-inner was missing from page'
36 | # # end
37 | # end
38 |
--------------------------------------------------------------------------------
/test/integration_test_config_files/example_service_test_config.yml:
--------------------------------------------------------------------------------
1 | # This file is used to describe your real-life local plex server so it can be used for testing.
2 | # The actual service_test_config.yml file is not intended to be used after cassettes recordings of
3 | # interactions with a Plex Server are added to the test/fixtures/cassettes/ folder
4 |
5 | plex_server_1:
6 | ip: 127.0.0.1
7 | port: 32400
8 | url: https://127.0.0.1:32400/web
9 | username: bob
10 | password: 1234
11 |
12 | # Future usages could look like this:
13 | couchpotato_server_1:
14 | ip: 127.0.0.1
15 | port: 5050
16 | url: https://127.0.0.1:5050
17 |
--------------------------------------------------------------------------------
/test/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/test/mailers/.keep
--------------------------------------------------------------------------------
/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/test/models/.keep
--------------------------------------------------------------------------------
/test/models/plex_object_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_objects
4 | #
5 | # id :integer not null, primary key
6 | # image :string
7 | # thumb_url :string not null
8 | # description :text
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # plex_object_flavor_id :integer
12 | # plex_object_flavor_type :string
13 | # media_title :string not null
14 | #
15 |
16 | require 'test_helper'
17 |
18 | class PlexObjectTest < ActiveSupport::TestCase
19 |
20 | test 'plex_objects should be valid' do
21 | assert @plex_object_session_2.valid?
22 | assert @plex_object_session_1.valid?
23 | assert @plex_object_session_3.valid?
24 | assert @plex_object_recently_added_1.valid?
25 | end
26 |
27 | # test 'plex_object with no plex_session should not be valid' do
28 | # skip('This test needs more thought')
29 | # @plex_object_session_1.plex_object_flavor = nil
30 | # assert_not @plex_object_session_1.valid?, 'Plex object should not be valid if there is no parent plex session'
31 | # end
32 |
33 | test 'plex_object media_title must not be blank' do
34 | @plex_object_session_1.media_title = nil
35 | assert_not @plex_object_session_1.valid?, 'media_title should not be allowed to be nil'
36 | @plex_object_session_1.media_title = ''
37 | assert_not @plex_object_session_1.valid?, 'media_title should not be allowed to be an empty string'
38 | end
39 |
40 | test 'user_name should not be allowed to be whitespace only' do
41 | @plex_object_session_1.media_title = ' '
42 | assert_not @plex_object_session_1.valid?, 'media_title should not be allowed to be a whitespace string'
43 | end
44 |
45 | test 'plex_object should successfully retrieve image' do
46 | # Temporary until I figure out why this directory doesn't get created in proper time.
47 | unless File.directory? Rails.root.join 'test/test_images'
48 | skip 'The test/test_images folder does not exist. This test will probably fail.'
49 | end
50 | assert @plex_object_session_1.delete_thumbnail, 'Deleting thumbnail failed'
51 | assert_not File.file?(Rails.root.join 'test/test_images', (@plex_object_session_1.id.to_s + '.jpeg')),
52 | 'Image file should not be present'
53 | assert_not_nil @plex_object_session_1.get_img, 'Image file was not retrieved'
54 | assert File.file?(Rails.root.join 'test/test_images', (@plex_object_session_1.id.to_s + '.jpeg')),
55 | 'Image file was not found'
56 | end
57 |
58 | test 'destroying a plex_object will delete the associated image' do
59 | # Temporary until I figure out why this directory doesn't get created in proper time.
60 | unless File.directory? Rails.root.join 'test/test_images'
61 | skip 'The test/test_images folder does not exist. This test will probably fail.'
62 | end
63 | assert_not_nil @plex_object_session_1.get_img, 'Image file was not retrieved'
64 | assert File.file?(Rails.root.join 'test/test_images', (@plex_object_session_1.id.to_s + '.jpeg')),
65 | 'Image file was not found'
66 | assert @plex_object_session_1.destroy, 'Destroying the session failed'
67 | assert_not File.file?(Rails.root.join 'test/test_images', (@plex_object_session_1.id.to_s + '.jpeg')),
68 | 'The image file was not deleted'
69 | end
70 |
71 | # test 'destroying a plex_object with a nil image will be successful' do
72 | # ps = Fabricate(:plex_service)
73 | # # ps.plex_recently_added.plex_object.image = nil
74 | #
75 | # # assert(ps.plex_recently_added.destroy, 'The PlexObject was not destroyed')
76 | # end
77 | end
78 |
--------------------------------------------------------------------------------
/test/models/plex_recently_added_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_recently_addeds
4 | #
5 | # id :integer not null, primary key
6 | # added_date :datetime not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | # plex_service_id :integer
10 | # uuid :string not null
11 | #
12 |
13 | require 'test_helper'
14 |
15 | class PlexRecentlyAddedTest < ActiveSupport::TestCase
16 | test 'plex_recently_addeds should be valid' do
17 | assert @plex_service_w1ra_pra_1.valid?, 'plex_service_w1ra_pra_1 was not valid'
18 | end
19 |
20 | test 'added_date should be present' do
21 | @plex_service_w1ra_pra_1.added_date = ''
22 | @plex_service_w1ra_pra_1.reload
23 | assert @plex_service_w1ra_pra_1.valid?, 'PRA was valid with blank added_date'
24 | @plex_service_w1ra_pra_1.added_date = nil
25 | @plex_service_w1ra_pra_1.reload
26 | assert @plex_service_w1ra_pra_1.valid?, 'PRA was valid with nil added_date'
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/models/plex_session_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: plex_sessions
4 | #
5 | # id :integer not null, primary key
6 | # progress :integer not null
7 | # total_duration :integer not null
8 | # plex_user_name :string
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # session_key :string not null
12 | # plex_service_id :integer
13 | # stream_type :string not null
14 | #
15 |
16 | require 'test_helper'
17 |
18 | class PlexSessionTest < ActiveSupport::TestCase
19 |
20 | test 'sessions should be valid' do
21 | assert @plex_service_w1sess_session_1.valid?, 'Session_one was invalid'
22 | assert @plex_service_w2sess_session_1.valid?, 'Session_two was invalid'
23 | assert @plex_service_w2sess_session_2.valid?, 'Session_three was invalid'
24 | end
25 |
26 | test 'plex_session should have progress' do
27 | plex_session = @plex_service_w1sess_session_1
28 | plex_session.progress = nil
29 | assert_not plex_session.valid?
30 | end
31 |
32 | test 'plex_session should have total_duration' do
33 | plex_session = @plex_service_w1sess_session_1
34 | plex_session.total_duration = nil
35 | assert_not plex_session.valid?
36 | end
37 |
38 | test 'plex_user_name should be present' do
39 | @plex_service_w1sess_session_1.plex_user_name = nil
40 | assert_not @plex_service_w1sess_session_1.valid?, 'plex_user_name should not be nil'
41 | @plex_service_w1sess_session_1.plex_user_name = ''
42 | assert_not @plex_service_w1sess_session_1.valid?, 'plex_user_name should not be empty string'
43 | end
44 |
45 | test 'user_name should not be allowed to be whitespace only' do
46 | @plex_service_w1sess_session_1.plex_user_name = ' '
47 | assert_not @plex_service_w1sess_session_1.valid?, 'plex_user_name should not be valid with whitespace string'
48 | end
49 |
50 | test 'session should be unique' do
51 | duplicate_session = @plex_service_w1sess_session_1.dup
52 | @plex_service_w1sess_session_1.save
53 | assert_not duplicate_session.valid?, 'Duplicate session should not be valid'
54 | end
55 |
56 | test 'session will correctly identify stream_type Stream' do
57 | assert_equal('Stream', PlexSession.determine_stream_type('copy'),
58 | 'copy videoDecision was not correctly translated to Stream')
59 | assert_equal('Stream', PlexSession.determine_stream_type('COPY'),
60 | 'COPY videoDecision was not correctly translated to Stream')
61 | end
62 |
63 | test 'session will correctly identify stream_type Transcode' do
64 | assert_equal('Transcode', PlexSession.determine_stream_type('transcode'),
65 | 'transcode videoDecision was not correctly translated to Transcode')
66 | assert_equal('Transcode', PlexSession.determine_stream_type('TRANSCODE'),
67 | 'TRANSCODE videoDecision was not correctly translated to Transcode')
68 | end
69 |
70 | test 'session will correctly default stream_type nil or empty to Stream' do
71 | assert_equal('Stream', PlexSession.determine_stream_type(''),
72 | 'empty string videoDecision was not correctly translated to Stream')
73 | assert_equal('Stream', PlexSession.determine_stream_type(nil),
74 | 'nil videoDecision was not correctly translated to Stream')
75 | end
76 |
77 | #Tests for Plex integration
78 |
79 |
80 | end
81 |
--------------------------------------------------------------------------------
/test/models/server_load_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: server_loads
4 | #
5 | # id :integer not null, primary key
6 | # name :string not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | # service_host_id :integer
10 | #
11 |
12 | require 'test_helper'
13 |
14 | class ServerLoadTest < ActiveSupport::TestCase
15 | # test "the truth" do
16 | # assert true
17 | # end
18 | end
19 |
--------------------------------------------------------------------------------
/test/models/weather_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: weathers
4 | #
5 | # id :integer not null, primary key
6 | # api_key :string
7 | # latitude :float
8 | # longitude :float
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # address :string
12 | # units :text
13 | # city :string
14 | # state :string
15 | #
16 |
17 | require 'test_helper'
18 |
19 | class WeatherTest < ActiveSupport::TestCase
20 | test 'weather with lat and long is valid' do
21 | weather = Fabricate(:weather)
22 | assert weather.valid?, "Weather with lat: #{weather.latitude} and long: #{weather.longitude} was not valid."
23 | end
24 |
25 | test 'a provided address will be converted to lat and long' do
26 | weather = Fabricate.build(:weather)
27 | weather.latitude = nil
28 | weather.longitude = nil
29 | weather.address = '2300 Traverwood Dr, Ann Arbor, MI 48105'
30 | weather.save!
31 | assert_equal 42.306642, weather.latitude
32 | assert_equal -83.71466199999999, weather.longitude
33 | assert weather.valid?, "Weather with address: \"#{weather.address}\" should have been valid"
34 | end
35 |
36 | test 'weather with only latitude is not valid' do
37 | weather = Fabricate.build(:weather)
38 | weather.longitude = nil
39 | weather.latitude = 35.2341
40 | assert_not weather.valid?, 'Weather should not be valid if only supplied latitude.'
41 | end
42 |
43 | test 'weather with only longitude is not valid' do
44 | weather = Fabricate.build(:weather)
45 | weather.longitude = 88.0515
46 | weather.latitude = nil
47 | assert_not weather.valid?, 'Weather should not be valid if only supplied longitude.'
48 | end
49 |
50 | test 'weather with no api key is not valid' do
51 | weather = Fabricate.build(:weather)
52 | weather.api_key = nil
53 | assert_not weather.valid?, 'Weather should not be valid if there is no api key.'
54 | end
55 |
56 | test 'an invalid address will throw a RecordInvalid exception' do
57 | expected_message = 'Fetching the precise location failed. Please check that the address is valid.'
58 | weather = Fabricate.build(:weather)
59 | weather.longitude = nil
60 | weather.latitude = nil
61 | weather.address = 'This is not a valid address'
62 |
63 | exception = assert_raises(ActiveRecord::RecordInvalid) { weather.save! }
64 | assert exception.message.include?(expected_message),
65 | "The exception didn't mention the address error message as expected. \nGot: '#{exception.message}'\nwhen expecting: '#{expected_message}'."
66 | end
67 |
68 | test 'an nil address will throw a RecordInvalid exception' do
69 | expected_message = 'Fetching the precise location failed. Please check that the address is valid.'
70 | weather = Fabricate.build(:weather)
71 | weather.longitude = nil
72 | weather.latitude = nil
73 | weather.address = nil
74 |
75 | exception = assert_raises(ActiveRecord::RecordInvalid) { weather.save! }
76 | assert exception.message.include?(expected_message),
77 | "The exception didn't mention the address error message as expected. \nGot: '#{exception.message}'\nwhen expecting: '#{expected_message}'."
78 | end
79 |
80 | test 'weather can be retrieved with valid parameters' do
81 | weather = Fabricate(:weather)
82 | weather.latitude = 42.306642
83 | weather.longitude = -83.71466199999999
84 | weather.api_key = '0ca1d9fc73742b2dca0dc2643d89994d'
85 | assert_not_nil weather.get_weather, 'weather.get_weather should not return nil for a valid weather object'
86 | assert_equal 42.306642, weather.get_weather['latitude']
87 | assert_equal -83.71466199999999, weather.get_weather['longitude']
88 | end
89 | end
90 |
--------------------------------------------------------------------------------
/travisSetup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | mv example.server_config.yml server_config.yml
3 | SECRETS="config/secrets.yml"
4 | SECRET="$(bundle exec rake secret)"
5 | BOGUS="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
6 | # rm $SECRETS
7 | echo -e "development:\n secret_key_base: " ${BOGUS} "\n" >> ${SECRETS}
8 | echo -e "test:\n secret_key_base: " ${BOGUS} "\n" >> ${SECRETS}
9 | echo -e "production:\n secret_key_base: " ${SECRET} >> ${SECRETS}
10 | # rm db/*sqlite3
11 | mkdir -p log/
12 | touch log/test.log
13 | bundle exec rake db:create
14 | bundle exec rake db:migrate
15 | mkdir -p public/images
16 | mkdir -p test/test_images
17 |
18 |
--------------------------------------------------------------------------------
/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | case "$(uname -s)" in
5 |
6 | Darwin)
7 | OS="Mac OSX"
8 | ;;
9 |
10 | Linux)
11 | OS="Linux"
12 | ;;
13 |
14 | CYGWIN*|MINGW32*|MSYS*)
15 | OS="Windows"
16 | ;;
17 |
18 | *)
19 | OS="Unknown"
20 | ;;
21 | esac
22 |
23 | cd "$(dirname "$0")"
24 | if [[ "$OS" == "Windows" ]]; then
25 | printf "\nSince we're on Windows the local Gemfile.lock will be deleted prevent cross-platform conflicts.\n"
26 | rm Gemfile.lock
27 | fi
28 |
29 | printf "\nPulling down the latest for the current branch.\n"
30 | git pull
31 | printf "\nExecuting the serverSetup.sh script to recompile assets and update dependencies.\n"
32 | source serverSetup.sh
33 |
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/vendor/assets/javascripts/.keep
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scytherswings/Plex-Board/c83fd13223d33b6565fd30fd1c237549800708c9/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------